BTStack 协议栈接口
本页介绍杰理 AC630N 蓝牙 SDK 中 BTStack 协议栈对外暴露的接口层:从 HCI 数据包/事件定义、协议栈任务生命周期、模块裁剪配置,到低功耗蓝牙(BLE)的 GAP/ATT/GATT/SM 接口与经典蓝牙 AVRCP 用户接口,说明各接口的职责、控制流与使用方式。
Purpose and Scope
BTStack 协议栈接口(include_lib/btstack/ 目录)是 AC630N 芯片蓝牙协议栈与上层应用之间的唯一契约层。应用代码不直接接触控制器寄存器或链路层细节,而是通过本页所述的接口完成:
- 协议栈的启动与退出(
btstack_init/btstack_exit); - 协议栈功能模块的编译期/运行期裁剪(Classic、LE Advertising、LE 三类模块);
- HCI 数据包与事件的定义和解析(广播、连接、配对等事件);
- BLE 服务端(ATT Server / GATT)与客户端(GATT Client)的数据收发;
- 安全管理(SM)的配对认证配置;
- 经典蓝牙 AVRCP 用户接口。
本页不覆盖:具体 Profile(如 A2DP/AVRCP 的具体业务逻辑)的内部实现、音频编解码链路、以及芯片底层 HCI 传输(UART/SPI 驱动)。这些内容属于各自的 Profile 与驱动页面。
概述
背景与设计意图
在 AC630N 的软件架构中,蓝牙协议栈被封装为独立的库(btstack_lib.ld 链接脚本描述了库的内存布局),对外仅暴露头文件接口。这种"库 + 头文件契约"的设计有两点意图:
- 隔离性:上层应用与协议栈实现解耦,协议栈升级(如修复 HCI 事件解析 bug)时应用代码无需改动;
- 资源可控:通过
bt_profile_config.h中的模块位掩码,可裁剪掉不需要的协议栈模块,节省 RAM/Flash——这对 RAM 受限的嵌入式蓝牙 SoC 至关重要。
头文件地图
| 头文件 | 职责 |
|---|---|
bluetooth.h | HCI 数据包类型、OGF 命令分组、HCI 事件码定义 |
btstack_task.h | 协议栈任务生命周期:btstack_init() / btstack_exit() |
bt_profile_config.h | 协议栈模块裁剪(Classic / LE Adv / LE)与内存池长度查询 |
le_user.h | BLE 用户侧接口:回调类型、事件码、ATT/GATT/SM/GAP API |
ble_api.h | 底层 BLE API(被 le_user.h 包含) |
avctp_user.h | 经典蓝牙 AVRCP 用户接口 |
ble_data_types.h | BLE 数据类型定义 |
btstack_lib.ld | 协议栈库的链接脚本 |
关键概念
- HCI 数据包类型:控制器与主机之间通过 4 种数据包通信——命令(0x01)、ACL 数据(0x02)、SCO 数据(0x03)、事件(0x04),定义见
bluetooth.h。 - 回调驱动:BLE 接口以
btstack_packet_handler_t回调为核心,事件异步到达,应用在回调中按packet_type分派处理。 - ATT 事务模式:ATT 写入支持
NONE / ACTIVE / EXECUTE / CANCEL / VALIDATE五种事务模式,用于长属性(Long Attribute)的分段写入。
架构
下图展示了 BTStack 协议栈接口层在 AC630N 固件中的位置与依赖关系:
flowchart TD
subgraph sg_App["应用层 (App)"]
App["上层应用 / Profile 业务"]
end
subgraph sg_Interface["接口层 include_lib/btstack"]
TaskAPI["btstack_task.h<br/>btstack_init / btstack_exit"]
LEUser["le_user.h<br/>GAP / ATT / GATT / SM 接口"]
BLEAPI["ble_api.h<br/>底层 BLE API"]
AVRCP["avctp_user.h<br/>AVRCP 用户接口"]
Config["bt_profile_config.h<br/>模块裁剪 / 内存池"]
HCI["bluetooth.h<br/>HCI 数据包与事件定义"]
end
subgraph sg_Stack["协议栈实现 (btstack_lib.ld)"]
StackLib["BTStack 库"]
end
subgraph sg_HW["硬件层"]
Controller["蓝牙控制器 / 射频"]
end
App --> TaskAPI
App --> LEUser
App --> AVRCP
LEUser --> BLEAPI
LEUser --> HCI
TaskAPI --> StackLib
LEUser --> StackLib
AVRCP --> StackLib
Config --> StackLib
StackLib --> Controller
架构要点:
le_user.h是 BLE 侧最主要的"门面"(Facade):它统一定义了回调函数类型(btstack_packet_handler_t、sm_stack_packet_handler_t)、事件码(BTSTACK_EVENT_STATE、GATT_EVENT_*、SM_EVENT_*等)、以及服务端/客户端的操作表(ble_server_operation_t/ble_client_operation_t)。bluetooth.h提供的是纯常量契约:HCI 事件码与参数格式注释(如@format 1B11132)用于解析控制器上报的事件,上层通过le_user.h中内联的解析函数(如hci_event_le_meta_get_subevent_code())读取事件字段。bt_profile_config.h用config_stack_modules位掩码控制协议栈裁剪,并通过app_bredr_pool[]、app_le_pool[]、app_l2cap_pool[]、app_bredr_profile[]等外部数组描述各模块的内存池,get_*_len()函数返回池长度供应用查询。
协议栈分层详解
HCI 数据包与事件层(bluetooth.h)
bluetooth.h 是协议栈最底层的契约头文件,定义了主机-控制器接口(HCI)的数据包类型与事件码。这些定义在整个协议栈中作为"公共语言"被上层接口引用。
数据包类型(bluetooth.h):
#define HCI_COMMAND_DATA_PACKET 0x01
#define HCI_ACL_DATA_PACKET 0x02
#define HCI_SCO_DATA_PACKET 0x03
#define HCI_EVENT_PACKET 0x04
Source: bluetooth.h
OGF 命令分组:链路控制(0x01)、链路策略(0x02)、控制器基带(0x03)、信息参数(0x04)、状态参数(0x05)、测试(0x06)、LE 控制器(0x08)、厂商 LE(0x3E)、厂商(0x3F)。其中 OGF_VENDOR 与 OGF_VENDOR_LE_CONTROLLER 为杰理芯片扩展命令保留了空间,这是芯片厂商在标准 HCI 之上扩展私有命令的惯例做法。
事件码设计意图:每个事件码都配有 @format 注释描述参数布局(如 HCI_EVENT_CONNECTION_COMPLETE 为 12B11——1 字节 status、2 字节 connection_handle、6 字节 bd_addr、1 字节 link_type、1 字节 encryption_enabled)。这种"格式字符串"式注释是 BTStack 上游的经典风格,SDK 头文件保留了它,便于上层解析器与上游实现保持同步。关键事件包括:
| 事件 | 码 | 用途 |
|---|---|---|
HCI_EVENT_CONNECTION_COMPLETE | 0x03 | 经典蓝牙连接建立完成 |
HCI_EVENT_DISCONNECTION_COMPLETE | 0x05 | 连接断开 |
HCI_EVENT_COMMAND_COMPLETE | 0x0E | HCI 命令完成(带返回参数) |
HCI_EVENT_COMMAND_STATUS | 0x0F | HCI 命令状态 |
HCI_EVENT_INQUIRY_RESULT_WITH_RSSI | 0x22 | 带 RSSI 的经典查询结果 |
HCI_EVENT_EXTENDED_INQUIRY_RESULT | 0x2F | 扩展查询结果(含 EIR 数据) |
HCI_EVENT_SYNCHRONOUS_CONNECTION_COMPLETE | 0x2C | SCO/eSCO 同步连接完成 |
协议栈任务生命周期(btstack_task.h)
btstack_task.h 只暴露两个函数,构成协议栈的完整生命周期:
int btstack_init();
int btstack_exit();
Source: btstack_task.h
btstack_init():初始化协议栈。应用通常在系统启动早期(如主循环或系统任务创建阶段)调用一次,内部会完成 HCI 层、L2CAP、GATT 等子系统的初始化,并根据config_stack_modules裁剪加载模块。btstack_exit():反初始化协议栈,释放资源,进入可重新初始化的状态。典型使用场景是系统级省电或协议栈复位。
接口如此精简的原因:协议栈作为一个整体运行在自己的任务/中断上下文中,应用侧只需要"启动/停止"两个钩子,其余交互全部通过回调与事件完成。
模块裁剪与内存池(bt_profile_config.h)
嵌入式蓝牙 SoC 的 RAM 极为有限,因此协议栈支持按需裁剪。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))
Source: bt_profile_config.h
BT_BTSTACK_CLASSIC:经典蓝牙(BR/EDR),支撑 A2DP/AVRCP 等传统 Profile;BT_BTSTACK_LE_ADV:仅 BLE 广播(Beacon 类应用,无需连接);BT_BTSTACK_LE:完整 BLE(GATT 客户端/服务端)。
STACK_MODULES_IS_SUPPORT(x) 宏用于运行时判断某个模块是否被编译进固件,应用代码据此决定是否调用对应 Profile 的初始化流程。这一设计让同一份应用源码可以适配不同配置的固件(例如"仅 Beacon"与"全功能"两个固件变体)。
内存池方面,头文件声明了四个外部数组及其长度查询函数:
| 数组 | 长度查询函数 | 用途 |
|---|---|---|
app_bredr_pool[] | get_bredr_pool_len() | 经典蓝牙协议栈堆 |
app_le_pool[] | get_le_pool_len() | BLE 协议栈堆 |
app_l2cap_pool[] | get_l2cap_stack_len() | L2CAP 层堆 |
app_bredr_profile[] | get_profile_pool_len() | 经典 Profile(AVRCP 等)堆 |
这些池的实际大小由链接脚本(btstack_lib.ld)与编译配置决定,应用可通过 get_*_len() 查询实际可用长度,用于内存统计与调试。
BLE 用户接口(le_user.h)
le_user.h 是 BLE 功能的核心接口文件,按职责可分为五组:
1. 回调与事件契约
typedef void (*btstack_packet_handler_t)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
typedef int (*sm_stack_packet_handler_t)(uint8_t packet_type, uint8_t *packet, uint16_t size);
typedef void (*ble_cbk_handler_t)(void);
Source: le_user.h
btstack_packet_handler_t 是协议栈向应用分发事件的统一回调:packet_type 区分 HCI 事件/GATT 事件/SM 事件,channel 携带连接句柄(con_handle),packet/size 指向事件负载。所有 BLE 异步结果(MTU 交换、通知、GATT 查询结果、SM 配对请求)都通过这类回调到达应用,这是 BTStack 事件驱动模型的核心。
2. 状态机与枚举
- HCI 状态枚举:
HCI_STATE_OFF / INITIALIZING / WORKING / HALTING / SLEEPING / FALLING_ASLEEP,BTSTACK_EVENT_STATE(0x60)事件上报状态迁移,应用据此感知协议栈可用性(例如WORKING后才能开启广播)。 - IO 能力枚举
io_capability_t:IO_CAPABILITY_DISPLAY_ONLY / DISPLAY_YES_NO / KEYBOARD_ONLY / NO_INPUT_NO_OUTPUT / KEYBOARD_DISPLAY,用于 SM 配对时选择认证方式(Just Works / Passkey / 数字比较)。
3. 服务端(Peripheral)操作表
struct ble_server_operation_t {
int(*adv_enable)(void *priv, u32 enable);
int(*disconnect)(void *priv);
int(*get_buffer_vaild)(void *priv);
int(*send_data)(void *priv, void *buf, u16 len);
int(*regist_wakeup_send)(void *priv, void *cbk);
int(*regist_recieve_cbk)(void *priv, void *cbk);
int(*regist_state_cbk)(void *priv, void *cbk);
int(*latency_enable)(void *priv, u32 enable);
};
void ble_get_server_operation_table(struct ble_server_operation_t **interface_pt);
Source: le_user.h
ble_get_server_operation_table() 返回服务端操作表,这是 SDK 对上层隐藏具体协议栈实现、以"操作函数指针表"形式提供接口的典型模式(类似内核的 file_operations 表)。latency_enable 支持低功耗连接参数(减少监听窗口),是 BLE 低功耗优化的关键钩子。
4. 客户端(Central)操作表
struct ble_client_operation_t {
int(*scan_enable)(void *priv, u32 enable);
int(*disconnect)(void *priv);
int(*get_buffer_vaild)(void *priv);
int(*write_data)(void *priv, void *buf, u16 len);
int(*read_do)(void *priv);
int(*regist_wakeup_send)(void *priv, void *cbk);
int(*regist_recieve_cbk)(void *priv, void *cbk);
int(*regist_state_cbk)(void *priv, void *cbk);
};
void ble_get_client_operation_table(struct ble_client_operation_t **interface_pt);
Source: le_user.h
与服务端对称,客户端操作表提供扫描、断开、写数据、读数据等原语,应用通过统一接口驱动 GATT 客户端流程,不感知底层是标准 BTStack 还是厂商优化实现。
5. ATT/GATT/SM 关键 API
- ATT 服务端:
ble_att_server_setup_init(const u8 *profile_db, att_read_callback_t read_cbk, att_write_callback_t write_cbk)注册属性数据库与读写回调;att_server_notify()/att_server_indicate()发送通知/指示。 - GATT 客户端:
gatt_client_read_value_of_characteristic_using_value_handle()、gatt_client_write_value_of_characteristic()等读写特征值,结果同样经回调异步返回。 - SM:
ble_sm_setup_init(io_capability_t io_type, u8 auth_req, uint8_t min_key_size, u8 security_en)配置配对参数;SM_EVENT_JUST_WORKS_REQUEST(0xD0)、SM_EVENT_PASSKEY_DISPLAY_NUMBER(0xD2)事件驱动配对交互。 - GAP:
gap_advertisements_enable()、gap_advertisements_set_data()、gap_scan_response_set_data()、gap_advertisements_set_params()控制广播;gap_request_connection_parameter_update()请求更新连接参数。 - 动态数据读写回调:
att_read_callback_t支持"buffer 为 NULL 时只返回长度"的两阶段读取协议,避免大属性值(如 512 字节长特征)拷贝浪费;att_write_callback_t通过transaction_mode参数支持 ATT 准备写(Prepared Write)与执行写(Execute Write)事务。
核心流程
BLE 服务端事件分发流程
BLE 外设(Peripheral)的数据通路以"回调注册 → 事件分派"为主线。下图为从控制器事件到应用回调的完整链路:
sequenceDiagram
participant HC as HCI 控制器
participant ST as BTStack 库
participant APP as 应用 (le_user.h 接口)
participant CBK as 回调 handler
APP->>ST: ble_att_server_setup_init(profile_db, read_cbk, write_cbk)
APP->>ST: ble_cbk_handler_register(packet_cbk, sm_cbk)
APP->>ST: gap_advertisements_set_data(...)
APP->>ST: gap_advertisements_enable(1)
ST->>HC: HCI LE Set Advertising Enable
HC-->>ST: HCI_EVENT_COMMAND_COMPLETE
ST-->>APP: BTSTACK_EVENT_STATE (WORKING)
HC-->>ST: HCI_EVENT_LE_META (Connection Complete)
ST-->>CBK: btstack_packet_handler_t(packet_type=HCI_EVENT_PACKET)
APP->>ST: att_server_notify(con_handle, attr_handle, value, len)
ST->>HC: ATT Handle Value Notification
流程要点:
- 应用先注册 ATT 属性数据库(
profile_db)与读写回调,再注册全局事件回调(ble_cbk_handler_register); - 开启广播后,协议栈收到
HCI_EVENT_COMMAND_COMPLETE,随后状态迁移到WORKING; - 对端连接建立时,控制器上报 LE Meta 事件,协议栈解析连接句柄后分派给应用回调;
- 应用通过
att_server_notify()/att_server_indicate()主动推送数据,写操作则由协议栈调用att_write_callback_t回调应用。
协议栈状态机
HCI 状态枚举构成了协议栈生命周期状态机:
stateDiagram-v2
[*] --> OFF
OFF --> INITIALIZING: btstack_init()
INITIALIZING --> WORKING: 初始化完成
WORKING --> HALTING: btstack_exit() / 错误
HALTING --> OFF: 资源释放
WORKING --> SLEEPING: 低功耗请求
SLEEPING --> FALLING_ASLEEP: 睡眠握手
FALLING_ASLEEP --> SLEEPING: 唤醒失败
FALLING_ASLEEP --> OFF: 深度睡眠
SLEEPING --> WORKING: 唤醒
应用通过 BTSTACK_EVENT_STATE 事件观察状态迁移;只有 WORKING 状态下才允许执行广播、扫描、连接等 GAP 操作,这避免了在协议栈未就绪时下发命令导致的竞态。
使用示例
示例 1:注册 BLE 事件回调与状态监听
应用通过 ble_cbk_handler_register 注册两类回调:全局协议栈事件回调与 SM 安全事件回调:
void ble_cbk_handler_register(btstack_packet_handler_t packet_cbk, sm_stack_packet_handler_t sm_cbk);
Source: le_user.h
在回调中,应用先用 hci_event_packet_get_type(event) 与 hci_event_le_meta_get_subevent_code(event) 两个内联解析函数判断事件类型,再按需读取字段:
static inline uint8_t hci_event_packet_get_type(const uint8_t *event)
{
return event[0];
}
static inline uint8_t hci_event_le_meta_get_subevent_code(const uint8_t *event)
{
return event[2];
}
Source: le_user.h
这两个内联函数避免了重复的字节偏移计算:event[0] 是包类型字节,event[2] 在 LE Meta 事件中保存子事件码(如连接完成 0x01、连接更新完成 0x03)。
示例 2:配置并启动广播
设置广播数据与参数,然后使能广播。参数接口与标准 BTStack GAP API 对齐:
extern void gap_advertisements_enable(int enabled);
extern void gap_advertisements_set_data(uint8_t advertising_data_length, uint8_t *advertising_data);
extern void gap_scan_response_set_data(uint8_t scan_response_data_length, uint8_t *scan_response_data);
extern void gap_advertisements_set_params(uint16_t adv_int_min, uint16_t adv_int_max, uint8_t adv_type,
uint8_t direct_address_typ, uint8_t *direct_address, uint8_t channel_map, uint8_t filter_policy);
Source: le_user.h
示例 3:服务端数据推送与客户端特征读写
服务端使用 att_server_notify 推送通知;客户端使用 gatt_client_* 系列发起读/写:
extern int att_server_notify(hci_con_handle_t con_handle, uint16_t attribute_handle, uint8_t *value, uint16_t value_len);
extern uint8_t gatt_client_read_value_of_characteristic_using_value_handle(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle);
extern uint8_t gatt_client_write_value_of_characteristic(btstack_packet_handler_t callback, hci_con_handle_t con_handle, uint16_t value_handle, uint16_t value_length, uint8_t *data);
Source: le_user.h
注意 GATT 客户端的读/写结果不是同步返回的,而是通过调用时传入的 callback 以 GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT(0xA5)、GATT_EVENT_NOTIFICATION(0xA7)、GATT_EVENT_INDICATION(0xA8)等事件异步送达。
示例 4:SM 配对配置
ble_sm_setup_init 一次性配置安全管理的认证参数,sm_just_event_t 结构体描述配对请求中的对端信息:
extern void ble_sm_setup_init(io_capability_t io_type, u8 auth_req, uint8_t min_key_size, u8 security_en);
typedef struct {
//base info
uint8_t type; ///< See <btstack/hci_cmds.h> SM_...
uint8_t size;
hci_con_handle_t con_handle;
uint8_t addr_type;
uint8_t address[6];
//extend info
uint8_t data[4];
} sm_just_event_t;
auth_req 可取 SM_AUTHREQ_BONDING(0x01,支持绑定)、SM_AUTHREQ_MITM_PROTECTION(0x04,防中间人)、SM_AUTHREQ_SECURE_CONNECTION(0x08,LE Secure Connections)。min_key_size 设定最小密钥长度,security_en 开关安全功能;io_type 选择 Just Works(NO_INPUT_NO_OUTPUT)或 Passkey(DISPLAY_YES_NO)等认证方式,最终通过 SM_EVENT_JUST_WORKS_REQUEST / SM_EVENT_PASSKEY_DISPLAY_NUMBER 事件与用户交互。
配置选项
协议栈模块裁剪
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
config_stack_modules | const int | 由固件编译配置决定 | 模块位掩码,BIT(0) Classic、BIT(1) LE Adv、BIT(2) LE |
BT_BTSTACK_CLASSIC | 宏 (BIT(0)) | 取决于固件 | 启用经典蓝牙 BR/EDR |
BT_BTSTACK_LE_ADV | 宏 (BIT(1)) | 取决于固件 | 仅启用 BLE 广播(Beacon) |
BT_BTSTACK_LE | 宏 (BIT(2)) | 取决于固件 | 启用完整 BLE(连接 + GATT) |
STACK_MODULES_IS_SUPPORT(x) | 宏 | — | 运行时判断模块是否被支持 |
内存池
| 选项 | 类型 | 说明 |
|---|---|---|
app_bredr_pool[] / get_bredr_pool_len() | u8 数组 / u16 | 经典蓝牙协议栈堆 |
app_le_pool[] / get_le_pool_len() | u8 数组 / u16 | BLE 协议栈堆 |
app_l2cap_pool[] / get_l2cap_stack_len() | u8 数组 / u16 | L2CAP 层堆 |
app_bredr_profile[] / get_profile_pool_len() | u8 数组 / u16 | 经典 Profile 堆 |
BLE 行为常量
| 选项 | 值 | 说明 |
|---|---|---|
ATT_DEFAULT_MTU | 23 | 默认 ATT MTU(BLE 4.x 最小 MTU) |
BT_NAME_LEN_MAX | 29 | 本地名称最大长度 |
ADV_RSP_PACKET_MAX | 31 | 广播/扫描响应数据最大字节数 |
HCI_CON_HANDLE_INVALID | 0xffff | 无效连接句柄哨兵值 |
SM 认证选项(ble_sm_setup_init 参数)
| 参数 | 类型 | 取值/默认 | 说明 |
|---|---|---|---|
io_type | io_capability_t | 无默认 | IO 能力:DISPLAY_ONLY、DISPLAY_YES_NO、KEYBOARD_ONLY、NO_INPUT_NO_OUTPUT |
auth_req | u8 | 无默认 | SM_AUTHREQ_NO_BONDING(0x00)、BONDING(0x01)、MITM_PROTECTION(0x04)、SECURE_CONNECTION(0x08)、KEYPRESS(0x10),可位或组合 |
min_key_size | uint8_t | 无默认 | 最小密钥长度(字节) |
security_en | u8 | 无默认 | 是否启用安全配对 |
API 参考
生命周期
| 函数 | 签名 | 说明 |
|---|---|---|
btstack_init | int btstack_init() | 初始化协议栈,返回 0 表示成功 |
btstack_exit | int btstack_exit() | 反初始化协议栈,释放资源 |
GAP(广播与连接参数)
| 函数 | 签名 | 说明 |
|---|---|---|
gap_advertisements_enable | void (int enabled) | 使能/关闭广播 |
gap_advertisements_set_data | void (uint8_t len, uint8_t *data) | 设置广播数据(≤31 字节) |
gap_scan_response_set_data | void (uint8_t len, uint8_t *data) | 设置扫描响应数据 |
gap_advertisements_set_params | void (adv_int_min, adv_int_max, adv_type, direct_addr_typ, direct_addr, channel_map, filter_policy) | 设置广播参数(间隔、类型、信道、过滤策略) |
gap_request_connection_parameter_update | int (con_handle, conn_interval_min, conn_interval_max, conn_latency, supervision_timeout) | 请求更新连接参数 |
ATT/GATT 服务端
| 函数 | 签名 | 说明 |
|---|---|---|
ble_att_server_setup_init | void (const u8 *profile_db, att_read_callback_t read_cbk, att_write_callback_t write_cbk) | 注册属性数据库与动态读写回调 |
att_server_notify | int (con_handle, attribute_handle, value, value_len) | 发送通知(无需对端确认) |
att_server_indicate | int (con_handle, attribute_handle, value, value_len) | 发送指示(需要对端确认) |
att_server_request_can_send_now_event | void (con_handle) | 请求"可以发送"事件(流控) |
GATT 客户端
| 函数 | 签名 | 说明 |
|---|---|---|
gatt_client_read_value_of_characteristic_using_value_handle | uint8_t (callback, con_handle, value_handle) | 读特征值,结果异步回调 |
gatt_client_read_long_value_of_characteristic_using_value_handle_with_offset | uint8_t (callback, con_handle, value_handle, offset) | 从偏移读长特征值 |
gatt_client_write_value_of_characteristic | uint8_t (callback, con_handle, value_handle, value_length, data) | 写特征值,带确认 |
gatt_client_write_value_of_characteristic_without_response | uint8_t (con_handle, value_handle, value_length, value) | 无响应写(Write Command) |
gatt_client_request_can_send_now_event | void (con_handle) | 请求客户端发送窗口 |
SM 安全
| 函数 | 签名 | 说明 |
|---|---|---|
ble_sm_setup_init | void (io_capability_t io_type, u8 auth_req, uint8_t min_key_size, u8 security_en) | 配置 SM 配对参数 |
回调类型
| 类型 | 签名 | 说明 |
|---|---|---|
btstack_packet_handler_t | void (*)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) | 全局协议栈事件回调 |
sm_stack_packet_handler_t | int (*)(uint8_t packet_type, uint8_t *packet, uint16_t size) | SM 安全事件回调 |
att_read_callback_t | uint16_t (*)(uint16_t con_handle, uint16_t attribute_handle, uint16_t offset, uint8_t *buffer, uint16_t buffer_size) | ATT 动态读回调(buffer 为 NULL 时返回长度) |
att_write_callback_t | int (*)(uint16_t con_handle, uint16_t attribute_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size) | ATT 动态写回调,返回 0 表示成功 |
关键事件码
| 事件 | 值 | 说明 |
|---|---|---|
BTSTACK_EVENT_STATE | 0x60 | 协议栈状态迁移 |
GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT | 0xA5 | GATT 读结果 |
GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT | 0xA6 | 长特征读结果 |
GATT_EVENT_NOTIFICATION | 0xA7 | 收到通知 |
GATT_EVENT_INDICATION | 0xA8 | 收到指示 |
ATT_EVENT_MTU_EXCHANGE_COMPLETE | 0xB5 | MTU 交换完成 |
ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE | 0xB6 | 指示确认完成 |
ATT_EVENT_CAN_SEND_NOW | 0xB7 | 允许发送通知/指示 |
SM_EVENT_JUST_WORKS_REQUEST | 0xD0 | 请求 Just Works 确认 |
SM_EVENT_PASSKEY_DISPLAY_NUMBER | 0xD2 | 显示 Passkey |
GAP_EVENT_ADVERTISING_REPORT | 0xE2 | 扫描到广播包 |
L2CAP_EVENT_CONNECTION_PARAMETER_UPDATE_RESPONSE | 0x77 | 连接参数更新响应 |
失败模式、边界情况与并发
状态机竞态
协议栈未进入 HCI_STATE_WORKING 时,广播、扫描、连接等 GAP 命令会被协议栈拒绝或静默丢弃。应用必须在收到 BTSTACK_EVENT_STATE 且状态为 WORKING 之后再下发命令。这一约束是事件驱动架构的必然结果——协议栈命令是异步的,不能假设"调用即生效"。HCI_STATE_SLEEPING / FALLING_ASLEEP 状态下,发送数据会触发 regist_wakeup_send 注册的唤醒回调,应用需配合低功耗调度。
连接句柄无效
HCI_CON_HANDLE_INVALID(0xffff)是无效句柄哨兵值。当连接已断开(HCI_EVENT_DISCONNECTION_COMPLETE 之后),应用仍持有旧句柄调用 att_server_notify() / gatt_client_*() 时,应主动用该哨兵值校验句柄合法性,避免对已释放的连接执行 ATT 操作。协议栈内部对无效句柄的响应未在本头文件契约中保证,因此上层必须自行管理句柄生命周期。
缓冲区不足与流控
get_buffer_vaild(服务端/客户端操作表成员):发送数据前应先查询发送缓冲是否可用,返回非 0 表示可发送;否则数据应排队等待ATT_EVENT_CAN_SEND_NOW(0xB7)事件(由att_server_request_can_send_now_event()/gatt_client_request_can_send_now_event()触发)。这是避免 ATT 层丢包的关键机制。att_write_callback_t返回值契约:返回 0 表示写入成功;ATT_ERROR_PREPARE_QUEUE_FULL表示准备写队列已满;ATT_ERROR_INVALID_OFFSET表示偏移越界。应用在实现该回调时必须正确处理这两个错误码,否则长属性分段写入会失败。
广播数据超限
ADV_RSP_PACKET_MAX(31 字节)是 BLE 广播/扫描响应数据硬上限。gap_advertisements_set_data() 传入超过 31 字节的数据会被截断或导致广播失败(具体行为由协议栈实现决定),SDK 未在接口层做长度校验,因此应用在构造广播载荷时必须以 BT_NAME_LEN_MAX(29,含长度/类型头)与 31 字节为约束进行静态规划。
并发模型
接口层为单线程 + 中断回调模型:协议栈事件回调(btstack_packet_handler_t)运行在协议栈任务/中断上下文,应用主循环运行在应用上下文。二者共享的数据(如发送缓冲、连接状态标志)必须通过临界区保护或仅在回调内修改,避免数据竞争。regist_wakeup_send 回调用于从低功耗唤醒路径触发发送,同样需要注意上下文切换开销。
MTU 协商
默认 ATT_DEFAULT_MTU 为 23(3 字节 ATT 头 + 20 字节有效载荷)。若应用需要更大传输单元,须在连接建立后发起 MTU 交换,并通过 ATT_EVENT_MTU_EXCHANGE_COMPLETE(0xB5)事件读取协商结果——解析函数 att_event_mtu_exchange_complete_get_MTU(event) 返回 little_endian_read_16(event, 4)。在 MTU 协商完成前按 23 字节 MTU 分片发送,可避免对端无法解析。
性能与运维注意事项
- 内存池感知:通过
get_bredr_pool_len()/get_le_pool_len()等函数可统计协议栈内存占用。若出现异常(如经典蓝牙连接频繁失败),应检查对应池是否耗尽;SDK 头文件未暴露池水位查询,运维上可借助链接脚本(btstack_lib.ld)确认池的静态分配。 - 低功耗优化:
latency_enable(服务端)与gap_request_connection_parameter_update()配合,可增大连接间隔与从延迟(conn_latency),显著降低待机功耗;代价是双向数据时延上升。广播间隔(adv_int_min/max)同理,需在功耗与发现时延间权衡。 - 发送路径:
send_data/write_data均要求"先查缓冲、再发送"的顺序,违反该顺序在高吞吐场景(如数据透传)下会丢包。流控事件ATT_EVENT_CAN_SEND_NOW是最高效的背压信号,优于轮询。 - 厂商扩展命令空间:
OGF_VENDOR(0x3F)与OGF_VENDOR_LE_CONTROLLER(0x3E)为杰理私有 HCI 命令保留,芯片级调试(如 RF 测试、功率控制)经由这些命令下发,与标准命令共存于同一 HCI 通道。
扩展点
- 动态 ATT 属性:
att_read_callback_t/att_write_callback_t允许属性值不静态存储于profile_db,而是每次读写时动态生成/消费(如传感器读数、流式数据)。两阶段读(buffer == NULL 返回长度)机制支持超大属性,是实现"动态 GATT 服务"的标准扩展路径。 - 操作表注入:
ble_get_server_operation_table()/ble_get_client_operation_table()返回的ble_server_operation_t/ble_client_operation_t函数指针表是 SDK 的注入点——替换该表即可用自定义协议栈实现(如厂商私有 BLE)替换标准 BTStack,而上层应用代码无需改动。这是"接口与实现分离"的最直接体现。 - 事件回调注册:
ble_cbk_handler_register()允许应用同时挂接协议栈事件与 SM 安全事件两条回调链,可在此基础上扩展安全 UI(Passkey 显示、Just Works 确认弹窗)。 - 唤醒钩子:
regist_wakeup_send回调为低功耗发送路径预留,可接入 RTOS 信号量/事件组,实现"睡眠中被唤醒后立即补发数据"。
测试与使用模式启示
SDK 未在 include_lib/btstack 目录内提供单元测试源码(该目录为纯头文件契约层)。但接口设计本身揭示了推荐的测试策略:
- 回调契约测试:针对
att_read_callback_t的两阶段读(NULL buffer 返回长度)与att_write_callback_t的错误码返回进行桩测试,这是最容易出错的边界; - 状态机测试:验证应用在
BTSTACK_EVENT_STATE非WORKING时不下发 GAP 命令,以及断线后句柄置为HCI_CON_HANDLE_INVALID的逻辑; - 流控测试:模拟发送缓冲占满 →
ATT_EVENT_CAN_SEND_NOW→ 补发 的完整链路,确保高吞吐下无丢失。
相关链接
- bluetooth.h - HCI 数据包与事件定义
- le_user.h - BLE 用户接口
- ble_api.h - 底层 BLE API
- ble_data_types.h - BLE 数据类型
- bt_profile_config.h - 协议栈模块配置
- btstack_task.h - 协议栈任务生命周期
- avctp_user.h - AVRCP 用户接口
- btstack_lib.ld - 协议栈库链接脚本
相关主题页:BLE 广播与连接管理、AVRCP 协议控制、协议栈内存配置等页面分别从 Profile 与系统资源角度展开,本页聚焦于接口契约本身。