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 : )

Parents Reply Children
  • 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
  • Dear Andreas,

    Today I have tried to change ble_peripheral_lbs_coex 's LBS service to my nus_handler, and I can get the data through NUS central. Though there are still some problems that BLE mesh sometimes is not compatible to NUS, it turn out that the my NUS code is OK. So the problems should be beteween BLE mesh sensor client and BLE mesh onoff. What is the difference between these two, I hope you could help me figure out Grin

  • Hi,

    I have successfully intergrate these two together, however, I notice a issue.

    1.When NUS is not connected, the sensor client can get the readings correctly every time it requests.

    2.When the nus is connected, the sensor client can make the correct request, but sometimes it cannot receive the correct data, causing the last received data to be used

    Below are my code:

    model handler:

    /*
     * Copyright (c) 2020 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    #include <zephyr/bluetooth/bluetooth.h>
    #include <bluetooth/mesh/models.h>
    #include "model_handler.h"
    #include "nus_handler.h" 
    
    #define GET_DATA_INTERVAL 9000
    
    static struct k_work_delayable get_data_work;
    
    /* 传感器客户端回调函数 - 只处理People Count */
    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) {
            //printk("People count is %s\n", bt_mesh_sensor_ch_str(value));
             const char *count_str = bt_mesh_sensor_ch_str(value);
            printk("People count is %s\n", count_str);
    
            /* 更新 NUS 模块中的 people count 字符串 */
            nus_update_people_count(count_str);
        }
    }
    
    /* 简化的传感器客户端处理程序 */
    static const struct bt_mesh_sensor_cli_handlers bt_mesh_sensor_cli_handlers = {
        .data = sensor_cli_data_cb,
    };
    
    static struct bt_mesh_sensor_cli sensor_cli =
        BT_MESH_SENSOR_CLI_INIT(&bt_mesh_sensor_cli_handlers);
    
    /* 数据获取工作处理函数 - 只请求People Count */
    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 = bt_mesh_sensor_cli_get(&sensor_cli, 
                                       NULL, 
                                       &bt_mesh_sensor_people_count, 
                                       NULL);
        if (err) {
            printk("Error getting people count (%d)\n", err);
        }
        
        k_work_schedule(&get_data_work, K_MSEC(GET_DATA_INTERVAL));
    }
    
    /* 健康服务回调(保留基本功能) */
    static void attention_on(const struct bt_mesh_model *mod) {}
    static void attention_off(const struct bt_mesh_model *mod) {}
    
    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(&get_data_work, get_data);
        k_work_schedule(&get_data_work, K_MSEC(GET_DATA_INTERVAL));
        
        return &comp;
    }

    nus_handler:

    #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>
    #include <zephyr/bluetooth/conn.h>
    #include <string.h>
    
    #define PEOPLE_COUNT_STR_SIZE 32
    #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 = 1;
    
    static int start_extended_advertising(void);
    static void send_work_handler(struct k_work *work);
    static int init_extended_advertising(void);
    
    
    
    
    
    static char people_count_str[PEOPLE_COUNT_STR_SIZE] = "0";
    void nus_update_people_count(const char *new_val)
    {
        /* 将传入的字符串复制到全局变量中,注意防止溢出 */
        strncpy(people_count_str, new_val, sizeof(people_count_str) - 1);
        people_count_str[sizeof(people_count_str) - 1] = '\0';
    }
    
    
    
    
    
    
    /* 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)
    {
        struct bt_conn_info conn_info;
    
        if (err) {
            printk("Connection failed (err 0x%02x)\n", err);
            return;
        }
    
        // 获取连接信息
        if (bt_conn_get_info(conn, &conn_info) != 0) {
            printk("Failed to get connection info\n");
            return;
        }
    
        // 检查连接是否属于NUS服务的标识
        if (conn_info.id == nus_conn_id) {
            printk("NUS Connected\n");
            current_conn = bt_conn_ref(conn); // 保存连接引用
    
            // 初始化定时发送任务
            k_work_init_delayable(&send_work, send_work_handler);
            k_work_schedule(&send_work, K_SECONDS(10)); // 每 10 秒发送一次数据
        } else {
            printk("Connected to another service (Mesh), not handling\n");
        }
    }
    
    
    static void disconnected(struct bt_conn *conn, uint8_t reason) {
        printk("Disconnected (reason 0x%02x)\n", reason);
    
        if (current_conn) {
            // 强制断开物理连接
            bt_conn_disconnect(current_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
            bt_conn_unref(current_conn);
            current_conn = NULL; 
        }
    
         k_work_cancel_delayable(&send_work);
    
    
            if (nus_adv) {
            bt_le_ext_adv_stop(nus_adv);
            bt_le_ext_adv_delete(nus_adv);
            nus_adv = NULL;
        }
        // 重新启动广告
        init_extended_advertising();
        start_extended_advertising();
    
    }
    
    /* 定义连接回调结构 */
    BT_CONN_CB_DEFINE(conn_callbacks) = {
        .connected = connected,
        .disconnected = disconnected,
    };
    
    /* 数据发送工作处理 */
    static void send_work_handler(struct k_work *work)
    {
        if (current_conn) {
            /* 直接发送更新后的 people_count_str */
            int err = bt_nus_send(current_conn, people_count_str, strlen(people_count_str));
            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 People Count: %s\n", people_count_str);
            }
        } else {
            printk("No active connection, skipping send\n");
        }
    
        /* 定时调度下一次发送任务 */
        k_work_schedule(&send_work, K_SECONDS(10));
    }
    
    /* 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;
    
    	struct bt_le_adv_param adv_params = {
            .id = nus_conn_id,
            .options = 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,
        };
        /* 检查当前标识符数量 */
        (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 = 1;
            printk("Recovered identity for NUS: %d\n", 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;
        }
    
        
    
        printk("NUS Handler initialized\n");
        return 0;
    }

    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;
    }
    

    projconfig

    #
    # 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=y
    CONFIG_BT_EXT_ADV_MAX_ADV_SET=9
    # 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=9
    CONFIG_BT_MAX_CONN=9
    CONFIG_BT_BUF_CMD_TX_COUNT=30
    
    #为了调试加的
    CONFIG_LOG=y
    #CONFIG_LOG_DEFAULT_LEVEL=4

    Thank you so much for your time!

Related