Hi,
Happy New Year! I hope this year brings fewer bugs than the last.
SDK Version: 2.7.0
Board: Seeed Studio XIAO nRF52840 Sense
System Description:
I have a setup with one BLE scanner and multiple BLE peripherals, using the Nordic UART Service (NUS) for data exchange. My goal is to ensure that the scanner always reconnects to the same peripheral once a connection is established. Switching to a different peripheral should only happen when a button is pressed.
To achieve this, I implemented non-volatile storage (NVS) and scanner filters (BT_SCAN_FILTER_TYPE_UUID
, BT_UUID_NUS_SERVICE
, BT_SCAN_FILTER_TYPE_ADDR
). The logic works as follows:
- If the NVS doesn't contain a saved BLE address, the scanner connects to the first peripheral that matches the filters (UUID and NUS service).
- Upon successful connection, the BLE address is saved in the NVS for future reconnections.
Issue:
Initially, the system worked as expected. However, after switching to a different peripheral, I now encounter an error with code 2 (BT_HCI_DEDICATED_BONDING 0x02
). I’m unclear about the cause of this error and its implications. Even switching back does not work anymore.
Here’s what I see in the console:
Questions:
- What might I be doing wrong?
- Is there a better or more efficient way to achieve this functionality?
Relevant Code:
Below is the portion of my code related to connection establishment, other code I omitted:
#include <stdlib.h> #include <stddef.h> #include <errno.h> #include <zephyr/types.h> #include <zephyr/kernel.h> #include <zephyr/sys/printk.h> #include <zephyr/sys/byteorder.h> #include <zephyr/bluetooth/hci.h> #include <zephyr/bluetooth/conn.h> #include <zephyr/bluetooth/uuid.h> #include <zephyr/bluetooth/gatt.h> #include <zephyr/bluetooth/bluetooth.h> #include <bluetooth/services/nus.h> #include <bluetooth/services/nus_client.h> #include <bluetooth/gatt_dm.h> #include <bluetooth/scan.h> #include <dk_buttons_and_leds.h> #include <zephyr/sys/reboot.h> #include "storage_functions.h" #include "gpio_functions.h" static void _start_scan_init(void); static void _start_scan_start(void); struct bt_conn *central_conn; static struct bt_nus_client nus_client; static bt_addr_le_t global_addr; // working address to read from the nvs to checkh against the filter static bt_addr_le_t ble_address_empty; // container for presenting a empty ble address static bool ble_is_connected= false; void update_the_address(struct k_work *work){ int err; char addr[BT_ADDR_LE_STR_LEN]; static bt_addr_le_t temp_addr; bt_addr_le_to_str(&global_addr, addr, sizeof(addr)); err = storage_write(BLE_ADDRESS_ID,(uint8_t*)&global_addr, sizeof(global_addr)); if (err) { printk("Save the ble address to the storage. bytes: %d, addr: %s.\n", err, addr); } else{ err = storage_read(BLE_ADDRESS_ID,(uint8_t*)&temp_addr, sizeof(temp_addr)); bt_addr_le_to_str(&global_addr, addr, sizeof(addr)); printk("storage write returned 0 for ble address: %s, bytes:%d.\n", addr, err); } } K_WORK_DEFINE(update_the_address_work, update_the_address); static void discovery_complete(struct bt_gatt_dm *dm, void *context) { int err; struct bt_nus_client *nus = context; printk("Service discovery completed.\n"); bt_gatt_dm_data_print(dm); bt_nus_handles_assign(dm, nus); err = bt_nus_subscribe_receive(nus); if (err) { printk("bt_nus_subscribe_receive failed (err %d)\n", err); } bt_gatt_dm_data_release(dm); } static void discovery_service_not_found(struct bt_conn *conn, void *context) { printk("Service not found.\n"); _start_scan_start(); } static void discovery_error(struct bt_conn *conn, int err, void *context) { printk("Error while discovering GATT database: (%d).\n", err); } // gatt discovery manager struct bt_gatt_dm_cb discovery_cb = { .completed = discovery_complete, .service_not_found = discovery_service_not_found, .error_found = discovery_error, }; static void _gatt_discover(struct bt_conn *conn) { int err; if (conn != central_conn) { return; } err = bt_gatt_dm_start(conn, BT_UUID_NUS_SERVICE, &discovery_cb, &nus_client); if (err) { printk("could not start the discovery procedure, error code: %d.\n", err); } } static void scan_filter_match(struct bt_scan_device_info *device_info, struct bt_scan_filter_match *filter_match, bool connectable) { char addr_str[BT_ADDR_LE_STR_LEN]; bt_addr_le_copy(&global_addr, device_info->recv_info->addr); bt_addr_le_to_str(&global_addr, addr_str, sizeof(addr_str)); printk("scan filter matched with the address %s, match %d \n", addr_str, filter_match->name.match); } void scan_connecting_error(struct bt_scan_device_info *device_info) { printk("Scan Connecting Error.\n"); k_sleep(K_SECONDS(7)); } static void scan_connecting(struct bt_scan_device_info *device_info, struct bt_conn *conn) { central_conn = bt_conn_ref(conn); printk("Connecting to the peripheral.\n"); } BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL, scan_connecting_error, scan_connecting); static void connected(struct bt_conn *conn, uint8_t conn_err) { int _err; ARG_UNUSED(_err); bt_addr_le_t temp_ble_address; bt_addr_le_copy(&temp_ble_address, bt_conn_get_dst(conn)); //struct bt_conn_info info; char addr[BT_ADDR_LE_STR_LEN]; 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); if(central_conn == conn){ bt_conn_disconnect(central_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); bt_conn_unref(central_conn); central_conn = NULL; _start_scan_start(); } return; } printk("Connected to addr: %s\n", addr); _gatt_discover(conn); _err = bt_scan_stop(); if ((!_err) && (_err != -EALREADY)) { printk("Stop LE scan failed (err %d)\n", _err); } ble_is_connected= true; _err = storage_read(BLE_ADDRESS_ID,(uint8_t*)&temp_ble_address, sizeof(temp_ble_address)); // compare it, if it is equal to the empty ble address, start the work, otherwise do not do anything if(bt_addr_le_eq(&temp_ble_address, &ble_address_empty)){ k_work_submit(&update_the_address_work); } else{ printk("No storage write performed for ble address: %s.\n", addr); } } static void disconnected(struct bt_conn *conn, uint8_t reason) { char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); printk("Disconnected: %s (reason 0x%02x) led pwm increased\n", addr, reason); if (central_conn != conn) { return; } bt_conn_unref(central_conn); central_conn = NULL; ble_is_connected= false; _start_scan_start(); } BT_CONN_CB_DEFINE(conn_callbacks) = { .connected = connected, .disconnected = disconnected, }; static int nus_client_init(void) { int err; struct bt_nus_client_init_param init = { .cb = { .received = ble_data_received, //.sent = ble_data_sent, } }; err = bt_nus_client_init(&nus_client, &init); if (err) { printk("NUS Client initialization failed (err %d)\n", err); return err; } printk("NUS Client module initialized\n"); return err; } //#pragma GCC pop_options static void _start_scan_init(void) { int err; bt_addr_le_t _temp_ble_address = {0}; char addr[BT_ADDR_LE_STR_LEN]; //match_all parameters set to true it's not working for combined filtering bool match_all = true; static struct bt_le_scan_param scan_param = { .type = BT_LE_SCAN_TYPE_ACTIVE, .interval = BT_GAP_SCAN_FAST_INTERVAL, .window = BT_GAP_SCAN_FAST_WINDOW, .options = BT_LE_SCAN_OPT_NONE, .timeout = 0, }; static struct bt_scan_init_param scan_init = { .connect_if_match = true, .scan_param = &scan_param, .conn_param = NULL }; bt_scan_init(&scan_init); bt_scan_cb_register(&scan_cb); err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_UUID, BT_UUID_NUS_SERVICE); if (err) { printk("Scanning filters cannot be set (err %d)\n", err); return; } err = storage_read(BLE_ADDRESS_ID,(uint8_t*)&_temp_ble_address, sizeof(_temp_ble_address)); bt_addr_le_to_str(&_temp_ble_address, addr, sizeof(addr)); printk("Current address filter:%s, bytes read: %d.\n", addr, err); if(!bt_addr_le_eq(&_temp_ble_address, &ble_address_empty)){ // add a new type of the filter of the scanning err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_ADDR, &_temp_ble_address); if (err) { printk("Scanning filters cannot be set (err %d)\n", err); return; } err = bt_scan_filter_enable(BT_SCAN_UUID_FILTER | BT_SCAN_ADDR_FILTER, match_all); if (err) { printk("Filters cannot be turned on (err %d)\n", err); return; } } else{ printk("Not adding address filter.\n"); // enable the filter only for the BLE NUS UUID. err = bt_scan_filter_enable(BT_SCAN_UUID_FILTER, match_all); if (err) { printk("Filters cannot be turned on (err %d)\n", err); return; } } printk("Scan module initialized.\n"); } void _start_scan_start(void){ // start scanning int _err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE); if (_err) { printk("Scanning failed to start (err %d)\n", _err); return; } printk("Scan module started.\n"); } void bnt_callback(int btn_counter){ //runs in thread mode printk("bnt count: %d\n", btn_counter); switch (btn_counter) { case DELETE_NVS_ENTRY: printk("Emptying the BLE address in nvs.\n"); int _err = storage_write(BLE_ADDRESS_ID,(uint8_t*)&ble_address_empty, sizeof(ble_address_empty)); if (_err) { printk("storage has written so many bytes: %d.\n", _err); } bt_scan_stop(); bt_conn_disconnect(central_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); bt_conn_unref(central_conn); central_conn = NULL; k_sleep(K_SECONDS(5)); // reset the system sys_reboot(0); break; default: break; } } int main(void) { int err; printk("Application started, board: %s\n", CONFIG_BOARD); err = storage_init(); if (err) { printk("storage init failed (err %d)\n", err); return err; } k_sleep(K_MSEC(1)); init_gpio_functions(bnt_callback); dk_set_led(DK_LED1, 0); dk_set_led(DK_LED2, 0); dk_set_led(DK_LED3, 0); dk_set_led(DK_LED4, 0); led_green_for_ble_connection_check = NO_ACTION; deactivating_actuators_for_period_of_time = NO_ACTION; err = bt_enable(NULL); if (err) { printk("Bluetooth init failed (err %d)\n", err); return err; } err = nus_client_init(); if (err != 0) { printk("nus_client_init failed (err %d)\n", err); return 0; } _start_scan_init(); _start_scan_start(); for (;;) {} return 0; }
Thank you in advance for the help!