How to integrate BLE Mesh + NUS together in Zephyr

I am using Zephyr to create a program that integrates BLE Mesh and NUS. My goal is to use a sensor_client to read data from a sensor_server, and then send the data, via peripheral_uart, to an external central_uart device after reading it. I referred to the official examples, including sensor_client, sensor_server, peripheral_uart, and ble_peripheral_lbs_coex, and developed the final program using NCS 2.9 on an nRF52833. My code shows below

main.c

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

/** @file
 *  @brief Nordic mesh sensor observer sample
 */
#include <zephyr/bluetooth/bluetooth.h>
#include <bluetooth/mesh/models.h>
#include <bluetooth/mesh/dk_prov.h>
#include <dk_buttons_and_leds.h>
#include "model_handler.h"


#include "nus_handler.h"//头文件


static void bt_ready(int err)
{
	if (err) {
		printk("Bluetooth init failed (err %d)\n", err);
		return;
	}

	printk("Bluetooth initialized\n");

	err = dk_leds_init();
	if (err) {
		printk("Initializing LEDs failed (err %d)\n", err);
		return;
	}

	err = dk_buttons_init(NULL);
	if (err) {
		printk("Initializing buttons failed (err %d)\n", err);
		return;
	}

	
		


	err = bt_mesh_init(bt_mesh_dk_prov_init(), model_handler_init());
	if (err) {
		printk("Initializing mesh failed (err %d)\n", err);
		return;
	}

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

	/* This will be a no-op if settings_load() loaded provisioning info */
	bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT);

	printk("Mesh initialized\n");

/* 初始化 NUS handler */
	err = nus_handler_init();
	if (err) {
		printk("NUS handler initialization failed (err %d)\n", err);
		return;
	}
	printk("NUS handler initialized\n");
	 
}


int main(void)
{
	int err;

	printk("Initializing...\n");

	err = bt_enable(bt_ready);
	if (err) {
		printk("Bluetooth init failed (err %d)\n", err);
	}

	return 0;
}

model_handler.c

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

#include <zephyr/bluetooth/bluetooth.h>
#include <bluetooth/mesh/models.h>
#include <dk_buttons_and_leds.h>
#include "model_handler.h"



#define GET_DATA_INTERVAL 10000
#define GET_DATA_INTERVAL_QUICK 3000
#define MOTION_TIMEOUT K_SECONDS(60)

static bool is_occupied;
static struct k_work_delayable motion_timeout_work;

static void motion_timeout(struct k_work *work)
{
	is_occupied = false;
	printk("Area is now vacant.\n");
}

// static void sensor_cli_data_cb(struct bt_mesh_sensor_cli *cli,
// 			       struct bt_mesh_msg_ctx *ctx,
// 			       const struct bt_mesh_sensor_type *sensor,
// 			       const struct bt_mesh_sensor_value *value)
// {
// 	enum bt_mesh_sensor_value_status status;

// 	if (sensor->id == bt_mesh_sensor_present_dev_op_temp.id) {
// 		printk("Chip temperature: %s\n", bt_mesh_sensor_ch_str(value));
// 	} else if (sensor->id == bt_mesh_sensor_presence_detected.id) {
// 		int64_t presence_detected = 0;

// 		status = bt_mesh_sensor_value_to_micro(value, &presence_detected);
// 		if (!bt_mesh_sensor_value_status_is_numeric(status)) {
// 			printk("Warning: unexpected behaviour during conversion of presence "
// 			       "detected value (%d)\n",
// 			       status);
// 			return;
// 		}
// 		if (!!presence_detected) {
// 			printk("Presence detected\n");
// 		} else {
// 			printk("No presence detected\n");
// 		}
// 	} else if (sensor->id ==
// 		   bt_mesh_sensor_time_since_presence_detected.id) {
// 		int64_t time_since_presence_detected = 0;

// 		status = bt_mesh_sensor_value_to_micro(value, &time_since_presence_detected);
// 		if (status == BT_MESH_SENSOR_VALUE_UNKNOWN) {
// 			printk("Unknown last presence detected\n");
// 		} else if (!time_since_presence_detected) {
// 			printk("Presence detected, or under 1 second since presence detected\n");
// 		} else {
// 			printk("%s second(s) since last presence detected\n",
// 			       bt_mesh_sensor_ch_str(value));
// 		}
// 	} else if (sensor->id == bt_mesh_sensor_present_amb_light_level.id) {
// 		printk("Ambient light level: %s\n", bt_mesh_sensor_ch_str(value));
// 	} else if (sensor->id == bt_mesh_sensor_motion_sensed.id) {
// 		int64_t motion_sensed = 0;

// 		status = bt_mesh_sensor_value_to_micro(value, &motion_sensed);
// 		if (!bt_mesh_sensor_value_status_is_numeric(status)) {
// 			printk("Warning: unexpected behaviour during conversion of motion sensed "
// 			       "value (%d)\n",
// 			       status);
// 			return;
// 		}
// 		if (!!motion_sensed) {
// 			is_occupied = true;
// 			printk("Motion detected (%s %%). Area is occupied.\n",
// 			       bt_mesh_sensor_ch_str(value));
// 			k_work_cancel_delayable(&motion_timeout_work);
// 		} else {
// 			if (is_occupied) {
// 				printk("No current motion detected. Area is still occupied.\n");
// 				k_work_reschedule(&motion_timeout_work, MOTION_TIMEOUT);
// 			} else {
// 				printk("No motion detected. Area is vacant.\n");
// 			}
// 		}
// 	} else if (sensor->id == bt_mesh_sensor_time_since_motion_sensed.id) {
// 		int64_t time_since_motion_sensed = 0;

// 		status = bt_mesh_sensor_value_to_micro(value, &time_since_motion_sensed);
// 		if (status == BT_MESH_SENSOR_VALUE_UNKNOWN) {
// 			printk("Unknown last motion sensed\n");
// 		} else if (!time_since_motion_sensed) {
// 			printk("Motion sensed, or under 1 second since motion sensed\n");
// 		} else {
// 			printk("%s second(s) since last motion sensed\n",
// 			       bt_mesh_sensor_ch_str(value));
// 		}
// 	} else if (sensor->id == bt_mesh_sensor_people_count.id) {
// 		printk("People count is %s\n", bt_mesh_sensor_ch_str(value));
// 	}
// }

static void sensor_cli_data_cb(struct bt_mesh_sensor_cli *cli,
                               struct bt_mesh_msg_ctx *ctx,
                               const struct bt_mesh_sensor_type *sensor,
                               const struct bt_mesh_sensor_value *value)
{
    if (sensor->id == bt_mesh_sensor_people_count.id) {
        // 打印 People Count 数据
        printk("People count is %s\n", bt_mesh_sensor_ch_str(value));
    }
}


static void sensor_cli_series_entry_cb(
	struct bt_mesh_sensor_cli *cli, struct bt_mesh_msg_ctx *ctx,
	const struct bt_mesh_sensor_type *sensor, uint8_t index, uint8_t count,
	const struct bt_mesh_sensor_series_entry *entry)
{
	printk("Relative runtime in %s", bt_mesh_sensor_ch_str(&entry->value[1]));
	printk(" to %s degrees: ", bt_mesh_sensor_ch_str(&entry->value[2]));
	printk("%s percent\n", bt_mesh_sensor_ch_str(&entry->value[0]));
}

static void sensor_cli_setting_status_cb(struct bt_mesh_sensor_cli *cli,
					 struct bt_mesh_msg_ctx *ctx,
					 const struct bt_mesh_sensor_type *sensor,
					 const struct bt_mesh_sensor_setting_status *setting)
{
	printk("Sensor ID: 0x%04x, Setting ID: 0x%04x\n", sensor->id, setting->type->id);
	for (int chan = 0; chan < setting->type->channel_count; chan++) {
		printk("\tChannel %d value: %s\n", chan,
		       bt_mesh_sensor_ch_str(&(setting->value[chan])));
	}
}

static void sensor_cli_desc_cb(struct bt_mesh_sensor_cli *cli, struct bt_mesh_msg_ctx *ctx,
			       const struct bt_mesh_sensor_info *sensor)
{
	printk("Descriptor of sensor with ID 0x%04x:\n", sensor->id);
	printk("\ttolerance: { positive: %d negative: %d }\n",
	       sensor->descriptor.tolerance.positive, sensor->descriptor.tolerance.negative);
	printk("\tsampling type: %d\n", sensor->descriptor.sampling_type);
}

static const struct bt_mesh_sensor_cli_handlers bt_mesh_sensor_cli_handlers = {
	.data = sensor_cli_data_cb,
	.series_entry = sensor_cli_series_entry_cb,
	.setting_status = sensor_cli_setting_status_cb,
	.sensor = sensor_cli_desc_cb,
};

static struct bt_mesh_sensor_cli sensor_cli =
	BT_MESH_SENSOR_CLI_INIT(&bt_mesh_sensor_cli_handlers);

static struct k_work_delayable get_data_work;

// static void get_data(struct k_work *work)
// {
// 	if (!bt_mesh_is_provisioned()) {
// 		k_work_schedule(&get_data_work, K_MSEC(GET_DATA_INTERVAL));
// 		return;
// 	}

// 	static uint32_t sensor_idx;
// 	int err;

// 	/* Only one message can be published at a time. Swap sensor after each timeout. */
// 	switch (sensor_idx++) {
// 	case (0): {
// 		err = bt_mesh_sensor_cli_get(
// 			&sensor_cli, NULL, &bt_mesh_sensor_present_dev_op_temp,
// 			NULL);
// 		if (err) {
// 			printk("Error getting chip temperature (%d)\n", err);
// 		}
// 		break;
// 	}
// 	case (1): {
// 		err = bt_mesh_sensor_cli_series_entries_get(
// 			&sensor_cli, NULL,
// 			&bt_mesh_sensor_rel_runtime_in_a_dev_op_temp_range, NULL, NULL,
// 			NULL, NULL);
// 		if (err) {
// 			printk("Error getting relative chip temperature data (%d)\n", err);
// 		}
// 		break;
// 	}
// 	case (2): {
// 		err = bt_mesh_sensor_cli_get(
// 			&sensor_cli, NULL, &bt_mesh_sensor_time_since_presence_detected,
// 			NULL);
// 		if (err) {
// 			printk("Error getting time since presence detected (%d)\n", err);
// 		}
// 		break;
// 	}
// 	case (3): {
// 		err = bt_mesh_sensor_cli_get(
// 			&sensor_cli, NULL, &bt_mesh_sensor_present_amb_light_level, NULL);
// 		if (err) {
// 			printk("Error getting ambient light level (%d)\n", err);
// 		}
// 		break;
// 	}
// 	case (4): {
// 		err = bt_mesh_sensor_cli_get(&sensor_cli, NULL,
// 					     &bt_mesh_sensor_time_since_motion_sensed, NULL);
// 		if (err) {
// 			printk("Error getting time since motion detected (%d)\n", err);
// 		}
// 		break;
// 	}
// 	case (5): {
// 		err = bt_mesh_sensor_cli_get(&sensor_cli, NULL, &bt_mesh_sensor_people_count, NULL);
// 		if (err) {
// 			printk("Error getting people count (%d)\n", err);
// 		}
// 		break;
// 	}
// 	}

// 	if (sensor_idx % 6) {
// 		k_work_schedule(&get_data_work, K_MSEC(GET_DATA_INTERVAL_QUICK));
// 	} else {
// 		k_work_schedule(&get_data_work, K_MSEC(GET_DATA_INTERVAL));
// 		sensor_idx = 0;
// 	}
// }

static void get_data(struct k_work *work)
{
    if (!bt_mesh_is_provisioned()) {
        k_work_schedule(&get_data_work, K_MSEC(GET_DATA_INTERVAL));
        return;
    }

    int err;

    /* 只获取 people count 数据 */
    err = bt_mesh_sensor_cli_get(&sensor_cli, NULL, &bt_mesh_sensor_people_count, NULL);
    if (err) {
        printk("Error getting people count (%d)\n", err);
    } else {
        printk("Requesting people count data...\n");
    }

    /* 定时任务,保持轮询获取 people count */
    k_work_schedule(&get_data_work, K_MSEC(GET_DATA_INTERVAL));
}


static const int temp_ranges[][2] = {
	{ 0, 100 },
	{ 10, 20 },
	{ 22, 30 },
	{ 40, 50 },
};

static const int presence_motion_threshold[] = { 0, 25, 50, 75, 100 };

static int setting_set_int(const struct bt_mesh_sensor_type *sensor_type,
			   const struct bt_mesh_sensor_type *setting_type,
			   const int *values)
{
	struct bt_mesh_sensor_value sensor_vals[CONFIG_BT_MESH_SENSOR_CHANNELS_MAX];
	int err;

	for (int i = 0; i < setting_type->channel_count; i++) {
		err = bt_mesh_sensor_value_from_micro(setting_type->channels[i].format,
						      values[i] * 1000000LL, &sensor_vals[i]);
		if (err) {
			return err;
		}
	}

	return bt_mesh_sensor_cli_setting_set(&sensor_cli, NULL, sensor_type,
					      setting_type, sensor_vals, NULL);
}

static void button_handler_cb(uint32_t pressed, uint32_t changed)
{
	if (!bt_mesh_is_provisioned()) {
		return;
	}

	static uint32_t temp_idx;
	static uint32_t motion_threshold_idx;
	int err;

	if (pressed & changed & BIT(0)) {
		err = bt_mesh_sensor_cli_setting_get(&sensor_cli, NULL,
						     &bt_mesh_sensor_present_dev_op_temp,
						     &bt_mesh_sensor_dev_op_temp_range_spec, NULL);
		if (err) {
			printk("Error getting range setting (%d)\n", err);
		}
	}
	if (pressed & changed & BIT(1)) {
		err = setting_set_int(&bt_mesh_sensor_present_dev_op_temp,
				      &bt_mesh_sensor_dev_op_temp_range_spec,
				      temp_ranges[temp_idx++]);
		if (err) {
			printk("Error setting range setting (%d)\n", err);
		}
		temp_idx = temp_idx % ARRAY_SIZE(temp_ranges);
	}
	if (pressed & changed & BIT(2)) {
		err = bt_mesh_sensor_cli_desc_get(&sensor_cli, NULL,
						  &bt_mesh_sensor_present_dev_op_temp, NULL);
		if (err) {
			printk("Error getting sensor descriptor (%d)\n", err);
		}
	}
	if (pressed & changed & BIT(3)) {
		err = setting_set_int(&bt_mesh_sensor_presence_detected,
				      &bt_mesh_sensor_motion_threshold,
				      &presence_motion_threshold[motion_threshold_idx++]);
		if (err) {
			printk("Error setting motion threshold setting (%d)\n", err);
		}
		motion_threshold_idx = motion_threshold_idx % ARRAY_SIZE(presence_motion_threshold);
	}
}

static struct button_handler button_handler = {
	.cb = button_handler_cb,
};

/* Set up a repeating delayed work to blink the DK's LEDs when attention is
 * requested.
 */
static struct k_work_delayable attention_blink_work;
static bool attention;

static void attention_blink(struct k_work *work)
{
	static int idx;
	const uint8_t pattern[] = {
		BIT(0) | BIT(1),
		BIT(1) | BIT(2),
		BIT(2) | BIT(3),
		BIT(3) | BIT(0),
	};

	if (attention) {
		dk_set_leds(pattern[idx++ % ARRAY_SIZE(pattern)]);
		k_work_reschedule(&attention_blink_work, K_MSEC(30));
	} else {
		dk_set_leds(DK_NO_LEDS_MSK);
	}
}

static void attention_on(const struct bt_mesh_model *mod)
{
	attention = true;
	k_work_reschedule(&attention_blink_work, K_NO_WAIT);
}

static void attention_off(const struct bt_mesh_model *mod)
{
	/* Will stop rescheduling blink timer */
	attention = false;
}

static const struct bt_mesh_health_srv_cb health_srv_cb = {
	.attn_on = attention_on,
	.attn_off = attention_off,
};

static struct bt_mesh_health_srv health_srv = {
	.cb = &health_srv_cb,
};

BT_MESH_HEALTH_PUB_DEFINE(health_pub, 0);

static struct bt_mesh_elem elements[] = {
	BT_MESH_ELEM(1,
		     BT_MESH_MODEL_LIST(BT_MESH_MODEL_CFG_SRV,
					BT_MESH_MODEL_HEALTH_SRV(&health_srv,
								 &health_pub),
					BT_MESH_MODEL_SENSOR_CLI(&sensor_cli)),
		     BT_MESH_MODEL_NONE),
};

static const struct bt_mesh_comp comp = {
	.cid = CONFIG_BT_COMPANY_ID,
	.elem = elements,
	.elem_count = ARRAY_SIZE(elements),
};

const struct bt_mesh_comp *model_handler_init(void)
{
	k_work_init_delayable(&attention_blink_work, attention_blink);
	k_work_init_delayable(&get_data_work, get_data);
	k_work_init_delayable(&motion_timeout_work, motion_timeout);

	dk_button_handler_add(&button_handler);
	k_work_schedule(&get_data_work, K_MSEC(GET_DATA_INTERVAL));

	return &comp;
}

nus_handler.c

#include "nus_handler.h"
#include <zephyr/types.h>
#include <zephyr/sys/printk.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/sys/byteorder.h>

#include <zephyr/types.h>
#include <stddef.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <soc.h>

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

#include <bluetooth/services/nus.h>
#include <dk_buttons_and_leds.h>

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

static struct bt_conn *current_conn;
static struct k_work_delayable send_work;
static struct bt_le_ext_adv *nus_adv; // 独立的扩展广告实例
static const char cmd_str[] = "123456789";
static uint8_t nus_conn_id = BT_ID_DEFAULT;

/* Advertising配置 */
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),
};

/* 蓝牙连接回调函数 */
static void connected(struct bt_conn *conn, uint8_t err)
{
    if (err) {
        printk("Connection failed (err 0x%02x)\n", err);
        return;
    }

    printk("Connected\n");
    current_conn = bt_conn_ref(conn); // 保存连接引用
}

static void disconnected(struct bt_conn *conn, uint8_t reason)
{
    printk("Disconnected (reason 0x%02x)\n", reason);

    if (current_conn) {
        bt_conn_unref(current_conn); // 释放连接引用
        current_conn = NULL;
    }
}

/* 定义连接回调结构 */
BT_CONN_CB_DEFINE(conn_callbacks) = {
    .connected = connected,
    .disconnected = disconnected,
};

/* 数据发送工作处理 */
static void send_work_handler(struct k_work *work)
{
    if (current_conn) {
        int err = bt_nus_send(current_conn, cmd_str, sizeof(cmd_str) - 1);
        if (err == -ENOMEM) {
            printk("Failed to send NUS data: Out of memory (err %d)\n", err);
        } else if (err) {
            printk("Failed to send NUS data (err %d)\n", err);
        } else {
            printk("Sent: %s\n", cmd_str);
        }
    } else {
        printk("No active connection, skipping send\n");
    }

    // 定时调度下一次发送任务
    k_work_schedule(&send_work, K_SECONDS(5));
}

/* NUS回调函数 */
static void bt_receive_cb(struct bt_conn *conn, const uint8_t *const data, uint16_t len)
{
    printk("Received data: %.*s\n", len, data);
}

/* NUS回调结构 */
static struct bt_nus_cb nus_cb = {
    .received = bt_receive_cb,
};

/* 初始化扩展广告 */
static int init_extended_advertising(void)
{
    int err;
    size_t id_count = 0xFF;
    struct bt_le_adv_param adv_params = *BT_LE_ADV_CONN;
    /* 检查当前标识符数量 */
    (void)bt_id_get(NULL, &id_count);

    if (id_count < CONFIG_BT_ID_MAX) {
        int id = bt_id_create(NULL, NULL);

        if (id < 0) {
            printk("Unable to create a new identity for NUS (err %d). Using the default one.\n", id);
            nus_conn_id = BT_ID_DEFAULT;
        } else {
            nus_conn_id = id;
            printk("Created a new identity for NUS: %d\n", nus_conn_id);
        }
    } else {
        nus_conn_id = BT_ID_DEFAULT;
        printk("Recovered identity for NUS: %d\n", nus_conn_id);
    }

    // struct bt_le_adv_param adv_params = {
    //     // .options = BT_LE_ADV_OPT_EXT_ADV | BT_LE_ADV_OPT_CONNECTABLE, // 启用扩展广告并支持连接
    //     // .interval_min = BT_GAP_ADV_FAST_INT_MIN_2,
    //     // .interval_max = BT_GAP_ADV_FAST_INT_MAX_2,
    //     // .peer = NULL, // 无特定目标设备
    //     // .sid = 0,     // 广播实例ID
    //     .id = nus_conn_id,
    // };

    adv_params.id = nus_conn_id;


    /* 创建扩展广告实例 */
    err = bt_le_ext_adv_create(&adv_params, NULL, &nus_adv);
    if (err) {
        printk("Failed to create extended advertising instance (err %d)\n", err);
        return err;
    }

    /* 设置广告和扫描响应数据 */
    err = bt_le_ext_adv_set_data(nus_adv, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
    if (err) {
        printk("Failed to set extended advertising data (err %d)\n", err);
        return err;
    }

    printk("Extended advertising instance created\n");
    return 0;
}

/* 启动扩展广告 */
static int start_extended_advertising(void)
{
    int err;

    err = bt_le_ext_adv_start(nus_adv, BT_LE_EXT_ADV_START_DEFAULT);
    if (err) {
        printk("Failed to start extended advertising (err %d)\n", err);
        return err;
    }

    printk("Extended advertising started\n");
    return 0;
}

/* 初始化NUS服务的入口函数 */
int nus_handler_init(void)
{
    int err;

    /* 初始化NUS服务 */
    err = bt_nus_init(&nus_cb);
    if (err) {
        printk("Failed to initialize NUS (err %d)\n", err);
        return err;
    }

    printk("NUS service initialized\n");

    /* 初始化扩展广告 */
    err = init_extended_advertising();
    if (err) {
        return err;
    }

    /* 启动扩展广告 */
    err = start_extended_advertising();
    if (err) {
        return err;
    }

    /* 初始化定时发送任务 */
    k_work_init_delayable(&send_work, send_work_handler);
    k_work_schedule(&send_work, K_SECONDS(5)); // 每 5 秒发送一次数据

    printk("NUS Handler initialized\n");
    return 0;
}

project config

#
# Copyright (c) 2020 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#
CONFIG_NCS_SAMPLES_DEFAULTS=y

# Deferred logging helps improve LPN power consumption
# when friendship is established.
CONFIG_LOG_MODE_DEFERRED=y

# General configuration
CONFIG_NCS_APPLICATION_BOOT_BANNER_STRING="Mesh Sensor Observer"
#CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 在后面加了个大的
CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
# Flash shell module uses 8k of RAM for testing buffers, disable to save RAM
CONFIG_FLASH_SHELL=n
CONFIG_NVS=y
CONFIG_NVS_LOOKUP_CACHE=y
CONFIG_SETTINGS=y
CONFIG_SETTINGS_NVS_NAME_CACHE=y
CONFIG_HWINFO=y
CONFIG_DK_LIBRARY=y
CONFIG_PM_SINGLE_IMAGE=y
CONFIG_PM_PARTITION_SIZE_SETTINGS_STORAGE=0x8000
CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE=y
CONFIG_CBPRINTF_FP_SUPPORT=y

# Bluetooth configuration
CONFIG_BT=y
CONFIG_BT_DEVICE_NAME="Mesh Sensor Observer"
CONFIG_BT_L2CAP_TX_BUF_COUNT=8
CONFIG_BT_OBSERVER=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_SETTINGS=y

# Disable unused Bluetooth features
CONFIG_BT_CTLR_LE_ENC=n
CONFIG_BT_PHY_UPDATE=n
CONFIG_BT_CTLR_CHAN_SEL_2=n
CONFIG_BT_CTLR_MIN_USED_CHAN=n
CONFIG_BT_CTLR_PRIVACY=n

# Bluetooth Mesh configuration
CONFIG_BT_MESH=y
CONFIG_BT_MESH_RELAY=y
CONFIG_BT_MESH_FRIEND=y
CONFIG_BT_MESH_TX_SEG_MAX=24
CONFIG_BT_MESH_RX_SEG_MAX=16
CONFIG_BT_MESH_PB_GATT=y
CONFIG_BT_MESH_GATT_PROXY=y
CONFIG_BT_MESH_PROXY_USE_DEVICE_NAME=y
CONFIG_BT_MESH_DK_PROV=y
CONFIG_BT_MESH_SUBNET_COUNT=2
CONFIG_BT_MESH_APP_KEY_COUNT=3
CONFIG_BT_MESH_MODEL_KEY_COUNT=3
CONFIG_BT_MESH_CRPL=32
CONFIG_BT_MESH_MSG_CACHE_SIZE=64
CONFIG_BT_MESH_SHELL=y

# Bluetooth Mesh models
CONFIG_BT_MESH_SENSOR_CLI=y

CONFIG_LOG_BACKEND_RTT=n


#我加的我加的

CONFIG_BT_NUS=y
# CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_BT_EXT_ADV_MAX_ADV_SET=6
# CONFIG_BT_BUF_ACL_RX_SIZE=27
# CONFIG_BT_BUF_ACL_TX_SIZE=27
# CONFIG_BT_BUF_ACL_TX_COUNT=10
# CONFIG_BT_BUF_EVT_RX_COUNT=10
# CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=58
# CONFIG_HEAP_MEM_POOL_SIZE=4096
# CONFIG_MAIN_STACK_SIZE=2048
# CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
CONFIG_BT_ID_MAX=2
CONFIG_BT_MAX_CONN=3

However, I encountered an issue: despite maintaining the logic and structure of the ble_peripheral_lbs_coex code entirely, I am unable to initialize advertising, and I frequently receive errors such as 'no BUFFER', 'no context', and 'No more contexts.'

*** Booting Mesh Sensor Observer v2.9.0-99e1dd02b3a7 ***
*** Using nRF Connect SDK v2.9.0-7787b2649840 ***
*** Using Zephyr OS v3.7.99-1f8f3dc29142 ***
Initializing...
[00:00:00.008,209] <inf> fs_nvs: 8 Sectors of 4096 bytes
[00:00:00.008,209] <inf> fs_nvs: alloc wra: 0, fe8
[00:00:00.008,239] <inf> fs_nvs: data wra: 0, 0
[00:00:00.008,575] <inf> bt_sdc_hci_driver: SoftDevice Controller build revision: 
                                            2d 79 a1 c8 6a 40 b7 3c  f6 74 f9 0b 22 d3 c4 80 |-y..j@.< .t.."...
                                            74 72 82 ba                                      |tr..             
[00:00:00.012,512] <inf> bt_hci_core: HW Platform: Nordic Semiconductor (0x0002)
[00:00:00.012,542] <inf> bt_hci_core: HW Variant: nRF52x (0x0002)
[00:00:00.012,603] <inf> bt_hci_core: Firmware: Standard Bluetooth controller (0x00) Version 45.41337 Build 3074452168
[00:00:00.012,939] <inf> bt_hci_core: No ID address. App must call settings_load()
Bluetooth initialized
[00:00:00.271,362] <inf> bt_hci_core: Identity: CC:E6:9E:65:8E:2C (random)
[00:00:00.271,392] <inf> bt_hci_core: HCI: version 6.0 (0x0e) revision 0x106b, manufacturer 0x0059
[00:00:00.271,423] <inf> bt_hci_core: LMP: version 6.0 (0x0e) subver 0x106b
[00:00:00.277,465] <inf> bt_mesh_provisionee: Device UUID: 0bc7df6f-43c0-4ca9-b438-2090bc3fc356
Mesh initialized
NUS service initialized
Recovered identity for NUS: 0
Failed to create extended advertising instance (err -12)
NUS handler initialization failed (err -12)

Could you let me know if my approach is correct? Is it possible to integrate NUS with BLE Mesh? Alternatively, is there another way to achieve similar functionality? I have not found relevant examples online and look forward to your response : )

  • Hi, 

    This is most likely not the reason for your fault, but could you enable CONFIG_BT_EXT_ADV=y? https://docs.nordicsemi.com/bundle/ncs-2.8.0/page/kconfig/index.html#CONFIG_BT_EXT_ADV_MAX_ADV_SET depends on that configuration and AFAIK from your prj.conf I can't see that you've enabled extended advertising

    Kind regards,
    Andreas

  • Thank you so much for your reply! I just tried the config but still cannot start ADV

  • Noted,

    Could you do some debugging and see where bt_le_ext_adv_create(&adv_params, NULL, &nus_adv); fails? If you're uncertain, then this lesson might be a good resource to follow: https://academy.nordicsemi.com/courses/nrf-connect-sdk-intermediate/lessons/lesson-2-debugging/ 

    Kind regards,
    Andreas

  • Dear Andreas,

    Thank you for your suggestion! I have tried to do the debug and I think the problem is ENOBUFS. 

    static int le_ext_adv_param_set(struct bt_le_ext_adv *adv,
    				const struct bt_le_adv_param *param,
    				bool  has_scan_data)
    {
    	struct bt_hci_cp_le_set_ext_adv_param *cp;
    	bool dir_adv = param->peer != NULL, scannable;
    	struct net_buf *buf, *rsp;
    	int err;
    	enum adv_name_type name_type;
    	uint16_t props = 0;
    
    	buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_EXT_ADV_PARAM, sizeof(*cp));
    	if (!buf) {
    		return -ENOBUFS;
    	}
    
    	cp = net_buf_add(buf, sizeof(*cp));
    	(void)memset(cp, 0, sizeof(*cp));
    
    	adv->options = param->options;
    
    	err = bt_id_set_adv_own_addr(adv, param->options, dir_adv,
    				     &cp->own_addr_type);
    	if (err) {
    		net_buf_unref(buf);
    		return err;
    	}
    
    	if (dir_adv) {
    		bt_addr_le_copy(&adv->target_addr, param->peer);
    	} else {
    		bt_addr_le_copy(&adv->target_addr, BT_ADDR_LE_ANY);
    	}
    
    	name_type = get_adv_name_type_param(param);
    
    	cp->handle = adv->handle;
    	sys_put_le24(param->interval_min, cp->prim_min_interval);
    	sys_put_le24(param->interval_max, cp->prim_max_interval);
    	cp->prim_channel_map = get_adv_channel_map(param->options);
    	cp->filter_policy = get_filter_policy(param->options);
    	cp->tx_power = BT_HCI_LE_ADV_TX_POWER_NO_PREF;
    
    	cp->prim_adv_phy = BT_HCI_LE_PHY_1M;
    	if ((param->options & BT_LE_ADV_OPT_EXT_ADV) &&
    	    !(param->options & BT_LE_ADV_OPT_NO_2M)) {
    		cp->sec_adv_phy = BT_HCI_LE_PHY_2M;
    	} else {
    		cp->sec_adv_phy = BT_HCI_LE_PHY_1M;
    	}
    
    	if (param->options & BT_LE_ADV_OPT_CODED) {
    		cp->prim_adv_phy = BT_HCI_LE_PHY_CODED;
    		cp->sec_adv_phy = BT_HCI_LE_PHY_CODED;
    	}
    
    	if (!(param->options & BT_LE_ADV_OPT_EXT_ADV)) {
    		props |= BT_HCI_LE_ADV_PROP_LEGACY;
    	}
    
    	if (param->options & BT_LE_ADV_OPT_USE_TX_POWER) {
    		props |= BT_HCI_LE_ADV_PROP_TX_POWER;
    	}
    
    	if (param->options & BT_LE_ADV_OPT_ANONYMOUS) {
    		props |= BT_HCI_LE_ADV_PROP_ANON;
    	}
    
    	if (param->options & BT_LE_ADV_OPT_NOTIFY_SCAN_REQ) {
    		cp->scan_req_notify_enable = BT_HCI_LE_ADV_SCAN_REQ_ENABLE;
    	}
    
    	if (param->options & BT_LE_ADV_OPT_CONNECTABLE) {
    		props |= BT_HCI_LE_ADV_PROP_CONN;
    		if (!dir_adv && !(param->options & BT_LE_ADV_OPT_EXT_ADV)) {
    			/* When using non-extended adv packets then undirected
    			 * advertising has to be scannable as well.
    			 * We didn't require this option to be set before, so
    			 * it is implicitly set instead in this case.
    			 */
    			props |= BT_HCI_LE_ADV_PROP_SCAN;
    		}
    	}
    
    	if ((param->options & BT_LE_ADV_OPT_SCANNABLE) || has_scan_data ||
    	    (name_type == ADV_NAME_TYPE_SD)) {
    		props |= BT_HCI_LE_ADV_PROP_SCAN;
    	}
    
    	scannable = !!(props & BT_HCI_LE_ADV_PROP_SCAN);
    
    	if (dir_adv) {
    		props |= BT_HCI_LE_ADV_PROP_DIRECT;
    		if (!(param->options & BT_LE_ADV_OPT_DIR_MODE_LOW_DUTY)) {
    			props |= BT_HCI_LE_ADV_PROP_HI_DC_CONN;
    		}
    
    		bt_addr_le_copy(&cp->peer_addr, param->peer);
    	}
    
    	cp->sid = param->sid;
    
    	cp->sec_adv_max_skip = param->secondary_max_skip;
    
    	cp->props = sys_cpu_to_le16(props);
    	err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_EXT_ADV_PARAM, buf, &rsp);
    	if (err) {
    		return err;
    	}
    
    #if defined(CONFIG_BT_EXT_ADV)
    	struct bt_hci_rp_le_set_ext_adv_param *rp = (void *)rsp->data;
    
    	adv->tx_power = rp->tx_power;
    #endif /* defined(CONFIG_BT_EXT_ADV) */
    
    	net_buf_unref(rsp);
    
    	atomic_set_bit(adv->flags, BT_ADV_PARAMS_SET);
    
    	if (atomic_test_and_clear_bit(adv->flags, BT_ADV_RANDOM_ADDR_PENDING)) {
    		err = bt_id_set_adv_random_addr(adv, &adv->random_addr.a);
    		if (err) {
    			return err;
    		}
    	}
    
    	/* Flag only used by bt_le_adv_start API. */
    	atomic_set_bit_to(adv->flags, BT_ADV_PERSIST, false);
    
    	atomic_set_bit_to(adv->flags, BT_ADV_INCLUDE_NAME_AD,
    			  name_type == ADV_NAME_TYPE_AD);
    
    	atomic_set_bit_to(adv->flags, BT_ADV_INCLUDE_NAME_SD,
    			  name_type == ADV_NAME_TYPE_SD);
    
    	atomic_set_bit_to(adv->flags, BT_ADV_CONNECTABLE,
    			  param->options & BT_LE_ADV_OPT_CONNECTABLE);
    
    	atomic_set_bit_to(adv->flags, BT_ADV_SCANNABLE, scannable);
    
    	atomic_set_bit_to(adv->flags, BT_ADV_USE_IDENTITY,
    			  param->options & BT_LE_ADV_OPT_USE_IDENTITY);
    
    	atomic_set_bit_to(adv->flags, BT_ADV_EXT_ADV,
    			  param->options & BT_LE_ADV_OPT_EXT_ADV);
    
    	return 0;
    }

  • Dear Ahaug
    Today I have successfully monitor the varible "err" and I found whenever the code go through this function, it will return err = -105
    err = le_ext_adv_param_set(adv, param, false);
        if (err) {
            adv_delete(adv);
            return err;
        }
    
    However, I cannor go deeper than this function. Sometimes when I go into this function it will return err -105, sometimes cannot. So I currenrly can only say that this function leads the problems.
    Could you please help me to figure it out?Smiley
Related