Communicate two microcontrollers via BLE

Hello,

I'm using a nRF52 DK to test BLE communication with another microcontroller. What I need to test is the nRF52 pairing with another brand microcontroller, send a data stream and close the connection.

Could you please tell me which example from the Bluetooth samples list I can use for starting?

Thanks for your attention.

Regards,

Parents
  • Hello ,

    Thank you very much. I've reviewed this example and it is supposed to connect with the first device with an strong signal. Is there a way to force the board to connect with the device with a given MAC address?

  • From nRF Connect I cannot detect the device. Would it be possible given that the nRF52 is working as a central?

  • Sorry, I meant to ask if you were able to pair with the peripheral device from your phone.

  • Yes, with my phone I can pair with the peripheral device.

  • Thanks for confirming. This indicates that the problem is likely in the nRF FW. Can you please show where you are calling bt_conn_set_security() or post your main.c file here?

  • Below the main.c file:

    /*
     * 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;
    
    #if 1
    static void device_found(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 addr_str_tmp[BT_ADDR_LE_STR_LEN];
    	int err;
    
    	printk("Device found\n");
    	bt_addr_le_to_str((addr), addr_str_tmp, sizeof(addr_str_tmp));
    	printk("MAC: %s found\n", addr_str_tmp);
    
    	if (default_conn) {
    		return;
    	}
    
    	/* We're only interested in connectable events */
    	if (type != BT_GAP_ADV_TYPE_ADV_IND &&
    	    type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) {
    		return;
    	}
    
    	bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
    	printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
    
    	/* connect only to devices in close proximity */
    	if (rssi < -70) {
    		return;
    	}
    
    	if (bt_le_scan_stop()) {
    		return;
    	}
    
    	err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN,
    				BT_LE_CONN_PARAM_DEFAULT, &default_conn);
    	if (err) {
    		printk("Create conn to %s failed (%u)\n", addr_str, err);
    		start_scan();
    	}
    }
    
    
    #endif
    
    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;
    	printk("uart_init\n");
    	if (!device_is_ready(uart)) {
    		LOG_ERR("UART device not ready");
    		printk("UART device not ready\n");
    		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");
    	printk("Service discovery completed\n");
    
    	bt_gatt_dm_data_print(dm);
    
    	/* Assign connection instance. */
    	nus_client.conn = bt_gatt_dm_conn_get(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");
    	printk("Service not found\n");
    }
    
    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);
    		printk("could not start the discovery procedure, error "
    			"code: %d\n", 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));
    	printk("connected conn_err: %u\n", conn_err);
    
    	if (conn_err) {
    		LOG_INF("Failed to connect to %s (%d)", addr, conn_err);
    		printk("Failed to connect to %s (%d)\n", 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);
    				printk("Scanning failed to start (err %d)\n",
    					err);
    			}
    		}
    
    		return;
    	}
    
    	LOG_INF("Connected: %s", addr);
    	printk("Connected: %s\n", 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);
    		printk("Stop LE scan failed (err %d)\n", 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);
    	printk("bt_scan_start err:%i\n", err);
    	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)
    {
    	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);
    	} 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,
    		}
    	};
    	printk("bt_nus_client_init\n");
    	err = bt_nus_client_init(&nus_client, &init);
    	if (err) {
    		LOG_ERR("NUS Client initialization failed (err %d)", err);
    		printk("NUS Client initialization failed (err %d)", err);
    		return err;
    	}
    
    	LOG_INF("NUS Client module initialized");
    	printk("NUS Client module initialized\n");
    	return err;
    }
    
    BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL,
    		scan_connecting_error, scan_connecting);
    
    static int scan_init(void)
    {
    	int err;
    	struct bt_scan_init_param scan_init = {
    		.connect_if_match = 1,
    	};
    
    	bt_addr_t esp_add[BT_ADDR_SIZE] = {0xD2, 0x29, 0xF5, 0xF9, 0x55, 0x60};
    	bt_addr_le_t esp32_address = {
    		.type = BT_ADDR_LE_PUBLIC,
    		.a = /*esp_add*/{0xD2, 0x29, 0xF5, 0xF9, 0x55, 0x60},
    	};
    
    	printk("scan_init\n");
    	bt_scan_init(&scan_init);
    	bt_scan_cb_register(&scan_cb);
    
    	//err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_UUID, BT_UUID_NUS_SERVICE);
    	//err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_ADDR, esp32_address);
    	err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_ADDR, &esp32_address);
    	if (err) {
    		LOG_ERR("Scanning filters cannot be set (err %d)", err);
    		printk("Scanning filters cannot be set (err %d)\n", err);
    		return err;
    	}
    	
    	char addr_str[BT_ADDR_LE_STR_LEN];
    	bt_addr_le_to_str(&esp32_address, addr_str,
    				  sizeof(addr_str));
    	printk("Address filter added %s\n", addr_str);
    
    	//err = bt_scan_filter_enable(BT_SCAN_UUID_FILTER, false);
    	err = bt_scan_filter_enable(BT_SCAN_ADDR_FILTER, false);
    	
    	if (err) {
    		LOG_ERR("Filters cannot be turned on (err %d)", err);
    		printk("Filters cannot be turned on (err %d)\n", err);
    		return err;
    	}
    
    	LOG_INF("Scan module initialized");
    	printk("Scan module initialized\n");
    	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));
    	printk("addr: %s", addr);
    
    	LOG_INF("Pairing completed: %s, bonded: %d", addr, bonded);
    	printk("Pairing completed: %s, bonded: %d\n", 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);
    	printk("Pairing failed conn: %s, reason %d\n", 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;
    	}
    	printk("bt_conn_auth_cb_register\n");
    
    	err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
    	printk("bt_conn_auth_info_cb_register err: %i\n", err);
    	if (err) {
    		printk("Failed to register authorization info callbacks.\n");
    		return;
    	}
    
    	err = bt_enable(NULL);
    	printk("bt_enable err: %i\n", err);
    	if (err) {
    		LOG_ERR("Bluetooth init failed (err %d)", err);
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    	printk("Bluetooth initialized\n");
    	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])();
    		//printk("i: %i\n", i);
    		if (err) {
    			printk("ERR\n");
    			return;
    		}
    	}
    	printk("\n");
    
    	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);
    		printk("Scanning failed to start (err %d)\n", err);
    		return;
    	}
    
    	LOG_INF("Scanning successfully started");
    	printk("Scanning successfully started\n");
    
    	for (;;) {
    		/* Wait indefinitely for data to be sent over Bluetooth */
    		//struct uart_data_t *buf = k_fifo_get(&fifo_uart_rx_data,
    		//				     K_FOREVER);
    
    		struct uart_data_t *buf;
    		buf->data[0] = 0;
    		buf->data[1] = 1;
    		buf->data[2] = 2;
    		buf->len = 3;
    
    		//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);
    			printk("Failed to send data over BLE connection"
    				"(err %d)\n", err);
    		}
    
    		//err = k_sem_take(&nus_write_sem, NUS_WRITE_TIMEOUT);
    		if (err) {
    			LOG_WRN("NUS send timeout");
    			//printk("NUS send timeout\n");
    		}
    	}
    }
    

Reply
  • Below the main.c file:

    /*
     * 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;
    
    #if 1
    static void device_found(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 addr_str_tmp[BT_ADDR_LE_STR_LEN];
    	int err;
    
    	printk("Device found\n");
    	bt_addr_le_to_str((addr), addr_str_tmp, sizeof(addr_str_tmp));
    	printk("MAC: %s found\n", addr_str_tmp);
    
    	if (default_conn) {
    		return;
    	}
    
    	/* We're only interested in connectable events */
    	if (type != BT_GAP_ADV_TYPE_ADV_IND &&
    	    type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) {
    		return;
    	}
    
    	bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
    	printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
    
    	/* connect only to devices in close proximity */
    	if (rssi < -70) {
    		return;
    	}
    
    	if (bt_le_scan_stop()) {
    		return;
    	}
    
    	err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN,
    				BT_LE_CONN_PARAM_DEFAULT, &default_conn);
    	if (err) {
    		printk("Create conn to %s failed (%u)\n", addr_str, err);
    		start_scan();
    	}
    }
    
    
    #endif
    
    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;
    	printk("uart_init\n");
    	if (!device_is_ready(uart)) {
    		LOG_ERR("UART device not ready");
    		printk("UART device not ready\n");
    		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");
    	printk("Service discovery completed\n");
    
    	bt_gatt_dm_data_print(dm);
    
    	/* Assign connection instance. */
    	nus_client.conn = bt_gatt_dm_conn_get(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");
    	printk("Service not found\n");
    }
    
    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);
    		printk("could not start the discovery procedure, error "
    			"code: %d\n", 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));
    	printk("connected conn_err: %u\n", conn_err);
    
    	if (conn_err) {
    		LOG_INF("Failed to connect to %s (%d)", addr, conn_err);
    		printk("Failed to connect to %s (%d)\n", 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);
    				printk("Scanning failed to start (err %d)\n",
    					err);
    			}
    		}
    
    		return;
    	}
    
    	LOG_INF("Connected: %s", addr);
    	printk("Connected: %s\n", 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);
    		printk("Stop LE scan failed (err %d)\n", 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);
    	printk("bt_scan_start err:%i\n", err);
    	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)
    {
    	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);
    	} 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,
    		}
    	};
    	printk("bt_nus_client_init\n");
    	err = bt_nus_client_init(&nus_client, &init);
    	if (err) {
    		LOG_ERR("NUS Client initialization failed (err %d)", err);
    		printk("NUS Client initialization failed (err %d)", err);
    		return err;
    	}
    
    	LOG_INF("NUS Client module initialized");
    	printk("NUS Client module initialized\n");
    	return err;
    }
    
    BT_SCAN_CB_INIT(scan_cb, scan_filter_match, NULL,
    		scan_connecting_error, scan_connecting);
    
    static int scan_init(void)
    {
    	int err;
    	struct bt_scan_init_param scan_init = {
    		.connect_if_match = 1,
    	};
    
    	bt_addr_t esp_add[BT_ADDR_SIZE] = {0xD2, 0x29, 0xF5, 0xF9, 0x55, 0x60};
    	bt_addr_le_t esp32_address = {
    		.type = BT_ADDR_LE_PUBLIC,
    		.a = /*esp_add*/{0xD2, 0x29, 0xF5, 0xF9, 0x55, 0x60},
    	};
    
    	printk("scan_init\n");
    	bt_scan_init(&scan_init);
    	bt_scan_cb_register(&scan_cb);
    
    	//err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_UUID, BT_UUID_NUS_SERVICE);
    	//err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_ADDR, esp32_address);
    	err = bt_scan_filter_add(BT_SCAN_FILTER_TYPE_ADDR, &esp32_address);
    	if (err) {
    		LOG_ERR("Scanning filters cannot be set (err %d)", err);
    		printk("Scanning filters cannot be set (err %d)\n", err);
    		return err;
    	}
    	
    	char addr_str[BT_ADDR_LE_STR_LEN];
    	bt_addr_le_to_str(&esp32_address, addr_str,
    				  sizeof(addr_str));
    	printk("Address filter added %s\n", addr_str);
    
    	//err = bt_scan_filter_enable(BT_SCAN_UUID_FILTER, false);
    	err = bt_scan_filter_enable(BT_SCAN_ADDR_FILTER, false);
    	
    	if (err) {
    		LOG_ERR("Filters cannot be turned on (err %d)", err);
    		printk("Filters cannot be turned on (err %d)\n", err);
    		return err;
    	}
    
    	LOG_INF("Scan module initialized");
    	printk("Scan module initialized\n");
    	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));
    	printk("addr: %s", addr);
    
    	LOG_INF("Pairing completed: %s, bonded: %d", addr, bonded);
    	printk("Pairing completed: %s, bonded: %d\n", 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);
    	printk("Pairing failed conn: %s, reason %d\n", 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;
    	}
    	printk("bt_conn_auth_cb_register\n");
    
    	err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
    	printk("bt_conn_auth_info_cb_register err: %i\n", err);
    	if (err) {
    		printk("Failed to register authorization info callbacks.\n");
    		return;
    	}
    
    	err = bt_enable(NULL);
    	printk("bt_enable err: %i\n", err);
    	if (err) {
    		LOG_ERR("Bluetooth init failed (err %d)", err);
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    	printk("Bluetooth initialized\n");
    	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])();
    		//printk("i: %i\n", i);
    		if (err) {
    			printk("ERR\n");
    			return;
    		}
    	}
    	printk("\n");
    
    	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);
    		printk("Scanning failed to start (err %d)\n", err);
    		return;
    	}
    
    	LOG_INF("Scanning successfully started");
    	printk("Scanning successfully started\n");
    
    	for (;;) {
    		/* Wait indefinitely for data to be sent over Bluetooth */
    		//struct uart_data_t *buf = k_fifo_get(&fifo_uart_rx_data,
    		//				     K_FOREVER);
    
    		struct uart_data_t *buf;
    		buf->data[0] = 0;
    		buf->data[1] = 1;
    		buf->data[2] = 2;
    		buf->len = 3;
    
    		//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);
    			printk("Failed to send data over BLE connection"
    				"(err %d)\n", err);
    		}
    
    		//err = k_sem_take(&nus_write_sem, NUS_WRITE_TIMEOUT);
    		if (err) {
    			LOG_WRN("NUS send timeout");
    			//printk("NUS send timeout\n");
    		}
    	}
    }
    

Children
  • I am not able to spot any errors in your implementation. Could you upload the full project so I can try reproducing this here?

  • I see the problem now: your main loop is always running as you have commented the k_fifo_get() function. 

    As a test, try to add a call to k_msleep(1000); in your loop. This will allow the other threads such as the system workqueue to run. 

  • Thanks! Now the connection is established but the pairing still doesn't work. I have uncommented the 'bt_nus_client_send' and 'k_sem_take' functions but no data is received by the ESP32 and the pairing fails after some time:

    *** Booting Zephyr OS build v3.2.99-ncs2 ***
    bt_conn_auth_cb_register
    bt_conn_auth_info_cb_register err: 0
    bt_enable err: 0
    Bluetooth initialized
    uart_init
    scan_init
    Address filter added 60:55:F9:F5:29:D2 (public)
    Scan module initialized
    bt_nus_client_init
    NUS Client module initialized
    
    Starting Bluetooth Central UART example
    scan err: 0
    Scanning
    Scanning successfully started
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    connected conn_err: 0
    Connected: 60:55:F9:F5:29:D2 (public)
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Failed to send data over BLE connection(err -128)
    NUS send timeout
    Pairing failed conn: 60:55:F9:F5:29:D2 (public), reason 9
    Service discovery completed
    NUS send timeout

    Do you know why this could be happening?

  • Did you add k_msleep(1000) to your main loop? Like this:

    	...
    	for (;;) {
    		/* Wait indefinitely for data to be sent over Bluetooth */
    		//struct uart_data_t *buf = k_fifo_get(&fifo_uart_rx_data,
    		//				     K_FOREVER);
    
    		struct uart_data_t *buf;
    		buf->data[0] = 0;
    		buf->data[1] = 1;
    		buf->data[2] = 2;
    		buf->len = 3;
    
    		//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);
    			printk("Failed to send data over BLE connection"
    				"(err %d)\n", err);
    		}
    
    		//err = k_sem_take(&nus_write_sem, NUS_WRITE_TIMEOUT);
    		if (err) {
    			LOG_WRN("NUS send timeout");
    			//printk("NUS send timeout\n");
    		}
    
    		k_msleep(1000);
    	}

Related