Bluetooth Low Energy failed to connect again(err:-22)

Hi,

When I used NCS V2.5.0,after two devices successfully establish a BLE connection but then disconnect due to a timeout, subsequent reconnection attempts fail with error code -22 . What could be causing this connection failure and how can it be resolved?(PS.The code added the 'bt_conn_unref(conn)',did it work?)

static void restart_scan_work_handler(struct k_work *work) {
    int err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
    if (err) {
        printk("Scan restart failed (err %d)\n", err);
    }


}
K_WORK_DEFINE(restart_scan_work, restart_scan_work_handler);
static void connected(struct bt_conn *conn, uint8_t conn_err)
{
	if (conn_err) {
		printk("Connection failed (err %d)\n", conn_err);
		bt_conn_unref(conn);
		int err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
		if (err) {
		printk("Scanning failed to start (err %d)\n", err);
		}

		return;
	}

	default_conn = bt_conn_ref(conn);
	

}

static void disconnected(struct bt_conn *conn, uint8_t reason)
{
    printk("Client disconnected (reason 0x%02x)\n", reason);
    
    // 释放连接对象并重置指针
    if (default_conn) {
        bt_conn_unref(default_conn);
        default_conn = NULL;
    }

    k_work_submit(&restart_scan_work);  // 使用工作队列
}

BT_CONN_CB_DEFINE(conn_callbacks) = {
	.connected = connected,
	.disconnected = disconnected,
};

// 过滤器匹配后回调
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_to_str(device_info->recv_info->addr, addr_str, sizeof(addr_str));
	
	printk("Filter matched device: %s, RSSI: %d\n", addr_str, device_info->recv_info->rssi);
	int err = bt_scan_stop();
	if (err) {
		printk("Stop LE scan failed (err %d)\n", err);
	}


	if (default_conn) {
		bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
		printk("Warning: previous connection still exists, cleaning up\n");
		bt_conn_unref(default_conn);
		default_conn = NULL;
		k_sleep(K_MSEC(500));
	}
	
	err = bt_conn_le_create(device_info->recv_info->addr,
								&create_param,
	                            &conn_param,
	                            &default_conn);
	if (err) {
		k_work_submit(&restart_scan_work);
		printk("Connection create failed (err %d)\n", err);
	} else {
		printk("Connecting to %s...\n", addr_str);
	}
}

BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL, NULL, NULL);
static void scan_init(void)
{
	int err;

	/* Use active scanning and disable duplicate filtering to handle any
	 * devices that might update their advertising data at runtime. */
	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
	};

	struct bt_scan_init_param scan_init = {
		.connect_if_match = 0,
		.scan_param = &scan_param,
		.conn_param = NULL
	};

	bt_scan_init(&scan_init);
	bt_scan_cb_register(&scan_cb);
	static uint16_t my_app=(uint16_t)MY_APPEARANCE;

	err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_APPEARANCE, &my_app);
	if (err) {
		printk("Failed to add appearance filter (err %d)\n", err);
		return;
	}

	err = bt_scan_filter_enable(BT_SCAN_APPEARANCE_FILTER, false);
	if (err) {
		printk("Failed to enable filter (err %d)\n", err);
		return;
	}
}
This is my Serial port T

Parents
  • Hi,

    Which devices do you use on both end?

    Is your issue reproducible on nrf52840-dk boards?

    Best regards,
    Dejan

  • Hi,

    Thank you for taking the time to respond. Both of our development boards are nRF52840. This is the source code where we made the mistake at that time. We made significant revisions subsequently and inadvertently solved the problem.

    #prj.conf
    #
    # Copyright (c) 2020 Nordic Semiconductor
    #
    # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
    #
    
    CONFIG_NCS_SAMPLES_DEFAULTS=y
    CONFIG_BT_SCAN_APPEARANCE_CNT=1
    CONFIG_HEAP_MEM_POOL_SIZE=2048
    
    CONFIG_BT=y
    CONFIG_BT_DEBUG_LOG=y
    CONFIG_BT_CENTRAL=y
    CONFIG_BT_GATT_CLIENT=y
    CONFIG_BT_HRS_CLIENT=y
    CONFIG_BT_GATT_DM=y
    
    
    #
    CONFIG_BT_NUS_CLIENT=y
    CONFIG_BT_SCAN=y
    CONFIG_BT_SCAN_FILTER_ENABLE=y
    CONFIG_BT_SCAN_UUID_CNT=1
    
    CONFIG_BT_CTLR_ADV_EXT=y
    CONFIG_BT_CTLR_PHY_CODED=y
    
    CONFIG_BT_EXT_ADV=y
    CONFIG_BT_USER_PHY_UPDATE=y
    CONFIG_BT_MAX_CONN=3
    #这三个用于配置串口还是RTT输出;
    CONFIG_USE_SEGGER_RTT=y
    CONFIG_RTT_CONSOLE=y
    CONFIG_UART_CONSOLE=y
    

  • #include <zephyr/types.h>
    #include <stddef.h>
    #include <errno.h>
    #include <zephyr/kernel.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/bluetooth/bluetooth.h>
    #include <zephyr/bluetooth/conn.h>
    #include <zephyr/bluetooth/gatt.h>
    #include <zephyr/bluetooth/uuid.h>
    #include <bluetooth/scan.h>
    
    #define MY_APPEARANCE 0x06  // 用大端书写,真实 appearance 是 AB00
    #define DEVICE_NAME "TS_Provider"
    
    // 与广告方一致的时间戳 UUID
    static struct bt_uuid_16 timestamp_uuid = BT_UUID_INIT_16(0x7856);
    
    static struct bt_conn *default_conn;
    static uint64_t local_conn_time_ns;
    static uint16_t timestamp_handle = 0;
    
    static const struct bt_le_conn_param conn_param=
    {  .interval_min = 16, 
       .interval_max =16, 
       .latency = 0, 
       .timeout = 300};
    
     static void restart_scan_work_handler(struct k_work *work) {
        int err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
        if (err) {
            printk("Scan restart failed (err %d)\n", err);
        }
    }
    K_WORK_DEFINE(restart_scan_work, restart_scan_work_handler);
    
    // GATT 读取回调
    static uint8_t gatt_read_cb(struct bt_conn *conn, uint8_t err,
                                struct bt_gatt_read_params *params,
                                const void *data, uint16_t length)
    {
    	if (err) {
    		printk("Read failed: err %d\n", err);
    		return BT_GATT_ITER_STOP;
    	}
    
    	if (data) {
    		uint64_t remote_ts;
    		memcpy(&remote_ts, data, sizeof(remote_ts));
    		printk("Received remote timestamp t1: %llu\n", remote_ts);
    		printk("Local timestamp t2: %llu\n", local_conn_time_ns);
    		printk("Clock offset: %lld ns\n", (int64_t)(local_conn_time_ns - remote_ts));
    	}
    
    	return BT_GATT_ITER_STOP;
    }
    
    static struct bt_gatt_read_params read_params = {
    	.func = gatt_read_cb,
    	.handle_count = 1,
    	.single.offset = 0
    };
    
    // GATT 服务发现回调
    static uint8_t discover_func(struct bt_conn *conn,
                                  const struct bt_gatt_attr *attr,
                                  struct bt_gatt_discover_params *params)
    {
    	if (!attr) {
    		printk("Discovery ended\n");
    		memset(params, 0, sizeof(*params));
    		return BT_GATT_ITER_STOP;
    	}
    
    	const struct bt_gatt_chrc *chrc = attr->user_data;
    
    	if (params->type == BT_GATT_DISCOVER_CHARACTERISTIC) {
    		if (!bt_uuid_cmp(chrc->uuid, &timestamp_uuid.uuid)) {
    			timestamp_handle = chrc->value_handle;
    			printk("Timestamp characteristic discovered, handle: 0x%04x\n", timestamp_handle);
    
    			read_params.single.handle = timestamp_handle;
    			bt_gatt_read(conn, &read_params);
    			return BT_GATT_ITER_STOP;
    		}
    	}
    
    	return BT_GATT_ITER_CONTINUE;
    }
    
    static struct bt_gatt_discover_params discover_params = { 0 };
    
    // 连接回调
    static void connected(struct bt_conn *conn, uint8_t conn_err)
    {
    	if (conn_err) {
    		printk("Connection failed (err %d)\n", conn_err);
    		bt_conn_unref(conn);
    		int err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
    		if (err) {
    		printk("Scanning failed to start (err %d)\n", err);
    		}
    
    		return;
    	}
    
    	default_conn = bt_conn_ref(conn);
    	local_conn_time_ns = k_ticks_to_ns_floor64(k_uptime_ticks());
    	printk("Connected, local timestamp t2: %llu\n", local_conn_time_ns);
    
    	// 启动 GATT 发现
    	discover_params.uuid = &timestamp_uuid.uuid;
    	discover_params.func = discover_func;
    	discover_params.start_handle = 0x0001;
    	discover_params.end_handle = 0xffff;
    	discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
    
    	int err = bt_gatt_discover(conn, &discover_params);
    	if (err) {
    		printk("GATT characteristic discovery failed: %d\n", err);
    	}
    }
    
    static void disconnected(struct bt_conn *conn, uint8_t reason)
    {
        printk("Client disconnected (reason 0x%02x)\n", reason);
        
        // 释放连接对象并重置指针
        if (default_conn) {
            bt_conn_unref(default_conn);
            default_conn = NULL;
        }
    
        // 重置发现参数
        memset(&discover_params, 0, sizeof(discover_params));
        
        // 重置读取参数
        memset(&read_params, 0, sizeof(read_params));
        read_params.func = gatt_read_cb;  // 重新设置回调函数
        read_params.handle_count = 1;
        read_params.single.offset = 0;
    
        // 重置特征值句柄
        timestamp_handle = 0;
    
    	//4. 延迟后重启扫描(避免竞争条件)
        k_work_submit(&restart_scan_work);  // 使用工作队列
    }
    
    BT_CONN_CB_DEFINE(conn_callbacks) = {
    	.connected = connected,
    	.disconnected = disconnected,
    };
    
    // 过滤器匹配后回调
    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_to_str(device_info->recv_info->addr, addr_str, sizeof(addr_str));
    	
    	printk("Filter matched device: %s, RSSI: %d\n", addr_str, device_info->recv_info->rssi);
    	int err = bt_scan_stop();
    	if (err) {
    		printk("Stop LE scan failed (err %d)\n", err);
    	}
    
    
    
    	err = bt_conn_le_create(device_info->recv_info->addr,
    	                            BT_CONN_LE_CREATE_CONN,
    	                            &conn_param,
    	                            &default_conn);
    	if (err) {
    		printk("Connection create failed (err %d)\n", err);
    	} else {
    		printk("Connecting to %s...\n", addr_str);
    	}
    }
    
    // 启动扫描
    static void start_scan(struct bt_le_scan_param *scan_params)
    {
    	int err;
    
    	struct bt_scan_init_param scan_init = {
    		.scan_param = scan_params
    	};
    
    	bt_scan_init(&scan_init);
    	BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL, NULL, NULL);
    	bt_scan_cb_register(&scan_cb);
         static uint16_t my_app=(uint16_t)MY_APPEARANCE;
    	err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_APPEARANCE, &my_app);
    	if (err) {
    		printk("Failed to add appearance filter (err %d)\n", err);
    		return;
    	}
    
    	err = bt_scan_filter_enable(BT_SCAN_APPEARANCE_FILTER, false);
    	if (err) {
    		printk("Failed to enable filter (err %d)\n", err);
    		return;
    	}
    
    	err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
    	if (err) {
    		printk("Scanning failed to start (err %d)\n", err);
    		return;
    	}
    
    	printk("Scanning started\n");
    }
    
    void main(void)
    {
    	int err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    
    	printk("Bluetooth initialized, starting scan\n");
    
    	struct bt_le_scan_param scan_params = {
    		.type = BT_LE_SCAN_TYPE_ACTIVE,
    		.options = BT_LE_SCAN_OPT_NONE,
    		.interval = 0x4000,
    		.window = 0x4000,
    		.timeout = 0
    	};
    
    	start_scan(&scan_params);
    
    	while (1) {
    		k_sleep(K_SECONDS(1));
    	}
    }

Reply
  • #include <zephyr/types.h>
    #include <stddef.h>
    #include <errno.h>
    #include <zephyr/kernel.h>
    #include <zephyr/sys/printk.h>
    #include <zephyr/bluetooth/bluetooth.h>
    #include <zephyr/bluetooth/conn.h>
    #include <zephyr/bluetooth/gatt.h>
    #include <zephyr/bluetooth/uuid.h>
    #include <bluetooth/scan.h>
    
    #define MY_APPEARANCE 0x06  // 用大端书写,真实 appearance 是 AB00
    #define DEVICE_NAME "TS_Provider"
    
    // 与广告方一致的时间戳 UUID
    static struct bt_uuid_16 timestamp_uuid = BT_UUID_INIT_16(0x7856);
    
    static struct bt_conn *default_conn;
    static uint64_t local_conn_time_ns;
    static uint16_t timestamp_handle = 0;
    
    static const struct bt_le_conn_param conn_param=
    {  .interval_min = 16, 
       .interval_max =16, 
       .latency = 0, 
       .timeout = 300};
    
     static void restart_scan_work_handler(struct k_work *work) {
        int err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
        if (err) {
            printk("Scan restart failed (err %d)\n", err);
        }
    }
    K_WORK_DEFINE(restart_scan_work, restart_scan_work_handler);
    
    // GATT 读取回调
    static uint8_t gatt_read_cb(struct bt_conn *conn, uint8_t err,
                                struct bt_gatt_read_params *params,
                                const void *data, uint16_t length)
    {
    	if (err) {
    		printk("Read failed: err %d\n", err);
    		return BT_GATT_ITER_STOP;
    	}
    
    	if (data) {
    		uint64_t remote_ts;
    		memcpy(&remote_ts, data, sizeof(remote_ts));
    		printk("Received remote timestamp t1: %llu\n", remote_ts);
    		printk("Local timestamp t2: %llu\n", local_conn_time_ns);
    		printk("Clock offset: %lld ns\n", (int64_t)(local_conn_time_ns - remote_ts));
    	}
    
    	return BT_GATT_ITER_STOP;
    }
    
    static struct bt_gatt_read_params read_params = {
    	.func = gatt_read_cb,
    	.handle_count = 1,
    	.single.offset = 0
    };
    
    // GATT 服务发现回调
    static uint8_t discover_func(struct bt_conn *conn,
                                  const struct bt_gatt_attr *attr,
                                  struct bt_gatt_discover_params *params)
    {
    	if (!attr) {
    		printk("Discovery ended\n");
    		memset(params, 0, sizeof(*params));
    		return BT_GATT_ITER_STOP;
    	}
    
    	const struct bt_gatt_chrc *chrc = attr->user_data;
    
    	if (params->type == BT_GATT_DISCOVER_CHARACTERISTIC) {
    		if (!bt_uuid_cmp(chrc->uuid, &timestamp_uuid.uuid)) {
    			timestamp_handle = chrc->value_handle;
    			printk("Timestamp characteristic discovered, handle: 0x%04x\n", timestamp_handle);
    
    			read_params.single.handle = timestamp_handle;
    			bt_gatt_read(conn, &read_params);
    			return BT_GATT_ITER_STOP;
    		}
    	}
    
    	return BT_GATT_ITER_CONTINUE;
    }
    
    static struct bt_gatt_discover_params discover_params = { 0 };
    
    // 连接回调
    static void connected(struct bt_conn *conn, uint8_t conn_err)
    {
    	if (conn_err) {
    		printk("Connection failed (err %d)\n", conn_err);
    		bt_conn_unref(conn);
    		int err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
    		if (err) {
    		printk("Scanning failed to start (err %d)\n", err);
    		}
    
    		return;
    	}
    
    	default_conn = bt_conn_ref(conn);
    	local_conn_time_ns = k_ticks_to_ns_floor64(k_uptime_ticks());
    	printk("Connected, local timestamp t2: %llu\n", local_conn_time_ns);
    
    	// 启动 GATT 发现
    	discover_params.uuid = &timestamp_uuid.uuid;
    	discover_params.func = discover_func;
    	discover_params.start_handle = 0x0001;
    	discover_params.end_handle = 0xffff;
    	discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
    
    	int err = bt_gatt_discover(conn, &discover_params);
    	if (err) {
    		printk("GATT characteristic discovery failed: %d\n", err);
    	}
    }
    
    static void disconnected(struct bt_conn *conn, uint8_t reason)
    {
        printk("Client disconnected (reason 0x%02x)\n", reason);
        
        // 释放连接对象并重置指针
        if (default_conn) {
            bt_conn_unref(default_conn);
            default_conn = NULL;
        }
    
        // 重置发现参数
        memset(&discover_params, 0, sizeof(discover_params));
        
        // 重置读取参数
        memset(&read_params, 0, sizeof(read_params));
        read_params.func = gatt_read_cb;  // 重新设置回调函数
        read_params.handle_count = 1;
        read_params.single.offset = 0;
    
        // 重置特征值句柄
        timestamp_handle = 0;
    
    	//4. 延迟后重启扫描(避免竞争条件)
        k_work_submit(&restart_scan_work);  // 使用工作队列
    }
    
    BT_CONN_CB_DEFINE(conn_callbacks) = {
    	.connected = connected,
    	.disconnected = disconnected,
    };
    
    // 过滤器匹配后回调
    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_to_str(device_info->recv_info->addr, addr_str, sizeof(addr_str));
    	
    	printk("Filter matched device: %s, RSSI: %d\n", addr_str, device_info->recv_info->rssi);
    	int err = bt_scan_stop();
    	if (err) {
    		printk("Stop LE scan failed (err %d)\n", err);
    	}
    
    
    
    	err = bt_conn_le_create(device_info->recv_info->addr,
    	                            BT_CONN_LE_CREATE_CONN,
    	                            &conn_param,
    	                            &default_conn);
    	if (err) {
    		printk("Connection create failed (err %d)\n", err);
    	} else {
    		printk("Connecting to %s...\n", addr_str);
    	}
    }
    
    // 启动扫描
    static void start_scan(struct bt_le_scan_param *scan_params)
    {
    	int err;
    
    	struct bt_scan_init_param scan_init = {
    		.scan_param = scan_params
    	};
    
    	bt_scan_init(&scan_init);
    	BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL, NULL, NULL);
    	bt_scan_cb_register(&scan_cb);
         static uint16_t my_app=(uint16_t)MY_APPEARANCE;
    	err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_APPEARANCE, &my_app);
    	if (err) {
    		printk("Failed to add appearance filter (err %d)\n", err);
    		return;
    	}
    
    	err = bt_scan_filter_enable(BT_SCAN_APPEARANCE_FILTER, false);
    	if (err) {
    		printk("Failed to enable filter (err %d)\n", err);
    		return;
    	}
    
    	err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
    	if (err) {
    		printk("Scanning failed to start (err %d)\n", err);
    		return;
    	}
    
    	printk("Scanning started\n");
    }
    
    void main(void)
    {
    	int err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    
    	printk("Bluetooth initialized, starting scan\n");
    
    	struct bt_le_scan_param scan_params = {
    		.type = BT_LE_SCAN_TYPE_ACTIVE,
    		.options = BT_LE_SCAN_OPT_NONE,
    		.interval = 0x4000,
    		.window = 0x4000,
    		.timeout = 0
    	};
    
    	start_scan(&scan_params);
    
    	while (1) {
    		k_sleep(K_SECONDS(1));
    	}
    }

Children
No Data
Related