蓝牙 Mesh 应用
本文档介绍杰理(Jieli)AC630N/AC631x 系列蓝牙 SoC SDK 中的 BLE Mesh 应用(apps/mesh):从系统上电入口、应用状态机、事件分发,到 SIG Mesh 协议栈分层、Mesh 模型选择、硬件/协议参数配置以及低功耗管理的完整实现。
Purpose and Scope
本页面覆盖 apps/mesh 目录所构成的完整 Mesh 应用子系统:
- 应用入口与任务表(
app_main.c)与 Mesh 应用主体(app_mesh.c); - Mesh 模型 API 与模型选择(
apps/mesh/api/model_api.h); - Mesh 硬件/协议参数配置(
apps/mesh/api/mesh_config_common.c); - SIG Mesh 协议栈(
apps/common/third_party_profile/sig_mesh)与应用的衔接方式; - 板级适配(
apps/mesh/board/bd29)与低功耗(软关机、LP target)行为。
以下内容属于兄弟页面、不在本页展开:btstack / btctrler 底层蓝牙协议栈与控制器任务(见 BT Stack 相关文档)、app_idle.c 空闲调度、通用系统事件框架(system/app_core.h)。
Overview
该应用是一个 BLE Mesh 演示(BLE MESH DEMO) 固件,运行于 AC630N(AC630x)/ AC631x 系列芯片上,支持:
- 标准 SIG Mesh 协议(基于
third_party_profile/sig_mesh移植库),包含 PB-ADV 配网、Friend/LPN 好友机制、代理(Proxy)广播等特性; - 通过编译期宏在 Generic OnOff Client/Server、Vendor Client/Server、天猫精灵 Vendor 等模型之间切换(默认
SIG_MESH_GENERIC_ONOFF_CLIENT); - 与经典蓝牙(EDR)共存的地址管理:由 EDR MAC 推导 BLE 地址;
- 按键驱动 Mesh 输入(
input_key_handler)、软关机、低功耗目标注册等应用级行为。
设计意图:SDK 将 Mesh 应用做成一个独立的 application 注册单元(REGISTER_APPLICATION(app_mesh)),由 app_core 框架通过 intent 启动,事件统一由 event_handler 分发,硬件参数与协议参数通过弱符号(_WEAK_)常量集中配置,便于不同板级工程覆盖默认值——这保证了"应用代码与板级配置解耦、一套 Mesh 固件适配多颗芯片"。
Architecture
flowchart TD
subgraph sg_App["应用层 apps/mesh"]
AppMain["app_main.c<br/>应用入口/任务表"]
AppMesh["app_mesh.c<br/>mesh 应用注册与事件"]
AppIdle["app_idle.c<br/>空闲/低功耗查询"]
end
subgraph sg_Api["Mesh API 层 apps/mesh/api"]
ModelApi["model_api.h<br/>模型选择宏"]
MeshConfig["mesh_config_common.c<br/>协议/硬件参数"]
FeatureCorrect["feature_correct.h"]
end
subgraph sg_Stack["SIG Mesh 协议栈<br/>apps/common/third_party_profile/sig_mesh"]
SigMeshApi["sig_mesh_api.c/.h<br/>对外 API"]
MeshCore["mesh.h<br/>协议核心/网络层"]
MeshConfigH["mesh_config.h<br/>协议栈配置"]
end
subgraph sg_Bt["蓝牙底座"]
Btstack["btstack 任务<br/>BR/EDR + BLE"]
Btctrler["btctrler 控制器任务"]
end
subgraph sg_Board["板级适配 apps/mesh/board/bd29"]
Board["board_ac630x_demo.c<br/>AC630N/AC631x"]
end
AppMain -->|"intent(name=mesh)"| AppMesh
AppMesh --> ModelApi
AppMesh --> MeshConfig
ModelApi --> SigMeshApi
MeshConfig --> MeshConfigH
SigMeshApi --> MeshCore
SigMeshApi -->|"BLE 广播/连接"| Btstack
Btstack --> Btctrler
AppMesh -->|"注册与初始化"| Board
架构说明:
- 应用层:
app_main.c定义系统任务表与app_main()入口,构造intent启动名为"mesh"的应用;app_mesh.c通过REGISTER_APPLICATION(app_mesh)注册应用操作表(状态机 + 事件处理器),并注册低功耗目标。 - API 层:
model_api.h以编译期宏选择当前使用的 Mesh 模型;mesh_config_common.c用弱符号常量集中定义节点广播、代理广播、LPN/Friend、PB-ADV、Beacon 等参数,供协议栈库读取。 - 协议栈层:
sig_mesh为第三方移植的 SIG Mesh 库,通过sig_mesh_api向上提供配网/模型接口,向下驱动 btstack 的 BLE 广播与 GATT。 - 底座层:
btstack任务负责 BR/EDR 与 BLE 协议栈,btctrler为链路层控制器任务,Mesh 广播包最终由控制器发射。 - 板级层:
board_ac630x_demo.c等文件完成 IO/按键/时钟等硬件初始化与配置,board_config.h定义TCFG_*参数(如按键值TCFG_ADKEY_VALUE6、系统时钟TCFG_CLOCK_OSC_HZ)。
应用入口与任务表
app_main.c 是 Mesh 固件的第一个 C 入口,它同时定义了整个系统的任务表:
/*任务列表 */
const struct task_info task_info_table[] = {
{"app_core", 1, 1024, 128 },
{"sys_event", 7, 256, 0 },
{"btctrler", 4, 512, 256 },
{"btstack", 3, 1024, 512 },
{"systimer", 7, 128, 0 },
#ifdef CONFIG_UPDATA_ENABLE
{"update", 1, 320, 0 },
#endif
#if (RCSP_BTMATE_EN)
{"rcsp_task", 2, 640, 128 },
#endif
{0, 0},
};
来源:app_main.c
任务表按 {"任务名", 优先级, 栈大小, 队列大小} 组织:app_core 为应用框架任务,sys_event 负责系统事件汇聚分发,btctrler/btstack 构成蓝牙底座,systimer 提供软件定时器;update 与 rcsp_task 按宏条件编译。Mesh 协议栈本身不单独占用任务,运行在 btstack 任务上下文中。
app_main() 构造 intent 并启动 "mesh" 应用:
void app_main()
{
struct intent it;
#ifdef CONFIG_UPDATA_ENABLE
int update = 0;
update = update_result_deal();
#endif
init_intent(&it);
it.name = "mesh";
it.action = ACTION_AT_MAIN;
start_app(&it);
}
来源:app_main.c
设计意图:通过 start_app(&it) 将控制权交给 app_core 框架,由框架查找到 REGISTER_APPLICATION(app_mesh) 注册的应用并驱动其状态机,实现"入口统一、模式可切换"(app_switch() 可退出当前 app 并切换到其他应用)。
应用注册与状态机
app_mesh.c 末尾注册应用,名称 "mesh",默认动作 ACTION_AT_MAIN:
static const struct application_operation app_at_ops = {
.state_machine = state_machine,
.event_handler = event_handler,
};
/*
* 注册AT Module模式
*/
REGISTER_APPLICATION(app_mesh) = {
.name = "mesh",
.action = ACTION_AT_MAIN,
.ops = &app_at_ops,
.state = APP_STA_DESTROY,
};
来源:app_mesh.c
状态机处理 APP_STA_CREATE / START / PAUSE / RESUME / STOP / DESTROY 六种状态,其中 APP_STA_START 且动作 ACTION_AT_MAIN 时执行 app_start();其余状态为空实现(透传返回 0)。app_start() 是 Mesh 固件的真正初始化序列:
static void app_start()
{
log_info("=======================================");
log_info("-------------BLE MESH DEMO-------------");
log_info("=======================================");
clk_set("sys", 24*1000000);
u32 sys_clk = clk_get("sys");
bt_pll_para(TCFG_CLOCK_OSC_HZ, sys_clk, 0, 0);
bt_function_select_init();
btstack_init();
/* 按键消息使能 */
sys_key_event_enable();
}
来源:app_mesh.c
初始化顺序的意义:先把系统时钟设为 24MHz 并按晶振/系统频率配置蓝牙 PLL(保证射频时序),再生成并写入 BLE MAC 地址,然后启动 btstack 协议栈,最后使能按键事件。其中 bt_function_select_init() 从 EDR 地址推导 BLE 地址(lib_make_ble_address),并写入 LE 控制器:
static void bt_function_select_init()
{
u8 tmp_ble_addr[6];
/* le_controller_set_mac((void*)"012345"); */
lib_make_ble_address(tmp_ble_addr, (void *)bt_get_mac_addr());
le_controller_set_mac((void *)tmp_ble_addr);
printf("\n-----edr + ble 's address-----");
printf_buf((void *)bt_get_mac_addr(), 6);
printf_buf((void *)tmp_ble_addr, 6);
/* bt_set_tx_power(9);//0~9 */
}
来源:app_mesh.c
事件分发与蓝牙初始化
所有系统事件经 event_handler() 统一分发:SYS_KEY_EVENT 进入按键处理,SYS_BT_EVENT 按子类型分流到连接状态或 HCI 状态处理:
static int event_handler(struct application *app, struct sys_event *event)
{
switch (event->type) {
case SYS_KEY_EVENT:
app_key_event_handler(event);
return 0;
case SYS_BT_EVENT:
if ((u32)event->arg == SYS_BT_EVENT_TYPE_CON_STATUS) {
bt_connction_status_event_handler(&event->u.bt);
} else if ((u32)event->arg == SYS_BT_EVENT_TYPE_HCI_STATUS) {
bt_hci_event_handler(&event->u.bt);
}
return 0;
case SYS_DEVICE_EVENT:
return 0;
default:
return FALSE;
}
return FALSE;
}
来源:app_mesh.c
蓝牙底座初始化完成后(BT_STATUS_INIT_OK),应用调用 bt_ble_init() 初始化 BLE(Mesh 的承载层):
static int bt_connction_status_event_handler(struct bt_event *bt)
{
log_info("-----------------------bt_connction_status_event_handler %d", bt->event);
switch (bt->event) {
case BT_STATUS_INIT_OK:
/*
* 蓝牙初始化完成
*/
log_info("BT_STATUS_INIT_OK\n");
bt_ble_init();
break;
default:
log_info(" BT STATUS DEFAULT\n");
break;
}
return 0;
}
来源:app_mesh.c
HCI 事件处理器还实现了一个特殊的厂商测试事件 HCI_EVENT_VENDOR_REMOTE_TEST (0xFE):当 EDR 建立连接(bt->value == 1)时关闭 BLE 广播,避免 EDR/BLE 共存场景下的射频竞争:
#define HCI_EVENT_VENDOR_REMOTE_TEST 0xFE
static int bt_hci_event_handler(struct bt_event *bt)
{
//对应原来的蓝牙连接上断开处理函数 ,bt->value=reason
log_info("------------------------bt_hci_event_handler reason %x %x", bt->event, bt->value);
if (bt->event == HCI_EVENT_VENDOR_REMOTE_TEST) {
if (0 == bt->value) {
log_info("clear_test_box_flag");
return 0;
} else {
//1:edr con;2:ble con;
if(1 == bt->value) {
bt_ble_adv_enable(0);
}
}
}
return 0;
}
来源:app_mesh.c
按键事件将原始按键值转交 input_key_handler(event_type, key_value)(Mesh 应用层的按键输入入口,具体动作由协议栈/示例模型实现);长按 TCFG_ADKEY_VALUE6(板级 AD 按键定义)触发软关机:
static void app_key_event_handler(struct sys_event *event)
{
u8 event_type = 0;
u8 key_value = 0;
if (event->arg == (void *)DEVICE_EVENT_FROM_KEY) {
event_type = event->u.key.event;
key_value = event->u.key.value;
printf("app_key_evnet: %d,%d\n", event_type, key_value);
input_key_handler(event_type, key_value);
if (event_type == KEY_EVENT_LONG && key_value == TCFG_ADKEY_VALUE6) {
app_set_soft_poweroff();
}
}
}
来源:app_mesh.c
Mesh 模型层与协议栈衔接
apps/mesh/api/model_api.h 定义了可选的 Mesh 模型(对应 SIG Mesh Model 规范,注释引用 MshMDLv1.0.1),通过编译期宏 CONFIG_MESH_MODEL 决定固件编译进哪个示例模型:
//< Detail in "MshMDLv1.0.1"
#define SIG_MESH_GENERIC_ONOFF_CLIENT 0 // examples/generic_onoff_client.c
#define SIG_MESH_GENERIC_ONOFF_SERVER 1 // examples/generic_onoff_server.c
#define SIG_MESH_VENDOR_CLIENT 2 // examples/vendor_client.c
#define SIG_MESH_VENDOR_SERVER 3 // examples/vendor_server.c
#define SIG_MESH_TMALL_GENIE_VENDOR 4 // examples/tmall_genie_vendor.c
// more...
//< Config whick example will use in <examples>
#define CONFIG_MESH_MODEL SIG_MESH_GENERIC_ONOFF_CLIENT
来源:model_api.h
同文件还提供两个字节序转换宏,用于把 48 位 MAC/地址常量展开成小端或大端字节序列(用于组网/配网包中的设备标识):
#define MAC_TO_LITTLE_ENDIAN(x) \
(x & 0xff), \
((x >> 8) & 0xff), \
((x >> 16) & 0xff), \
((x >> 24) & 0xff), \
((x >> 32) & 0xff), \
((x >> 40) & 0xff)
#define MAC_TO_BIG_ENDIAN(x) \
((x >> 40) & 0xff), \
((x >> 32) & 0xff), \
((x >> 24) & 0xff), \
((x >> 16) & 0xff), \
((x >> 8) & 0xff), \
(x & 0xff)
来源:model_api.h
协议栈本身位于 apps/common/third_party_profile/sig_mesh/:sig_mesh_api.c/.h 提供配网(Provisioning)与模型调用入口,mesh.h 为协议核心(网络层/传输层/承载层),mesh_config.h 为协议栈级配置,mesh_log.h 提供 MESH_HCI/MESH_GATT 分类日志开关(见下文配置)。应用层通过 model_api.c 与 sig_mesh_api 交互,无需直接接触协议核心——这是"库与示例分离"的移植设计。
配置参数体系
apps/mesh/api/mesh_config_common.c 用弱符号(_WEAK_)常量集中定义 Mesh 协议/硬件参数,协议栈库直接引用这些符号;板级工程可以重新定义同名符号覆盖默认值(未覆盖时链接器取弱符号默认值)。这是 SDK"默认可用、按需裁剪"的关键机制。
/**
* @brief Config adv bearer hardware param when node send messages
*/
/*-----------------------------------------------------------*/
const u16 config_bt_mesh_node_msg_adv_interval = ADV_SCAN_UNIT(10); // unit: ms
const u16 config_bt_mesh_node_msg_adv_duration = 100; // unit: ms
/**
* @brief Config proxy connectable adv hardware param
*/
/*-----------------------------------------------------------*/
const u16 config_bt_mesh_proxy_unprovision_adv_interval = ADV_SCAN_UNIT(30); // unit: ms
const u16 config_bt_mesh_proxy_pre_node_adv_interval = ADV_SCAN_UNIT(10); // unit: ms
_WEAK_
const u16 config_bt_mesh_proxy_node_adv_interval = ADV_SCAN_UNIT(300); // unit: ms
主要参数分组如下:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
config_bt_mesh_node_msg_adv_interval | u16 | ADV_SCAN_UNIT(10)(10 ms) | 节点消息广播间隔 |
config_bt_mesh_node_msg_adv_duration | u16 | 100 ms | 节点消息广播时长 |
config_bt_mesh_proxy_unprovision_adv_interval | u16 | ADV_SCAN_UNIT(30) | 未配网代理可连接广播间隔 |
config_bt_mesh_proxy_pre_node_adv_interval | u16 | ADV_SCAN_UNIT(10) | 配网前节点代理广播间隔 |
config_bt_mesh_proxy_node_adv_interval | u16(WEAK) | ADV_SCAN_UNIT(300) | 已配网节点代理广播间隔 |
config_bt_mesh_lpn_auto_timeout | u8 | 0 s | LPN 自动进入低功耗超时(0=关闭) |
config_bt_mesh_lpn_retry_timeout | u8 | 10 s | LPN 重试超时 |
config_bt_mesh_lpn_scan_latency | int | 10 ms | LPN 扫描延迟 |
config_bt_mesh_lpn_init_poll_timeout | u32 | 300(×100 ms) | LPN 初始 Poll 超时 |
config_bt_mesh_lpn_powerup_add_sub_list | u8 | 1 | 上电时是否加入订阅列表 |
config_bt_mesh_lpn_recv_delay | u8 | 100 ms | LPN 接收延迟(Friend Request,3.6.5.3) |
config_bt_mesh_lpn_poll_timeout | u32 | 200(×100 ms) | LPN Poll 超时 |
config_bt_mesh_lpn_rssi_factor / recv_win_factor | u8 | 0 / 0 | LPN 邻居/接收窗口因子 |
config_bt_mesh_lpn_min_queue_size | u8 | 1 | LPN 最小队列长度 |
config_bt_mesh_friend_lpn_count | u8 | 1 | Friend 节点可服务的 LPN 数 |
config_bt_mesh_friend_recv_win | u8 | 250 | Friend 接收窗口(Friend Offer,3.6.5.4) |
config_bt_mesh_friend_sub_list_size | u8 | 2 | Friend 订阅列表大小 |
config_bt_mesh_friend_queue_size | u8 | 2 | Friend 消息队列大小 |
config_bt_mesh_adv_buf_count | u8(WEAK) | 5 | 广播缓存缓冲区个数 |
config_bt_mesh_pb_adv_interval | u16 | ADV_SCAN_UNIT(15) | PB-ADV 配网广播间隔 |
config_bt_mesh_pb_adv_duration | u16 | 40 ms | PB-ADV 广播时长 |
config_bt_mesh_prov_retransmit_timeout | u32 | 300 ms | 配网重传超时 |
config_bt_mesh_prov_transaction_timeout | u8 | 30 s | 配网事务超时 |
config_bt_mesh_prov_link_close_timeout | u8 | 3 s | 配网链路关闭超时 |
config_bt_mesh_prov_protocol_timeout | u8 | 60 s | 配网协议总超时 |
config_bt_mesh_unprov_beacon_interval | u32 | 200 ms | 未配网 Beacon 广播间隔 |
config_bt_mesh_secure_beacon_interval | u16 | 10 s | Secure Network Beacon 间隔 |
参数全部来自:mesh_config_common.c
日志开关同样在此文件用 CONFIG_DEBUG_LIB(0) 定义 MESH_HCI 与 MESH_GATT 两组的 v/i/d/w/e 五个级别 tag:
/**
* @brief Ble Mesh Log
*/
/*-----------------------------------------------------------*/
const char log_tag_const_v_MESH_HCI AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
...
const char log_tag_const_e_MESH_GATT AT(.LOG_TAG_CONST) = CONFIG_DEBUG_LIB(0);
低功耗与软关机
应用通过 REGISTER_LP_TARGET 向系统注册低功耗目标:空闲查询函数返回 !is_app_active,即未主动关机时允许系统进入睡眠(配合 eSystemConfirmStopStatus() 的 Endless Sleep 策略):
//-----------------------
//system check go sleep is ok
static u8 app_state_idle_query(void)
{
return !is_app_active;
}
REGISTER_LP_TARGET(app_state_lp_target) = {
.name = "app_state_deal",
.is_idle = app_state_idle_query,
};
来源:app_mesh.c
软关机流程强调"先断开蓝牙链路再断电":先 ble_module_enable(0) 关闭 BLE 模块,再延时 300 ms 确保 BT 退出链路后再调用 power_set_soft_poweroff():
static void app_set_soft_poweroff(void)
{
log_info("set_soft_poweroff\n");
is_app_active = 1;
//必须先主动断开蓝牙链路,否则要等链路超时断开
ble_module_enable(0);
//延时300ms,确保BT退出链路断开
sys_timeout_add(NULL, power_set_soft_poweroff, WAIT_DISCONN_TIME_MS);
}
来源:app_mesh.c
设计意图:若直接断电,蓝牙链路需等底层超时才释放,可能导致射频残留占用或功耗异常;300 ms 延时让控制器完成断链清理,属于典型的"时序敏感型关机"处理。
核心流程
sequenceDiagram
participant Boot as 系统启动
participant Main as app_main
participant Core as app_core 框架
participant Mesh as app_mesh 应用
participant Bt as btstack
participant Ble as BLE 控制器
Boot->>Main: app_main()
Main->>Main: 构造 intent(name="mesh", ACTION_AT_MAIN)
Main->>Core: start_app(&it)
Core->>Mesh: state_machine(APP_STA_START)
Mesh->>Mesh: clk_set("sys", 24MHz) / bt_pll_para()
Mesh->>Mesh: bt_function_select_init() 由 EDR MAC 推导 BLE 地址
Mesh->>Bt: btstack_init()
Bt-->>Mesh: BT_STATUS_INIT_OK (事件回调)
Mesh->>Ble: bt_ble_init()
Ble-->>Mesh: HCI 状态事件 / 连接状态事件
Mesh->>Mesh: input_key_handler() 处理按键输入
事件分发的完整决策路径如下:
flowchart TD
SysEvent["sys_event 任务"] --> EH["event_handler()"]
EH --> Key{"SYS_KEY_EVENT?"}
Key -->|"是"| KeyH["app_key_event_handler()"]
KeyH --> Input["input_key_handler(event_type, key_value)"]
KeyH --> Off{"KEY_EVENT_LONG 且 ADKEY_VALUE6?"}
Off -->|"是"| SoftOff["app_set_soft_poweroff()"]
EH --> BtEvt{"SYS_BT_EVENT?"}
BtEvt -->|"CON_STATUS"| ConnH["bt_connction_status_event_handler()"]
BtEvt -->|"HCI_STATUS"| HciH["bt_hci_event_handler()"]
ConnH --> Ok{"BT_STATUS_INIT_OK?"}
Ok -->|"是"| BleInit["bt_ble_init() 启动 BLE/Mesh 承载"]
HciH --> Vendor{"HCI_EVENT_VENDOR_REMOTE_TEST?"}
Vendor -->|"value=1 (EDR 连接)"| AdvOff["bt_ble_adv_enable(0) 停广播"]
API 参考
void app_main(void)
系统 C 入口。构造 intent(name="mesh",action=ACTION_AT_MAIN)并调用 start_app(&it) 启动 Mesh 应用;CONFIG_UPDATA_ENABLE 开启时先执行 update_result_deal() 处理升级结果。
- 位置:app_main.c
void app_switch(const char *name, int action)
应用切换。先向当前应用发送 ACTION_BACK 使其经历 APP_STA_STOP/APP_STA_DESTROY,再以新 intent 启动目标应用。
- 位置:app_main.c
static int state_machine(struct application *app, enum app_state state, struct intent *it)
应用状态机。APP_STA_START + ACTION_AT_MAIN 时调用 app_start();其余状态为空实现,返回 0。
- 位置:app_mesh.c
static void app_start(void)
Mesh 初始化序列:设置系统时钟 24 MHz → 配置蓝牙 PLL → bt_function_select_init()(生成 BLE 地址)→ btstack_init() → sys_key_event_enable()。
- 位置:app_mesh.c
static int event_handler(struct application *app, struct sys_event *event)
全局事件分发。返回 0 表示已处理;未识别类型返回 FALSE。SYS_BT_EVENT 按 event->arg 区分 SYS_BT_EVENT_TYPE_CON_STATUS 与 SYS_BT_EVENT_TYPE_HCI_STATUS。
- 位置:app_mesh.c
static void app_set_soft_poweroff(void)
软关机:ble_module_enable(0) 关闭 BLE 模块,300 ms 后经 sys_timeout_add 调用 power_set_soft_poweroff()。置位 is_app_active 使低功耗查询返回忙。
- 位置:app_mesh.c
低功耗目标注册
REGISTER_LP_TARGET(app_state_lp_target):is_idle = app_state_idle_query,返回 !is_app_active,决定系统是否可睡眠。
- 位置:app_mesh.c
故障模式、边界情况与并发
- 蓝牙共存竞争:EDR 与 BLE 共用射频。
bt_hci_event_handler在 EDR 连接建立(厂商事件0xFE且 value=1)时主动bt_ble_adv_enable(0)关闭 BLE 广播;若 HCI 事件丢失,广播可能持续占用空口,属依赖控制器调度的软约束。 - 关机时序:
app_set_soft_poweroff必须先断 BLE 链路再延时关机;注释明确"否则要等链路超时断开",即跳过断链会导致关机延迟或功耗异常。 - 并发模型:Mesh 应用本身不建任务,回调(状态机、事件处理、
sys_timeout_add定时回调)都在app_core/btstack任务上下文中执行,因此对is_app_active等共享标志的访问无需加锁;但应用回调中不应执行阻塞操作,否则会阻塞事件循环。 - 模型选择约束:
CONFIG_MESH_MODEL为编译期宏,运行时不可切换模型;SIG_MESH_*值 0-4 由协议栈示例库决定,新增模型需同步修改示例库与model_api.h。 - 弱符号覆盖:
config_bt_mesh_adv_buf_count、config_bt_mesh_proxy_node_adv_interval为_WEAK_,若板级重复定义且类型不一致,链接行为未定义,覆盖时须保持类型与符号名完全一致。
性能与运维注意事项
- 时钟与功耗:
app_start()固定将系统时钟设为 24 MHz 并据此配置 PLL;Mesh 低功耗(LPN)依赖config_bt_mesh_lpn_auto_timeout等参数,默认auto_timeout=0表示不自动进入 LPN,需用户按功耗目标调整。 - 广播参数权衡:节点消息广播间隔默认 10 ms、时长 100 ms,适用于低时延演示;
config_bt_mesh_adv_buf_count(默认 5)决定可排队广播包数量,广播拥塞时优先增大该值。 - 配网超时:PB-ADV 配网链路关闭超时 3 s、协议总超时 60 s、事务超时 30 s——配网失败多为这些超时到期,排查时先核对
MESH_HCI/MESH_GATT日志 tag(默认CONFIG_DEBUG_LIB(0)关闭,可改为 1 打开)。 - 诊断手段:
app_mesh.c使能LOG_DEBUG_ENABLE/LOG_INFO_ENABLE/LOG_CLI_ENABLE,启动横幅"BLE MESH DEMO"与BT_STATUS_INIT_OK日志是判断初始化进度的关键锚点。
扩展点
- 新增 Mesh 模型:在
model_api.h中扩展SIG_MESH_*枚举并把CONFIG_MESH_MODEL指向新模型;模型逻辑位于 sig_mesh 示例库(examples/generic_onoff_client.c等),按注释对应关系接入。 - 板级参数覆盖:在
board_ac630x_demo_cfg.h或板级 C 文件中重新定义config_bt_mesh_*弱符号,即可为特定芯片/认证需求定制广播、LPN、Friend、配网参数,无需改动应用代码。 - 按键动作扩展:
input_key_handler()是按键→Mesh 的桥接点;新增按键组合只需在app_key_event_handler增加分支(参照KEY_EVENT_LONG + TCFG_ADKEY_VALUE6的软关机模式)。 - 多应用切换:
app_switch(name, action)支持在 Mesh 与其它应用(如经典蓝牙音箱应用)之间切换,应用间共享task_info_table任务骨架。 - 低功耗策略:通过
REGISTER_LP_TARGET的is_idle查询可挂接更精细的睡眠准入条件(当前仅依赖is_app_active)。
相关链接
- 应用入口与任务表:apps/mesh/app_main.c
- Mesh 应用主体(状态机/事件/软关机):apps/mesh/app_mesh.c
- 模型选择与地址宏:apps/mesh/api/model_api.h
- 模型 API 实现:apps/mesh/api/model_api.c
- 协议/硬件参数配置:apps/mesh/api/mesh_config_common.c
- SIG Mesh 协议栈(第三方移植库):apps/common/third_party_profile/sig_mesh/api/sig_mesh_api.h 与 mesh.h
- 板级适配(AC630x 示例):apps/mesh/board/bd29/board_ac630x_demo.c 与 board_config.h
- 空闲调度(兄弟页面):apps/mesh/app_idle.c
使用示例
示例 1:注册一个 Mesh 应用(入口接线)
任何应用要接入该框架,只需声明 application_operation 并调用 REGISTER_APPLICATION,框架即可按 name 找到它:
static const struct application_operation app_at_ops = {
.state_machine = state_machine,
.event_handler = event_handler,
};
REGISTER_APPLICATION(app_mesh) = {
.name = "mesh",
.action = ACTION_AT_MAIN,
.ops = &app_at_ops,
.state = APP_STA_DESTROY,
};
来源:app_mesh.c
示例 2:由 EDR 地址推导 BLE 地址
Mesh 节点需要稳定的 BLE MAC,SDK 的做法是从经典蓝牙 MAC 推导,保证 EDR/BLE 同源且可复现:
static void bt_function_select_init()
{
u8 tmp_ble_addr[6];
/* le_controller_set_mac((void*)"012345"); */
lib_make_ble_address(tmp_ble_addr, (void *)bt_get_mac_addr());
le_controller_set_mac((void *)tmp_ble_addr);
printf("\n-----edr + ble 's address-----");
printf_buf((void *)bt_get_mac_addr(), 6);
printf_buf((void *)tmp_ble_addr, 6);
/* bt_set_tx_power(9);//0~9 */
}
来源:app_mesh.c
示例 3:覆盖弱符号配置(板级定制)
板级工程无需改动 mesh_config_common.c,直接重定义同名符号即可定制节点广播间隔等参数:
/* 板级文件:board_ac6311_demo_cfg.h 中覆盖默认的 10ms 节点广播间隔 */
const u16 config_bt_mesh_node_msg_adv_interval = ADV_SCAN_UNIT(20); // 20ms,降低空口占用
说明:
config_bt_mesh_node_msg_adv_interval的默认定义见 mesh_config_common.c,弱符号覆盖机制允许板级重定义;重定义时需保持类型与符号名一致。
示例 4:启动指定的 Mesh 模型
编译期选定模型——例如改为 Vendor Server 或天猫精灵 Vendor:
//< Config whick example will use in <examples>
#define CONFIG_MESH_MODEL SIG_MESH_GENERIC_ONOFF_CLIENT
来源:model_api.h(将
SIG_MESH_GENERIC_ONOFF_CLIENT替换为SIG_MESH_VENDOR_SERVER/SIG_MESH_TMALL_GENIE_VENDOR等,见同文件第 4-10 行的枚举定义)