Hello there,
I'm designing a set of devices composed of a remote and 2 peripheral. The remote's job is to be connected to the 2 peripherals as a central and occasionnaly connect to a smartphone as a peripheral.
All of the devices are custom board, we already figured out the antenna matching which help to reduce bug. My development environment is :
- NCS & toolchain 3.0.1
- nRF52833 for all 3 devices
What is working :
- The advertising and the scanning
- The pairing process
- The discovering procedure
- Read, write and subscribe to gatt atribute
What is not working :
- Mainly the reconnect procedure
I succeed to implement accept list for peripheral and to open it when i need to thank to the lesson from Academy, but i struggle to make the reconnect works. It is crucial because all 3 devices are battery powered and i need to save energy.
In my understanding, there is 2 steps :
When no bond are available on the remote, i have to go though a scan with specific filtering and then connect / pair
################ # Board config # ################ CONFIG_EVENTS=y CONFIG_SMF=y CONFIG_HWINFO=y # Enable PWM led CONFIG_PWM=y CONFIG_NRFX_PWM0=y CONFIG_LED=y # Enable button CONFIG_INPUT=y CONFIG_INPUT_GPIO_KEYS=y # Enable ADC for battery monitoring CONFIG_ADC=y # Enable sensor (temperature & IMU) CONFIG_SENSOR=y CONFIG_FPU=y CONFIG_I2C=y # CONFIG_LSM6DSL_TRIGGER_GLOBAL_THREAD=y # External memory CONFIG_SPI_NOR=y CONFIG_SPI_NOR_SFDP_DEVICETREE=y CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 ################ # Flash config # ################ CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y CONFIG_NVS=y CONFIG_SETTINGS=y CONFIG_HEAP_MEM_POOL_SIZE=1024 ############## # BLE config # ############## CONFIG_BT=y CONFIG_BT_CENTRAL=y CONFIG_BT_COMPANY_ID=0x0ef2 CONFIG_BT_PERIPHERAL=y CONFIG_BT_DEVICE_NAME="Remote" CONFIG_BT_SMP=y CONFIG_BT_GATT_CLIENT=y CONFIG_BT_GATT_DM=y CONFIG_BT_GATT_DM_DATA_PRINT=y CONFIG_BT_MAX_CONN=3 CONFIG_BT_MAX_PAIRED=10 CONFIG_BT_CONN_CTX=y CONFIG_BT_SCAN=y CONFIG_BT_SCAN_FILTER_ENABLE=y CONFIG_BT_SCAN_MANUFACTURER_DATA_CNT=1 CONFIG_BT_SCAN_CONN_ATTEMPTS_FILTER=y CONFIG_BT_SCAN_CONN_ATTEMPTS_FILTER_LEN=10 CONFIG_BT_FILTER_ACCEPT_LIST=y CONFIG_BT_PRIVACY=y CONFIG_BT_SETTINGS=y # BLE services CONFIG_BT_BAS=y CONFIG_BT_ZEPHYR_NUS=y CONFIG_BT_DIS=y CONFIG_BT_DIS_MODEL_NUMBER=n CONFIG_BT_DIS_MANUF_NAME=n CONFIG_BT_DIS_PNP=n CONFIG_BT_DIS_FW_REV=y # OTA DFU with mcumgr CONFIG_NCS_SAMPLE_MCUMGR_BT_OTA_DFU=y CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS=y CONFIG_MCUMGR_GRP_IMG_STATUS_HOOKS=y ######################## # No memory optimizing # ######################## # Enable log module though RTT CONFIG_LOG=y CONFIG_USE_SEGGER_RTT=y CONFIG_LOG_BACKEND_RTT=y CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=4096
static void accept_list_add_cb(const struct bt_bond_info *info, void *user_data) { int *bond_count = (void *)user_data; int err = 0; char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(&info->addr, addr, sizeof(addr)); if ((*bond_count) < 0) { return; } /* Check if the bond is with a blinker */ for (uint8_t i = 0; i < MAX_BLINKER; i++) { if (bt_addr_le_cmp(storage_get_blinker_addr(i), &info->addr) == 0) { /* It is, so add it to the filter accept list */ err = bt_le_filter_accept_list_add(&info->addr); if (err) { LOG_ERR("%s cannot add to filter accept list (err %d)", addr, err); (*bond_count) = -EIO; } else { // LOG_DBG("%s added to the filter accept list", addr); (*bond_count)++; } } } } static void accept_list_remove_cb(struct bt_conn *conn, void *data) { uint8_t *conn_count = (void *)data; struct bt_conn_info info; int err = 0; char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); if ((*conn_count) < 0) { return; } /* Check if the connection is with a blinker */ for (uint8_t i = 0; i < MAX_BLINKER; i++) { if (bt_addr_le_cmp(bt_conn_get_dst(conn), storage_get_blinker_addr(i)) == 0) { /* It is, is it connected tho ? */ err = bt_conn_get_info(conn, &info); if (err) { LOG_ERR("%s failed to get conn info (err %d)", addr, err); return; } if (info.state == BT_CONN_STATE_CONNECTED) { /* Blinker is connected, we don't need to reconnect to it */ err = bt_le_filter_accept_list_remove(bt_conn_get_dst(conn)); if (err) { LOG_ERR("%s cannot remove to filter accept list (err %d)", addr, err); (*conn_count) = -EIO; } else { // LOG_DBG("%s removed to the filter accept list", addr); (*conn_count)--; } } } } } static int auto_conn_procedure(void) { int err = 0; uint8_t count = 0; /* Check firstly if we have 2 bonded blinker in memory */ for (uint8_t i = 0; i < MAX_BLINKER; i++) { if (bt_addr_le_cmp(storage_get_blinker_addr(i), BT_ADDR_LE_NONE) == 0) { LOG_DBG("Auto connection stopped (no address in memory)"); return -1; } } err = bt_le_filter_accept_list_clear(); if (err) { LOG_ERR("Failed to clear accept list (err %d)", err); return err; } /* Increase count by the number of matching bound */ bt_foreach_bond(BT_ID_DEFAULT, accept_list_add_cb, &count); if (count < MAX_BLINKER) { LOG_DBG("Auto connection stopped (not enought bound count : %d)", count); return -1; } /* Decrease count by the number of connected connection */ bt_conn_foreach(BT_CONN_TYPE_LE, accept_list_remove_cb, &count); if (count <= 0) { LOG_DBG("Auto connection stopped (enought connection count)"); return -1; } err = bt_conn_le_create_auto(BT_CONN_LE_CREATE_CONN_AUTO, BT_LE_CONN_PARAM_DEFAULT); if (err) { LOG_ERR("Auto connection start failed (err %d)", err); return err; } else { LOG_DBG("Auto connection started"); } return err; } static void conn_count_cb(struct bt_conn *conn, void *data) { uint8_t *actual_conn_count = (void *)data; struct bt_conn_info info; int err = 0; char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); /* Get conn info */ err = bt_conn_get_info(conn, &info); if (err) { LOG_ERR("%s failed to get conn info (err %d)", addr, err); return; } /* Verify it is active */ if ((info.state == BT_CONN_STATE_CONNECTED) && (info.role == BT_CONN_ROLE_CENTRAL)) { (*actual_conn_count)++; } } static int scan_procedure(void) { int err = 0; uint8_t conn_count = 0; /* Make sure we're not scanning */ err = bt_scan_stop(); if ((err != 0) && (err != -EALREADY)) { LOG_ERR("Scan stop failed (err %d)", err); return err; } bt_conn_foreach(BT_CONN_TYPE_LE, conn_count_cb, &conn_count); if (conn_count >= MAX_BLINKER) { LOG_DBG("Scan stopped (connection count : %d)", conn_count); return -1; } err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE); if (err) { LOG_ERR("Scan start failed (err %d)", err); return err; } else { LOG_DBG("Scan started"); } return err; } static void conn_procedure_work_handler(struct k_work *work) { /* If a discovering is happening, report the work for later */ if (k_event_test(&event, EVENT_BLE_DISCOVERING)) { k_work_schedule(&conn_procedure_work, K_MSEC(CONN_PROCEDURE_RESCHEDULE_MS)); return; } if (k_event_test(&event, EVENT_FSM_PAIR)) { scan_procedure(); } else { auto_conn_procedure(); } } static void scan_filter_match(struct bt_scan_device_info *device_info, struct bt_scan_filter_match *filter_match, bool connectable) { char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(device_info->recv_info->addr, addr, sizeof(addr)); LOG_INF("%s filters matched", addr); } static void scan_connecting_error(struct bt_scan_device_info *device_info) { char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(device_info->recv_info->addr, addr, sizeof(addr)); LOG_ERR("%s connecting error", addr); k_work_schedule(&conn_procedure_work, K_NO_WAIT); } static void scan_connecting(struct bt_scan_device_info *device_info, struct bt_conn *conn) { char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(device_info->recv_info->addr, addr, sizeof(addr)); LOG_INF("%s connecting", addr); bt_conn_ref(conn); } BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL, scan_connecting_error, scan_connecting); static int scan_init(void) { int err = 0; struct bt_scan_init_param scan_init = { .connect_if_match = true, .scan_param = BT_LE_SCAN_ACTIVE, .conn_param = BT_LE_CONN_PARAM_DEFAULT, }; bt_scan_init(&scan_init); bt_scan_cb_register(&scan_cb); /* Filtering */ adv_mfg_data_s adv_mfg_data = {CONFIG_BT_COMPANY_ID}; struct bt_scan_manufacturer_data scan_manufacturer_data = { .data = (uint8_t *)&adv_mfg_data, .data_len = sizeof(adv_mfg_data_s), }; err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_MANUFACTURER_DATA, &scan_manufacturer_data); if (err) { LOG_ERR("Add scan filters failed (err %d)", err); return err; } err = bt_scan_filter_enable(BT_SCAN_MANUFACTURER_DATA_FILTER, false); if (err) { LOG_ERR("Enable scan filters failed (err %d)", err); return err; } return err; }