杰理 SDK 文档中心
首页
首页
  • SDK 概述与快速开始

    • SDK 概览与 AC791N 芯片平台
    • 环境搭建与编译指南
    • 烧录与固件升级
    • 工程结构导览
  • 产品方案应用

    • WiFi 摄像头方案
    • WiFi IPC 可视对讲方案
    • WiFi 故事机方案
    • 扫码枪 HID 方案
    • 开发板示例工程
  • 公共应用组件

    • 语音识别 ASR 引擎
    • LLM 与 AI 语音助手接入
    • 摄像头传感器驱动
    • UI 显示框架与驱动
    • USB 主机与设备栈
    • 文件系统与存储管理
    • 系统服务与外设管理
    • 生产测试与射频工具
  • 蓝牙协议栈

    • 经典蓝牙 BR/EDR
    • BLE 低功耗蓝牙
    • 蓝牙 Mesh 网络
    • 蓝牙扩展协议(RCSP/广播/无线麦克风)
  • WiFi 与网络协议栈

    • WiFi 驱动与网络模式
    • lwIP TCP/IP 协议栈
    • 网络安全与加密库
    • 应用层网络协议
    • 流媒体与音视频传输
    • 云平台接入 SDK
    • P2P 远程访问与设备互联
  • 芯片平台与驱动

    • wl82 平台与硬件加速
    • 外设驱动框架
    • 平台配置与固件打包工具
  • 媒体与音频引擎

    • 音频编解码与音源
    • 音效处理引擎
    • 视频与图像处理
  • 操作系统与运行时

    • 实时操作系统与 POSIX 层
    • C/C++ 运行时库
  • 开发资源与文档

    • 文档与规格书
    • 公共示例工程
    • UI 资源工程与打包
    • SDK 辅助工具与脚本

BLE 低功耗蓝牙

AC79NN SDK 的 BLE(低功耗蓝牙)子系统:基于 BTstack 协议栈的 GATT Server/Client 框架、WiFi 配网、透明数据传输、HID/HOGP、穿戴协议、Central 角色、2.4G 共存处理以及 BLE Mesh 节点实现。本文从应用层 Demo 到协议栈与硬件射频,端到端说明其架构、控制流、配置与扩展方式。

Purpose and Scope

本页覆盖 apps/common/ble/ 目录下的 BLE 应用层实现,以及与之配套的 third_party/common/ble_user.h 用户 API、btstack 协议栈接口和 btcontroller_modules.h 控制器接口。内容包括:

  • BLE Demo 的整体组织方式与编译期选择机制(TCFG_BLE_DEMO_SELECT)
  • 各 Demo 的职责:WiFi 配网(le_net_cfg.c)、透明传输(le_trans_data.c)、HOGP(le_hogp.c)、穿戴协议(le_mambo.c)、Central 配网(le_net_cfg_central.c)、2.4G 共存(le_24g_deal.c)、BLE Mesh(apps/common/ble/mesh/)
  • GATT 数据收发路径、ATT 缓冲区布局、连接参数更新与流控机制
  • 配置选项、核心 API、失败模式与扩展点

经典蓝牙(BR/EDR)的 A2DP/HFP 等属于独立话题,不在本页展开;BLE Mesh 的各个 vendor 模型示例(AliGenie/Tuya 等)仅做总览级介绍,详细模型文档见对应的 Mesh 页面。

Overview

AC79NN 是杰理(Jieli)面向 AIoT 场景的蓝牙 SoC 系列,其 BLE 子系统承担三类核心职责:

  1. 配网通道:设备作为 GATT Server,通过手机 App 写入 WiFi SSID/密码完成一键配网(le_net_cfg.c 及各家云端配网变体 le_net_cfg_dui.c、le_net_cfg_tencent.c、le_net_cfg_qyai.c、le_net_cfg_turing.c)。
  2. 数据通道:为上层应用提供双向透传(le_trans_data.c),支持 MTU 协商、发送缓冲、流控与速率/音频上传测试。
  3. 外围角色:HID 键盘鼠标(HOGP)、智能穿戴私有协议(Mambo)、Central 主动连接、以及智能家居 BLE Mesh 节点。

所有应用层 Demo 共用同一套底层框架:ble_user.h 提供用户级 API,BTstack 提供 GATT/ATT/SMP/L2CAP 协议实现,btcontroller_modules.h 连接链路层控制器,最终与经典蓝牙共享同一颗 2.4GHz 射频,因此需要 le_24g_deal.c 之类的共存处理。编译期通过 TCFG_BLE_DEMO_SELECT 宏从多个 DEF_BLE_DEMO_* 值中选定一个 Demo 编入固件,两个已核实的取值是 DEF_BLE_DEMO_NET_CFG(配网)与 DEF_BLE_DEMO_TRANS_DATA(透传)。

Architecture

flowchart TD
    subgraph sg_App["应用层 (apps/common/ble)"]
        NetCfg["le_net_cfg.c<br/>WiFi 配网 GATT Server"]
        NetCfgDui["le_net_cfg_dui.c 等<br/>各家云端配网变体"]
        TransData["le_trans_data.c<br/>透明数据传输"]
        Hogp["le_hogp.c<br/>HID over GATT"]
        Mambo["le_mambo.c<br/>穿戴私有协议"]
        NetCentral["le_net_central.c<br/>Central 主动配网"]
        Deal24G["le_24g_deal.c<br/>2.4G 共存处理"]
        Mesh["mesh/examples<br/>BLE Mesh 节点"]
    end

    subgraph sg_Stack["协议栈层"]
        BleUser["third_party/common/ble_user.h<br/>用户 API 封装"]
        Btstack["btstack/btstack_task.h<br/>BlueKitchen BTstack"]
        Controller["btcontroller_modules.h<br/>链路层控制器"]
    end

    subgraph sg_HW["硬件层"]
        RF["2.4GHz RF<br/>(与经典蓝牙 BR/EDR 共享)"]
    end

    NetCfg --> BleUser
    NetCfgDui --> NetCfg
    TransData --> BleUser
    Hogp --> BleUser
    Mambo --> BleUser
    NetCentral --> BleUser
    Deal24G --> BleUser
    Mesh --> BleUser
    BleUser --> Btstack
    Btstack --> Controller
    Controller --> RF

架构图说明:

  • 应用层:每个 le_*.c 文件是一个独立 Demo,全部以 #if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_XXX) 编译开关包裹,一次固件只编译其中一个。它们负责定义 GATT 服务/特征值、广播数据、连接参数表,并通过回调把上层数据接入协议栈。
  • 用户 API 层:ble_user.h 是所有 Demo 共同包含的头文件,屏蔽 BTstack 细节,向上层提供收发与状态回调注册接口。
  • 协议栈层:BTstack 处理 GATT/ATT/SMP/L2CAP/LL 标准协议;btcontroller_modules.h 提供控制器模块接口(如 ATT 控制块、流控使能)。
  • 硬件层:BLE 与经典蓝牙共用 2.4GHz 射频,le_24g_deal.c 专门处理两者同时工作时的调度与共存问题。

从源码可见,两个 Demo 都同样包含 btstack/btstack_task.h、btstack/bluetooth.h、btcontroller_modules.h、bt_common.h 与 third_party/common/ble_user.h,印证了"应用层 Demo 全部构建在统一协议栈框架之上"的设计。这样做的好处是:新增一个业务 Demo 只需复制现有 le_*.c 模板、修改 GATT 特征值与回调逻辑,协议栈与射频部分完全复用。

模块结构与 Demo 选择机制

编译期 Demo 开关

BLE 应用层以"一文件一 Demo"的方式组织,每个文件开头都有同样的编译门控。以配网 Demo 为例:

#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_NET_CFG)
...
#endif

Source: le_net_cfg.c

透明传输 Demo 使用同样的模式:

#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_TRANS_DATA)
...
#endif

Source: le_trans_data.c

TCFG_BLE_DEMO_SELECT 是工程级配置宏(在 app_config.h 或板级配置中定义),DEF_BLE_DEMO_NET_CFG / DEF_BLE_DEMO_TRANS_DATA 等取值定义了可选的 Demo 枚举。这种设计把"选择哪个业务"从代码中抽离为配置项:同一份 SDK 固件镜像模板,只需改一个宏即可切换成配网设备、透传设备或 HID 设备,降低多产品线维护成本。

ATT 缓冲区布局(所有 Server Demo 共用)

无论配网还是透传,GATT Server 都采用同一套内存分配策略:把"ATT 控制块 + 本地负载 + 发送环形缓冲"合并为一块 4 字节对齐的静态数组:

#define ATT_LOCAL_PAYLOAD_SIZE    (128)                   //note: need >= 20
#define ATT_SEND_CBUF_SIZE        (512)                   //note: need >= 20,缓存大小,可修改
#define ATT_RAM_BUFSIZE           (ATT_CTRL_BLOCK_SIZE + ATT_LOCAL_PAYLOAD_SIZE + ATT_SEND_CBUF_SIZE)
static u8 att_ram_buffer[ATT_RAM_BUFSIZE] __attribute__((aligned(4)));
...
#if (ATT_RAM_BUFSIZE < 64)
#error "adv_data & rsp_data buffer error!!!!!!!!!!!!"
#endif

#define adv_data       &att_ram_buffer[0]
#define scan_rsp_data  &att_ram_buffer[32]

Source: le_net_cfg.c

设计意图:把广播包(adv_data)和扫描应答(scan_rsp_data)从同一块 RAM 中切片出来,减少静态内存碎片;__attribute__((aligned(4))) 保证控制器 DMA 访问安全;#error 在编译期拦截过小配置(广播包 31 字节 + 应答包 31 字节的最小需求,加上控制块后不足 64 字节必然出错)。注释中的 need >= 20 表明负载长度至少应覆盖经典 20 字节 ATT 默认 MTU 的写入上限。

广播与连接参数

配网 Demo 的广播间隔与连接参数如下:

#define ADV_INTERVAL_MIN          (160)

//连接参数设置
static const uint8_t connection_update_enable = 1; ///0--disable, 1--enable
static uint8_t connection_update_cnt = 0; //
static const struct conn_update_param_t connection_param_table[] = {
    {16, 24, 10, 600},//11
    {12, 28, 10, 600},//3.7
    {8,  20, 10, 600},
};
#define CONN_PARAM_TABLE_CNT      (sizeof(connection_param_table)/sizeof(struct conn_update_param_t))

Source: le_net_cfg.c

  • ADV_INTERVAL_MIN = 160(单位 0.625ms,即 100ms)是广播间隔下限,配网场景下保证手机能快速发现设备。
  • 连接参数表是一个降级协商序列:首选 {16, 24, 10, 600}(间隔 20ms、从机延迟 10、超时 600),若对端拒绝则依次尝试更宽松的组合。connection_update_cnt 记录协商次数,connection_update_enable 是总开关,注释标注了每个组合对应的估算连接间隔(11ms / 3.7ms)。

WiFi 配网实现详解(le_net_cfg.c)

角色与数据流

设备作为 GATT Server,广播设备名为 gap_device_name[] = "wl80_ble_test"(实际名称运行时可由 bt_get_local_name() 覆盖)。手机 App(GATT Client)发现 ae82 服务后,向特征值 ATT_CHARACTERISTIC_ae82_01_VALUE_HANDLE 写入 JSON 配网指令;设备解析后调用系统 WiFi 配网接口,完成后通过 app_send_user_data 回复带杰理私有帧头的应答帧。

应答帧格式(rsp_cmd0)

//配网成回复命令
static const u8 rsp_cmd0[] = {
    0x4A, 0x4C, 0x00, 0x0e, 0x10, 0x02,
    '{', '"', 's', 't', 'a', 't', 'u', 's', '"', ':', '0', '}',
    0x7C, 0xC3, 0xFF,
};

Source: le_net_cfg.c

帧结构解读:0x4A 0x4C("JL")是杰理私有协议魔数头;0x00 0x0e 为长度字段(0x0e = 14,即后续命令+载荷长度);0x10 0x02 是命令字(配网结果通知);载荷为 JSON 文本 {"status":0},status:0 表示配网成功;0x7C 0xC3 0xFF 是帧尾校验魔数。这种"魔数头 + 长度 + 命令 + JSON 载荷 + 帧尾"的封装便于手机端协议栈快速解帧,同时让载荷保持人类可读。

回调接口与互斥

配网 Demo 向上层暴露三个回调槽位,并配一把互斥锁保护并发访问:

static u8 ble_work_state = 0;
static u8 adv_ctrl_en;
static OS_MUTEX mutex;
static void (*app_recieve_callback)(void *priv, void *buf, u16 len) = NULL;
static void (*app_ble_state_callback)(void *priv, ble_state_e state) = NULL;
static void (*ble_resume_send_wakeup)(void) = NULL;
static u32 channel_priv;

static int app_send_user_data_check(u16 len);
static int app_send_user_data_do(void *priv, u8 *data, u16 len);
static int app_send_user_data(u16 handle, const u8 *data, u16 len, u8 handle_type);

Source: le_net_cfg.c

  • app_recieve_callback:收到手机下发的数据(如配网 JSON)时回调,业务侧在此解析并执行配网动作。
  • app_ble_state_callback:连接/断开等 BLE 状态变化通知,ble_state_e 定义状态枚举。
  • ble_resume_send_wakeup:发送缓冲从满恢复为空时唤醒阻塞发送方(与下方流控配合)。
  • app_send_user_data_check → app_send_user_data_do → app_send_user_data 构成三级发送路径:先查缓冲余量、再执行发送、最终按句柄类型写 ATT 通道。
  • OS_MUTEX mutex:保护共享的发送缓冲与状态变量,防止协议栈线程与业务线程并发写造成数据错乱。

配网是典型的"事件驱动 + 回调"模型:BLE 协议栈事件(连接、收到写请求)在栈线程触发,业务逻辑(WiFi 连接)在业务上下文执行,两者通过回调槽位解耦。这也是 BTstack 类协议栈的标准集成方式。

透明数据传输实现详解(le_trans_data.c)

大 MTU 与测试开关

透传 Demo 的核心诉求是吞吐,因此把 ATT 本地 MTU 提到 200 字节(远超经典 20 字节限制),并预留多个测试开关:

#define TEST_RECEIVE_DATA_RATE      0 /*测试记录接收数据速度*/
#define TEST_TRANS_TIMER_MS          500

static u32 trans_recieve_test_count;

#define TEST_SEND_DATA_RATE          0  //测试上行发送数据
#define TEST_SEND_HANDLE_VAL         ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE
#define EXT_ADV_MODE_EN              0

#define TEST_AUDIO_DATA_UPLOAD       0 //测试文件上传

//ATT发送的包长,    note: 20 <=need >= MTU
#define ATT_LOCAL_MTU_SIZE    (200)                   //
//ATT缓存的buffer大小,  note: need >= 20,可修改
#define ATT_SEND_CBUF_SIZE        (512)                   //

//共配置的RAM
#define ATT_RAM_BUFSIZE           (ATT_CTRL_BLOCK_SIZE + ATT_LOCAL_MTU_SIZE + ATT_SEND_CBUF_SIZE)
static u8 att_ram_buffer[ATT_RAM_BUFSIZE] __attribute__((aligned(4)));

Source: le_trans_data.c

  • ATT_LOCAL_MTU_SIZE = 200:本地 MTU 越大,单包承载数据越多,吞吐越高;注释 20 <= need >= MTU 强调不能低于 20 字节默认 MTU。
  • TEST_RECEIVE_DATA_RATE / TEST_SEND_DATA_RATE / TEST_AUDIO_DATA_UPLOAD 三个开关分别用于下行速率统计、上行速率统计和文件上传压力测试,量产固件置 0 关闭以省资源。
  • EXT_ADV_MODE_EN 控制是否使用扩展广播(LE Extended Advertising),关闭时使用传统广播以兼容老手机。

ATT 流控机制

透传场景最怕"发送方写爆接收缓冲",源码注释明确给出了流控用法:

/*
 打开流控使能后,确定使能接口 att_server_flow_enable 被调用
 然后使用过程 通过接口 att_server_flow_hold 来控制流控开关
 注意:流控只能控制对方使用带响应READ/WRITE等命令方式
 例如:ATT_WRITE_REQUEST = 0x12
 */

Source: le_trans_data.c

要点:先调用 att_server_flow_enable 使能流控,之后用 att_server_flow_hold 暂停/恢复对端带响应操作(如 ATT_WRITE_REQUEST = 0x12)。流控只对带响应的 ATT 命令生效——因为这类命令对端会等待应答,设备可以借"不回复/延迟回复"天然限速;对无响应的 Write Command(0x52)则无法阻止对端持续灌包,只能靠本地缓冲吸收,缓冲溢出即丢包,这也是 ATT_SEND_CBUF_SIZE = 512 偏大的原因。理解这一点对设计可靠透传协议至关重要:应用层协议必须自带重传/确认,不能依赖链路层兜底。

其他 BLE 角色与 Demo

apps/common/ble/ 目录还包含以下同级模块(均遵循上述统一框架):

文件角色典型应用
le_hogp.cHID over GATT Profile(GATT Server)BLE 键盘、鼠标、遥控器
le_mambo.c杰理穿戴私有协议手表/手环与手机 App 数据同步
le_net_central.cCentral(主机)配网设备作为主机主动扫描并连接 AP 配网
le_net_cfg_dui.c / le_net_cfg_tencent.c / le_net_cfg_qyai.c / le_net_cfg_turing.c各家云端配网变体DUI / 腾讯 / 启英 / 图灵语音平台一键配网
le_24g_deal.c2.4G 共存调度BLE 与经典蓝牙(BR/EDR)同时工作
mesh/examples/BLE Mesh 节点示例智能家居(灯、插座、风扇、开关、provisioner)

其中 le_hogp.c 复用同样的 GATT Server 框架,只是把特征值替换为 HID 报告特征并实现报告发送;le_net_cfg_*.c 系列是 le_net_cfg.c 的协议变体——配网流程完全一致,仅 JSON 载荷格式与云端接入命令不同,验证了"模板复用 + 协议替换"的扩展模式。Mesh 示例则独立成 mesh/examples/ 子目录,包含 AliGenie 灯/插座/风扇、Tuya 灯、generic onoff client/server、light lightness server、onoff provision、provisioner 与 vendor client,覆盖了 Mesh 节点端(provisionee)与配网端(provisioner)两端角色。

另外,SDK 还提供独立的 GATT Client 示例:apps/common/example/bluetooth/ble/bt_gatt_client/ble.c,用于设备主动连接手机或传感器等外围设备,与上面以 Server 为主的 Demo 互补。

Core Flow

配网主流程(GATT Server 视角)

sequenceDiagram
    participant Phone as 手机 App (GATT Client)
    participant BleS as le_net_cfg (GATT Server)
    participant Wifi as WiFi 系统

    Phone->>BleS: 扫描广播 (ADV_INTERVAL_MIN=160)
    BleS-->>Phone: 广播/扫描应答 (设备名)
    Phone->>BleS: 发起连接
    BleS->>Phone: 连接建立
    Note over Phone,BleS: 连接参数表逐档协商 {16,24,10,600} → {12,28,10,600} → {8,20,10,600}
    Phone->>BleS: GATT 发现 ae82 服务/特征
    Phone->>BleS: Write 配网 JSON (SSID/密码)
    BleS->>BleS: app_recieve_callback 解析载荷
    BleS->>Wifi: 下发配网指令
    Wifi-->>BleS: 配网结果 (status)
    BleS-->>Phone: 回复 rsp_cmd0 {"status":0} (JL 私有帧)
    Phone->>BleS: 断开/保持连接

透传数据发送路径与流控

flowchart TD
    App["业务层调用 app_send_user_data"] --> Check["app_send_user_data_check<br/>检查缓冲余量"]
    Check -->|"缓冲满"| Wake["等待 ble_resume_send_wakeup<br/>唤醒(发送完成中断)"]
    Wake --> Check
    Check -->|"有余量"| Do["app_send_user_data_do<br/>写 ATT 通道"]
    Do --> Flow{"流控使能?"}
    Flow -->|"是"| Hold["att_server_flow_hold<br/>暂停对端带响应读写"]
    Hold --> Done["数据到达手机端"]
    Flow -->|"否"| Done
    Done --> Notify["att_server_flow_enable 恢复<br/>下一条数据继续"]

流程说明:发送侧先查缓冲(app_send_user_data_check),满则挂起等待 ble_resume_send_wakeup 唤醒;写入 ATT 通道后若开了流控,用 att_server_flow_hold 限制对端灌入速率,防止 ATT_SEND_CBUF_SIZE 缓冲溢出。整个路径在协议栈线程与业务线程之间通过互斥锁与回调完成同步,是理解 BLE 吞吐上限与丢包行为的关键路径。

Usage Examples

以下示例均直接取自 SDK 源码,展示如何在自己的产品中复用这套 BLE 框架。

示例 1:选择 Demo 并配置 ATT 缓冲(新建配网类产品的最小模板)

#if (TCFG_BLE_DEMO_SELECT == DEF_BLE_DEMO_NET_CFG)

//------
#define ATT_LOCAL_PAYLOAD_SIZE    (128)                   //note: need >= 20
#define ATT_SEND_CBUF_SIZE        (512)                   //note: need >= 20,缓存大小,可修改
#define ATT_RAM_BUFSIZE           (ATT_CTRL_BLOCK_SIZE + ATT_LOCAL_PAYLOAD_SIZE + ATT_SEND_CBUF_SIZE)                   //note:
static u8 att_ram_buffer[ATT_RAM_BUFSIZE] __attribute__((aligned(4)));
//---------------

Source: le_net_cfg.c

用法说明:把工程配置 TCFG_BLE_DEMO_SELECT 设为 DEF_BLE_DEMO_NET_CFG 即启用该模块;ATT_LOCAL_PAYLOAD_SIZE 按业务单包最大载荷调整(下限 20 字节),ATT_SEND_CBUF_SIZE 决定发送缓冲深度,两者共同决定 att_ram_buffer 占用的静态 RAM。

示例 2:配置连接参数协商表(控制连接间隔与功耗)

//连接参数设置
static const uint8_t connection_update_enable = 1; ///0--disable, 1--enable
static uint8_t connection_update_cnt = 0; //
static const struct conn_update_param_t connection_param_table[] = {
    {16, 24, 10, 600},//11
    {12, 28, 10, 600},//3.7
    {8,  20, 10, 600},
};
#define CONN_PARAM_TABLE_CNT      (sizeof(connection_param_table)/sizeof(struct conn_update_param_t))

Source: le_net_cfg.c

用法说明:每个元组按 {连接间隔, 从机延迟, 监督超时, 未知/保留字段} 排列(字段语义以 struct conn_update_param_t 定义为准)。首档间隔最小(约 20ms 实际连接事件),吞吐最高但耗电;后续档位逐级放宽以兼容对端设备的能力。connection_update_enable = 0 可完全关闭连接参数更新。

示例 3:透传 Demo 的测试开关(用于吞吐评估与压力测试)

#define TEST_RECEIVE_DATA_RATE      0 /*测试记录接收数据速度*/
#define TEST_TRANS_TIMER_MS          500

static u32 trans_recieve_test_count;

#define TEST_SEND_DATA_RATE          0  //测试上行发送数据
#define TEST_SEND_HANDLE_VAL         ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE
#define EXT_ADV_MODE_EN              0

#define TEST_AUDIO_DATA_UPLOAD       0 //测试文件上传

Source: le_trans_data.c

用法说明:开发期把 TEST_RECEIVE_DATA_RATE / TEST_SEND_DATA_RATE 置 1,配合 TEST_TRANS_TIMER_MS = 500 周期打印速率统计;TEST_AUDIO_DATA_UPLOAD = 1 可模拟音频文件上传压力。量产固件必须全部置 0,避免定时器与统计代码占用 CPU 和 RAM。TEST_SEND_HANDLE_VAL 指定上行发送使用的特征值句柄(对应自定义 GATT 服务的 ae02_01 特征)。

Configuration Options

配置项类型默认值说明
TCFG_BLE_DEMO_SELECT宏由工程定义选择编译哪个 BLE Demo(如 DEF_BLE_DEMO_NET_CFG、DEF_BLE_DEMO_TRANS_DATA),一次固件只编译一个
ATT_LOCAL_PAYLOAD_SIZE宏128(配网)/ ATT_LOCAL_MTU_SIZE 200(透传)GATT Server 本地 ATT 负载长度,须 ≥ 20
ATT_SEND_CBUF_SIZE宏512发送缓冲大小,决定上行数据突发能力
ATT_RAM_BUFSIZE宏由上式求和静态 RAM 总量(ATT_CTRL_BLOCK_SIZE + 负载 + 缓冲),小于 64 触发 #error
ADV_INTERVAL_MIN宏160(≈100ms)广播间隔下限,越小越易被发现、越耗电
connection_update_enable静态变量1是否允许更新连接参数(0 关闭)
connection_param_table静态表{16,24,10,600} 等三档连接参数协商降级序列
gap_device_name字符串"wl80_ble_test"广播设备名,可被 bt_get_local_name() 覆盖
EXT_ADV_MODE_EN宏0是否启用扩展广播(透传 Demo)
TEST_RECEIVE_DATA_RATE宏0下行速率统计测试开关
TEST_SEND_DATA_RATE宏0上行速率统计测试开关
TEST_AUDIO_DATA_UPLOAD宏0文件/音频上传压力测试开关
TEST_TRANS_TIMER_MS宏500速率统计定时周期(ms)

API Reference

以下接口在 le_net_cfg.c 中声明,是 BLE 业务层与协议栈之间的核心发送接口(static 局部声明,具体实现在文件后续部分):

app_send_user_data(u16 handle, const u8 *data, u16 len, u8 handle_type)

发送数据到对端 GATT Client。

参数:

  • handle (u16):目标特征值句柄(如 ATT_CHARACTERISTIC_ae82_01_VALUE_HANDLE)
  • data (const u8*):待发送数据指针
  • len (u16):数据长度
  • handle_type (u8):句柄类型(区分 Value/CCCD 等)

返回: int,非 0 表示发送结果状态。

app_send_user_data_check(u16 len)

参数: len (u16) — 欲发送的数据长度。

返回: int — 缓冲是否容纳得下本次发送(满则需等待唤醒)。

app_send_user_data_do(void *priv, u8 *data, u16 len)

参数: priv (void*) 通道私有参数、data (u8*) 数据、len (u16) 长度。

返回: int 发送结果。

调用约定:业务侧统一走 app_send_user_data →(内部先 app_send_user_data_check 再 app_send_user_data_do),发送被阻塞时由 ble_resume_send_wakeup 唤醒重试。

回调注册槽位(static 函数指针)

  • app_recieve_callback(void *priv, void *buf, u16 len):接收对端数据(如配网 JSON),业务在此解析。
  • app_ble_state_callback(void *priv, ble_state_e state):连接状态变化通知。
  • ble_resume_send_wakeup(void):发送缓冲恢复空间时的唤醒钩子。

ATT 流控接口(透传 Demo,由协议栈提供)

  • att_server_flow_enable:使能流控。
  • att_server_flow_hold:暂停/恢复对端带响应读写(ATT_WRITE_REQUEST = 0x12),仅对带响应命令有效。

Failure Modes、边界情况与并发

缓冲溢出与编译期防护

ATT_RAM_BUFSIZE 过小时编译直接失败(#error "adv_data & rsp_data buffer error"),从源头杜绝广播缓冲越界。运行期溢出则由发送路径防护:app_send_user_data_check 在写入前检查余量,满时挂起等待 ble_resume_send_wakeup。若对端使用无响应 Write Command(0x52)灌包,流控无法生效,ATT_SEND_CBUF_SIZE 是唯一防线——超过即丢包,因此上层协议必须自带确认/重传,不能假设链路可靠。

连接参数协商失败

connection_param_table 提供三档降级序列,但若对端(如某些老旧手机或兼容性差的第三方设备)拒绝全部档位,连接参数更新将以 connection_update_cnt 计数退出,设备保持默认参数工作。此时表现为吞吐偏低或延迟偏高,可通过调大 connection_update_enable 前的等待时间或增加表项缓解。

并发访问

OS_MUTEX mutex 保护共享的 att_ram_buffer、ble_work_state、adv_ctrl_en 等状态。协议栈线程(接收/事件回调)与业务线程(发送/配网逻辑)可能同时触碰这些变量,任何新增的共享状态都应纳入同一把锁,否则会出现广播数据与发送缓冲被撕裂的偶发问题。

2.4G 共存

BLE 与经典蓝牙(BR/EDR)共用 2.4GHz 射频,同时工作时存在收发时隙竞争。le_24g_deal.c 负责两者调度;在未正确处理共存的产品上,典型故障是 BLE 连接频繁掉线或音频卡顿。若产品同时使用 BLE 与经典蓝牙,必须包含该共存模块并验证时隙分配。

Performance 与运维注意事项

  • 吞吐上限:受 ATT_LOCAL_MTU_SIZE(配网 128 / 透传 200)、连接间隔(首档约 20ms)与 ATT_SEND_CBUF_SIZE(512)共同约束。透传 Demo 的 TEST_*_RATE 开关可直接测量实际吞吐,TEST_AUDIO_DATA_UPLOAD 用于长时压力验证。
  • 功耗:广播间隔 ADV_INTERVAL_MIN = 160 属于偏快配置(便于被发现),量产省电场景可适当增大;连接参数表首档间隔较小,可把首档调大换取低功耗。
  • 静态内存:att_ram_buffer 为静态分配,每个 Demo 独占一块(配网约 128+512+控制块,透传约 200+512+控制块),RAM 紧张的工程应裁剪 ATT_SEND_CBUF_SIZE。
  • 调试手段:两个 Demo 顶部都有 log_info / log_info_hexdump(映射到 printf / printf_buf)以及被注释的 LOG_TAG_CONST、LOG_TAG、LOG_ERROR_ENABLE 等调试宏,打开后可用 debug.h 分级日志排查收发问题。

Extension Points

  1. 新增业务 Demo:复制 le_net_cfg.c 模板,替换 GATT 特征值句柄(如 ATT_CHARACTERISTIC_ae82_01_VALUE_HANDLE 改为自定义 UUID 特征),在 app_recieve_callback 中实现业务解析,并在 TCFG_BLE_DEMO_SELECT 的取值枚举中新增 DEF_BLE_DEMO_XXX。
  2. 自定义应答帧:参照 rsp_cmd0 的 0x4A 0x4C + 长度 + 命令 + JSON + 0x7C 0xC3 0xFF 帧格式,扩展更多命令字与 JSON 字段(如配网失败原因、设备能力查询)。
  3. 云端配网变体:le_net_cfg_dui.c / le_net_cfg_tencent.c 等展示了在通用配网流程上替换载荷协议的做法——保持 GATT 服务与回调框架不变,仅改 JSON 结构与云对接逻辑。
  4. HID / 穿戴 / Central:le_hogp.c、le_mambo.c、le_net_central.c 分别示范了报告特征发送、私有协议封装与主机角色 API,可作为对应品类的起点。
  5. Mesh 节点:mesh/examples/ 中的 vendor client/server 提供自定义模型模板,可在其上定义厂商专属 opcode 实现私有智能家居协议。

Related Links

  • 经典蓝牙(BR/EDR):A2DP/HFP 等经典蓝牙协议栈与音频应用(与 BLE 共用 2.4G 射频,涉及 le_24g_deal.c 共存逻辑)。
  • BLE Mesh:Mesh 各模型(AliGenie/Tuya、generic onoff、light lightness、provisioner)的详细实现。
  • 配网相关:le_net_cfg.c、le_net_cfg_dui.c、le_net_cfg_tencent.c、le_net_cfg_qyai.c、le_net_cfg_turing.c、le_net_central.c
  • 透传相关:le_trans_data.c
  • 角色示例:le_hogp.c、le_mambo.c、le_24g_deal.c
  • GATT Client 示例:apps/common/example/bluetooth/ble/bt_gatt_client/ble.c
Prev
经典蓝牙 BR/EDR
Next
蓝牙 Mesh 网络