杰理 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)
  • 文档与开发资源

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

蓝牙协议栈与 Profile(btstack)

杰理 AC63 系列蓝牙 SoC 的 BTstack 协议栈集成说明:本页介绍 btstack 在 fw-AC63_BT_SDK 中的组织方式、编译期裁剪配置、内存池划分、事件分发机制以及经典蓝牙(BR/EDR)与低功耗蓝牙(BLE)各 Profile 的实现边界。btstack 以预编译静态库(btstack.a)形式随 SDK 发布,SDK 提供配套头文件与配置源文件,应用层通过 lib_btstack_config.c 与 bt_profile_config.h 决定协议栈的编译形态。

Purpose and Scope

本页覆盖与 btstack 直接相关的全部集成面:

  • 协议栈库在仓库中的存放位置(include_lib/btstack/ 头文件、各 CPU 目录下的 btstack.a 预编译库、链接脚本)。
  • 协议栈的编译期配置机制(lib_btstack_config.c)与模块裁剪(bt_profile_config.h 中的 config_stack_modules)。
  • 协议栈内存池(app_bredr_pool、app_le_pool、app_l2cap_pool、app_bredr_profile)的划分与容量获取接口。
  • 事件回调机制:btstack_event.h 提供的 HCI 事件包解析辅助函数(A2DP/AVRCP/HFP/HSP/ANCS/GOEP 等 meta-event 子事件码提取)。
  • 经典 Profile(A2DP/AVRCP/HFP/HSP/SPP/GOEP)与 LE Profile(ATT/GATT/SM)在头文件层面的接口边界。

以下内容属于兄弟页面,不在本页展开:具体应用示例(SPP、HID、Mesh 等)的 App 层实现、蓝牙控制器(controller)固件与射频驱动、协议栈之上的应用业务逻辑(如音视频流播放、配网逻辑)。

Overview

btstack 是一个运行于嵌入式系统上的开源蓝牙协议栈实现,杰理(Jieli)将其移植并适配到 AC63 系列芯片,编译为与具体 CPU 型号对应的 btstack.a 静态库。SDK 中该库通过 配置源文件 + 头文件接口 两层方式暴露给应用:

  1. 配置层:每个应用工程(如 apps/spp_and_le、apps/hid、apps/mesh)各自携带一份 lib_btstack_config.c,通过一组 const int 全局变量告诉预编译库当前固件需要哪些功能(AAC 编解码、RCSP 智能音箱协议、LE 连接数、GATT server/client 数量、SM 加密等)。因为库是预编译的,所以功能裁剪发生在编译链接期而非库编译期——未启用的模块在链接时不会引入相关代码/数据段。
  2. 接口层:include_lib/btstack/ 下的头文件定义了应用可见的全部 API:任务生命周期(btstack_task.h)、事件解析(btstack_event.h)、经典蓝牙基础(bluetooth.h)、A2DP 编解码(a2dp_media_codec.h)、AVCTP 控制(avctp_user.h)、LE 协议族(le/ 下的 ATT/GATT/SM/BLE API)以及第三方协议(third_party/)。

典型使用场景:音箱(soundbox)同时启用经典蓝牙(A2DP 播放 + HFP 通话 + AVRCP 控制)与 BLE(手机 App 配网/RCSP 控制);耳机/头戴设备只启用部分 Profile;Beacon/24G 无连接场景则完全关闭 GATT 与加密以省内存。

Architecture

flowchart TD
    subgraph sg_App["应用层 apps/"]
        APP["app 工程<br/>(spp_and_le / hid / mesh)"]
        CFG["lib_btstack_config.c<br/>编译期配置变量"]
        PROFILE_H["bt_profile_config.h<br/>模块掩码 + 内存池声明"]
    end

    subgraph sg_Btstack["btstack 协议栈 (预编译 btstack.a)"]
        TASK["btstack_task<br/>btstack_init / btstack_exit"]
        EVT["btstack_event.h<br/>HCI 事件包解析"]
        CLASSIC["经典 Profile<br/>A2DP / AVRCP / HFP / HSP<br/>SPP / GOEP / AVDTP"]
        LE["LE 协议族<br/>ATT / GATT / SM / L2CAP"]
        THIRD["第三方协议<br/>ANCS / RCSP / app_protocol"]
    end

    subgraph sg_Hw["硬件平台"]
        CPU["cpu/bd19|bd29|br23|br25|br30|br34<br/>btstack.a 静态库"]
        CTRL["蓝牙控制器<br/>HCI 传输"]
    end

    subgraph sg_Mem["内存资源"]
        POOL["app_bredr_pool<br/>app_le_pool<br/>app_l2cap_pool<br/>app_bredr_profile"]
    end

    APP --> CFG
    APP --> PROFILE_H
    CFG -->|"const int 配置符号"| TASK
    PROFILE_H -->|"STACK_MODULES_IS_SUPPORT"| TASK
    TASK --> EVT
    TASK --> CLASSIC
    TASK --> LE
    TASK --> THIRD
    EVT --> APP
    CLASSIC --> CPU
    LE --> CPU
    CPU --> CTRL
    TASK --> POOL

架构说明:

  • 应用层通过 lib_btstack_config.c 中的 const int 符号(如 CONFIG_BTSTACK_SUPPORT_AAC、config_le_gatt_server_num)和 bt_profile_config.h 中的 config_stack_modules 模块掩码,在链接期决定协议栈最终形态。这是预编译库方案的关键设计:库代码全量存在,但未启用模块对应的符号引用不成立,链接器将其丢弃,从而节省 Flash 与 RAM。
  • btstack 库内部分三层:任务与事件基础设施(btstack_task.h、btstack_event.h)、经典 Profile 层、LE 协议族层。btstack_event.h 中所有事件解析函数都基于统一的 HCI 事件包格式(event[0] 为事件类型,event[2] 为 meta 子事件码),说明库通过单一事件管道向应用分发所有 Profile 的通知。
  • 硬件层:cpu/ 目录下每个 CPU 型号(bd19/bd29/br23/br25/br30/br34)各有一份 btstack.a,因为协议栈与芯片的 HCI 传输、定时器、内存模型深度耦合;应用链接时选择与目标芯片匹配的库文件。
  • 内存资源:协议栈工作区由应用侧提供的静态字节池支撑,bt_profile_config.h 声明的四个池(BR/EDR、LE、L2CAP、Profile)由应用分配,库通过 get_*_pool_len() 接口查询容量。

协议栈源码布局与构建产物

头文件目录 include_lib/btstack/

仓库以 include_lib/btstack/ 作为协议栈的唯一公开接口面,头文件按功能分组:

头文件职责
btstack_task.h协议栈任务生命周期:btstack_init() / btstack_exit(),以及产线测试用 ble_bqb_test_thread_init()
btstack_event.hHCI 事件包解析:从统一事件包中提取事件类型与各 Profile 的 meta 子事件码
btstack_typedef.h基础类型与通用宏定义
bluetooth.h经典蓝牙(BR/EDR)基础 API 与常量
bt_profile_config.h模块选择掩码(config_stack_modules)与四个内存池的声明、容量接口
a2dp_media_codec.hA2DP 媒体编解码相关定义(SBC/AAC 等)
avctp_user.hAVCTP 传输层用户接口(AVRCP 依赖)
le/att.h、le/gatt.hLE 属性协议与通用属性规范接口
le/ble_api.h、le/le_user.hBLE 用户层 API 与配置
le/sm.hLE 安全管理(配对、加密)
le/le_common_define.h、le/ble_data_types.hLE 公共常量与数据类型
third_party/app_protocol_event.h第三方/App 私有协议事件
third_party/common/btstack_3th_protocol_user.h第三方协议(如 RCSP)用户接口
third_party/common/ble_config.hBLE 配置项
btstack_lib*.ld库的链接脚本(text/data/bss 段布局)

说明:头文件只声明接口,实现全部封装在 btstack.a 中。这使应用层与协议栈实现解耦,也意味着无法通过阅读源码了解协议栈内部算法——可观测的只有配置符号、事件包格式与回调接口。

预编译库 btstack.a

cpu/ 下每个芯片目录的 liba/ 中存放对应型号的协议栈静态库:

  • cpu/bd19/liba/btstack.a
  • cpu/bd29/liba/btstack.a
  • cpu/br23/liba/btstack.a
  • cpu/br25/liba/btstack.a
  • cpu/br30/liba/btstack.a
  • cpu/br34/liba/btstack.a

同一份协议栈源码针对不同 CPU 编译出不同库,原因在于各芯片的 HCI 控制器接口、中断/定时器实现与内存访问方式不同。应用工程通过链接脚本与 Makefile 选择与目标芯片匹配的库,避免协议栈直接依赖硬件抽象层(HAL),而是把差异封装进库内。

编译期配置机制:lib_btstack_config.c

每个应用工程都有一份自己的 lib_btstack_config.c(例如 apps/spp_and_le/config/lib_btstack_config.c)。其核心思想是:用一组 const int 全局符号作为预编译库的“配置开关”,应用在链接期提供这些符号的定义,库内代码引用它们来决定行为。由于是常量,编译器可做常量传播与死代码消除,未启用功能即被剔除。

配置项分为四类:

1. Flash 容量与编解码

#ifdef CONFIG_SOUNDBOX_FLASH_256K
const int CONFIG_BTSTACK_BIG_FLASH_ENABLE     = 0;
#else
const int CONFIG_BTSTACK_BIG_FLASH_ENABLE     = 1;
#endif

#if TCFG_BT_SUPPORT_AAC
const int CONFIG_BTSTACK_SUPPORT_AAC    = 1;
#else
const int CONFIG_BTSTACK_SUPPORT_AAC    = 0;
#endif
  • CONFIG_BTSTACK_BIG_FLASH_ENABLE:小 Flash(256K 音箱)固件关闭“大 Flash”优化路径,以节省代码体积;普通固件开启,可启用更多 Flash 驻留数据。
  • CONFIG_BTSTACK_SUPPORT_AAC:是否编译 A2DP AAC 解码路径,直接跟随应用宏 TCFG_BT_SUPPORT_AAC。此开关影响协议栈与媒体流两侧的编解码资源占用。

2. Sniff 模式行为

#if SNIFF_MODE_RESET_ANCHOR
//协议栈接收到命令是否自动退出sniff
const int config_btstask_auto_exit_sniff = 0;
#else
const int config_btstask_auto_exit_sniff = 1;
#endif

config_btstask_auto_exit_sniff 控制协议栈在收到主机命令时是否自动退出 sniff 低功耗模式。当 SNIFF_MODE_RESET_ANCHOR 定义时置 0(不自动退出,保持锚点),否则置 1(自动退出以便快速响应)。这是功耗与响应延迟之间的权衡:自动退出能降低命令延迟,但会破坏 sniff 锚点的低功耗收益。

3. 智能音箱/RCSP 协议

#if SMART_BOX_EN
const int config_rcsp_stack_enable = 1;
#else
const int config_rcsp_stack_enable = 0;
#endif

config_rcsp_stack_enable 启用杰理 RCSP(Remote Control & Smart Protocol,用于智能音箱与手机 App 联动的自定义协议)栈,跟随应用宏 SMART_BOX_EN。启用后协议栈会包含 third_party 相关的协议解析与事件处理代码。

4. LE 协议栈资源配额

#if TCFG_USER_BLE_ENABLE

#if CONFIG_APP_NONCONN_24G || CONFIG_APP_BEACON
//无链接,不需要gatt功能
const int config_le_hci_connection_num = 0;//支持同时连接个数
const int config_le_sm_support_enable = 0; //是否支持加密配对
const int config_le_gatt_server_num = 0;   //支持server角色个数
const int config_le_gatt_client_num = 0;   //支持client角色个数

#else
const int config_le_hci_connection_num = CONFIG_BT_GATT_CONNECTION_NUM;//支持同时连接个数
const int config_le_sm_support_enable = CONFIG_BT_SM_SUPPORT_ENABLE; //是否支持加密配对
const int config_le_gatt_server_num = CONFIG_BT_GATT_SERVER_NUM;   //支持server角色个数
const int config_le_gatt_client_num = CONFIG_BT_GATT_CLIENT_NUM;   //支持client角色个数
#endif

#else
const int config_le_hci_connection_num = 0;//支持同时连接个数
const int config_le_sm_support_enable = 0; //是否支持加密配对
const int config_le_gatt_server_num = 0;   //支持server角色个数
const int config_le_gatt_client_num = 0;   //支持client角色个数
#endif

/*config_le_sm_sub_sc_enable: SC加密模式使能,need config_le_sm_support_enable = 1*/
const int config_le_sm_sub_sc_enable = CONFIG_BT_SM_SUPPORT_ENABLE & 0;//

const int config_le_sm_sub_sc_bridge_edr_enable = 0; /*default 0*/

LE 侧共五个配额变量:

  • config_le_hci_connection_num:LE 同时连接数上限(多连接时分配对应的链路资源)。
  • config_le_sm_support_enable:是否支持 SM 加密配对。
  • config_le_gatt_server_num / config_le_gatt_client_num:GATT Server / Client 角色实例数。
  • config_le_sm_sub_sc_enable:LE Secure Connections(SC)加密模式,当前源码中硬编码为 CONFIG_BT_SM_SUPPORT_ENABLE & 0,即总是 0(关闭);注释明确指出其依赖 config_le_sm_support_enable = 1。
  • config_le_sm_sub_sc_bridge_edr_enable:SC-over-BREDR 桥接使能,默认 0。

关键设计意图:非连接型应用(24G 遥控、Beacon)直接把所有 LE 配额置 0,从而在链接期剥离整个 ATT/GATT/SM 模块,最大程度节省 RAM/Flash;普通 BLE 应用则从 CONFIG_BT_* 系列应用宏映射配额。配额不是运行时动态分配,而是编译期常量,因此内存池大小可以静态确定。

文件末尾还保留了调试开关的注释示例(l2cap_debug_enable = 0xf0、rfcomm_debug_enable = 0xf、profile_debug_enable = 0xff、ble_debug_enable = 0xff),表明协议栈内部支持按模块打开调试日志,但默认不启用。

模块选择与内存池:bt_profile_config.h

bt_profile_config.h 定义了协议栈顶层功能域的模块掩码:

#define BT_BTSTACK_CLASSIC                   BIT(0)
#define BT_BTSTACK_LE_ADV                    BIT(1)
#define BT_BTSTACK_LE                        BIT(2)

extern const int config_stack_modules;
#define STACK_MODULES_IS_SUPPORT(x)         (config_stack_modules & (x))
  • BT_BTSTACK_CLASSIC:经典蓝牙(BR/EDR,A2DP/HFP/SPP 等)。
  • BT_BTSTACK_LE_ADV:仅广播(Adv-only,无连接,对应 Beacon/24G 场景)。
  • BT_BTSTACK_LE:完整 LE(含连接、GATT、SM)。

config_stack_modules 由应用定义(在某个 lib_btstack_config.c 或应用配置中),库内所有模块代码通过 STACK_MODULES_IS_SUPPORT(x) 判断自己是否应生效。这是一个典型的编译期特性开关 + 位掩码设计:单个 int 即可描述协议栈形态,且与 LE 配额变量(上一节)互为补充——掩码决定“有/无”,配额决定“多少个”。

同一头文件还声明了协议栈运行所需的四个静态内存池:

extern u8 app_bredr_pool[];
extern u8 app_le_pool[];
extern u8 app_l2cap_pool[];
extern u8 app_bredr_profile[];

extern u16 get_bredr_pool_len(void);
extern u16 get_le_pool_len(void);
extern u16 get_l2cap_stack_len(void);
extern u16 get_profile_pool_len(void);

池的划分遵循协议栈的资源域边界:

池用途域容量接口
app_bredr_pool经典蓝牙链路与控制get_bredr_pool_len()
app_le_poolLE 链路、GATT、SMget_le_pool_len()
app_l2cap_poolL2CAP 通道(BR/EDR 与 LE 共用)get_l2cap_stack_len()
app_bredr_profile经典 Profile 实例(A2DP/AVRCP/HFP 等)get_profile_pool_len()

池内存由应用提供(静态数组),协议栈只消费;容量通过 getter 暴露给应用,便于在启动日志中核对内存占用。这种“库不持有全局大缓冲、工作区由宿主注入”的模式,是嵌入式协议栈常见的资源所有权划分:Flash 里库代码可全量存在,但 RAM 只按需分配。

核心流程:初始化与事件分发

初始化流程

协议栈的入口在 btstack_task.h,仅暴露三个函数:

int btstack_init();
int btstack_exit();

void ble_bqb_test_thread_init(void);

应用在系统启动阶段调用 btstack_init()。从配置符号可以还原其内部大致流程:

flowchart TD
    Start([应用启动]) --> Init["btstack_init()"]
    Init --> Check{"config_stack_modules<br/>模块掩码检查"}
    Check -->|"BT_BTSTACK_CLASSIC"| CPool["使用 app_bredr_pool<br/>+ app_l2cap_pool<br/>初始化经典协议栈"]
    Check -->|"BT_BTSTACK_LE_ADV / LE"| LPool["使用 app_le_pool<br/>初始化 LE 栈"]
    Check -->|"全 0"| Lite["最小化启动<br/>仅任务与 HCI"]
    CPool --> EvtLoop["事件循环启动<br/>等待 HCI 事件"]
    LPool --> EvtLoop
    Lite --> EvtLoop
    EvtLoop -->|"事件到达"| Parse["btstack_event.h<br/>解析事件包"]
    Parse --> Dispatch["按子事件码分发<br/>给各 Profile 回调"]
    Dispatch --> AppCB["应用回调处理"]

btstack_exit() 用于反向拆除协议栈任务、释放资源;ble_bqb_test_thread_init() 是产测(BQB 认证测试)专用线程入口,仅测试固件使用。

统一事件管道与解析辅助函数

btstack_event.h 的核心设计是所有 Profile 的通知都通过同一种 HCI 事件包格式上抛,应用通过内联辅助函数解析。文件开头即定义:

static inline uint8_t hci_event_packet_get_type(const uint8_t *event)
{
    return event[0];
}

static inline uint8_t hci_event_ancs_meta_get_subevent_code(const uint8_t *event)
{
    return event[2];
}
static inline uint8_t hci_event_avdtp_meta_get_subevent_code(const uint8_t *event)
{
    return event[2];
}
static inline uint8_t hci_event_a2dp_meta_get_subevent_code(const uint8_t *event)
{
    return event[2];
}
static inline uint8_t hci_event_avrcp_meta_get_subevent_code(const uint8_t *event)
{
    return event[2];
}
static inline uint8_t hci_event_goep_meta_get_subevent_code(const uint8_t *event)
{
    return event[2];
}
static inline uint8_t hci_event_hfp_meta_get_subevent_code(const uint8_t *event)
{
    return event[2];
}
static inline uint8_t hci_event_hsp_meta_get_subevent_code(const uint8_t *event)
{
    return event[2];
}

btstack_event.h 事件解析辅助函数

设计要点:

  • 事件包布局:event[0] 是事件类型;当事件类型表示“meta 事件”时,event[2] 存放子事件码。各 Profile 的 meta getter 都读取 event[2],因此应用只需按 Profile 匹配对应的 getter 即可取得该 Profile 的子事件码,再据此进入具体的事件 switch。
  • 命名即契约:hci_event_<profile>_meta_get_subevent_code() 的命名模式与上游 BTstack 一致,方便开发者将杰理 SDK 的用法映射回标准 BTstack 文档。
  • 覆盖范围:ANCS、AVDTP、A2DP、AVRCP、GOEP、HFP、HSP 均有专属 getter,说明这些 Profile 是 SDK 的“一等公民”;事件头文件同时 #include "le/gatt.h"(在 ENABLE_BLE 定义下),LE 侧事件走 GATT/ATT 事件通道。

事件分发时序

sequenceDiagram
    participant CTRL as 蓝牙控制器(HCI)
    participant STACK as btstack.a 协议栈任务
    participant EVT as btstack_event.h 解析层
    participant APP as 应用回调

    CTRL->>STACK: HCI Event Packet
    STACK->>STACK: 按 event[0] 识别事件类型
    STACK->>EVT: hci_event_packet_get_type(event)
    alt A2DP 事件
        EVT-->>APP: hci_event_a2dp_meta_get_subevent_code(event)
        APP->>APP: 处理 A2DP 子事件 (连接/流状态)
    else AVRCP 事件
        EVT-->>APP: hci_event_avrcp_meta_get_subevent_code(event)
        APP->>APP: 处理 AVRCP 控制事件
    else HFP/HSP 事件
        EVT-->>APP: hci_event_hfp_meta_get_subevent_code(event)
        APP->>APP: 处理通话事件
    else LE 事件
        EVT-->>APP: GATT/ATT 事件通道
        APP->>APP: 处理 LE 连接/服务发现/通知
    end

整个机制保证:无论底层是哪个 Profile 产生的事件,应用只面对一个事件回调 + 一组子事件码,避免了多回调注册的复杂度,也使得“协议栈内部异步、应用侧同步处理”的模型易于实现。

配置选项汇总

以下配置符号全部为 const int,由应用工程定义(主要来自 lib_btstack_config.c),在链接期生效。

配置符号类型默认/来源说明
CONFIG_BTSTACK_BIG_FLASH_ENABLEint256K Flash 固件=0,否则=1大 Flash 优化路径开关
CONFIG_BTSTACK_SUPPORT_AACint跟随 TCFG_BT_SUPPORT_AACA2DP AAC 编解码支持
config_btstask_auto_exit_sniffint跟随 SNIFF_MODE_RESET_ANCHOR(定义=0,否则=1)协议栈收到命令是否自动退出 sniff
config_rcsp_stack_enableint跟随 SMART_BOX_ENRCSP 智能音箱协议栈
config_le_hci_connection_numint跟随 TCFG_USER_BLE_ENABLE/CONFIG_BT_GATT_CONNECTION_NUM,非连接应用=0LE 同时连接数
config_le_sm_support_enableint跟随 CONFIG_BT_SM_SUPPORT_ENABLE,非连接应用=0SM 加密配对支持
config_le_gatt_server_numint跟随 CONFIG_BT_GATT_SERVER_NUM,非连接应用=0GATT Server 角色数
config_le_gatt_client_numint跟随 CONFIG_BT_GATT_CLIENT_NUM,非连接应用=0GATT Client 角色数
config_le_sm_sub_sc_enableint恒 0(CONFIG_BT_SM_SUPPORT_ENABLE & 0)LE Secure Connections 模式(当前关闭)
config_le_sm_sub_sc_bridge_edr_enableint0SC-over-BREDR 桥接使能
config_stack_modulesint应用定义模块掩码:BT_BTSTACK_CLASSIC(BIT0) / BT_BTSTACK_LE_ADV(BIT1) / BT_BTSTACK_LE(BIT2)

调试开关(源码中为注释示例,默认关闭):l2cap_debug_enable、rfcomm_debug_enable、profile_debug_enable、ble_debug_enable,可用于按模块打开协议栈内部日志。

API 参考

int btstack_init()

初始化并启动 btstack 协议栈任务。应用应在系统资源(内存池、HCI 传输)就绪后调用。

  • 返回:0 表示成功,非 0 表示初始化失败(如资源不足)。
  • 设计意图:一次性拉起协议栈事件循环;实际启用的模块由 config_stack_modules 与各 config_* 配额符号决定,因此不同固件调用同一函数得到不同规模的协议栈实例。

来源:btstack_task.h

int btstack_exit()

停止并拆除协议栈任务,释放协议栈占用的运行资源。通常用于系统级休眠/关机或固件升级前的协议栈卸载。

来源:btstack_task.h

void ble_bqb_test_thread_init(void)

初始化 BQB 蓝牙认证测试线程,仅测试固件使用,量产固件不应调用。

来源:btstack_task.h

uint8_t hci_event_packet_get_type(const uint8_t *event)

返回事件包的事件类型(读取 event[0]),用于识别事件属于哪个大类。

来源:btstack_event.h

uint8_t hci_event_<profile>_meta_get_subevent_code(const uint8_t *event)

其中 <profile> 可为 ancs、avdtp、a2dp、avrcp、goep、hfp、hsp。返回对应 Profile meta 事件的子事件码(读取 event[2]),应用据此进入该 Profile 的事件分支。

  • 参数:event — 协议栈回调传入的事件包指针。
  • 返回:子事件码 uint8_t。
  • 注意:调用前应先确认事件类型确为该 Profile 的 meta 事件,否则 event[2] 语义不成立。

来源:btstack_event.h

u16 get_bredr_pool_len() / get_le_pool_len() / get_l2cap_stack_len() / get_profile_pool_len()

返回各协议栈内存池的容量(字节数),供应用核对内存占用或调整池大小。

来源:bt_profile_config.h

bool STACK_MODULES_IS_SUPPORT(x)

模块支持判断宏:config_stack_modules & (x) 非零表示该模块被编译进当前固件。应用可在运行时据此决定是否展示相应功能 UI 或注册相关回调。

来源:bt_profile_config.h

使用示例

1. 按应用类型裁剪 LE 协议栈(无连接 vs 全功能)

以下代码展示如何根据应用形态(Beacon/24G 无连接、普通 BLE)设置 LE 配额:

#if TCFG_USER_BLE_ENABLE

#if CONFIG_APP_NONCONN_24G || CONFIG_APP_BEACON
//无链接,不需要gatt功能
const int config_le_hci_connection_num = 0;//支持同时连接个数
const int config_le_sm_support_enable = 0; //是否支持加密配对
const int config_le_gatt_server_num = 0;   //支持server角色个数
const int config_le_gatt_client_num = 0;   //支持client角色个数

#else
const int config_le_hci_connection_num = CONFIG_BT_GATT_CONNECTION_NUM;//支持同时连接个数
const int config_le_sm_support_enable = CONFIG_BT_SM_SUPPORT_ENABLE; //是否支持加密配对
const int config_le_gatt_server_num = CONFIG_BT_GATT_SERVER_NUM;   //支持server角色个数
const int config_le_gatt_client_num = CONFIG_BT_GATT_CLIENT_NUM;   //支持client角色个数
#endif

#else
const int config_le_hci_connection_num = 0;//支持同时连接个数
const int config_le_sm_support_enable = 0; //是否支持加密配对
const int config_le_gatt_server_num = 0;   //支持server角色个数
const int config_le_gatt_client_num = 0;   //支持client角色个数
#endif

来源:apps/spp_and_le/config/lib_btstack_config.c

2. 声明模块掩码与内存池

应用侧需提供 config_stack_modules 定义,并声明四个字节池供协议栈使用:

#define BT_BTSTACK_CLASSIC                   BIT(0)
#define BT_BTSTACK_LE_ADV                    BIT(1)
#define BT_BTSTACK_LE                        BIT(2)

extern const int config_stack_modules;
#define STACK_MODULES_IS_SUPPORT(x)         (config_stack_modules & (x))

extern u8 app_bredr_pool[];
extern u8 app_le_pool[];
extern u8 app_l2cap_pool[];
extern u8 app_bredr_profile[];

extern u16 get_bredr_pool_len(void);
extern u16 get_le_pool_len(void);
extern u16 get_l2cap_stack_len(void);
extern u16 get_profile_pool_len(void);

来源:include_lib/btstack/bt_profile_config.h

3. 解析 A2DP 子事件

事件回调中按 Profile 解析子事件码的惯用法:

static inline uint8_t hci_event_packet_get_type(const uint8_t *event)
{
    return event[0];
}

static inline uint8_t hci_event_a2dp_meta_get_subevent_code(const uint8_t *event)
{
    return event[2];
}

来源:include_lib/btstack/btstack_event.h

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

1. 配置符号缺失或冲突

lib_btstack_config.c 中的 const int 符号是库的正常链接依赖。若应用工程缺少某个符号定义,链接期会报未定义符号错误;若定义类型不一致(如改成了 volatile 或非 const),可能破坏库内的常量折叠优化,导致代码体积与行为偏离预期。边界情况:config_stack_modules 为 0 时,协议栈进入最小化模式(仅任务与 HCI 通道),此时调用 Profile 相关 API 可能无响应——应用应通过 STACK_MODULES_IS_SUPPORT(x) 先行判断。

2. 内存池不足

四个内存池(app_bredr_pool、app_le_pool、app_l2cap_pool、app_bredr_profile)由应用静态分配。若容量估算偏小:

  • 经典侧(A2DP/HFP 多连接)会因 app_bredr_pool/app_bredr_profile 不足导致建链失败或 Profile 初始化失败;
  • LE 侧多连接、多 GATT 实例会消耗 app_le_pool 与 app_l2cap_pool。

由于池是静态数组,运行时无法扩容,只能通过 get_*_pool_len() 返回值核对实际占用并反推余量。修改 CONFIG_BT_GATT_* 等应用宏后必须同步复核池大小。

3. sniff 低功耗与响应延迟

config_btstask_auto_exit_sniff = 0(SNIFF_MODE_RESET_ANCHOR 定义时)意味着协议栈收到命令不自动退出 sniff,命令处理延迟会增加,但保持 sniff 锚点以维持低功耗;反之自动退出则牺牲功耗换响应速度。应用在调试“命令不响应”问题时,应首先确认该开关的取值与预期功耗策略一致。

4. LE SC 模式当前强制关闭

config_le_sm_sub_sc_enable = CONFIG_BT_SM_SUPPORT_ENABLE & 0 在源码层面恒为 0,即 LE Secure Connections 加密模式当前不可通过该符号启用(除非修改源码)。若产品需要 SC 配对(防中间人攻击),需评估此限制;普通 Legacy Pairing 不受影响。

5. 并发与回调上下文

协议栈为独立任务(btstack_init() 启动),事件通过统一事件管道投递到应用回调。应用回调运行在协议栈任务上下文,因此:

  • 回调内不应执行长时间阻塞操作(会阻塞后续事件分发);
  • 跨任务访问共享数据需加锁或使用消息队列转发到应用任务;
  • btstack_exit() 不应在事件回调中直接调用(存在任务自毁风险),应延后到应用任务执行。

6. 事件包解析的前置条件

hci_event_<profile>_meta_get_subevent_code() 只读取 event[2],不校验事件类型。若事件不是对应 Profile 的 meta 事件,返回的子事件码无意义。应用必须先通过 hci_event_packet_get_type() 确认事件类型,再调用对应 getter。

性能与运维考虑

  • 链接期裁剪是最大的性能杠杆:CONFIG_BTSTACK_BIG_FLASH_ENABLE、AAC、RCSP、LE 配额等开关直接决定 Flash 占用与 RAM 池大小。256K Flash 音箱固件通过 CONFIG_SOUNDBOX_FLASH_256K 自动降级,印证了该 SDK 对极小 Flash 的适配策略。
  • 事件解析为 O(1) 内联函数:hci_event_*_get_subevent_code() 全部是 static inline 读内存操作,事件分发路径零函数调用开销,适合高频 HFP/A2DP 事件流。
  • 多连接能力由配额而非运行时决定:config_le_hci_connection_num 等常量让协议栈在编译期就能确定资源布局,避免动态分配带来的碎片与不确定性,但也意味着固件形态(如 1 连接 vs 2 连接)必须预先规划。
  • 产测支持:ble_bqb_test_thread_init() 表明协议栈保留 BQB 认证测试通道,量产与认证固件可共享同一库。

扩展点

  1. 新增/调整 Profile 编译形态:修改 config_stack_modules 掩码即可整体启用/禁用 CLASSIC / LE_ADV / LE 三大域;新增 Profile 实例数通过 config_le_gatt_*_num 或经典侧 Profile 池配额调节。
  2. 第三方协议接入:include_lib/btstack/third_party/(app_protocol_event.h、btstack_3th_protocol_user.h)是杰理私有/第三方协议(如 RCSP)的挂载点,config_rcsp_stack_enable 控制其编译。
  3. 事件扩展:新事件类型沿用统一事件管道,在 btstack_event.h 中按既有模式新增 hci_event_<profile>_meta_get_subevent_code() 即可获得一致的应用侧接口。
  4. 编解码扩展:a2dp_media_codec.h 与 CONFIG_BTSTACK_SUPPORT_AAC 表明编解码器以编译开关接入 A2DP 媒体路径,可参照增加其他 codec。

测试

仓库中 apps/*/config/lib_btstack_config.c(spp_and_le、hid、mesh 三份)可视为协议栈的配置矩阵测试用例:

  • apps/spp_and_le:经典 SPP + LE 双栈典型配置,LE 配额走完整 CONFIG_BT_GATT_* 映射;
  • apps/hid:HID 应用视角的协议栈配置;
  • apps/mesh:Mesh 应用视角的配置,验证 LE 栈在不同应用层协议下的复用。

三份配置共享同一 btstack.a 的事实,直接验证了“预编译库 + 链接期裁剪”方案的可行性:同一二进制库服务完全不同的应用形态。

相关链接

  • 配置源文件:apps/spp_and_le/config/lib_btstack_config.c、apps/hid/config/lib_btstack_config.c、apps/mesh/lib_config/lib_btstack_config.c
  • 模块与内存池定义:include_lib/btstack/bt_profile_config.h
  • 任务生命周期 API:include_lib/btstack/btstack_task.h
  • 事件解析辅助函数:include_lib/btstack/btstack_event.h
  • LE 协议族头文件:include_lib/btstack/le/gatt.h、include_lib/btstack/le/sm.h、include_lib/btstack/le/ble_api.h
  • 预编译库(按 CPU 选择):cpu/br25/liba/btstack.a、cpu/br23/liba/btstack.a、cpu/bd29/liba/btstack.a
  • 关联目录页:蓝牙协议栈总览(5-bluetooth-stack)、各 Profile 应用页(SPP、HID、Mesh 等)
Prev
蓝牙控制器层(btctrler)
Next
蓝牙模块选择与配置