杰理 SDK 文档中心
首页
首页
  • 项目概览

    • 项目概述与能力地图
    • 构建系统与编译流程
    • 芯片系列与规格
  • 应用示例

    • SPP 与 BLE 双模透传
    • AT 指令串口协议
    • HID 设备应用
    • 蓝牙 Mesh 应用
    • 公共组件与第三方协议
  • 芯片平台支持

    • 外设驱动
    • 电源与充电管理
    • 启动与链接脚本
    • 配置工具与 OTA 资源
  • 协议栈与系统库

    • 蓝牙控制器
    • BTStack 协议栈接口
    • 系统内核与服务
    • OTA 升级机制
  • 文档与参考

    • 蓝牙 AT 协议参考
    • 开发文档与认证信息

蓝牙 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

来源:mesh_config_common.c

主要参数分组如下:

参数类型默认值说明
config_bt_mesh_node_msg_adv_intervalu16ADV_SCAN_UNIT(10)(10 ms)节点消息广播间隔
config_bt_mesh_node_msg_adv_durationu16100 ms节点消息广播时长
config_bt_mesh_proxy_unprovision_adv_intervalu16ADV_SCAN_UNIT(30)未配网代理可连接广播间隔
config_bt_mesh_proxy_pre_node_adv_intervalu16ADV_SCAN_UNIT(10)配网前节点代理广播间隔
config_bt_mesh_proxy_node_adv_intervalu16(WEAK)ADV_SCAN_UNIT(300)已配网节点代理广播间隔
config_bt_mesh_lpn_auto_timeoutu80 sLPN 自动进入低功耗超时(0=关闭)
config_bt_mesh_lpn_retry_timeoutu810 sLPN 重试超时
config_bt_mesh_lpn_scan_latencyint10 msLPN 扫描延迟
config_bt_mesh_lpn_init_poll_timeoutu32300(×100 ms)LPN 初始 Poll 超时
config_bt_mesh_lpn_powerup_add_sub_listu81上电时是否加入订阅列表
config_bt_mesh_lpn_recv_delayu8100 msLPN 接收延迟(Friend Request,3.6.5.3)
config_bt_mesh_lpn_poll_timeoutu32200(×100 ms)LPN Poll 超时
config_bt_mesh_lpn_rssi_factor / recv_win_factoru80 / 0LPN 邻居/接收窗口因子
config_bt_mesh_lpn_min_queue_sizeu81LPN 最小队列长度
config_bt_mesh_friend_lpn_countu81Friend 节点可服务的 LPN 数
config_bt_mesh_friend_recv_winu8250Friend 接收窗口(Friend Offer,3.6.5.4)
config_bt_mesh_friend_sub_list_sizeu82Friend 订阅列表大小
config_bt_mesh_friend_queue_sizeu82Friend 消息队列大小
config_bt_mesh_adv_buf_countu8(WEAK)5广播缓存缓冲区个数
config_bt_mesh_pb_adv_intervalu16ADV_SCAN_UNIT(15)PB-ADV 配网广播间隔
config_bt_mesh_pb_adv_durationu1640 msPB-ADV 广播时长
config_bt_mesh_prov_retransmit_timeoutu32300 ms配网重传超时
config_bt_mesh_prov_transaction_timeoutu830 s配网事务超时
config_bt_mesh_prov_link_close_timeoutu83 s配网链路关闭超时
config_bt_mesh_prov_protocol_timeoutu860 s配网协议总超时
config_bt_mesh_unprov_beacon_intervalu32200 ms未配网 Beacon 广播间隔
config_bt_mesh_secure_beacon_intervalu1610 sSecure 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);

来源:mesh_config_common.c

低功耗与软关机

应用通过 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 日志是判断初始化进度的关键锚点。

扩展点

  1. 新增 Mesh 模型:在 model_api.h 中扩展 SIG_MESH_* 枚举并把 CONFIG_MESH_MODEL 指向新模型;模型逻辑位于 sig_mesh 示例库(examples/generic_onoff_client.c 等),按注释对应关系接入。
  2. 板级参数覆盖:在 board_ac630x_demo_cfg.h 或板级 C 文件中重新定义 config_bt_mesh_* 弱符号,即可为特定芯片/认证需求定制广播、LPN、Friend、配网参数,无需改动应用代码。
  3. 按键动作扩展:input_key_handler() 是按键→Mesh 的桥接点;新增按键组合只需在 app_key_event_handler 增加分支(参照 KEY_EVENT_LONG + TCFG_ADKEY_VALUE6 的软关机模式)。
  4. 多应用切换:app_switch(name, action) 支持在 Mesh 与其它应用(如经典蓝牙音箱应用)之间切换,应用间共享 task_info_table 任务骨架。
  5. 低功耗策略:通过 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 行的枚举定义)

Prev
HID 设备应用
Next
公共组件与第三方协议