Something is wrong when I merge BLE OTA and NUS together (with source code)

Hi,

I want to get a sample that supports both BLE OTA and NUS functions, so I find the following two samples as reference and merge them together.

...\zephyr\samples\subsys\mgmt\mcumgr\smp_svr

...\nrf\samples\bluetooth\peripheral_uart

When finished, I test BLE OTA and NUS functions on nrf52840dk. Then I found a problem: NUS function is abnormal, sending over BLE failed.

I tried to debug it, and found that data sending succeeds when this section was commented:

#if defined(CONFIG_MCUMGR_SMP_BT) && defined(CONFIG_MCUMGR_CMD_IMG_MGMT) &&    \
	defined(CONFIG_MCUMGR_CMD_OS_MGMT)
	os_mgmt_register_group();
	img_mgmt_register_group();
	img_mgmt_set_upload_cb(software_update_confirmation_handler, NULL);
	smp_bt_register();
#endif

But BLE OTA cannot be performed after this section is commented......

So how can I modify this project to support both BLE OTA and NUS functions?

Here are main.c and prj.conf:

man.c

/*
 * Copyright (c) 2018 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */

/** @file
 *  @brief Nordic UART Bridge Service (NUS) sample
 */
#include "uart_async_adapter.h"

#include <zephyr/types.h>
#include <zephyr.h>
#include <drivers/uart.h>
#include <usb/usb_device.h>

#include <device.h>
#include <soc.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/conn.h>
#include <bluetooth/uuid.h>
#include <bluetooth/gatt.h>
#include <bluetooth/hci.h>

#include <bluetooth/services/nus.h>

#include <dk_buttons_and_leds.h>

#include <settings/settings.h>

#include <stdio.h>

#include <logging/log.h>

#include "tlv.h"

/* MCUMgr BT FOTA includes */
#ifdef CONFIG_MCUMGR_CMD_OS_MGMT
#include "os_mgmt/os_mgmt.h"
#endif
#ifdef CONFIG_MCUMGR_CMD_IMG_MGMT
#include "img_mgmt/img_mgmt.h"
#endif
#ifdef CONFIG_MCUMGR_SMP_BT
#include <mgmt/mcumgr/smp_bt.h>
#endif

#define LOG_MODULE_NAME peripheral_uart
LOG_MODULE_REGISTER(LOG_MODULE_NAME);

#define STACKSIZE CONFIG_BT_NUS_THREAD_STACK_SIZE
#define PRIORITY 7

#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN	(sizeof(DEVICE_NAME) - 1)

#define RUN_STATUS_LED DK_LED1
#define RUN_LED_BLINK_INTERVAL 1000

#define CON_STATUS_LED DK_LED2

#define KEY_PASSKEY_ACCEPT DK_BTN1_MSK
#define KEY_PASSKEY_REJECT DK_BTN2_MSK

#define UART_BUF_SIZE CONFIG_BT_NUS_UART_BUFFER_SIZE
#define UART_WAIT_FOR_BUF_DELAY K_MSEC(50)
#define UART_WAIT_FOR_RX CONFIG_BT_NUS_UART_RX_WAIT_TIME

/* The default MTU size before negotiating a longer MTU */
#define BLE_GATT_ATT_MTU_DEFAULT 23

static K_SEM_DEFINE(ble_init_ok, 0, 1);

struct bt_conn *current_conn;

static struct bt_gatt_exchange_params exchange_params;
static uint16_t m_nus_max_send_len = BLE_GATT_ATT_MTU_DEFAULT - 3;

struct k_timer m_throughput_timer;
extern void sample_throughput(struct k_timer *timer_id);

static uint32_t m_total_num_bytes;

void sample_throughput(struct k_timer *timer_id)
{
	static uint32_t last_recv_byte_cnt;

	LOG_INF("%d kbps", (m_total_num_bytes - last_recv_byte_cnt) / 128);
	last_recv_byte_cnt = m_total_num_bytes;
}

static const struct bt_data ad[] = {
	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
	BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
};

static const struct bt_data sd[] = {
	BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_NUS_VAL),
};

#if CONFIG_BT_NUS_UART_ASYNC_ADAPTER
UART_ASYNC_ADAPTER_INST_DEFINE(async_adapter);
#else
static const struct device *const async_adapter;
#endif

static void exchange_func(struct bt_conn *conn, uint8_t err, struct bt_gatt_exchange_params *params)
{
	if (!err) {
		m_nus_max_send_len = bt_nus_get_mtu(conn);
		LOG_INF("ATT MTU size updated to %d bytes", m_nus_max_send_len + 3);
#if CONFIG_BT_USER_DATA_LEN_UPDATE
		err = bt_conn_le_data_len_update(current_conn, BT_LE_DATA_LEN_PARAM_MAX);
		if (err) {
			LOG_ERR("Failed to update data length (error %u)", err);
		}
#endif
	}
}

static void connected(struct bt_conn *conn, uint8_t err)
{
	char addr[BT_ADDR_LE_STR_LEN];

	if (err) {
		LOG_ERR("Connection failed (err %u)", err);
		return;
	}

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
	LOG_INF("Connected %s", log_strdup(addr));

	current_conn = bt_conn_ref(conn);

	exchange_params.func = exchange_func;

	err = bt_gatt_exchange_mtu(current_conn, &exchange_params);
	if (err) {
		LOG_WRN("bt_gatt_exchange_mtu: %d", err);
	}

	dk_set_led_on(CON_STATUS_LED);
}

static void disconnected(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));

	LOG_INF("Disconnected: %s (reason %u)", log_strdup(addr), reason);

	if (current_conn) {
		bt_conn_unref(current_conn);
		current_conn = NULL;
		dk_set_led_off(CON_STATUS_LED);
	}
}

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

static void bt_receive_cb(struct bt_conn *conn, const uint8_t *const data,
			  uint16_t len)
{

}

static struct bt_nus_cb nus_cb = {
	.received = bt_receive_cb,
};

void error(void)
{
	dk_set_leds_state(DK_ALL_LEDS_MSK, DK_NO_LEDS_MSK);

	while (true) {
		/* Spin for ever */
		k_sleep(K_MSEC(1000));
	}
}

static void configure_gpio(void)
{
	int err;

	err = dk_leds_init();
	if (err) {
		LOG_ERR("Cannot init LEDs (err: %d)", err);
	}
}

#if defined(CONFIG_MCUMGR_SMP_BT)
static int software_update_confirmation_handler(uint32_t offset, uint32_t size,
						void *arg)
{
	/* For now just print update progress and confirm data chunk without any additional
	 * checks.
	 */
	LOG_INF("Device firmware upgrade progress %d B / %d B", offset, size);

	return 0;
}
#endif

void main(void)
{
	int blink_status = 0;
	int err = 0;

	configure_gpio();

	err = bt_enable(NULL);
	if (err) {
		error();
	}

	LOG_INF("Bluetooth initialized");

	k_sem_give(&ble_init_ok);

	if (IS_ENABLED(CONFIG_SETTINGS)) {
		settings_load();
	}

#if defined(CONFIG_MCUMGR_SMP_BT) && defined(CONFIG_MCUMGR_CMD_IMG_MGMT) &&    \
	defined(CONFIG_MCUMGR_CMD_OS_MGMT)
	os_mgmt_register_group();
	img_mgmt_register_group();
	img_mgmt_set_upload_cb(software_update_confirmation_handler, NULL);
	smp_bt_register();
#endif

	err = bt_nus_init(&nus_cb);
	if (err) {
		LOG_ERR("Failed to initialize UART service (err: %d)", err);
		return;
	}

	err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd,
			      ARRAY_SIZE(sd));
	if (err) {
		LOG_ERR("Advertising failed to start (err %d)", err);
		return;
	}

	uint8_t test_data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
							1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
	uint8_t test_data_len = sizeof(test_data);
	for (;;) {
		if(current_conn){
			if(bt_nus_send(NULL, &test_data, test_data_len)){
				LOG_WRN("Failed to send data over BLE connection %d.", test_data_len);
			}
		}
		
		dk_set_led(RUN_STATUS_LED, (++blink_status) % 2);
		k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
	}
}

prj.conf

#
# Copyright (c) 2018 Nordic Semiconductor
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

# Enable the UART driver
CONFIG_UART_ASYNC_API=y
CONFIG_NRFX_UARTE0=y
CONFIG_SERIAL=y

CONFIG_GPIO=y

# Make sure printk is printing to the UART console
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y

CONFIG_HEAP_MEM_POOL_SIZE=2048

CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="Nordic_NUS_DFU"
CONFIG_BT_DEVICE_APPEARANCE=833
CONFIG_BT_MAX_CONN=1
CONFIG_BT_MAX_PAIRED=1

# Enable the NUS service
CONFIG_BT_NUS=y

# Enable bonding
CONFIG_BT_SETTINGS=y
CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FLASH_MAP=y
CONFIG_NVS=y
CONFIG_SETTINGS=y

# Enable DK LED and Buttons library
CONFIG_DK_LIBRARY=y

# This example requires more workqueue stack
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048

# Config logger
CONFIG_LOG=y
CONFIG_LOG2_MODE_IMMEDIATE=y
CONFIG_LOG_BACKEND_UART=y

CONFIG_ASSERT=y

CONFIG_BT_USER_DATA_LEN_UPDATE=y
CONFIG_BT_USER_PHY_UPDATE=y

CONFIG_BT_BUF_ACL_RX_SIZE=251
CONFIG_BT_GATT_CLIENT=y
CONFIG_BT_ATT_PREPARE_COUNT=2
CONFIG_BT_L2CAP_TX_MTU=247
CONFIG_BT_BUF_ACL_TX_COUNT=10
CONFIG_BT_BUF_ACL_TX_SIZE=251

CONFIG_BT_SMP=y

CONFIG_BOOTLOADER_MCUBOOT=y

# MCU Manager and SMP configuration
CONFIG_MCUMGR=y
CONFIG_MCUMGR_CMD_IMG_MGMT=y
CONFIG_MCUMGR_CMD_OS_MGMT=y
CONFIG_MCUMGR_SMP_BT=y
CONFIG_MCUMGR_SMP_BT_AUTHEN=n
CONFIG_MCUMGR_BUF_COUNT=6

# Allow for large Bluetooth data packets.
CONFIG_BT_L2CAP_TX_MTU=252
CONFIG_BT_BUF_ACL_RX_SIZE=256

# Reduce GAP event length to avoid heavy BLE traffic generated during DFU
CONFIG_BT_CTLR_SDC_MAX_CONN_EVENT_LEN_DEFAULT=3000

# Some command handlers require a large stack.
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2304
CONFIG_MAIN_STACK_SIZE=2048

Platform: Windows 10

NCS version: 1.9.1

Boards: nrf52840dk_nrf52840

Looking forward to your reply.

Best wished,

Joyop

Parents
  • Hi Yao Jiao, 

    Have you tried to follow the tutorial here:  Add DFU support to your application 

    Could you explain what exactly happened when "NUS function is abnormal, sending over BLE failed." we need to know what exactly happened. Do you have any assertion  ? 

    Did you test the application using a phone ? Please also try to test using a different phone because the phone may cache the att table and may not update the attribute table and this may explain why the NUS service doesn't work.

    Please use nRF Connect app for testing and you can try to turn off and on Bluetooth to clear the cache. 

  • Hi Hung Bui,

    Thanks for your reply.

    Have you tried to follow the tutorial here:  Add DFU support to your application 

    I will tried to add DFU again by following this tutorial.

    Could you explain what exactly happened when "NUS function is abnormal, sending over BLE failed." we need to know what exactly happened. Do you have any assertion  ? 

    Here in main.c, when BLE sending failed this log will be printed:

    LOG_WRN("Failed to send data over BLE connection %d.", test_data_len);

    I saw this log and didn't receive anything on my phone, so I judged that the sending is failed.

    Did you test the application using a phone ? Please also try to test using a different phone because the phone may cache the att table and may not update the attribute table and this may explain why the NUS service doesn't work.

    Yes, I tested  using my phone. I also tried other phones, it didn't work either.

    Also, I would appreciate it if you could try to reproduce the problem based on main.c and prj.conf above.

    Thanks again!

    Best wishes,

    Joyop

  • Hi Yao Jiao, 

    I won't be able to test your application right now. 

    But please check the return code from bt_nus_send() to see why it's printing out Failed to send data over BLE. 

    Please try to test using nRF Connect app, make sure you enable notification. 

    Please try to follow the tutorial that I pointed to. 

Reply Children
No Data
Related