Simple Bluetooth Pairing using a Button, based on peripheral_uart example, not working

Hi guys,

I am trying to implement the possibility to have one central device made with a nrf52840DK and a peripheral with another nrf52840DK.

As I could have more nrf52840DK with the same BLE Name, I wanted to pair one particoular DK to the central, and be able to connect only to that board.
So, as I found bonding examples in the classic central_uart example, and in the perpheral example, I wanted to know how to use that part of the code, to implement this simple situation.


I am using the simple example of central_uart and peripheral_uart, I have went deep inside the KConfigs related, but I'm not able to see the activation of callbacks called 

	err = bt_conn_auth_cb_register(&conn_auth_callbacks);
	if (err) {
		printk("Failed to register authorization callbacks.\n");
		return;
	}

	err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
	if (err) {
		printk("Failed to register authorization info callbacks.\n");
		return;
	}


even if they are configured properly, in the main() ...... is it normal ?
I also added, trying to check if it was a problem of KConfigs, this:

CONFIG_BT_NUS_SECURITY_ENABLED=y
CONFIG_BT_SMP=y

in the conf file, but nothing happens.

the callbacks are registered properly, but they are not called.
And the central connects without any pariring request to the peripheral.

I also tryed with nRF connect for iPhone, but the same result: directy connected to the peripheral.


Starting Nordic UART service example
*** Booting Zephyr OS build v3.2.99-ncs2 ***
[00:00:00.014,984] <inf> fs_nvs: 8 Sectors of 4096 bytes
[00:00:00.015,075] <inf> fs_nvs: alloc wra: 0, fe8
[00:00:00.015,106] <inf> fs_nvs: data wra: 0, 0
[00:00:00.015,441] <inf> bt_sdc_hci_driver: SoftDevice Controller build revision: 
                                            d8 0c 2d 2f 36 ae e2 5c  80 26 80 4c 3f 4d 16 53 |..-/6..\ .&.L?M.S
                                            50 96 c7 73                                      |P..s             
[00:00:00.023,529] <inf> bt_hci_core: No ID address. App must call settings_load()
[00:00:00.023,529] <inf> peripheral_uart: Bluetooth initialized
[00:10:49.892,028] <inf> peripheral_uart: Connected F5:A0:02:E4:32:BC (random)

 

I think it's a child game, but I'm not able to continue... 

Parents
  • Hello,

    To make iOS initiate pairing, you need to set CONFIG_BT_NUS_AUTHEN=y to require authentication for the NUS service and then try to access one of the NUS characteristics from the app. 

    log messages from the 'auth' callbacks:

    00> [00:00:00.449,035] <inf> fs_nvs: 2 Sectors of 4096 bytes
    00> [00:00:00.449,096] <inf> fs_nvs: alloc wra: 0, fe8
    00> [00:00:00.449,127] <inf> fs_nvs: data wra: 0, 0
    00> [00:00:00.471,771] <inf> bt_hci_core: No ID address. App must call settings_load()
    00> [00:00:00.471,801] <inf> peripheral_uart: Bluetooth initialized
    00> [00:00:39.964,569] <inf> peripheral_uart: Connected 65:CC:ED:2F:2C:35 (random)
    00> [00:00:40.850,860] <wrn> bt_l2cap: Ignoring data for unknown channel ID 0x003a
    00> [00:00:45.908,050] <inf> peripheral_uart: Passkey for 65:CC:ED:2F:2C:35 (random): 225374
    00> [00:00:45.908,050] <inf> peripheral_uart: Press Button 1 to confirm, Button 2 to reject.
    00> [00:00:50.574,768] <inf> peripheral_uart: Numeric Match, conn 0x20009558
    00> [00:00:50.946,624] <inf> peripheral_uart: Security changed: 65:CC:ED:2F:2C:35 (random) level 4
    00> [00:00:51.041,900] <inf> peripheral_uart: Pairing completed: A8:4A:28:EC:76:99 (public), bonded: 1

    Best regards,

    Vidar

  • Hello Vidar,
    How are you ? Hope it's going on everything great.

    Now it works the NUS service auth. :-)

    But...I have a more generic question:

    Is there the possibility to implement this type of pairing autenticated with the device, at a level of connection (or at GATT level) ?

    I mean, in the real application, the situation is this:
    I have, e.g. 3 Centrals which has to be paired with respectively 6 peripherals, two for each central. they are in the same room.

    Previously I turned on one at time, and paired them with button accept request.



    Now, imagine to have all devices pre-autenticated in the same room, all turned ON.

    As the peripheral support 1 connection at time (or you can can set it to more than one, but it's not safe to set it to 10 for example I think), the fastest central connects to the P1 Green for example, keeps locked the peripheral as it's "CONNECTED BUT NOT AUTENTICATED FOR NUS SERVICE". 
    It's pre-autenticated with another central, but the connection keeps it locked.

    Well, how Can I implement this simple situation, allowing that only pre-authorized device can connect to my peripheral, and not every central ....? 

    Thanks Vidar!
    Enrico

  • Hi Encrico,

    I am doing good thanks. Hope you are too.

    enprevosti said:
    As the peripheral support 1 connection at time (or you can can set it to more than one, but it's not safe to set it to 10 for example I think), the fastest central connects to the P1 Green for example, keeps locked the peripheral as it's "CONNECTED BUT NOT AUTENTICATED FOR NUS SERVICE". 

    It may be better to change the security level from requiring authentication to encryption assuming you have limited IO capabilities on these devices. There is no Kconfig setting for this option. However, you can achieve it by manually replacing the BT_GATT_PERM_***_AUTH symbols with BT_GATT_PERM_***_ENCRYPT in your nus.c file.

    enprevosti said:
    Well, how Can I implement this simple situation, allowing that only pre-authorized device can connect to my peripheral, and not every central ....? 

    You can scan with the filter accept list (https://developer.nordicsemi.com/nRF_Connect_SDK/doc/2.3.0/zephyr/connectivity/bluetooth/api/gap.html#c.bt_le_filter_accept_list_add). With a filter accept list, the controller will only scan for devices in the list and ignore the rest. You can load the list with addresses from the bond table.

    I tested this with the central_uart sample by adding the following changes:

    diff --git a/prj.conf b/prj.conf
    index 7a7f864..4b218fb 100644
    --- a/prj.conf
    +++ b/prj.conf
    @@ -24,6 +24,8 @@ CONFIG_BT_SCAN_FILTER_ENABLE=y
     CONFIG_BT_SCAN_UUID_CNT=1
     CONFIG_BT_GATT_DM=y
     CONFIG_HEAP_MEM_POOL_SIZE=2048
    +CONFIG_BT_FILTER_ACCEPT_LIST=y
    +CONFIG_BT_KEYS_OVERWRITE_OLDEST=y
     
     # This example requires more workqueue stack
     CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
    @@ -44,3 +46,4 @@ CONFIG_LOG_BACKEND_UART=n
     CONFIG_LOG_PRINTK=n
     
     CONFIG_ASSERT=y
    +
    diff --git a/src/main.c b/src/main.c
    index ac5c2b9..df04a62 100644
    --- a/src/main.c
    +++ b/src/main.c
    @@ -62,6 +62,11 @@ static K_FIFO_DEFINE(fifo_uart_rx_data);
     static struct bt_conn *default_conn;
     static struct bt_nus_client nus_client;
     
    +struct bt_le_scan_param *scan_param_filter_accept_list = BT_LE_SCAN_PARAM(
    +	BT_LE_SCAN_TYPE_ACTIVE,
    +	BT_LE_SCAN_OPT_FILTER_DUPLICATE | BT_LE_SCAN_OPT_FILTER_ACCEPT_LIST,
    +	BT_GAP_SCAN_FAST_INTERVAL, BT_GAP_SCAN_FAST_WINDOW);
    +
     static void ble_data_sent(struct bt_nus_client *nus, uint8_t err,
     					const uint8_t *const data, uint16_t len)
     {
    @@ -423,12 +428,22 @@ static void disconnected(struct bt_conn *conn, uint8_t reason)
     static void security_changed(struct bt_conn *conn, bt_security_t level,
     			     enum bt_security_err err)
     {
    +	int ret;
     	char addr[BT_ADDR_LE_STR_LEN];
     
     	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
     
     	if (!err) {
     		LOG_INF("Security changed: %s level %u", addr, level);
    +		/* Enable scanning with filter accept list */
    +		ret = bt_le_filter_accept_list_add(bt_conn_get_dst(conn));
    +		if (ret) {
    +			LOG_INF("bt_le_filter_accept_list_add() failed. Err %d", ret);
    +		}
    +		ret = bt_scan_params_set(scan_param_filter_accept_list);
    +		if (ret) {
    +			LOG_INF("bt_scan_params_set() failed. Err %d", ret);
    +		}
     	} else {
     		LOG_WRN("Security failed: %s level %u err %d", addr,
     			level, err);
    @@ -486,17 +501,54 @@ static int nus_client_init(void)
     	return err;
     }
     
    +static void setup_accept_list_cb(const struct bt_bond_info *info, void *user_data)
    +{
    +	int *bond_cnt = user_data;
    +	char addr[BT_ADDR_LE_STR_LEN];
    +
    +	if ((*bond_cnt) < 0) {
    +		return;
    +	}
    +
    +	int err = bt_le_filter_accept_list_add(&info->addr);
    +
    +	bt_addr_le_to_str(&info->addr, addr, sizeof(addr));
    +
    +	if (err) {
    +		LOG_ERR("Cannot add peer to filter accept list (err: %d)", err);
    +		(*bond_cnt) = -EIO;
    +	} else {
    +		(*bond_cnt)++;
    +		LOG_INF("%s added to the filter accept list", addr);
    +	}
    +}
    +
     BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL,
     		scan_connecting_error, scan_connecting);
     
     static int scan_init(void)
     {
     	int err;
    +	int bond_cnt = 0;
    +
     	struct bt_scan_init_param scan_init = {
     		.connect_if_match = 1,
     	};
     
    -	bt_scan_init(&scan_init);
    +	struct bt_scan_init_param scan_init_with_accept_list = {
    +		.connect_if_match = 1,
    +	    .scan_param = scan_param_filter_accept_list,
    +	};
    +
    +	bt_foreach_bond(BT_ID_DEFAULT, setup_accept_list_cb, &bond_cnt);
    +
    +	if (bond_cnt == 0) {
    +		bt_scan_init(&scan_init);
    +	}
    +	else {
    +		bt_scan_init(&scan_init_with_accept_list);
    +	}
    +
     	bt_scan_cb_register(&scan_cb);

    /*
     * Copyright (c) 2018 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    /** @file
     *  @brief Nordic UART Service Client sample
     */
    
    #include <errno.h>
    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/devicetree.h>
    #include <zephyr/sys/byteorder.h>
    #include <zephyr/sys/printk.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/services/nus.h>
    #include <bluetooth/services/nus_client.h>
    #include <bluetooth/gatt_dm.h>
    #include <bluetooth/scan.h>
    
    #include <zephyr/settings/settings.h>
    
    #include <zephyr/drivers/uart.h>
    
    #include <zephyr/logging/log.h>
    
    #define LOG_MODULE_NAME central_uart
    LOG_MODULE_REGISTER(LOG_MODULE_NAME);
    
    /* UART payload buffer element size. */
    #define UART_BUF_SIZE 20
    
    #define KEY_PASSKEY_ACCEPT DK_BTN1_MSK
    #define KEY_PASSKEY_REJECT DK_BTN2_MSK
    
    #define NUS_WRITE_TIMEOUT K_MSEC(150)
    #define UART_WAIT_FOR_BUF_DELAY K_MSEC(50)
    #define UART_RX_TIMEOUT 50
    
    static const struct device *uart = DEVICE_DT_GET(DT_NODELABEL(uart0));
    static struct k_work_delayable uart_work;
    
    K_SEM_DEFINE(nus_write_sem, 0, 1);
    
    struct uart_data_t {
    	void *fifo_reserved;
    	uint8_t  data[UART_BUF_SIZE];
    	uint16_t len;
    };
    
    static K_FIFO_DEFINE(fifo_uart_tx_data);
    static K_FIFO_DEFINE(fifo_uart_rx_data);
    
    static struct bt_conn *default_conn;
    static struct bt_nus_client nus_client;
    
    struct bt_le_scan_param *scan_param_filter_accept_list = BT_LE_SCAN_PARAM(
    	BT_LE_SCAN_TYPE_ACTIVE,
    	BT_LE_SCAN_OPT_FILTER_DUPLICATE | BT_LE_SCAN_OPT_FILTER_ACCEPT_LIST,
    	BT_GAP_SCAN_FAST_INTERVAL, BT_GAP_SCAN_FAST_WINDOW);
    
    static void ble_data_sent(struct bt_nus_client *nus, uint8_t err,
    					const uint8_t *const data, uint16_t len)
    {
    	ARG_UNUSED(nus);
    
    	struct uart_data_t *buf;
    
    	/* Retrieve buffer context. */
    	buf = CONTAINER_OF(data, struct uart_data_t, data);
    	k_free(buf);
    
    	k_sem_give(&nus_write_sem);
    
    	if (err) {
    		LOG_WRN("ATT error code: 0x%02X", err);
    	}
    }
    
    static uint8_t ble_data_received(struct bt_nus_client *nus,
    						const uint8_t *data, uint16_t len)
    {
    	ARG_UNUSED(nus);
    
    	int err;
    
    	for (uint16_t pos = 0; pos != len;) {
    		struct uart_data_t *tx = k_malloc(sizeof(*tx));
    
    		if (!tx) {
    			LOG_WRN("Not able to allocate UART send data buffer");
    			return BT_GATT_ITER_CONTINUE;
    		}
    
    		/* Keep the last byte of TX buffer for potential LF char. */
    		size_t tx_data_size = sizeof(tx->data) - 1;
    
    		if ((len - pos) > tx_data_size) {
    			tx->len = tx_data_size;
    		} else {
    			tx->len = (len - pos);
    		}
    
    		memcpy(tx->data, &data[pos], tx->len);
    
    		pos += tx->len;
    
    		/* Append the LF character when the CR character triggered
    		 * transmission from the peer.
    		 */
    		if ((pos == len) && (data[len - 1] == '\r')) {
    			tx->data[tx->len] = '\n';
    			tx->len++;
    		}
    
    		err = uart_tx(uart, tx->data, tx->len, SYS_FOREVER_MS);
    		if (err) {
    			k_fifo_put(&fifo_uart_tx_data, tx);
    		}
    	}
    
    	return BT_GATT_ITER_CONTINUE;
    }
    
    static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data)
    {
    	ARG_UNUSED(dev);
    
    	static size_t aborted_len;
    	struct uart_data_t *buf;
    	static uint8_t *aborted_buf;
    	static bool disable_req;
    
    	switch (evt->type) {
    	case UART_TX_DONE:
    		LOG_DBG("UART_TX_DONE");
    		if ((evt->data.tx.len == 0) ||
    		    (!evt->data.tx.buf)) {
    			return;
    		}
    
    		if (aborted_buf) {
    			buf = CONTAINER_OF(aborted_buf, struct uart_data_t,
    					   data);
    			aborted_buf = NULL;
    			aborted_len = 0;
    		} else {
    			buf = CONTAINER_OF(evt->data.tx.buf,
    					   struct uart_data_t,
    					   data);
    		}
    
    		k_free(buf);
    
    		buf = k_fifo_get(&fifo_uart_tx_data, K_NO_WAIT);
    		if (!buf) {
    			return;
    		}
    
    		if (uart_tx(uart, buf->data, buf->len, SYS_FOREVER_MS)) {
    			LOG_WRN("Failed to send data over UART");
    		}
    
    		break;
    
    	case UART_RX_RDY:
    		LOG_DBG("UART_RX_RDY");
    		buf = CONTAINER_OF(evt->data.rx.buf, struct uart_data_t, data);
    		buf->len += evt->data.rx.len;
    
    		if (disable_req) {
    			return;
    		}
    
    		if ((evt->data.rx.buf[buf->len - 1] == '\n') ||
    		    (evt->data.rx.buf[buf->len - 1] == '\r')) {
    			disable_req = true;
    			uart_rx_disable(uart);
    		}
    
    		break;
    
    	case UART_RX_DISABLED:
    		LOG_DBG("UART_RX_DISABLED");
    		disable_req = false;
    
    		buf = k_malloc(sizeof(*buf));
    		if (buf) {
    			buf->len = 0;
    		} else {
    			LOG_WRN("Not able to allocate UART receive buffer");
    			k_work_reschedule(&uart_work, UART_WAIT_FOR_BUF_DELAY);
    			return;
    		}
    
    		uart_rx_enable(uart, buf->data, sizeof(buf->data),
    			       UART_RX_TIMEOUT);
    
    		break;
    
    	case UART_RX_BUF_REQUEST:
    		LOG_DBG("UART_RX_BUF_REQUEST");
    		buf = k_malloc(sizeof(*buf));
    		if (buf) {
    			buf->len = 0;
    			uart_rx_buf_rsp(uart, buf->data, sizeof(buf->data));
    		} else {
    			LOG_WRN("Not able to allocate UART receive buffer");
    		}
    
    		break;
    
    	case UART_RX_BUF_RELEASED:
    		LOG_DBG("UART_RX_BUF_RELEASED");
    		buf = CONTAINER_OF(evt->data.rx_buf.buf, struct uart_data_t,
    				   data);
    
    		if (buf->len > 0) {
    			k_fifo_put(&fifo_uart_rx_data, buf);
    		} else {
    			k_free(buf);
    		}
    
    		break;
    
    	case UART_TX_ABORTED:
    		LOG_DBG("UART_TX_ABORTED");
    		if (!aborted_buf) {
    			aborted_buf = (uint8_t *)evt->data.tx.buf;
    		}
    
    		aborted_len += evt->data.tx.len;
    		buf = CONTAINER_OF(aborted_buf, struct uart_data_t,
    				   data);
    
    		uart_tx(uart, &buf->data[aborted_len],
    			buf->len - aborted_len, SYS_FOREVER_MS);
    
    		break;
    
    	default:
    		break;
    	}
    }
    
    static void uart_work_handler(struct k_work *item)
    {
    	struct uart_data_t *buf;
    
    	buf = k_malloc(sizeof(*buf));
    	if (buf) {
    		buf->len = 0;
    	} else {
    		LOG_WRN("Not able to allocate UART receive buffer");
    		k_work_reschedule(&uart_work, UART_WAIT_FOR_BUF_DELAY);
    		return;
    	}
    
    	uart_rx_enable(uart, buf->data, sizeof(buf->data), UART_RX_TIMEOUT);
    }
    
    static int uart_init(void)
    {
    	int err;
    	struct uart_data_t *rx;
    
    	if (!device_is_ready(uart)) {
    		LOG_ERR("UART device not ready");
    		return -ENODEV;
    	}
    
    	rx = k_malloc(sizeof(*rx));
    	if (rx) {
    		rx->len = 0;
    	} else {
    		return -ENOMEM;
    	}
    
    	k_work_init_delayable(&uart_work, uart_work_handler);
    
    	err = uart_callback_set(uart, uart_cb, NULL);
    	if (err) {
    		return err;
    	}
    
    	return uart_rx_enable(uart, rx->data, sizeof(rx->data),
    			      UART_RX_TIMEOUT);
    }
    
    static void discovery_complete(struct bt_gatt_dm *dm,
    			       void *context)
    {
    	struct bt_nus_client *nus = context;
    	LOG_INF("Service discovery completed");
    
    	bt_gatt_dm_data_print(dm);
    
    	bt_nus_handles_assign(dm, nus);
    	bt_nus_subscribe_receive(nus);
    
    	bt_gatt_dm_data_release(dm);
    }
    
    static void discovery_service_not_found(struct bt_conn *conn,
    					void *context)
    {
    	LOG_INF("Service not found");
    }
    
    static void discovery_error(struct bt_conn *conn,
    			    int err,
    			    void *context)
    {
    	LOG_WRN("Error while discovering GATT database: (%d)", err);
    }
    
    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 != default_conn) {
    		return;
    	}
    
    	err = bt_gatt_dm_start(conn,
    			       BT_UUID_NUS_SERVICE,
    			       &discovery_cb,
    			       &nus_client);
    	if (err) {
    		LOG_ERR("could not start the discovery procedure, error "
    			"code: %d", err);
    	}
    }
    
    static void exchange_func(struct bt_conn *conn, uint8_t err, struct bt_gatt_exchange_params *params)
    {
    	if (!err) {
    		LOG_INF("MTU exchange done");
    	} else {
    		LOG_WRN("MTU exchange failed (err %" PRIu8 ")", err);
    	}
    }
    
    static void connected(struct bt_conn *conn, uint8_t conn_err)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    	int err;
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	if (conn_err) {
    		LOG_INF("Failed to connect to %s (%d)", addr, conn_err);
    
    		if (default_conn == conn) {
    			bt_conn_unref(default_conn);
    			default_conn = NULL;
    
    			err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
    			if (err) {
    				LOG_ERR("Scanning failed to start (err %d)",
    					err);
    			}
    		}
    
    		return;
    	}
    
    	LOG_INF("Connected: %s", addr);
    
    	static struct bt_gatt_exchange_params exchange_params;
    
    	exchange_params.func = exchange_func;
    	err = bt_gatt_exchange_mtu(conn, &exchange_params);
    	if (err) {
    		LOG_WRN("MTU exchange failed (err %d)", err);
    	}
    
    	err = bt_conn_set_security(conn, BT_SECURITY_L2);
    	if (err) {
    		LOG_WRN("Failed to set security: %d", err);
    
    		gatt_discover(conn);
    	}
    
    	err = bt_scan_stop();
    	if ((!err) && (err != -EALREADY)) {
    		LOG_ERR("Stop LE scan failed (err %d)", err);
    	}
    }
    
    static void disconnected(struct bt_conn *conn, uint8_t reason)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    	int err;
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	LOG_INF("Disconnected: %s (reason %u)", addr, reason);
    
    	if (default_conn != conn) {
    		return;
    	}
    
    	bt_conn_unref(default_conn);
    	default_conn = NULL;
    
    	err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
    	if (err) {
    		LOG_ERR("Scanning failed to start (err %d)",
    			err);
    	}
    }
    
    static void security_changed(struct bt_conn *conn, bt_security_t level,
    			     enum bt_security_err err)
    {
    	int ret;
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	if (!err) {
    		LOG_INF("Security changed: %s level %u", addr, level);
    		/* Enable scanning with filter accept list */
    		ret = bt_le_filter_accept_list_add(bt_conn_get_dst(conn));
    		if (ret) {
    			LOG_INF("bt_le_filter_accept_list_add() failed. Err %d", ret);
    		}
    		ret = bt_scan_params_set(scan_param_filter_accept_list);
    		if (ret) {
    			LOG_INF("bt_scan_params_set() failed. Err %d", ret);
    		}
    	} else {
    		LOG_WRN("Security failed: %s level %u err %d", addr,
    			level, err);
    	}
    
    	gatt_discover(conn);
    }
    
    BT_CONN_CB_DEFINE(conn_callbacks) = {
    	.connected = connected,
    	.disconnected = disconnected,
    	.security_changed = security_changed
    };
    
    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_WRN("Connecting failed");
    }
    
    static void scan_connecting(struct bt_scan_device_info *device_info,
    			    struct bt_conn *conn)
    {
    	default_conn = bt_conn_ref(conn);
    }
    
    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) {
    		LOG_ERR("NUS Client initialization failed (err %d)", err);
    		return err;
    	}
    
    	LOG_INF("NUS Client module initialized");
    	return err;
    }
    
    static void setup_accept_list_cb(const struct bt_bond_info *info, void *user_data)
    {
    	int *bond_cnt = user_data;
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	if ((*bond_cnt) < 0) {
    		return;
    	}
    
    	int err = bt_le_filter_accept_list_add(&info->addr);
    
    	bt_addr_le_to_str(&info->addr, addr, sizeof(addr));
    
    	if (err) {
    		LOG_ERR("Cannot add peer to filter accept list (err: %d)", err);
    		(*bond_cnt) = -EIO;
    	} else {
    		(*bond_cnt)++;
    		LOG_INF("%s added to the filter accept list", addr);
    	}
    }
    
    BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL,
    		scan_connecting_error, scan_connecting);
    
    static int scan_init(void)
    {
    	int err;
    	int bond_cnt = 0;
    
    	struct bt_scan_init_param scan_init = {
    		.connect_if_match = 1,
    	};
    
    	struct bt_scan_init_param scan_init_with_accept_list = {
    		.connect_if_match = 1,
    	    .scan_param = scan_param_filter_accept_list,
    	};
    
    	bt_foreach_bond(BT_ID_DEFAULT, setup_accept_list_cb, &bond_cnt);
    
    	if (bond_cnt == 0) {
    		bt_scan_init(&scan_init);
    	}
    	else {
    		bt_scan_init(&scan_init_with_accept_list);
    	}
    
    	bt_scan_cb_register(&scan_cb);
    
    	err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_UUID, BT_UUID_NUS_SERVICE);
    	if (err) {
    		LOG_ERR("Scanning filters cannot be set (err %d)", err);
    		return err;
    	}
    
    	err = bt_scan_filter_enable(BT_SCAN_UUID_FILTER, false);
    	if (err) {
    		LOG_ERR("Filters cannot be turned on (err %d)", err);
    		return err;
    	}
    
    	LOG_INF("Scan module initialized");
    	return err;
    }
    
    
    static void auth_cancel(struct bt_conn *conn)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	LOG_INF("Pairing cancelled: %s", addr);
    }
    
    
    static void pairing_complete(struct bt_conn *conn, bool bonded)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	LOG_INF("Pairing completed: %s, bonded: %d", addr, bonded);
    }
    
    
    static void pairing_failed(struct bt_conn *conn, enum bt_security_err reason)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    	LOG_WRN("Pairing failed conn: %s, reason %d", addr, reason);
    }
    
    static struct bt_conn_auth_cb conn_auth_callbacks = {
    	.cancel = auth_cancel,
    };
    
    static struct bt_conn_auth_info_cb conn_auth_info_callbacks = {
    	.pairing_complete = pairing_complete,
    	.pairing_failed = pairing_failed
    };
    
    
    
    void main(void)
    {
    	int err;
    
    	err = bt_conn_auth_cb_register(&conn_auth_callbacks);
    	if (err) {
    		LOG_ERR("Failed to register authorization callbacks.");
    		return;
    	}
    
    	err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
    	if (err) {
    		printk("Failed to register authorization info callbacks.\n");
    		return;
    	}
    
    	err = bt_enable(NULL);
    	if (err) {
    		LOG_ERR("Bluetooth init failed (err %d)", err);
    		return;
    	}
    	LOG_INF("Bluetooth initialized");
    
    	if (IS_ENABLED(CONFIG_SETTINGS)) {
    		settings_load();
    	}
    
    	int (*module_init[])(void) = {uart_init, scan_init, nus_client_init};
    	for (size_t i = 0; i < ARRAY_SIZE(module_init); i++) {
    		err = (*module_init[i])();
    		if (err) {
    			return;
    		}
    	}
    
    	printk("Starting Bluetooth Central UART example\n");
    
    	err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
    	if (err) {
    		LOG_ERR("Scanning failed to start (err %d)", err);
    		return;
    	}
    
    	LOG_INF("Scanning successfully started");
    
    	for (;;) {
    		/* Wait indefinitely for data to be sent over Bluetooth */
    		struct uart_data_t *buf = k_fifo_get(&fifo_uart_rx_data,
    						     K_FOREVER);
    
    		err = bt_nus_client_send(&nus_client, buf->data, buf->len);
    		if (err) {
    			LOG_WRN("Failed to send data over BLE connection"
    				"(err %d)", err);
    		}
    
    		err = k_sem_take(&nus_write_sem, NUS_WRITE_TIMEOUT);
    		if (err) {
    			LOG_WRN("NUS send timeout");
    		}
    	}
    }
    

    And it seemed to work. But it needs more review and testing to ensure it covers all scenarios. The accept list will for instance need to be updated when bonds are removed. I did not implement that.

    Zephyr includes a sample to demonstrate how the filter accept list can be used which you can use as a reference.  https://github.com/nrfconnect/sdk-zephyr/tree/main/samples/bluetooth/peripheral_accept_list. But note that it is for the peripheral role, so there will be some slight differences in the implementation. 

    Best regards,

    Vidar

  • Hello Vidar, thanks for your informations!
    I tried and implemented a scenario different than your example, using your suggestions on zephyr example on peripheral. 
    Using Peripheral accept list, I implemented a targeted advertise, so if there's a bond, the device is adv only at that central, otherwise it has no address list adv.

    This seems to be working now, and I'm trying to move in that direction.
    Thanks a lot for your support!

    Enrico

  • Sorry for Re-Opening the ticket  ...

    I have a problem with the implementation.
    The first time, everything works properly.

    Peripheral just flashed, empty.
    Central just flashed, empty.

    Well, after the pairing, as suggested in the example, I soft-reboot the peripheral device in order to start advertising only to my whitelisted device, i.e. the just bonded central.

    BUT, after restarting the peripheral, the central seems not able to initiate the connection again.

    In fact, during the re-connection, the central device on "connected" callback, gives the error:

    BT_HCI_ERR_UNKNOWN_CONN_ID

    And, as all examples shows, this lead to a failure on connection establishment.

    So, where's the problem ?


    Note: using iOS nRF App, it seems that the re-connection works... after reboot I can see the device in the list, click CONNECT and that's okay.

    I imagine problem is on central side... is there something to enable, to catch this re-connection after bonding ?

    Thanks......

     
    [    0.020 B] AppInit.c: ---------------------------------------------
    [    0.027 B] AppInit.c: INIT 
    [    0.029 B] AppInit.c: ---------------------------------------------
    [    0.036 B] AppInit.c: Debug Log init
    [    0.039 B] AppInit.c: System Timer init
    [    0.000 B] AppInit.c: SPI init
    [    0.003 B] Spi3.c: SPI Inialized
    [    0.006 B] AppInit.c: AppFunction Manager init
    [    0.024 I] AppFuncBLE.c: Settings Loaded
    [    0.029 I] AppFuncBLE.c: Authorization callbacks registered
    [    0.035 I] AppFuncBLE.c: Bluetooth initialized
    [    0.040 E] AppFuncLsm6dsv16x.c: ERROR: func:AppFuncLsm6dsv16x_Init   line:181
    [    0.047 I] main.c: 
    [    0.050 I] main.c: AppThread START
    [    0.053 I] main.c: 
    [    0.055 I] AppFuncBLE.c: AppFuncBLE_ThreadRun START - Tx Power = 8dB
    *** Booting Zephyr OS build v3.2.99-ncs2 ***
    [00:00:00.061,614] <inf> fs_nvs: nvs_mount: 8 Sectors of 4096 bytes
    [00:00:00.061,645] <inf> fs_nvs: nvs_mount: alloc wra: 0, f10
    [00:00:00.061,645] <inf> fs_nvs: nvs_mount: data wra: 0, 21c
    [00:00:00.061,920] <inf> bt_sdc_hci_driver: hci_driver_open: SoftDevice Controller build revision: 
                                                d8 0c 2d 2f 36 ae e2 5c  80 26 80 4c 3f 4d 16 53 |..-/6..\ .&.L?M.S
                                                50 96 c7 73                                      |P..s             
    [00:00:00.065,887] <inf> bt_hci_core: hci_vs_init: HW Platform: Nordic Semiconductor (0x0002)
    [00:00:00.065,917] <inf> bt_hci_core: hci_vs_init: HW Variant: nRF52x (0x0002)
    [00:00:00.065,948] <inf> bt_hci_core: hci_vs_init: Firmware: Standard Bluetooth controller (0x00) Version 216.11532 Build 3803067951
    [00:00:00.066,680] <inf> bt_hci_core: bt_init: No ID address. App must call settings_load()
    [00:00:00.067,901] <inf> bt_hci_core: bt_dev_show_info: Identity: CD:C7:6A:14:0F:5B (random)
    [00:00:00.067,962] <inf> bt_hci_core: bt_dev_show_info: HCI: version 5.3 (0x0c) revision 0x124b, manufacturer 0x0059
    [00:00:00.067,993] <inf> bt_hci_core: bt_dev_show_info: LMP: version 5.3 (0x0c) subver 0x124b
    [    0.300 I] AppFuncBLE.c: Numeric Match, conn (nil)[    0.305 I] AppFuncInput.c: Button Released[    6.705 I] AppFuncBLE.c: Connected to [4B:1F:EB:72:C2:D4 (random)]
    [    7.201 I] AppFuncBLE.c: LE PHY Updated: 4B:1F:EB:72:C2:D4 (random) Tx 0x2, Rx 0x2
    [    7.261 I] AppFuncBLE.c: Data length updated: 4B:1F:EB:72:C2:D4 (random) max tx 251 (2120 us) max rx 251 (2120 us)
    [    7.953 I] AppFuncBLE.c: Passkey Confirm for destAddr [4B:1F:EB:72:C2:D4 (random)]: 923524
    [    7.961 I] AppFuncBLE.c: Press Button 1 to confirm, Button 2 to reject.
    [00:00:07.365,325] <wrn> bt_l2cap: bt_l2cap_recv: Ignoring data for unknown channel ID 0x003a
    [   10.357 I] AppFuncInput.c: Button Pressed [   10.548 I] AppFuncBLE.c: Numeric Match, conn 0x20002c48[   10.553 I] AppFuncInput.c: Button Released[   10.772 I] AppFuncBLE.c: Security changed on dev[4B:1F:EB:72:C2:D4 (random)] level 4
    [   10.780 I] AppFuncBLE.c: Connection encrypted and authenticated[   10.868 I] AppFuncBLE.c: Pairing completed: destAddr [A0:FB:C5:1B:53:77 (public)], bonded: 1
    [    0.000 I] main.c: ---------------------------------------------
    [    0.006 I] main.c: Starting 2B220732 Node - Sofware v1.0.0
    [    0.012 I] main.c: ---------------------------------------------
    [    0.018 I] main.c: 
    [    0.020 B] AppInit.c: ---------------------------------------------
    [    0.027 B] AppInit.c: INIT 
    [    0.029 B] AppInit.c: ---------------------------------------------
    [    0.036 B] AppInit.c: Debug Log init
    [    0.039 B] AppInit.c: System Timer init
    [    0.000 B] AppInit.c: SPI init
    [    0.003 B] Spi3.c: SPI Inialized
    [    0.006 B] AppInit.c: AppFunction Manager init
    [    0.025 I] AppFuncBLE.c: Settings Loaded
    [    0.029 I] AppFuncBLE.c: Added A0:FB:C5:1B:53:77 (public) to advertising accept filter list
    [    0.037 I] AppFuncBLE.c: Find Bonded [1]
    [    0.043 I] AppFuncBLE.c: Authorization callbacks registered
    [    0.049 I] AppFuncBLE.c: Bluetooth initialized
    [    0.054 E] AppFuncLsm6dsv16x.c: ERROR: func:AppFuncLsm6dsv16x_Init   line:181
    [    0.061 I] main.c: 
    [    0.063 I] main.c: AppThread START
    [    0.066 I] main.c: 
    [    0.069 I] AppFuncBLE.c: AppFuncBLE_ThreadRun START - Tx Power = 8dB
    *** Booting Zephyr OS build v3.2.99-ncs2 ***
    [00:00:00.061,401] <inf> fs_nvs: nvs_mount: 8 Sectors of 4096 bytes
    [00:00:00.061,401] <inf> fs_nvs: nvs_mount: alloc wra: 0, ef8
    [00:00:00.061,431] <inf> fs_nvs: nvs_mount: data wra: 0, 298
    [00:00:00.061,706] <inf> bt_sdc_hci_driver: hci_driver_open: SoftDevice Controller build revision: 
                                                d8 0c 2d 2f 36 ae e2 5c  80 26 80 4c 3f 4d 16 53 |..-/6..\ .&.L?M.S
                                                50 96 c7 73                                      |P..s             
    [00:00:00.065,643] <inf> bt_hci_core: hci_vs_init: HW Platform: Nordic Semiconductor (0x0002)
    [00:00:00.065,673] <inf> bt_hci_core: hci_vs_init: HW Variant: nRF52x (0x0002)
    [00:00:00.065,734] <inf> bt_hci_core: hci_vs_init: Firmware: Standard Bluetooth controller (0x00) Version 216.11532 Build 3803067951
    [00:00:00.066,467] <inf> bt_hci_core: bt_init: No ID address. App must call settings_load()
    [00:00:00.067,871] <inf> bt_hci_core: bt_dev_show_info: Identity: CD:C7:6A:14:0F:5B (random)
    [00:00:00.067,901] <inf> bt_hci_core: bt_dev_show_info: HCI: version 5.3 (0x0c) revision 0x124b, manufacturer 0x0059
    [00:00:00.067,932] <inf> bt_hci_core: bt_dev_show_info: LMP: version 5.3 (0x0c) subver 0x124b
    [    9.641 I] AppFuncBLE.c: Connected to [A0:FB:C5:1B:53:77 (public)]
    [    9.914 I] AppFuncBLE.c: Security changed on dev[A0:FB:C5:1B:53:77 (public)] level 4
    [    9.922 I] AppFuncBLE.c: Connection encrypted and authenticated[   10.303 I] AppFuncBLE.c: LE PHY Updated: A0:FB:C5:1B:53:77 (public) Tx 0x2, Rx 0x2
    [   10.364 I] AppFuncBLE.c: Data length updated: A0:FB:C5:1B:53:77 (public) max tx 251 (2120 us) max rx 251 (2120 us)
    [00:00:10.467,803] <wrn> bt_l2cap: bt_l2cap_recv: Ignoring data for unknown channel ID 0x003a
Reply
  • Sorry for Re-Opening the ticket  ...

    I have a problem with the implementation.
    The first time, everything works properly.

    Peripheral just flashed, empty.
    Central just flashed, empty.

    Well, after the pairing, as suggested in the example, I soft-reboot the peripheral device in order to start advertising only to my whitelisted device, i.e. the just bonded central.

    BUT, after restarting the peripheral, the central seems not able to initiate the connection again.

    In fact, during the re-connection, the central device on "connected" callback, gives the error:

    BT_HCI_ERR_UNKNOWN_CONN_ID

    And, as all examples shows, this lead to a failure on connection establishment.

    So, where's the problem ?


    Note: using iOS nRF App, it seems that the re-connection works... after reboot I can see the device in the list, click CONNECT and that's okay.

    I imagine problem is on central side... is there something to enable, to catch this re-connection after bonding ?

    Thanks......

     
    [    0.020 B] AppInit.c: ---------------------------------------------
    [    0.027 B] AppInit.c: INIT 
    [    0.029 B] AppInit.c: ---------------------------------------------
    [    0.036 B] AppInit.c: Debug Log init
    [    0.039 B] AppInit.c: System Timer init
    [    0.000 B] AppInit.c: SPI init
    [    0.003 B] Spi3.c: SPI Inialized
    [    0.006 B] AppInit.c: AppFunction Manager init
    [    0.024 I] AppFuncBLE.c: Settings Loaded
    [    0.029 I] AppFuncBLE.c: Authorization callbacks registered
    [    0.035 I] AppFuncBLE.c: Bluetooth initialized
    [    0.040 E] AppFuncLsm6dsv16x.c: ERROR: func:AppFuncLsm6dsv16x_Init   line:181
    [    0.047 I] main.c: 
    [    0.050 I] main.c: AppThread START
    [    0.053 I] main.c: 
    [    0.055 I] AppFuncBLE.c: AppFuncBLE_ThreadRun START - Tx Power = 8dB
    *** Booting Zephyr OS build v3.2.99-ncs2 ***
    [00:00:00.061,614] <inf> fs_nvs: nvs_mount: 8 Sectors of 4096 bytes
    [00:00:00.061,645] <inf> fs_nvs: nvs_mount: alloc wra: 0, f10
    [00:00:00.061,645] <inf> fs_nvs: nvs_mount: data wra: 0, 21c
    [00:00:00.061,920] <inf> bt_sdc_hci_driver: hci_driver_open: SoftDevice Controller build revision: 
                                                d8 0c 2d 2f 36 ae e2 5c  80 26 80 4c 3f 4d 16 53 |..-/6..\ .&.L?M.S
                                                50 96 c7 73                                      |P..s             
    [00:00:00.065,887] <inf> bt_hci_core: hci_vs_init: HW Platform: Nordic Semiconductor (0x0002)
    [00:00:00.065,917] <inf> bt_hci_core: hci_vs_init: HW Variant: nRF52x (0x0002)
    [00:00:00.065,948] <inf> bt_hci_core: hci_vs_init: Firmware: Standard Bluetooth controller (0x00) Version 216.11532 Build 3803067951
    [00:00:00.066,680] <inf> bt_hci_core: bt_init: No ID address. App must call settings_load()
    [00:00:00.067,901] <inf> bt_hci_core: bt_dev_show_info: Identity: CD:C7:6A:14:0F:5B (random)
    [00:00:00.067,962] <inf> bt_hci_core: bt_dev_show_info: HCI: version 5.3 (0x0c) revision 0x124b, manufacturer 0x0059
    [00:00:00.067,993] <inf> bt_hci_core: bt_dev_show_info: LMP: version 5.3 (0x0c) subver 0x124b
    [    0.300 I] AppFuncBLE.c: Numeric Match, conn (nil)[    0.305 I] AppFuncInput.c: Button Released[    6.705 I] AppFuncBLE.c: Connected to [4B:1F:EB:72:C2:D4 (random)]
    [    7.201 I] AppFuncBLE.c: LE PHY Updated: 4B:1F:EB:72:C2:D4 (random) Tx 0x2, Rx 0x2
    [    7.261 I] AppFuncBLE.c: Data length updated: 4B:1F:EB:72:C2:D4 (random) max tx 251 (2120 us) max rx 251 (2120 us)
    [    7.953 I] AppFuncBLE.c: Passkey Confirm for destAddr [4B:1F:EB:72:C2:D4 (random)]: 923524
    [    7.961 I] AppFuncBLE.c: Press Button 1 to confirm, Button 2 to reject.
    [00:00:07.365,325] <wrn> bt_l2cap: bt_l2cap_recv: Ignoring data for unknown channel ID 0x003a
    [   10.357 I] AppFuncInput.c: Button Pressed [   10.548 I] AppFuncBLE.c: Numeric Match, conn 0x20002c48[   10.553 I] AppFuncInput.c: Button Released[   10.772 I] AppFuncBLE.c: Security changed on dev[4B:1F:EB:72:C2:D4 (random)] level 4
    [   10.780 I] AppFuncBLE.c: Connection encrypted and authenticated[   10.868 I] AppFuncBLE.c: Pairing completed: destAddr [A0:FB:C5:1B:53:77 (public)], bonded: 1
    [    0.000 I] main.c: ---------------------------------------------
    [    0.006 I] main.c: Starting 2B220732 Node - Sofware v1.0.0
    [    0.012 I] main.c: ---------------------------------------------
    [    0.018 I] main.c: 
    [    0.020 B] AppInit.c: ---------------------------------------------
    [    0.027 B] AppInit.c: INIT 
    [    0.029 B] AppInit.c: ---------------------------------------------
    [    0.036 B] AppInit.c: Debug Log init
    [    0.039 B] AppInit.c: System Timer init
    [    0.000 B] AppInit.c: SPI init
    [    0.003 B] Spi3.c: SPI Inialized
    [    0.006 B] AppInit.c: AppFunction Manager init
    [    0.025 I] AppFuncBLE.c: Settings Loaded
    [    0.029 I] AppFuncBLE.c: Added A0:FB:C5:1B:53:77 (public) to advertising accept filter list
    [    0.037 I] AppFuncBLE.c: Find Bonded [1]
    [    0.043 I] AppFuncBLE.c: Authorization callbacks registered
    [    0.049 I] AppFuncBLE.c: Bluetooth initialized
    [    0.054 E] AppFuncLsm6dsv16x.c: ERROR: func:AppFuncLsm6dsv16x_Init   line:181
    [    0.061 I] main.c: 
    [    0.063 I] main.c: AppThread START
    [    0.066 I] main.c: 
    [    0.069 I] AppFuncBLE.c: AppFuncBLE_ThreadRun START - Tx Power = 8dB
    *** Booting Zephyr OS build v3.2.99-ncs2 ***
    [00:00:00.061,401] <inf> fs_nvs: nvs_mount: 8 Sectors of 4096 bytes
    [00:00:00.061,401] <inf> fs_nvs: nvs_mount: alloc wra: 0, ef8
    [00:00:00.061,431] <inf> fs_nvs: nvs_mount: data wra: 0, 298
    [00:00:00.061,706] <inf> bt_sdc_hci_driver: hci_driver_open: SoftDevice Controller build revision: 
                                                d8 0c 2d 2f 36 ae e2 5c  80 26 80 4c 3f 4d 16 53 |..-/6..\ .&.L?M.S
                                                50 96 c7 73                                      |P..s             
    [00:00:00.065,643] <inf> bt_hci_core: hci_vs_init: HW Platform: Nordic Semiconductor (0x0002)
    [00:00:00.065,673] <inf> bt_hci_core: hci_vs_init: HW Variant: nRF52x (0x0002)
    [00:00:00.065,734] <inf> bt_hci_core: hci_vs_init: Firmware: Standard Bluetooth controller (0x00) Version 216.11532 Build 3803067951
    [00:00:00.066,467] <inf> bt_hci_core: bt_init: No ID address. App must call settings_load()
    [00:00:00.067,871] <inf> bt_hci_core: bt_dev_show_info: Identity: CD:C7:6A:14:0F:5B (random)
    [00:00:00.067,901] <inf> bt_hci_core: bt_dev_show_info: HCI: version 5.3 (0x0c) revision 0x124b, manufacturer 0x0059
    [00:00:00.067,932] <inf> bt_hci_core: bt_dev_show_info: LMP: version 5.3 (0x0c) subver 0x124b
    [    9.641 I] AppFuncBLE.c: Connected to [A0:FB:C5:1B:53:77 (public)]
    [    9.914 I] AppFuncBLE.c: Security changed on dev[A0:FB:C5:1B:53:77 (public)] level 4
    [    9.922 I] AppFuncBLE.c: Connection encrypted and authenticated[   10.303 I] AppFuncBLE.c: LE PHY Updated: A0:FB:C5:1B:53:77 (public) Tx 0x2, Rx 0x2
    [   10.364 I] AppFuncBLE.c: Data length updated: A0:FB:C5:1B:53:77 (public) max tx 251 (2120 us) max rx 251 (2120 us)
    [00:00:10.467,803] <wrn> bt_l2cap: bt_l2cap_recv: Ignoring data for unknown channel ID 0x003a
Children
Related