杰理 SDK 文档中心
首页
首页
  • 概述

    • SDK 概览与产品定位
    • 支持芯片平台与蓝牙认证
    • SDK 架构与目录分层
  • 快速开始

    • 环境搭建与编译工具链
    • 编译构建系统
    • 板级工程与配置
    • 烧录与固件升级工具
  • 应用工程

    • 应用选择与工程总览
    • SPP + BLE 数传应用框架
    • 透传与 AT 指令示例
    • BLE 广播/中心与定位示例
    • 2.4G 私有协议与 Dongle 示例
    • 云平台接入示例
    • HID 人机交互应用框架
    • HID 示例工程(键盘/鼠标/遥控器/手柄)
    • Bluetooth Mesh 应用框架
    • Mesh 模型与 Mesh DFU 固件升级
    • Mesh 音频编解码演示
  • 芯片平台与硬件抽象

    • 芯片平台总览与差异
    • 音频编解码与时钟管理
    • 外设驱动接口(ADC/IIC/SPI/PWM/LED/充电)
    • 芯片配置工具与下载支持
  • 蓝牙协议栈

    • 蓝牙控制器层(btctrler)
    • 蓝牙协议栈与 Profile(btstack)
    • 蓝牙模块选择与配置
  • 媒体与音频框架

    • 音频流框架
    • 音频编解码与 A2DP 媒体
    • 音频效果处理(EQ/频谱/变调/环绕/超低音)
    • 本地 TWS 与音频同步
  • 系统服务与运行时

    • 实时操作系统与任务调度
    • 消息事件机制
    • 电源管理与低功耗
    • 存储与配置系统
    • 设备驱动框架(USB/RTC)
  • 应用公共组件

    • 音频应用组件
    • 设备外设抽象(按键/触摸/传感器/存储)
    • 蓝牙公共模块与消息联动
    • 调试与配置组件
    • 杰理关键词唤醒(jl_kws)
  • 第三方协议与云平台接入

    • 杰理 RCSP 私有协议
    • 低功耗蓝牙 Mesh 方案(llsync_mesh)
    • Sig Mesh 方案
    • 涂鸦协议接入
    • 腾讯连连接入
    • 华为 HiLink 接入
  • 固件升级与维护

    • OTA 升级机制
    • 升级补丁与版本维护
    • 升级工具链(BLE OTA / USB Dongle OTA)
  • 文档与开发资源

    • 数据手册与架构文档
    • 协议与云平台开发文档
    • 常见问题与技术支持

Bluetooth Mesh 应用框架

本文档介绍杰理(Jieli)AC63 蓝牙 SoC SDK 中 apps/mesh 应用工程所构成的 Bluetooth Mesh 应用框架:它如何基于 REGISTER_APPLICATION 应用注册机制接入 SDK 的应用核心(app_core),如何与内置的 SIG Mesh 协议栈(apps/common/third_party_profile/sig_mesh)交互,以及如何通过 mesh_config_common.c 的全局配置变量调节节点(Node)、低功耗节点(LPN)、Friend、代理(Proxy)和配网(PB-ADV)等行为。

Purpose and Scope

本页覆盖以下内容:

  • Mesh 应用工程的入口与生命周期管理(apps/mesh/app_mesh.c、apps/mesh/app_main.c);
  • 事件驱动架构:按键事件、蓝牙连接状态事件、HCI 事件如何路由到 Mesh 应用;
  • SIG Mesh 协议栈的统一 API 头文件(apps/common/third_party_profile/sig_mesh/api/sig_mesh_api.h)所暴露的模型、地址与错误码体系;
  • Mesh 硬件/协议参数配置(apps/mesh/api/mesh_config_common.c);
  • 工程目录结构、板级工程(board)与可扩展的示例(mesh_dfu、tencent_mesh、audio_codec_demo)。

以下主题属于兄弟页面,不在本页展开:

  • Mesh OTA/DFU 固件升级的详细协议(见 apps/mesh/mesh_dfu);
  • 腾讯 LL Sync Mesh(低功耗广域物联网)接入(见 apps/common/third_party_profile/llsync_mesh 与 apps/mesh/examples/tencent_mesh.c);
  • 具体芯片(AC631N/AC632N/AC635N/AC636N/AC637N/AC638N)的板级工程配置(见 apps/mesh/board)。

概述

apps/mesh 是 SDK 内置的 BLE Mesh 演示应用。与 SDK 中其它应用(如经典蓝牙音箱、通话应用)一样,它通过 REGISTER_APPLICATION(app_mesh) 宏注册为一个名为 "mesh" 的应用实例,并挂载 state_machine 与 event_handler 两个回调,从而融入 SDK 统一的应用框架(system/app_core.h)与事件系统(system/includes.h)。

框架的核心设计意图是:把"蓝牙协议栈初始化"、"应用状态迁移"和"系统事件分发"三者解耦。应用只负责声明自己关心的事件类型(按键、蓝牙状态、HCI 状态、设备事件),框架负责在合适的时机调用对应回调;Mesh 协议栈的具体实现则被封装在 sig_mesh_api 之下,应用层通过 mesh_config_common.c 的全局常量即可调整协议行为,无需修改协议栈源码。

Mesh 协议栈本身是一个 Zephyr 风格(net/buf.h、atomic_h.h)的 SIG Mesh 实现,覆盖配网(Provisioning)、模型(Models,如 cfg、health、scene、blob、dfu、rpr 等)、代理(Proxy)、LPN/Friend、私有信标(Private Beacon)与 Remote Provisioning 等能力。

架构

flowchart TD
    subgraph sg_App["应用层 apps/mesh"]
        AppMain["app_main.c<br/>注册 main 动作"]
        AppMesh["app_mesh.c<br/>REGISTER_APPLICATION(app_mesh)"]
        AudioDemo["audio_codec_demo.c"]
        MeshDfu["mesh_dfu/<br/>Distributor Loader"]
        TencentMesh["examples/tencent_mesh.c"]
    end

    subgraph sg_Core["SDK 应用框架"]
        AppCore["app_core / application<br/>state_machine + event_handler"]
        SysEvent["系统事件系统<br/>SYS_KEY_EVENT / SYS_BT_EVENT / SYS_DEVICE_EVENT"]
    end

    subgraph sg_Stack["SIG Mesh 协议栈"]
        SigApi["sig_mesh_api.h<br/>access / main / proxy / cfg / health<br/>blob / dfu / rpr / scene ..."]
        MeshCfg["api/mesh_config.h"]
        MeshLog["adaptation/mesh_log.h"]
    end

    subgraph sg_Hw["蓝牙控制器与硬件"]
        BtStack["btstack / btctrler_task"]
        BleModule["ble_module / adv & scan 硬件"]
        BtPll["bt_pll_para 时钟配置"]
    end

    subgraph sg_Cfg["参数配置层"]
        MeshCfgCommon["api/mesh_config_common.c<br/>adv / lpn / friend / pb-adv / beacon"]
    end

    AppMesh -->|"注册 application"| AppCore
    AppCore -->|"分发事件"| SysEvent
    SysEvent -->|"SYS_BT_EVENT"| AppMesh
    AppMesh -->|"调用"| SigApi
    SigApi -->|"基于"| MeshCfg
    MeshCfgCommon -->|"全局常量供栈读取"| SigApi
    SigApi -->|"经 btstack 收发"| BtStack
    BtStack --> BleModule
    AppMesh -->|"clk_set / bt_pll_para"| BtPll
    AppMesh --> AudioDemo
    AppMesh --> MeshDfu
    AppMesh --> TencentMesh
    AppMain -->|"ACTION_AT_MAIN 启动"| AppMesh

架构说明

  • 应用层:app_mesh.c 是框架的"心脏",它定义应用生命周期回调,并在 BT_STATUS_INIT_OK 事件后调用 bt_ble_init() 初始化 BLE,从而启动 Mesh 协议栈。app_main.c 则以 it.name = "mesh"; it.action = ACTION_AT_MAIN; 把 Mesh 应用声明为主入口动作。
  • SDK 应用框架:REGISTER_APPLICATION 将应用注册进 app_core,应用的状态迁移(CREATE/START/PAUSE/RESUME/STOP/DESTROY)由框架统一驱动;事件则通过 event_handler 分发。
  • SIG Mesh 协议栈:sig_mesh_api.h 是协议栈的"伞形头文件",聚合了配网、配置客户端/服务端、健康、代理、场景、BLOB/DFU 传输、远程配网(RPR)、私有信标等全部子模块。
  • 参数配置层:mesh_config_common.c 通过 _WEAK_ 弱符号定义协议栈可覆盖的默认参数(广播间隔、LPN/Friend 参数、PB-ADV 超时等),应用可在自己的工程里重定义同名符号实现覆盖。
  • 硬件层:协议栈的收发最终落到 btstack/btctrler 的 BLE 广播与扫描硬件上;app_start() 中通过 clk_set("sys", BT_NORMAL_HZ) 与 bt_pll_para(...) 完成射频时钟配置。

应用入口与生命周期

应用注册

Mesh 应用通过 REGISTER_APPLICATION(app_mesh) 注册,名称为 "mesh",绑定的动作为 ACTION_AT_MAIN,初始状态为 APP_STA_DESTROY:

REGISTER_APPLICATION(app_mesh) = {
    .name 	= "mesh",
    .action	= ACTION_AT_MAIN,
    .ops 	= &app_at_ops,
    .state  = APP_STA_DESTROY,
};

Source: app_mesh.c

其中 app_at_ops 挂载了两个回调:state_machine(状态机)与 event_handler(事件分发):

static const struct application_operation app_at_ops = {
    .state_machine  = state_machine,
    .event_handler 	= event_handler,
};

Source: app_mesh.c

app_main.c 则在主入口中把该应用声明为 "mesh" 并指定 ACTION_AT_MAIN,使系统启动后直接进入 Mesh 模式。

状态机

state_machine 处理六个应用状态。实际启动逻辑集中在 APP_STA_START 分支:只有收到 ACTION_AT_MAIN 动作时才调用 app_start(),其它状态(CREATE/PAUSE/RESUME/STOP/DESTROY)目前为空实现,为后续扩展预留了位置:

static int state_machine(struct application *app, enum app_state state, struct intent *it)
{
    switch (state) {
    case APP_STA_CREATE:
        break;
    case APP_STA_START:
        if (!it) {
            break;
        }
        switch (it->action) {
        case ACTION_AT_MAIN:
            app_start();
            break;
        }
        break;
    ...
    }
    return 0;
}

Source: app_mesh.c

启动流程

app_start() 完成三件事:打印 Mesh Demo 标志、配置系统/射频时钟、初始化蓝牙协议栈并打开按键消息使能:

static void app_start()
{
    log_info("-------------BLE MESH DEMO-------------");
    is_app_active = 1;
    clk_set("sys", BT_NORMAL_HZ);
    u32 sys_clk =  clk_get("sys");
    bt_pll_para(TCFG_CLOCK_OSC_HZ, sys_clk, 0, 0);
    btstack_init();
    sys_key_event_enable();
}

Source: app_mesh.c

设计意图:bt_pll_para 必须使用与 clk_set 相同的系统时钟参数,否则 BLE 射频频率会偏移;btstack_init() 在此时只是初始化协议栈任务,真正的 BLE/Mesh 初始化要等控制器上报 BT_STATUS_INIT_OK 之后才执行(见下文事件处理)。

事件处理

event_handler 是框架与外部世界之间的唯一入口,按事件类型分发:

  • SYS_KEY_EVENT → app_key_event_handler();
  • SYS_BT_EVENT 且 arg == SYS_BT_EVENT_TYPE_CON_STATUS → bt_connction_status_event_handler();
  • SYS_BT_EVENT 且 arg == SYS_BT_EVENT_TYPE_HCI_STATUS → bt_hci_event_handler();
  • SYS_DEVICE_EVENT → 直接返回 0(暂不处理)。
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;
}

Source: app_mesh.c

蓝牙就绪事件:Mesh 协议栈的真正起点

BT_STATUS_INIT_OK 事件是框架中最关键的分支点。收到该事件后,若处于 BQB 测试模式则启动 ble_bqb_test_thread_init();若开启 TCFG_NORMAL_SET_DUT_MODE 则进入 DUT 测试;否则调用 bt_ble_init() 正式初始化 BLE——Mesh 协议栈的配网广播(Unprovisioned Device Beacon)即由此开启:

case BT_STATUS_INIT_OK:
    log_info("BT_STATUS_INIT_OK\n");
    if (BT_MODE_IS(BT_BQB)) {
        void ble_bqb_test_thread_init(void);
        ble_bqb_test_thread_init();
    } else {
#if TCFG_NORMAL_SET_DUT_MODE
        log_info("set dut mode\n");
        extern void ble_standard_dut_test_init(void);
        ble_standard_dut_test_init();
#else
        extern void bt_ble_init(void);
        bt_ble_init();
#endif
    }
    is_app_active = 0;
    break;

Source: app_mesh.c

HCI 事件与软关机

bt_hci_event_handler 处理厂商自定义 HCI 事件 HCI_EVENT_VENDOR_REMOTE_TEST (0xFE):value == 0 表示清除测试盒标志;value == 1 表示 EDR 已连接、需要关闭 BLE 广播。按键长按 TCFG_ADKEY_VALUE6 触发 app_set_soft_poweroff():先调用 ble_module_enable(0) 主动断开蓝牙链路,再延时 300ms 等待链路断开完成后执行 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);
}

Source: app_mesh.c

注意 is_app_active 的双重作用:启动与关机期间置 1,蓝牙就绪后清 0,并被 app_state_idle_query() 用于系统休眠查询——只有 !is_app_active 时系统才允许进入休眠。

SIG Mesh 协议栈集成

apps/common/third_party_profile/sig_mesh/api/sig_mesh_api.h 是协议栈的伞形头文件,聚合了配网、模型、传输等全部子模块:

#include "api/basic_depend.h"
#include "api/mesh_config.h"
#include "kernel/atomic_h.h"
#include "net/buf.h"
#include "api/access.h"
#include "api/main.h"
#include "api/proxy.h"
#include "api/cfg.h"
#include "api/cfg_cli.h"
#include "api/cfg_srv.h"
#include "api/health_cli.h"
#include "api/health_srv.h"
#include "api/keys.h"
#include "api/cdb.h"
#include "api/sar_cfg.h"
#include "api/rpr.h"
#include "api/heartbeat.h"
#include "api/blob.h"
#include "api/blob_srv.h"
#include "api/blob_cli.h"
#include "api/dfd.h"
#include "api/dfd_srv.h"
#include "api/dfu.h"
#include "api/dfu_cli.h"
#include "api/dfu_metadata.h"
#include "api/dfu_srv.h"
#include "api/blob_io_flash.h"
...
#include "api/scene.h"
#include "api/scene_cli.h"
#include "api/statistic.h"

Source: sig_mesh_api.h

地址类型宏

头文件定义了 Mesh 地址判定宏,用于区分单播(Unicast)、组播(Group)、虚拟(Virtual)与保留地址(RFU),这是所有模型收发逻辑的基础:

#define BT_MESH_ADDR_IS_UNICAST(addr) ((addr) && (addr) < 0x8000)
#define BT_MESH_ADDR_IS_GROUP(addr) ((addr) >= 0xc000 && (addr) <= 0xff00)
#define BT_MESH_ADDR_IS_VIRTUAL(addr) ((addr) >= 0x8000 && (addr) < 0xc000)
#define BT_MESH_ADDR_IS_RFU(addr) ((addr) >= 0xff00 && (addr) <= 0xfffb)

Source: sig_mesh_api.h

模型列表宏

BT_MESH_MODEL_LIST 允许在元素(Element)定义中直接以内联数组声明模型列表,是注册模型的标准写法:

#define BT_MESH_MODEL_LIST(...) ((struct bt_mesh_model[]){ __VA_ARGS__ })

Source: sig_mesh_api.h

协议栈还定义了完整的 errno 风格错误码(ENONE 0 起,EPERM/ENOENT/ENOMEM/EINVAL/ETIMEDOUT 等),模型回调通过返回值向调用方表达失败原因,应用层可据此做重试或告警。

配置体系

apps/mesh/api/mesh_config_common.c 以全局常量形式给出协议栈硬件参数默认值,全部参数可在应用工程中通过重定义同名符号覆盖(部分声明带 _WEAK_):

分组参数默认值含义
节点消息广播config_bt_mesh_node_msg_adv_intervalADV_SCAN_UNIT(10)(10ms)节点发送消息的广播间隔
节点消息广播config_bt_mesh_node_msg_adv_duration50ms单次广播持续时间
代理广播config_bt_mesh_proxy_unprovision_adv_intervalADV_SCAN_UNIT(30)未配网代理广播间隔
代理广播config_bt_mesh_proxy_pre_node_adv_intervalADV_SCAN_UNIT(10)入网前代理广播间隔
代理广播config_bt_mesh_proxy_node_adv_intervalADV_SCAN_UNIT(300)(_WEAK_)入网后代理广播间隔
LPNconfig_bt_mesh_lpn_auto_timeout0sLPN 自动进入低功耗的超时
LPNconfig_bt_mesh_lpn_retry_timeout10s轮询失败重试超时
LPNconfig_bt_mesh_lpn_scan_latency10ms扫描延迟
LPNconfig_bt_mesh_lpn_init_poll_timeout300(×100ms)初始轮询超时
LPNconfig_bt_mesh_lpn_poll_timeout200(×100ms)常规轮询超时
LPNconfig_bt_mesh_lpn_powerup_add_sub_list1上电自动加入订阅列表
LPNconfig_bt_mesh_lpn_recv_delay100ms接收延迟(Friend Request 3.6.5.3)
Friendconfig_bt_mesh_friend_lpn_count1可服务的 LPN 数量
Friendconfig_bt_mesh_friend_recv_win250接收窗口(Friend Offer 3.6.5.4)
Friendconfig_bt_mesh_friend_sub_list_size2订阅列表大小
Friendconfig_bt_mesh_friend_queue_size2消息队列大小
广播缓存config_bt_mesh_adv_buf_count10(_WEAK_)广播缓冲区数量,必须 ≥ 3
PB-ADV 配网config_bt_mesh_pb_adv_intervalADV_SCAN_UNIT(15)PB-ADV 广播间隔
PB-ADV 配网config_bt_mesh_pb_adv_duration40msPB-ADV 广播时长
PB-ADV 配网config_bt_mesh_prov_retransmit_timeout300ms配网重传超时
PB-ADV 配网config_bt_mesh_prov_transaction_timeout30s配网事务超时
PB-ADV 配网config_bt_mesh_prov_link_close_timeout3s配网链路关闭超时
PB-ADV 配网config_bt_mesh_prov_protocol_timeout60s配网协议总超时
信标config_bt_mesh_unprov_beacon_interval200ms未配网信标间隔
信标config_bt_mesh_secure_beacon_interval10s安全网络信标间隔

Source: mesh_config_common.c

其中 ADV_SCAN_UNIT(_ms) 定义为 ((_ms) * 8 / 5),把毫秒转换为 0.625ms 的广播时隙单位。编译期约束通过 #if (MESH_ADV_BUFFER_COUNT < 3) #error 保证广播缓冲下限,防止缓冲不足导致消息丢失。

核心流程

sequenceDiagram
    participant AppCore as app_core 框架
    participant Mesh as app_mesh 应用
    participant Bt as btstack/控制器
    participant Sig as SIG Mesh 协议栈
    participant Hw as BLE 射频硬件

    AppCore->>Mesh: APP_STA_START + ACTION_AT_MAIN
    Mesh->>Mesh: app_start(): clk_set + bt_pll_para
    Mesh->>Bt: btstack_init()
    Bt-->>AppCore: SYS_BT_EVENT BT_STATUS_INIT_OK
    AppCore->>Mesh: bt_connction_status_event_handler()
    Mesh->>Mesh: bt_ble_init()
    Mesh->>Sig: 启动 Mesh 协议栈(读取 mesh_config_common 参数)
    Sig->>Hw: 开启未配网信标 / 代理广播
    Hw-->>Sig: 收到配网/消息广播
    Sig-->>Mesh: 模型回调 / 状态通知
    Mesh-->>AppCore: 按键/蓝牙/HCI 事件继续由 event_handler 分发

配网(Provisioning)成功前,节点持续以 config_bt_mesh_unprov_beacon_interval(200ms)发送未配网信标;配网后切换到安全网络信标(10s)与节点消息广播,LPN 则按 poll_timeout 周期向 Friend 轮询缓存消息。整套流程的时序完全由上述配置参数驱动,应用层无需干预协议细节。

使用示例

示例 1:按键事件驱动 Mesh 行为

应用层把按键事件统一转发给 input_key_handler,并监听长按 TCFG_ADKEY_VALUE6 触发软关机。这展示了"系统按键 → 应用框架 → Mesh 业务"的典型链路:

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

Source: app_mesh.c

示例 2:HCI 厂商事件处理

通过 HCI 事件控制 BLE 广播启停,是产测/外部主控联动的常用手段——EDR 连接建立后关闭 BLE 广播以避免射频冲突:

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

Source: app_mesh.c

示例 3:覆盖协议栈默认参数

协议栈参数以 _WEAK_ 弱符号导出,应用工程可以重定义同名全局变量实现定制。例如把入网后的代理广播间隔改为 100ms 以获得更快的手机连接响应:

_WEAK_
const u16 config_bt_mesh_proxy_node_adv_interval = ADV_SCAN_UNIT(300); // unit: ms

Source: mesh_config_common.c

示例 4:地址判定与模型列表

在自定义模型中,用地址宏区分单播/组播目标,用 BT_MESH_MODEL_LIST 声明元素模型:

#define BT_MESH_ADDR_IS_UNICAST(addr) ((addr) && (addr) < 0x8000)
#define BT_MESH_ADDR_IS_GROUP(addr) ((addr) >= 0xc000 && (addr) <= 0xff00)
#define BT_MESH_MODEL_LIST(...) ((struct bt_mesh_model[]){ __VA_ARGS__ })

Source: sig_mesh_api.h

工程结构与扩展点

flowchart LR
    subgraph sg_Apps["apps/mesh 工程"]
        A["app_mesh.c / app_main.c<br/>框架入口"]
        B["api/mesh_config_common.c<br/>协议参数"]
        C["mesh_dfu/<br/>DFU 升级"]
        D["examples/tencent_mesh.c<br/>腾讯 LL Sync"]
        E["audio_codec_demo.c<br/>音频编解码"]
        F["board/<br/>AC631N/AC632N/AC635N/AC636N/AC637N/AC638N"]
    end
    subgraph sg_Common["apps/common/third_party_profile"]
        G["sig_mesh/<br/>SIG Mesh 协议栈"]
        H["llsync_mesh/<br/>腾讯 LL Sync Mesh SDK"]
    end
    A --> B
    A --> C
    A --> D
    A --> E
    A --> F
    D --> H
    A --> G

扩展应用的方式:

  1. 新增应用动作:在 state_machine 的 APP_STA_START 分支中增加 it->action 判断,实现不同启动模式(如 AT 模式、产测模式);
  2. 新增模型:在 SIG Mesh 栈的 access.h/cfg.h 之上注册 struct bt_mesh_model,通过 BT_MESH_MODEL_LIST 挂载到元素;
  3. 新增板级工程:复制 board/ 下现有 .cbp(CodeBlocks 工程)并修改芯片型号与引脚配置;
  4. 覆盖弱符号:重定义 config_bt_mesh_* 系列参数调整协议行为,无需改动协议栈源码;
  5. 集成第三方协议:参考 tencent_mesh.c 接入 llsync_mesh SDK,与 SIG Mesh 共存或互斥运行。

配置选项

配置变量集中定义于 apps/mesh/api/mesh_config_common.c(详见上文"配置体系"表格),并通过 mesh_config.h 暴露给协议栈。所有间隔类参数均以 ADV_SCAN_UNIT(1 单位 = 0.625ms)换算;时间类参数按注释标注的单位解释(如 poll_timeout 单位为 100ms)。

选项类型默认值说明
config_bt_mesh_adv_buf_countu810(WEAK)广播缓冲数,编译期强制 ≥ 3
config_bt_mesh_lpn_auto_timeoutu80LPN 自动休眠超时(秒)
config_bt_mesh_lpn_poll_timeoutu32200LPN 轮询周期(×100ms)
config_bt_mesh_friend_lpn_countu81Friend 可服务 LPN 数
config_bt_mesh_prov_protocol_timeoutu860配网协议总超时(秒)
config_bt_mesh_unprov_beacon_intervalu32200未配网信标间隔(ms)
config_bt_mesh_secure_beacon_intervalu1610安全信标间隔(秒)

API 参考

应用框架回调

函数签名作用
state_machinestatic int state_machine(struct application *app, enum app_state state, struct intent *it)应用状态机;APP_STA_START + ACTION_AT_MAIN 时执行 app_start()
event_handlerstatic int event_handler(struct application *app, struct sys_event *event)系统事件分发:按键/蓝牙连接/HCI 状态
app_startstatic void app_start(void)时钟配置 + btstack_init() + 按键使能
app_set_soft_poweroffstatic void app_set_soft_poweroff(void)关闭 BLE 并延时 300ms 后软关机
bt_connction_status_event_handlerstatic int bt_connction_status_event_handler(struct bt_event *bt)蓝牙状态回调;BT_STATUS_INIT_OK 后调用 bt_ble_init()
bt_hci_event_handlerstatic int bt_hci_event_handler(struct bt_event *bt)HCI 厂商事件(0xFE)处理:EDR 连接后关 BLE 广播
app_key_event_handlerstatic void app_key_event_handler(struct sys_event *event)按键事件转发至 input_key_handler

Source: app_mesh.c

协议栈宏与常量(sig_mesh_api.h)

宏/常量定义说明
ADV_SCAN_UNIT(_ms)((_ms) * 8 / 5)毫秒 → 0.625ms 广播时隙单位
BT_MESH_ADDR_IS_UNICAST(addr)(addr) && (addr) < 0x8000单播地址判定
BT_MESH_ADDR_IS_GROUP(addr)0xc000 <= addr <= 0xff00组播地址判定
BT_MESH_ADDR_IS_VIRTUAL(addr)0x8000 <= addr < 0xc000虚拟地址判定
BT_MESH_ADDR_IS_RFU(addr)0xff00 < addr <= 0xfffb保留地址判定
BT_MESH_MODEL_LIST(...)内联模型数组在元素中声明模型列表
ENONE/EPERM/ENOENT/ENOMEM/EINVAL/ETIMEDOUT 等errno 风格模型与协议回调的错误码约定

Source: sig_mesh_api.h

失败模式、边界情况与并发

软关机竞态

app_set_soft_poweroff() 先调用 ble_module_enable(0) 再延时 300ms 执行 power_set_soft_poweroff,注释明确说明"必须先主动断开蓝牙链路,否则要等链路超时断开"。若在链路活跃时直接关机,会导致关机流程阻塞在链路超时上,因此该延时是保证优雅下电的关键边界。

广播缓冲下限

mesh_config_common.c 通过编译期断言强制 MESH_ADV_BUFFER_COUNT >= 3:

#define MESH_ADV_BUFFER_COUNT           10
_WEAK_
const u8 config_bt_mesh_adv_buf_count = MESH_ADV_BUFFER_COUNT; // must >= 3
#if (MESH_ADV_BUFFER_COUNT < 3)
#error " MESH_ADV_BUFFER_COUNT must >= 3 "
#endif

Source: mesh_config_common.c

缓冲不足会在广播洪峰(多模型同时发消息)时丢弃消息,这是 Mesh 可靠性最典型的失败模式,因此用编译错误而非运行告警来拦截。

休眠准入控制

app_state_idle_query() 返回 !is_app_active。is_app_active 在 app_start() 与软关机时置 1、BT_STATUS_INIT_OK 后清 0,确保"协议栈尚未就绪"或"正在关机"时系统不会误入休眠——这是单核 SoC 上防止广播/配网流程被睡眠打断的关键保护。

并发模型

SDK 采用"蓝牙协议栈任务 + 应用任务"的线程模型:btstack_init() 创建协议栈任务,事件通过 SYS_BT_EVENT 异步投递给应用任务。因此 event_handler 内不应执行耗时操作(如长时间的配网重传),重传与超时均由协议栈任务内部状态机驱动(config_bt_mesh_prov_*_timeout 系列参数控制)。net/buf.h 与 atomic_h.h 的引入表明协议栈内部使用原子操作保护缓冲区引用计数。

测试盒联动

HCI_EVENT_VENDOR_REMOTE_TEST(0xFE)是厂商扩展的产测接口:value=0 清除测试标志,value=1(EDR 连接)时主动关闭 BLE 广播。边界情况是双模同时连接时的射频仲裁——BLE 广播关闭后需要由外部事件重新开启,框架未自动恢复,这是有意为之(避免与 EDR 语音链路争抢射频资源)。

日志分级

mesh_config_common.c 通过 CONFIG_DEBUG_LIB(0) 控制 MESH_HCI / MESH_GATT 标签的日志使能,且 log_config.c 中 log_tag_const_*_MESH 系列常量决定 [app_mesh] 标签各级别输出。调试 Mesh 问题时,可通过这些标签开关在保留协议栈性能的同时定位广播/连接问题。

性能与运行注意事项

  • 广播间隔与功耗权衡:节点消息广播间隔(10ms)与代理入网后广播间隔(300ms)相差 30 倍。入网后拉长间隔可显著降低平均电流,但会增加手机 App 发现/连接代理的时延;对功耗敏感的产品应优先调大 config_bt_mesh_proxy_node_adv_interval。
  • LPN 轮询周期:config_bt_mesh_lpn_poll_timeout = 200(×100ms = 20s)决定低功耗节点与 Friend 的同步频率。轮询越频繁消息时延越低、功耗越高;auto_timeout = 0 表示不自动进入低功耗,需由应用主动切换。
  • Friend 资源上限:friend_lpn_count = 1、sub_list_size = 2、queue_size = 2 是低成本 Friend 的典型配置,队列溢出时 Friend 会丢弃最旧消息,LPN 通过 retry_timeout = 10s 兜底重取。
  • 配网超时链:prov_retransmit_timeout(300ms) → prov_transaction_timeout(30s) → prov_protocol_timeout(60s) 构成三级超时。配网失败排查时按此层级定位:广播层丢失(看重传)、事务层超时(看距离/干扰)、协议层超时(看 Provisioner 行为)。
  • 射频时钟一致性:app_start() 中 clk_set("sys", BT_NORMAL_HZ) 与 bt_pll_para(TCFG_CLOCK_OSC_HZ, sys_clk, 0, 0) 必须保持参数一致,否则 BLE 频偏超标会导致配网与组网失败。
  • 休眠保护:is_app_active 标志位参与系统休眠准入判断,任何"正在配网/正在关机"状态都被显式排除在休眠之外,避免广播流程被睡眠打断。

测试与验证

仓库中的可验证载体:

  • 板级工程:apps/mesh/board/ 下为 AC631N、AC632N、AC635N、AC636N、AC637N、AC638N 提供独立 .cbp 工程,覆盖从低端到高端的全系列芯片;
  • 产测模式:BT_MODE_IS(BT_BQB) 走 ble_bqb_test_thread_init(),TCFG_NORMAL_SET_DUT_MODE 走 ble_standard_dut_test_init(),与 HCI_EVENT_VENDOR_REMOTE_TEST 测试盒联动共同构成产测闭环;
  • 示例:audio_codec_demo.c(Mesh 音频编解码测试)、tencent_mesh.c(腾讯 LL Sync 接入)、mesh_dfu/(配网器/分发器固件升级)验证了框架在不同业务场景下的可扩展性;
  • 链接脚本:cpu/bd19/sdk_ld.c 中 .bt_mesh_scene_entry_sig 段表明协议栈通过链接脚本收集场景(Scene)入口,新增场景模型时需确认目标芯片链接脚本包含对应段。

相关链接

  • app_mesh.c — 应用入口与事件处理
  • app_main.c — 主入口注册
  • sig_mesh_api.h — SIG Mesh 协议栈伞形头文件
  • mesh_config_common.c — 协议栈参数配置
  • sig_mesh_api.c — 协议栈 API 实现
  • mesh_dfu 目录 — Mesh 固件升级(DFU/分发器)
  • llsync_mesh 目录 — 腾讯 LL Sync Mesh 接入
  • board 目录 — 各芯片板级工程
Prev
HID 示例工程(键盘/鼠标/遥控器/手柄)
Next
Mesh 模型与 Mesh DFU 固件升级