BLE reconnect procedure

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 : 

  1. The advertising and the scanning
  2. The pairing process
  3. The discovering procedure
  4. Read, write and subscribe to gatt atribute

What is not working : 

  1. 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

When bond are available on the remote, i need to call bt_conn_le_create_auto at reboot and again at each connection.
However, i find some issue such as connection to the same device or hci error because no ressource are available. I need help to better understand this procedure and help me make it work.
Here's the KConfig of my remote project 
################
# 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
And there's an extract of the functions i called from end of discovering, error or pairing procedure : 
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("Failed to get conn info from %s", addr);
		return;
	}

	/*  Verify it is active */
	if ((info.state == BT_CONN_STATE_CONNECTED) && (info.role == BT_CONN_ROLE_CENTRAL)) {
		(*actual_conn_count)++;
	}
}

static int auto_conn_procedure(void)
{
	int err;
	uint8_t conn_count = 0;

	bt_conn_foreach(BT_CONN_TYPE_LE, conn_count_cb, &conn_count);
	if (conn_count >= MAX_BLINKER) {
		LOG_DBG("Don't auto conn, enough active connection (count : %d)", conn_count);
		return -1;
	}

	LOG_DBG("Auto connnection procedure started");

	err = bt_conn_le_create_auto(BT_CONN_LE_CREATE_CONN_AUTO, BT_LE_CONN_PARAM_DEFAULT);
	if (err) {
		LOG_ERR("failed (err %d)", err);
		return err;
	}

	return err;
}

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("Stop LE scan 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("Don't scan, enough active connection (count : %d)", conn_count);
		return -1;
	}

	LOG_DBG("Scan procedure started");

	err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
	if (err) {
		LOG_ERR("failed (err %d)", err);
		return err;
	}

	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 setup_accept_list_cb(const struct bt_bond_info *info, void *user_data)
{
	int *bond_cnt = user_data;
	int err;

	char addr[BT_ADDR_LE_STR_LEN];
	bt_addr_le_to_str(&info->addr, addr, sizeof(addr));

	if ((*bond_cnt) < 0) {
		return;
	}

	/* Add to accept list if it is a blinker */
	for (uint8_t i = 0; i < MAX_BLINKER; i++) {
		if (bt_addr_le_cmp(&info->addr, storage_get_blinker_addr(i)) == 0) {
			err = bt_le_filter_accept_list_add(&info->addr);
			if (err) {
				LOG_ERR("Cannot add blinker to filter accept list (err: %d)", err);
				(*bond_cnt) = -EIO;
			} else {
				(*bond_cnt)++;
				LOG_INF("%s added to the filter accept list", addr);
			}
		}
	}
}

static int auto_conn_init(void)
{
	int err = 0;
	int bond_cnt = 0;

	err = bt_le_filter_accept_list_clear();
	if (err) {
		LOG_WRN("Failed to clear accept list (err: %d)", err);
		return err;
	}

	bt_foreach_bond(BT_ID_DEFAULT, setup_accept_list_cb, &bond_cnt);

	if (bond_cnt >= MAX_BLINKER) {
		LOG_INF("Auto connection etablishement procedure");
		err = bt_conn_le_create_auto(BT_CONN_LE_CREATE_CONN_AUTO, BT_LE_CONN_PARAM_DEFAULT);
		if (err) {
			LOG_ERR("failed (err %d)", err);
			return err;
		}
	}

	return err;
}

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("Filters matched. Address: %s connectable: %d", addr, connectable);
}

static void scan_connecting_error(struct bt_scan_device_info *device_info)
{
	LOG_ERR("Connecting failed");

	k_work_schedule(&conn_procedure_work, K_NO_WAIT);
}

static void scan_connecting(struct bt_scan_device_info *device_info, struct bt_conn *conn)
{
	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("Filters cannot be turned on (err %d)", err);
		return err;
	}

	return err;
}
Related