diff --git a/README.md b/README.md index d89f9a6..f1b56b8 100644 --- a/README.md +++ b/README.md @@ -146,3 +146,10 @@ make html The output will be stored in the ``_build_sphinx`` folder. You may check for other output formats other than HTML by running ``make help``. + + +## Resources + +This was a useful tutorial for getting a bunch of bluetooth stuff working: +- https://academy.nordicsemi.com/courses/bluetooth-low-energy-fundamentals/lessons/lesson-4-bluetooth-le-data-exchange/topic/blefund-lesson-4-exercise-1/ +- Source code: https://github.com/NordicDeveloperAcademy/bt-fund/blob/main/l4/l4_e1_sol/src/my_lbs.h \ No newline at end of file diff --git a/firmware/app/src/bt_services.c b/firmware/app/src/bt_services.c new file mode 100644 index 0000000..f618b8a --- /dev/null +++ b/firmware/app/src/bt_services.c @@ -0,0 +1,64 @@ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "bt_services.h" + +#include + +LOG_MODULE_DECLARE(main, CONFIG_APP_LOG_LEVEL); + +static sensors_raw_t sensors; + +void set_sensors(const sensors_raw_t *values) +{ + sensors = *values; +} + +// Callback definitions +static ssize_t read_sensors(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, + uint16_t len, uint16_t offset) +{ + const char *value = attr->user_data; + size_t size = sizeof(sensors_raw_t); + + LOG_INF("Attribute read, handle: %u, conn: %p, bytes: %d", attr->handle, (void *)conn, size); + + return bt_gatt_attr_read(conn, attr, buf, len, offset, value, size); +} + +// Service declaration + +static ssize_t read_string(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) +{ + const char *value = attr->user_data; + LOG_INF("String read, handle: %u, conn: %p\t%s", attr->handle, (void *)conn, value); + return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data, strlen((char *)attr->user_data)); +} + +BT_GATT_SERVICE_DEFINE(my_lbs_svc, BT_GATT_PRIMARY_SERVICE(BT_UUID_IMU), + // Read raw sensor values + BT_GATT_CHARACTERISTIC(BT_UUID_IMU_SENSORS, + BT_GATT_CHRC_READ, + BT_GATT_PERM_READ, + read_sensors, + NULL, + &sensors), + BT_GATT_DESCRIPTOR(BT_UUID_GATT_CUD, + BT_GATT_PERM_READ, + read_string, + NULL, + "Read raw sensor values"), + // TODO: add characteristic to read state estimate +); diff --git a/firmware/app/src/bt_services.h b/firmware/app/src/bt_services.h new file mode 100644 index 0000000..5c258fa --- /dev/null +++ b/firmware/app/src/bt_services.h @@ -0,0 +1,36 @@ +#ifndef BT_SERVICES_H_ +#define BT_SERVICES_H_ + +// NOTE: these are randomly generated for development +// https://www.uuidgenerator.net/ +#define BT_UUID_IMU_VAL BT_UUID_128_ENCODE(0xc77cb872, 0xa346, 0x40bf, 0x97a5, 0x3223f6f0a47c) +#define BT_UUID_IMU_SENSORS_VAL BT_UUID_128_ENCODE(0x99b59474, 0x5570, 0x464b, 0xbe37, 0x64465aa050fd) +// #define BT_UUID_IMU_EULER_VAL BT_UUID_128_ENCODE() +// #define BT_UUID_IMU_QUATERNION_VAL BT_UUID_128_ENCODE() + +#define BT_UUID_IMU BT_UUID_DECLARE_128(BT_UUID_IMU_VAL) +#define BT_UUID_IMU_SENSORS BT_UUID_DECLARE_128(BT_UUID_IMU_SENSORS_VAL) + +typedef struct +{ + double accel_x; ///< [m/s] + double accel_y; ///< [m/s] + double accel_z; ///< [m/s] + double gyro_x; + double gyro_y; + double gyro_z; + double mag_x; + double mag_y; + double mag_z; +} sensors_raw_t; + +typedef sensors_raw_t (*sensors_cb_t)(void); + +struct my_imu_cb +{ + sensors_cb_t sensors_cb; +}; + +void set_sensors(const sensors_raw_t *values); + +#endif // BT_SERVICES_H_ \ No newline at end of file diff --git a/firmware/app/src/main.c b/firmware/app/src/main.c index 282df25..429f4fe 100644 --- a/firmware/app/src/main.c +++ b/firmware/app/src/main.c @@ -7,6 +7,8 @@ #include #include +#include +#include "bt_services.h" // #include // #include @@ -317,16 +319,28 @@ int thread_sensors(void) uint8_t pct_bat = 100.0 * (vbat - 3.3) / (4.2 - 3.3); bt_bas_set_battery_level(pct_bat); + sensors_raw_t values; + values.accel_x = accel_x.val1 + accel_x.val2 * 1e-6; + values.accel_y = accel_y.val1 + accel_y.val2 * 1e-6; + values.accel_z = accel_z.val1 + accel_z.val2 * 1e-6; + values.gyro_x = gyro_x.val1 + gyro_x.val2 * 1e-6; + values.gyro_y = gyro_y.val1 + gyro_y.val2 * 1e-6; + values.gyro_z = gyro_z.val1 + gyro_z.val2 * 1e-6; + values.mag_x = NAN; + values.mag_y = NAN; + values.mag_z = NAN; + set_sensors(&values); + sprintf(str_v, "V :%7.5f", vbat); sprintf(str_i, "I :%7.5f", current.val1 + current.val2 * 1e-6); sprintf(str_p, "P :%7.4f", pressure.val1 + pressure.val2 * 1e-6); sprintf(str_t, "T :%7.4f", temperature.val1 + temperature.val2 * 1e-6); - sprintf(str_ax, "AX:%+7.3f", accel_x.val1 + accel_x.val2 * 1e-6); - sprintf(str_ay, "AY:%+7.3f", accel_y.val1 + accel_y.val2 * 1e-6); - sprintf(str_az, "AZ:%+7.3f", accel_z.val1 + accel_z.val2 * 1e-6); - sprintf(str_gx, "GX:%+7.3f", gyro_x.val1 + gyro_x.val2 * 1e-6); - sprintf(str_gy, "GY:%+7.3f", gyro_y.val1 + gyro_y.val2 * 1e-6); - sprintf(str_gz, "GZ:%+7.3f", gyro_z.val1 + gyro_z.val2 * 1e-6); + sprintf(str_ax, "AX:%+7.3f", values.accel_x); + sprintf(str_ay, "AY:%+7.3f", values.accel_y); + sprintf(str_az, "AZ:%+7.3f", values.accel_z); + sprintf(str_gx, "GX:%+7.3f", values.gyro_x); + sprintf(str_gy, "GY:%+7.3f", values.gyro_y); + sprintf(str_gz, "GZ:%+7.3f", values.gyro_z); sprintf(str_az_ref, "Zr:%+7.3f", accel_z_ref.val1 + accel_z_ref.val2 * 1e-6); sprintf(str_h, "H :%7.3f", humidity.val1 + humidity.val2 * 1e-6); diff --git a/firmware/app/src/peripheral_gatt_write.c b/firmware/app/src/peripheral_gatt_write.c index be59ef9..44013cd 100644 --- a/firmware/app/src/peripheral_gatt_write.c +++ b/firmware/app/src/peripheral_gatt_write.c @@ -13,6 +13,8 @@ #include #include +#include "bt_services.h" + extern int mtu_exchange(struct bt_conn *conn); extern int write_cmd(struct bt_conn *conn); extern struct bt_conn *conn_connected; @@ -29,7 +31,8 @@ static const struct bt_data ad[] = { static unsigned char url_data[] = "\x17//brendanhaines.com"; static const struct bt_data sd[] = { - BT_DATA(BT_DATA_URI, url_data, sizeof(url_data) - 1), // -1 to strip \0 + // BT_DATA(BT_DATA_URI, url_data, sizeof(url_data) - 1), // -1 to strip \0 + BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_IMU_VAL), }; static void mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx) diff --git a/python/test_basic.py b/python/test_basic.py new file mode 100644 index 0000000..1530919 --- /dev/null +++ b/python/test_basic.py @@ -0,0 +1,39 @@ +# %% imports +import asyncio +import time + +import numpy as np +from bleak import BleakClient, BleakScanner +from matplotlib import pyplot as plt + +# %% +devices = await BleakScanner.discover() +for d in devices: + print(d) + + +# %% +address = "D7:FC:DA:4B:02:D7" +MODEL_NBR_UUID = "2A24" +SENSORS_UUID = "99b594745570464bbe3764465aa050fd" + + +timeseries = list() +async with BleakClient(address) as client: + # model_number = await client.read_gatt_char(MODEL_NBR_UUID) + # print("Model Number: {0}".format("".join(map(chr, model_number)))) + start_time = time.time() + print("Starting capture...") + while time.time() < start_time + 20: + buffer = await client.read_gatt_char(SENSORS_UUID) + sensor_values = np.frombuffer(bytes(buffer), dtype=np.double) + timeseries.append(sensor_values) + print("DONE") + +timeseries = np.array(timeseries) + +# %% +plt.plot(timeseries) +plt.show() + +# %%