Interface nRF5340dk with external BLE sensors

I'm developing a system where I want to connect simultaneously to different BLE and ANT+ sensors. I'm using the nRF5340 DK and I would like to be able to select which sensors to connect to once I detect nearby devices, so I can receive only the information that interests me.

Parents Reply Children
  • #include <stdio.h>
    #include <stddef.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <zephyr/kernel.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/sys/byteorder.h>
    #include <zephyr/console/console.h>
    #include <zephyr/bluetooth/bluetooth.h>
    #include <zephyr/bluetooth/hci.h>
    #include <zephyr/bluetooth/conn.h>
    #include <zephyr/bluetooth/uuid.h>
    #include <zephyr/bluetooth/gatt.h>
    
    #define MAX_DEVICES 20  // Define MAX_DEVICES
    
    static struct bt_conn *default_conn;
    static struct bt_uuid_16 discover_uuid = BT_UUID_INIT_16(0);
    static struct bt_gatt_discover_params discover_params;
    static struct bt_gatt_subscribe_params subscribe_params;
    static bt_addr_le_t discovered_devices[MAX_DEVICES];
    static uint8_t device_count = 0;
    
    static int scan_start(void);
    
    static uint8_t notify_func(struct bt_conn *conn,
                               struct bt_gatt_subscribe_params *params,
                               const void *data, uint16_t length)
    {
        if (!data) {
            printk("[UNSUBSCRIBED]\n");
            params->value_handle = 0U;
            return BT_GATT_ITER_STOP;
        }
    
        uint8_t flags = ((uint8_t *)data)[0];
        uint8_t heart_rate;
        uint16_t heart_rate_16;
    
        if (flags & 0x01) {
            heart_rate_16 = sys_get_le16(&((uint8_t *)data)[1]);
            printk("Heart Rate: %u bpm\n", heart_rate_16);
        } else {
            heart_rate = ((uint8_t *)data)[1];
            printk("Heart Rate: %u bpm\n", heart_rate);
        }
    
        return BT_GATT_ITER_CONTINUE;
    }
    
    static uint8_t discover_func(struct bt_conn *conn,
                                 const struct bt_gatt_attr *attr,
                                 struct bt_gatt_discover_params *params)
    {
        int err;
    
        if (!attr) {
            printk("Discover complete\n");
            (void)memset(params, 0, sizeof(*params));
            return BT_GATT_ITER_STOP;
        }
    
        printk("[ATTRIBUTE] handle %u\n", attr->handle);
    
        if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_HRS)) {
            memcpy(&discover_uuid, BT_UUID_HRS_MEASUREMENT, sizeof(discover_uuid));
            discover_params.uuid = &discover_uuid.uuid;
            discover_params.start_handle = attr->handle + 1;
            discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
    
            err = bt_gatt_discover(conn, &discover_params);
            if (err) {
                printk("Discover failed (err %d)\n", err);
            }
        } else if (!bt_uuid_cmp(discover_params.uuid,
                                BT_UUID_HRS_MEASUREMENT)) {
            memcpy(&discover_uuid, BT_UUID_GATT_CCC, sizeof(discover_uuid));
            discover_params.uuid = &discover_uuid.uuid;
            discover_params.start_handle = attr->handle + 2;
            discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
            subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);
    
            err = bt_gatt_discover(conn, &discover_params);
            if (err) {
                printk("Discover failed (err %d)\n", err);
            }
        } else {
            subscribe_params.notify = notify_func;
            subscribe_params.value = BT_GATT_CCC_NOTIFY;
            subscribe_params.ccc_handle = attr->handle;
    
            err = bt_gatt_subscribe(conn, &subscribe_params);
            if (err && err != -EALREADY) {
                printk("Subscribe failed (err %d)\n", err);
            } else {
                printk("[SUBSCRIBED]\n");
            }
    
            return BT_GATT_ITER_STOP;
        }
    
        return BT_GATT_ITER_STOP;
    }
    
    static void connected(struct bt_conn *conn, uint8_t conn_err)
    {
        char addr[BT_ADDR_LE_STR_LEN];
        int err;
    
        bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
        if (conn_err) {
            printk("Failed to connect to %s (%u)\n", addr, conn_err);
    
            bt_conn_unref(default_conn);
            default_conn = NULL;
    
            scan_start();
            return;
        }
    
        printk("Connected: %s\n", addr);
    
        if (conn == default_conn) {
            memcpy(&discover_uuid, BT_UUID_HRS, sizeof(discover_uuid));
            discover_params.uuid = &discover_uuid.uuid;
            discover_params.func = discover_func;
            discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
            discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
            discover_params.type = BT_GATT_DISCOVER_PRIMARY;
    
            err = bt_gatt_discover(default_conn, &discover_params);
            if (err) {
                printk("Discover failed(err %d)\n", err);
                return;
            }
        }
    }
    
    static bool eir_found(struct bt_data *data, void *user_data)
    {
        printk("[AD]: %u data_len %u\n", data->type, data->data_len);
        return true;
    }
    
    static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
                             struct net_buf_simple *ad)
    {
        char dev[BT_ADDR_LE_STR_LEN];
    
        bt_addr_le_to_str(addr, dev, sizeof(dev));
        printk("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i\n",
               dev, type, ad->len, rssi);
    
        if (type == BT_HCI_ADV_IND || type == BT_HCI_ADV_DIRECT_IND) {
            bt_data_parse(ad, eir_found, (void *)addr);
    
            // Check if the device is already in the list
            for (int i = 0; i < device_count; i++) {
                if (bt_addr_le_cmp(&discovered_devices[i], addr) == 0) {
                    return; // Device already in the list
                }
            }
    
            // Store the discovered device
            if (device_count < MAX_DEVICES) {
                bt_addr_le_copy(&discovered_devices[device_count++], addr);
            }
        }
    }
    
    static int scan_start(void)
    {
        struct bt_le_scan_param scan_param = {
            .type       = BT_LE_SCAN_TYPE_ACTIVE,
            .options    = BT_LE_SCAN_OPT_NONE,
            .interval   = BT_GAP_SCAN_FAST_INTERVAL,
            .window     = BT_GAP_SCAN_FAST_WINDOW,
        };
    
        return bt_le_scan_start(&scan_param, device_found);
    }
    
    static void disconnected(struct bt_conn *conn, uint8_t reason)
    {
        char addr[BT_ADDR_LE_STR_LEN];
        int err;
    
        bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
        printk("Disconnected: %s (reason 0x%02x)\n", addr, reason);
    
        if (default_conn != conn) {
            return;
        }
    
        bt_conn_unref(default_conn);
        default_conn = NULL;
    
        err = scan_start();
        if (err) {
            printk("Scanning failed to start (err %d)\n", err);
        }
    }
    
    BT_CONN_CB_DEFINE(conn_callbacks) = {
        .connected = connected,
        .disconnected = disconnected,
    };
    
    void get_user_input(char *input, size_t size) {
        char *line = console_getline();
        if (line != NULL) {
            strncpy(input, line, size - 1);
            input[size - 1] = '\0'; // Ensure null-termination
        }
    }
    
    int main(void) {
        char input[100];
        int selected_index;
        int err;
    
        err = bt_enable(NULL);
        if (err) {
            printk("Bluetooth init failed (err %d)\n", err);
            return 0;
        }
    
        printk("Bluetooth initialized\n");
    
        err = scan_start();
        if (err) {
            printk("Scanning failed to start (err %d)\n", err);
            return 0;
        }
    
        printk("Scanning successfully started\n");
    
        k_sleep(K_SECONDS(10));  // Adjust the scan duration as needed
    
        bt_le_scan_stop();
        printk("Scanning stopped\n");
    
        // List discovered devices
        printk("Discovered devices:\n");
        for (int i = 0; i < device_count; i++) {
            char addr_str[BT_ADDR_LE_STR_LEN];
            bt_addr_le_to_str(&discovered_devices[i], addr_str, sizeof(addr_str));
            printk("[%d] %s\n", i, addr_str);
        }
    
        // Select device
        selected_index = -1;
        while (selected_index < 0 || selected_index >= device_count) {
            printk("Enter the number of the device to connect to: ");
            get_user_input(input, sizeof(input));
            selected_index = atoi(input);
        }
    
        // Connect to the selected device
        bt_addr_le_t *selected_device = &discovered_devices[selected_index];
        err = bt_conn_le_create(selected_device, BT_CONN_LE_CREATE_CONN,
                                BT_LE_CONN_PARAM_DEFAULT, &default_conn);
        if (err) {
            printk("Create connection failed (err %d)\n", err);
            return 0;
        }
    
        printk("Connecting to selected device...\n");
    
        return 0;
    }



    What I would like is to be able to enter the number of the device I want to connect to via the keyboard, so that I can integrate it into a user interface with a TFT LCD display in the future. The attached code does not give me an error, but when I run it and it lists all the found devices, it does not allow me to make the selection. I don't know if I need to modify something in the prj.config or CMakeLists.txt or if I need to add something else.

  • Hi,

    Please make sure that your console is initialized properly, say, the console_init function. You could also try adding a printk statement in your get_user_input function to make sure that it handles the console input correctly:

    void get_user_input(char *input, size_t size)

    {
    printk("Input: ");
    char *line = console_getline();
    if (line != NULL) {
    strncpy(input, line, size - 1);
    input[size - 1] = '\0'; // Ensure null-termination
    }
    }

    Also, could you attach your prj.conf?

    -Priyanka

Related