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
  • Hi,

    For this you would to first scan in order to detect nearby BLE devices and then connect based on any criteria, say, device name, advertised services, signal strength or any other parameter of your choice. 

    Regards,

    Priyanka

  • Hi,

    I have tried with BLE examples where I receive information from different devices around me.

    I have also tried setting the MAC address of the device I'm interested in, which is a HR sensor, and that worked too.

    Now, what I would like to do is first detect the nearby devices and then, after that, be able to select the device(s) I want to connect to, in order to receive information only from them.

    At the moment, I'm trying to select the sensor I'm interested in by entering the MAC address via keyboard, but I am not getting the correct result.

    Thanks

  • Hi,

    Is it possible to share the code snippet where you try this? Do you get any errors when trying this?

    -Priyanka

  • #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.

Reply
  • #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.

Children
No Data
Related