Reconnect failed : bt_conn_le_create return error -22

Hi,

I'm working on a project with a nRF21540DK. I'm working with SDKs and toolchains V2.5.3.

I develop a BLE central following the sdf-nrf/samples/bluetooth/central_uart sample. I don't use filter and auto-connect. It can succesfully connect to a device the first time. After a disconnection the central cannot connect to a device anymore. I receive a error -22 from the bt_conn_le_create method. 

It appears that the peripheral disconnected appropriately based on the peripheral log that follows.

[01:23:45.583,404] <inf> ble_handler: BLE Connected E6:68:0D:63:46:32 (random)
[01:23:45.583,435] <inf> ble_handler: Called bt_conn_le_param_update(...) with min_interval: 618, max_interval: 937, latency: 0, timeout: 400
[01:23:47.634,765] <dbg> bt_snes: snes_ccc_status_changed: Notification for `Status` has been turned ON
[01:23:47.734,710] <dbg> bt_snes: snes_ccc_dor_changed: Notification for `Days of Records` has been turned ON
[01:23:47.834,716] <dbg> bt_snes: snes_ccc_mig_changed: Notification for `Mic INput Gain` has been turned ON
[01:23:50.934,539] <inf> ble_handler: Param updated -> interval: 937, latency: 0, timeout: 400
[01:23:50.934,570] <dbg> ble_handler: ble_param_updated: conn_param: min_interval: 618, max_interval: 937, latency: 0, timeout: 400
[01:23:59.183,441] <dbg> bt_snes: snes_ccc_status_changed: Notification for `Status` has been turned OFF
[01:23:59.183,502] <dbg> bt_snes: snes_ccc_dor_changed: Notification for `Days of Records` has been turned OFF
[01:23:59.183,563] <dbg> bt_snes: snes_ccc_mig_changed: Notification for `Mic INput Gain` has been turned OFF
[01:23:59.183,715] <inf> ble_handler: BLE Disconnected: E6:68:0D:63:46:32 (random) (reason 19)

No messages are printed in the log when a new connection is attempted after that.

Do you know what might be causing the issue?

The prj.conf is :

CONFIG_BT=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_GATT_CLIENT=y
CONFIG_BT_NUS_CLIENT=y
CONFIG_BT_SCAN=y
CONFIG_BT_SCAN_FILTER_ENABLE=n
CONFIG_BT_GATT_DM=y
CONFIG_HEAP_MEM_POOL_SIZE=2048

CONFIG_DEBUG=y

A part of the ble.c file : 

#include <zephyr/kernel.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>
#include <bluetooth/gatt_dm.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/logging/log.h>
#include <stdlib.h>

#include "ble.h"
#include "../define.h"
#include "connection.h"

// Define callbacks for the BLE connection
BT_CONN_CB_DEFINE(conn_callbacks) = {
	.connected = ble_connected_cb,
	.disconnected = ble_disconnected_cb,
    .le_param_updated = ble_param_updated_cb,
    .le_param_req = ble_param_request_cb
};

K_THREAD_STACK_DEFINE(BLE_STACK, BLE_STACK_SIZE);
static struct k_thread bleThread;

LOG_MODULE_REGISTER(ble, LOG_LEVEL_DBG);

struct k_work work;

struct snes_client snes;
const struct snes_client_cb snes_callbacks = {
    .cmd_sent = ble_data_written_cb,
    .status_received = ble_status_received_cb,
    .dor_received = ble_dor_received_cb,
    .device_id_received = ble_device_id_received_cb,
    .mic_gain_received = ble_mic_gain_received_cb,
    .status_unsubscribed = ble_status_unsubscribed_cb,
    .dor_unsubscribed = ble_dor_unsubscribed_cb,
    .device_id_unsubscribed = ble_device_id_unsubscribed_cb,
    .mic_gain_unsubscribed = ble_mic_gain_unsubscribed_cb
};

struct snes_client_init_param snes_init_params = {
    .cb = snes_callbacks
};

//struct bt_gatt_dm snes_dm;

static struct bt_gatt_dm_cb dm_callbacks = {
    .completed = ble_discovery_complete_cb,
    .service_not_found = ble_discovery_service_not_found_cb,
};

struct Monkey connectedMonkey;
uint16_t monkey_handle;

struct bt_uuid_128 monkey_src_UUID = BT_UUID_INIT_128(BT_UUID_SNES_VAL);

//Function to initialize the ble thread
void ble_thread_init(){
    k_thread_create	(&bleThread,
                BLE_STACK,										        
                BLE_STACK_SIZE,
                (k_thread_entry_t)ble_controller,
                NULL,
                NULL,
                NULL,
                BLE_PRIORITY,
                0,
                K_NO_WAIT);	

    k_thread_name_set(&bleThread, "bleThread");
    k_thread_start(&bleThread);

    #ifdef DEBUG_MODE
        printk("ble_thread_init\n");
    #endif

    k_work_init(&work, ble_controller);
}

int ble_init(void){
    setConnectCallback(ble_connect);
    setDisconnectCallback(ble_disconnect);
    setRecordingToggleCallback(ble_toggle_recording);
    setResetCollarCallback(ble_reset_collar);
    setOpenCollarCallback(ble_open_collar);
    
    memset(&snes, 0, sizeof(snes));
    memset(&connectedMonkey, 0, sizeof(connectedMonkey));

    int err = snes_client_init(&snes, &snes_init_params);
    if (err) {
        #ifdef DEBUG_MODE
            printk("SNES client init failed (err %d)\n", err);
        #endif
        return -1;
    }

    err = bt_enable(NULL);

    if (err) {
        #ifdef DEBUG_MODE
            printk("Bluetooth init failed (err %d)\n", err);
        #endif
        return -1;
    }

    #ifdef DEBUG_MODE
        printk("Bluetooth initialized\n");
    #endif
    return 0;
}

// Funtion to start the ble controller
void ble_controller(struct k_work *work){
    ble_init(); 
    ble_start_scan();

    while (true)
    {   
        
    }
}

// Function to start the ble scan
int ble_start_scan(){
    int err;

	err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, ble_device_found_cb);
	if (err) {
        #ifdef DEBUG_MODE
            printk("ble_start_scan failed (err %d)\n", err);
        #endif
		return err;
	}
    #ifdef DEBUG_MODE
        printk("ble_start_scan\n");
    #endif
    return 0;
}

// Function to stop the ble scan
int ble_stop_scan(){
    int err;

    err = bt_le_scan_stop();
    if (err) {
        #ifdef DEBUG_MODE
            printk("ble_stop_scan failed (err %d)\n", err);
        #endif
        return err;
    }
    #ifdef DEBUG_MODE
        //printk("ble_stop_scan\n");
    #endif

    return 0;
}

// Function called when a device is found. It will parse the advertising data to find the device name and the manufacturer data
void ble_device_found_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, struct net_buf_simple *ad){
    char addr_str[BT_ADDR_LE_STR_LEN];
    char name[NAME_LEN];
    uint8_t manufacturerData[MANUFACTURER_DATA_LEN];

    memset(name, 0, NAME_LEN);
    memset(manufacturerData, 0, MANUFACTURER_DATA_LEN);

    struct net_buf_simple *data1 = malloc(sizeof(struct net_buf_simple));
    struct net_buf_simple *data2 = malloc(sizeof(struct net_buf_simple));

    *data1 = *ad;
    *data2 = *ad;

    // Process the received data to extract the useful information
    bt_data_parse(data1, ble_manufacturer_data_cb, manufacturerData);
    bt_data_parse(data2, ble_data_cb, name);
    bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
    
    // If the device is a device of interest (manufacturer = 0x5A02 = University of Applied Sciences Valais / 
    // Haute Ecole Valaisanne), add it to the list or udpate if already exist
    if(manufacturerData[0] == 0x5A && manufacturerData[1] == 0x02){
        uint32_t currentTime = k_uptime_get_32();
        appendOrModifyMonkey(ble_parse_device_name(name), rssi, manufacturerData[2], manufacturerData[3], *addr, currentTime);
        #ifdef DEBUG_MODE
            //printMonkeys();
        #endif 
        ble_remove_device();
    }  

    free(data1);
    free(data2);
}

// Function to connect to a specific device
void ble_connect(struct Monkey monkey){
    struct bt_conn* conn;
    int err = ble_stop_scan();

	if (err) {
        #ifdef DEBUG_MODE
            printk("%s: Stop LE scan failed (err %d)\n", __func__, err);
        #endif  
        connectionFailed();
		return;
	}
    struct bt_conn_le_create_param create_param;

    create_param.options = BT_CONN_LE_OPT_NONE;
	create_param.interval = BT_GAP_SCAN_FAST_INTERVAL;
	create_param.window = BT_GAP_SCAN_FAST_WINDOW;
	create_param.interval_coded = 0;
	create_param.window_coded = 0;
	create_param.timeout = 0;

    struct bt_le_conn_param conn_param;
    conn_param.interval_min = BT_GAP_INIT_CONN_INT_MIN;
	conn_param.interval_max = BT_GAP_INIT_CONN_INT_MAX;
	conn_param.latency = 0;
	conn_param.timeout = 400;
    
    err = bt_conn_le_create((const bt_addr_le_t*) &monkey.btAddress, &create_param,
				        &conn_param, &conn);

	if (err) {
        #ifdef DEBUG_MODE
            printk("%s: Create conn failed (err %d)\n", __func__, err);
        #endif  
        connectionFailed();
		ble_start_scan();
        return;
	}
        
    snes.conn = bt_conn_ref(conn);
    connectedMonkey = monkey;

    #ifdef DEBUG_MODE
        printk("Connecting to Monkey %d\n", connectedMonkey.num);
    #endif
}

// Function called when a device is connected
void ble_connected_cb(struct bt_conn *conn, uint8_t err)
{
    char addr[BT_ADDR_LE_STR_LEN];
    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

    if(conn != snes.conn){
        return;
    }

    if (err != 0) {
	printk("Failed to connect to %s (%u)\n", addr, err);

	bt_conn_unref(snes.conn);
	snes = (struct snes_client){0};
        connectedMonkey = (struct Monkey){0};

        connectionFailed();
		return;
	}

    err = bt_gatt_dm_start(snes.conn, &monkey_src_UUID.uuid, &dm_callbacks, &snes);
      
    if (err != 0) {
		printk("Failed to assign service handle");

		bt_conn_unref(snes.conn);
		snes = (struct snes_client){0};
        connectedMonkey = (struct Monkey){0};

        connectionFailed();
		return;
	}

    #ifdef DEBUG_MODE
        printk("Connected to monkey %d\n", connectedMonkey.num);
    #endif
}

void ble_discovery_complete_cb(struct bt_gatt_dm *dm, void *context){
    snes.conn = context;
    #ifdef DEBUG_MODE
        printk("Discovery complete\n");
    #endif

    snes_handles_assign(dm, &snes);
    snes_status_subscribe_receive(&snes);
    snes_dor_subscribe_receive(&snes);
    snes_device_id_subscribe_receive(&snes);
    snes_mic_gain_subscribe_receive(&snes);

    bt_gatt_dm_data_release(dm);
}

void ble_discovery_service_not_found_cb(struct bt_gatt_dm *dm, void *context){
    #ifdef DEBUG_MODE
        printk("Service not found\n");
    #endif
}

void ble_exchange_func(struct bt_conn *conn, uint8_t err, struct bt_gatt_exchange_params *params)
{
	if (!err) {
		printk("MTU exchange done\n");
	} else {
		printk("MTU exchange failed (err %" PRIu8 ")", err);
	}
}

// Function to disconnect from a specific device
void ble_disconnect(void){
    bt_conn_disconnect(snes.conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
}

// Function called when a device is disconnected
void ble_disconnected_cb(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));

	if (conn != snes.conn) {
        printk("Conn different from snes.conn");
		return;
	}

    #ifdef DEBUG_MODE
        printk("Disconnected from monkey %d, reason 0x%x\n", connectedMonkey.num, reason);
    #endif
	
	bt_conn_unref(snes.conn);

    snes.conn = NULL;
    //memset(&snes, 0, sizeof(snes));
    //memset(&connectedMonkey, 0, sizeof(connectedMonkey));
    
    ble_remove_device();
    disconnected();
    ble_start_scan();
}

bool ble_param_request_cb(struct bt_conn *conn, struct bt_le_conn_param *param){
    #ifdef DEBUG_MODE
        printk("Connection parameters update request. min: %d, max: %d, latency: %d, timeout: %d\n", param->interval_min, param->interval_max, param->latency, param->timeout); 
    #endif

    int ret = bt_conn_le_param_update(conn, param);
    return (ret == 0);
}

void ble_param_updated_cb(struct bt_conn *conn, uint16_t interval, uint16_t latency, uint16_t timeout){
    #ifdef DEBUG_MODE
        printk("Connection parameters updated. interval: %d, latency: %d, timeout: %d\n", interval, latency, timeout);
    #endif
    connected(connectedMonkey);
}



Parents Reply Children
No Data
Related