蓝牙公共处理
蓝牙公共处理(bt_common)是 AW31N BLE SDK 中面向应用层复用的蓝牙能力抽象层:它统一封装 EDR(经典蓝牙)与 BLE 的初始化配置结构、HCI 事件/错误码定义、连接控制与配对辅助接口,以及用于射频认证的 BLE DUT(Direct Test Mode)测试 API,使 HID、Transfer 等不同应用可以基于同一套公共接口接入杰理 btstack 协议栈与蓝牙控制器库。
Purpose and Scope
本页面说明「蓝牙公共处理」这一子系统在 SDK 中的位置与职责,具体包括:
app_comm_bt.h中定义的 EDR/BLE 公共初始化配置结构(edr_init_cfg_t、ble_init_cfg_t、edr_sniff_par_t)- HCI 事件码与蓝牙错误码的公共映射(配对、连接、断开等场景)
- 公共 API(BLE 启动/退出、事件分发、连接控制、简易配对开关、重连广播配置)
bt_common/ble_test_api.c中实现的 BLE DUT 测试模式(定频/连续发射)
以下相关主题属于兄弟页面,不在本页展开:具体应用的业务流程(HID/Transfer 应用逻辑)、btstack 协议栈与控制器库内部实现(apps/include_lib/bt_controller_include/)、以及各 demo 的 lib_btstack_config.c / lib_btctrler_config.c 裁剪配置。本页只覆盖它们共同依赖的「公共处理」部分。
Overview
在 AW31N 的软件架构中,应用(HID、Transfer 等 demo)与杰理 btstack/控制器库之间隔着一层公共适配代码。这层代码解决三个共性问题:
- 初始化契约统一:BLE 与 EDR 共存的芯片上,BLE 和经典蓝牙共享射频与地址管理。
ble_init_cfg_t中的same_address字段专门用于声明 BLE 与 EDR 是否使用相同地址,这决定了控制器层如何分配 BD_ADDR,是双模共存的关键开关。 - 事件与错误语义统一:应用通过
struct bt_event收到协议栈上报的事件,公共层把 HCI 事件码(HCI_EVENT_CONNECTION_COMPLETE等)和错误码(ERROR_CODE_*)定义为可读常量,并区分「应用主动取消 Page」与「基带取消 Page」两种自定义事件(CUSTOM_BB_AUTO_CANCEL_PAGE/BB_CANCEL_PAGE),避免上层与库层语义混淆。 - 测试/产测能力挂载:
ble_test_api.c在TCFG_NORMAL_SET_DUT_MODE_API宏开启时提供 BLE 定频、DUT 模式入口,供产测或认证(FCC/CE 等)使用,与正常业务路径隔离。
公共层刻意保持「薄」:它只做参数组织、事件分发与状态机入口,不承载具体业务逻辑,因此所有 demo 都可以安全复用。
Architecture
flowchart TD
subgraph sg_App["应用层 (apps/demo)"]
HID["HID 应用"]
Transfer["Transfer 应用"]
end
subgraph sg_Common["蓝牙公共处理层 (bt_common)"]
CommBT["app_comm_bt.h<br/>配置结构 / 事件码 / 错误码 / 公共 API"]
DUT["ble_test_api.c<br/>BLE DUT 定频测试模式"]
end
subgraph sg_Lib["SDK 库层 (apps/include_lib)"]
BTStack["btstack 协议栈库<br/>(IRQ_BTSTACK_MSG_IP)"]
Ctrl["蓝牙控制器库 btctler<br/>(btctrler_task.h / hci_transport.h)"]
end
subgraph sg_HW["硬件层"]
RF["BLE/EDR 射频收发器"]
end
HID -->|"引用 app_comm_bt.h"| CommBT
Transfer -->|"引用 app_comm_bt.h"| CommBT
CommBT -->|"启动/退出/事件分发"| BTStack
CommBT -->|"连接/扫描控制"| Ctrl
DUT -->|"ll_hci_destory / __ble_dut_ops"| Ctrl
BTStack -->|"HCI 传输"| Ctrl
Ctrl -->|"空口收发"| RF
架构说明:app_comm_bt.h 是纯接口头文件(无实现依赖),被各 demo 直接 include;它声明的 API 指向 btstack/控制器库提供的服务。ble_test_api.c 位于 apps/app/bsp/common/bt_common/,编译期由 TCFG_NORMAL_SET_DUT_MODE_API 门控,仅在产测/认证固件中编入,正常业务固件不携带 DUT 代码。这样既保证公共 API 的单一来源,又避免测试代码进入量产固件。
核心数据结构
EDR 初始化配置
edr_init_cfg_t 聚合了经典蓝牙建立连接所需的核心参数:
class_type:设备类别(CoD),决定对端搜索时显示的图标;page_timeout/super_timeout:建链与监督超时(单位:时隙),影响连接失败时的等待时长;io_capabilities/authentication_req/oob_data/passkey_enable:配对与安全相关位域,共同决定简易配对(SSP)流程;report_map/report_map_size:HID 报告描述符指针与长度,供 HID 类设备上报;sniff_param:指向edr_sniff_par_t,配置低功耗 Sniff 模式参数。
typedef struct {
u16 max_interval_slots;
u16 min_interval_slots;
u8 attempt_slots;
u8 timeout_slots;
u16 check_timer_period; //检查周期
u8 cnt_time;//<空闲多少秒之后进入sniff模式
u8 sniff_mode;
} edr_sniff_par_t;
typedef struct {
u32 class_type;//搜索显示图标
u16 page_timeout;
u16 super_timeout;
u8 io_capabilities: 2;
u8 authentication_req: 3;
u8 oob_data: 2;
u8 passkey_enable: 1;
u16 report_map_size;
const u8 *report_map;
const edr_sniff_par_t *sniff_param;
} edr_init_cfg_t;
设计意图:sniff_param 与 report_map 使用指针而非内嵌数组,允许上层把大块数据(HID 报告描述符)放在只读段,减小栈上拷贝开销。sniff_mode 支持两种枚举值(SNIFF_MODE_DEF 与 SNIFF_MODE_ANCHOR),SNIFF_MODE_ANCHOR 用于对端支持锚点连接时进一步降低功耗。
BLE 初始化配置
typedef struct {
//ble跟edr的地址一样
u8 same_address;
u16 appearance; //搜索显示图标
u16 report_map_size;
const u8 *report_map;
} ble_init_cfg_t;
same_address 是双模共存的地址策略开关:置 1 时 BLE 与 EDR 共享同一 BD_ADDR,对端看到的两个接口地址一致,简化配对与绑定管理;置 0 时使用独立地址。appearance 决定 BLE 广播/扫描响应中对端显示的图标类型。
HCI 事件码与错误码定义
公共层把协议栈上报的事件与错误收敛为宏定义,应用的事件处理函数据此分发:
#define HCI_EVENT_INQUIRY_COMPLETE 0x01
#define HCI_EVENT_CONNECTION_COMPLETE 0x03
#define HCI_EVENT_DISCONNECTION_COMPLETE 0x05
#define HCI_EVENT_PIN_CODE_REQUEST 0x16
#define HCI_EVENT_IO_CAPABILITY_REQUEST 0x31
#define HCI_EVENT_USER_CONFIRMATION_REQUEST 0x33
#define HCI_EVENT_USER_PASSKEY_REQUEST 0x34
#define HCI_EVENT_USER_PRESSKEY_NOTIFICATION 0x3B
#define HCI_EVENT_VENDOR_NO_RECONN_ADDR 0xF8
#define HCI_EVENT_VENDOR_REMOTE_TEST 0xFE
#define BTSTACK_EVENT_HCI_CONNECTIONS_DELETE 0x6D
#define ERROR_CODE_SUCCESS 0x00
#define ERROR_CODE_PAGE_TIMEOUT 0x04
#define ERROR_CODE_AUTHENTICATION_FAILURE 0x05
#define ERROR_CODE_PIN_OR_KEY_MISSING 0x06
#define ERROR_CODE_CONNECTION_TIMEOUT 0x08
#define ERROR_CODE_SYNCHRONOUS_CONNECTION_LIMIT_TO_A_DEVICE_EXCEEDED 0x0A
#define ERROR_CODE_ACL_CONNECTION_ALREADY_EXISTS 0x0B
#define ERROR_CODE_CONNECTION_REJECTED_DUE_TO_LIMITED_RESOURCES 0x0D
#define ERROR_CODE_CONNECTION_REJECTED_DUE_TO_UNACCEPTABLE_BD_ADDR 0x0F
#define ERROR_CODE_CONNECTION_ACCEPT_TIMEOUT_EXCEEDED 0x10
#define ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION 0x13
#define ERROR_CODE_CONNECTION_TERMINATED_BY_LOCAL_HOST 0x16
#define CUSTOM_BB_AUTO_CANCEL_PAGE 0xFD //// app cancle page
#define BB_CANCEL_PAGE 0xFE //// bb cancle page
值得注意的设计细节:CUSTOM_BB_AUTO_CANCEL_PAGE(0xFD)与 BB_CANCEL_PAGE(0xFE)是杰理控制器库自定义的「取消 Page」事件——前者是应用发起取消、后者是基带(BB)因超时等原因自行取消。两者在 0xF0~0xFF 厂商保留区内取值,不会与标准 HCI 事件冲突;上层通常用 CUSTOM_BB_AUTO_CANCEL_PAGE 判断「用户主动停止搜索」,以区别被动失败。
WAIT_DISCONN_TIME_MS(1000ms)定义了默认断开等待时间,供公共层在收到断开请求后给协议栈留出完成断链动作的时间窗:
//默认断开BT等待时间
#define WAIT_DISCONN_TIME_MS (1000)
公共 API 接口
app_comm_bt.h 声明的全部公共接口如下(实现位于 SDK 库或应用源码,本页以接口契约为准):
void btstack_ble_start_before_init(const ble_init_cfg_t *cfg, int param);
void btstack_ble_start_after_init(int param);
void btstack_ble_exit(int param);
int bt_comm_ble_status_event_handler(struct bt_event *bt);
int bt_comm_ble_hci_event_handler(struct bt_event *bt);
void bt_wait_phone_connect_control_ext(u8 inquiry_en, u8 page_scan_en);
void bt_wait_phone_connect_control(u8 enable);
/*简易配对开关接口*/
void __set_simple_pair_flag(bool flag);
// void le_hogp_set_direct_adv_type(u8 type);
void le_hogp_set_reconnect_adv_cfg(u8 adv_type, u32 adv_timeout);
按职责可将接口分为四组:
- 生命周期管理:
btstack_ble_start_before_init(在控制器初始化前传入ble_init_cfg_t)、btstack_ble_start_after_init(初始化完成后启动 BLE 任务)、btstack_ble_exit(退出 BLE)。before/after的拆分是为了让地址策略(same_address)在控制器初始化阶段就生效,而协议栈任务在硬件就绪后才拉起。 - 事件分发:
bt_comm_ble_status_event_handler/bt_comm_ble_hci_event_handler接收struct bt_event,返回int表示事件是否被消费。这是公共层与应用状态机之间的唯一事件入口。 - 连接控制:
bt_wait_phone_connect_control(u8 enable)统一开关「等待手机连接」状态;bt_wait_phone_connect_control_ext进一步细分 inquiry 与 page scan 的独立开关,便于只开可被发现(Inquiry Scan)而暂不响应连接(Page Scan)的场景。 - 配对与重连:
__set_simple_pair_flag全局开关简易配对;le_hogp_set_reconnect_adv_cfg(adv_type, adv_timeout)配置 HOGP 重连广播的类型与超时(adv_type对应直连/可连接广播类型,adv_timeout控制重连窗口时长)。
核心流程
BLE 启动与事件分发流程
flowchart TD
Start(["应用启动"]) --> PreInit["btstack_ble_start_before_init<br/>(传入 ble_init_cfg_t)"]
PreInit --> AfterInit["btstack_ble_start_after_init"]
AfterInit --> WaitEvent["等待 bt_event 上报"]
WaitEvent --> StatusHandler["bt_comm_ble_status_event_handler"]
StatusHandler --> HciHandler["bt_comm_ble_hci_event_handler"]
HciHandler --> Decide{"HCI 事件类型?"}
Decide -->|"CONNECTION_COMPLETE 0x03"| Conn["连接建立<br/>记录对端地址"]
Decide -->|"DISCONNECTION_COMPLETE 0x05"| Disconn["连接断开<br/>等待 WAIT_DISCONN_TIME_MS 复位状态"]
Decide -->|"USER_CONFIRMATION_REQUEST 0x33"| Confirm["SSP 配对确认"]
Decide -->|"VENDOR_NO_RECONN_ADDR 0xF8"| Reconn["重连地址丢失<br/>触发重新广播/回连"]
Decide -->|"CUSTOM_BB_AUTO_CANCEL_PAGE 0xFD"| Cancel["应用取消 Page 成功"]
Conn --> AppState["应用状态机更新"]
Disconn --> AppState
Confirm --> AppState
Reconn --> AppState
Cancel --> AppState
流程说明:公共层的两个 event handler 是串行的(同一 bt_event 先走 status 再走 hci 分发),保证状态机按顺序推进。厂商自定义事件(0xF8/0xFD/0xFE)在标准 HCI 事件之前被识别,避免落入默认分支。
BLE DUT 测试模式流程
sequenceDiagram
participant App as 应用 (TCFG_NORMAL_SET_DUT_MODE_API)
participant DUT as ble_test_api.c
participant LL as 链路层 ll_hci_destory
participant Ops as __ble_dut_ops 操作表
participant HCI as HCI UART (115200)
App->>DUT: ble_dut_mode_init()
DUT->>LL: ll_hci_destory()
DUT->>Ops: __ble_dut_ops->init()
DUT->>HCI: 建立 HCI 传输 (hci_transport_config_uart_t)
App->>DUT: ble_fix_fre_api()
DUT->>HCI: bt_ble_adv_enable(0) 停止广播
DUT->>HCI: ble_enter_dut_tx_mode(dut_param)
Note over HCI: 连续发射 PRBS9/10101010/11110000<br/>等测试载荷 (ch_index 0~39)
BLE DUT 测试模式(ble_test_api.c)
apps/app/bsp/common/bt_common/ble_test_api.c 是整个 SDK 中位于 bt_common 目录下的实现文件,仅在 TCFG_NORMAL_SET_DUT_MODE_API 编译开关打开时编译(#if TCFG_NORMAL_SET_DUT_MODE_API 包裹)。它提供射频测试所需的载荷与 PHY 枚举、参数结构和入口函数。
载荷与 PHY 类型
enum BLE_DUT_PAYLOAD_TYPE {
PAYLOAD_TYPE_PRBS9 = 0,
PAYLOAD_TYPE_11110000,
PAYLOAD_TYPE_10101010,
PAYLOAD_TYPE_PRBS15,
PAYLOAD_TYPE_11111111,
PAYLOAD_TYPE_00000000,
PAYLOAD_TYPE_00001111,
PAYLOAD_TYPE_01010101,
PAYLOAD_TYPE_SINGLE_CARRIER = 0xf0,
};
enum BLE_DUT_PHY_TYPE {
BLE_1M_UNCODED_PHY = 1,
BLE_2M_UNCODED_PHY,
BLE_1M_CODED_PHY_S8,
BLE_1M_CODED_PHY_S2,
};
struct ble_dut_param_set {
u8 ch_index; //tx ch index;(0~39 -> 2402~2480)
u8 payload_type; //tx payload type
u8 payload_len; //payload_len(0~0xff) when continuous_tx = 0;
u8 continuous_tx; //enable or disable continuous transmission mode(0/1)
};
PAYLOAD_TYPE_PRBS9/PRBS15 是标准蓝牙测试载荷(伪随机序列),PAYLOAD_TYPE_SINGLE_CARRIER(0xF0)用于单载波测试;PHY 枚举覆盖 1M/2M 非编码与 1M 编码(S8/S2),对应 BLE 5.x 测试规范。ch_index 0~39 映射 2402~2480 MHz 的 40 个信道。
DUT 入口实现
static hci_transport_config_uart_t config = {
HCI_TRANSPORT_CONFIG_UART,
115200,
0, // main baudrate
0, // flow control
NULL,
};
/* !!!Notice:when this api is called and sleep mode should be sure to exit; */
void ble_fix_fre_api()
{
#if TCFG_USER_BLE_ENABLE
#if (CONFIG_BT_MODE == BT_NORMAL)
bt_ble_adv_enable(0);
#endif
os_time_dly(10);
struct ble_dut_param_set dut_param = {
.ch_index = 0,
.payload_type = PAYLOAD_TYPE_10101010,
.payload_len = 0x20,
.continuous_tx = 1,
};
ble_enter_dut_tx_mode(&dut_param);
#endif
}
void ble_dut_mode_init(void)
{
if (!ble_dut_hdl) {
ll_hci_destory();
ble_dut_hdl = __ble_dut_ops->init();
...
}
}
实现要点:
- 先停广播再进 DUT:
ble_fix_fre_api先调用bt_ble_adv_enable(0)关闭正常广播,再延时 10 个 OS tick 让空口安静,随后注入测试参数——避免正常广播干扰频谱测量。 - 销毁链路层再建测试会话:
ble_dut_mode_init通过ll_hci_destory()拆除正常协议栈的链路层实例,再用__ble_dut_ops->init()建立独立的测试控制通道,ble_dut_hdl静态句柄保证同一时刻只有一条 DUT 会话(非空则跳过重复初始化,见if (!ble_dut_hdl))。 - 回调操作表:
__ble_dut_ops是控制器库导出的函数指针表(init等成员),公共层不直接依赖具体函数,便于不同芯片/库版本替换——这是典型的 ops 表扩展点。 - 注释明确约束:源码注释强调调用 DUT API 前必须退出睡眠模式("when this api is called and sleep mode should be sure to exit"),因为 DUT 连续发射与低功耗睡眠互斥。
文件头部还声明了经典蓝牙测试入口:bredr_fcc_init(u8 mode, u8 fre)、dut_hci_controller_init(const hci_transport_t *transport, const void *config)、bt_ble_adv_enable(u8 enable) 等,供产测工具通过 UART HCI 驱动控制器进入 FCC 定频模式。文件内的 bt_fix_fre_api/bt_dut_api 示例目前被 #if 0 注释禁用(演示用途),正式定频入口是上方的 ble_fix_fre_api。
模块内使用 static volatile u8 bt_test_status 记录测试状态,volatile 保证中断/任务上下文之间对状态的读取一致;LOG_TAG "[BT_DUT]" 配合 LOG_*_ENABLE 宏使 DUT 日志独立可裁剪。
配置选项
公共处理层的配置以编译期宏和头文件常量为主(运行期配置由 ble_init_cfg_t / edr_init_cfg_t 传入):
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
TCFG_NORMAL_SET_DUT_MODE_API | 编译宏 | 由 app_config 决定 | 是否编入 BLE DUT 测试模式(ble_test_api.c 整体由 #if 包裹) |
TCFG_USER_BLE_ENABLE | 编译宏 | 由 app_config 决定 | 是否启用 BLE 功能;DUT 入口内部以此判断是否执行 bt_ble_adv_enable(0) |
CONFIG_BT_MODE | 编译宏 | BT_NORMAL | 蓝牙工作模式;BT_NORMAL 下 DUT 前先停广播 |
WAIT_DISCONN_TIME_MS | 常量 | 1000 | 默认断开 BT 等待时间(毫秒) |
SNIFF_MODE_DEF / SNIFF_MODE_ANCHOR | 枚举 | SNIFF_MODE_DEF | EDR Sniff 模式选择:默认 / 锚点模式 |
edr_sniff_par_t.check_timer_period | 结构体字段 | 上层设定 | Sniff 检查周期 |
edr_sniff_par_t.cnt_time | 结构体字段 | 上层设定 | 空闲多少秒后进入 Sniff 模式 |
HCI_TRANSPORT_CONFIG_UART baudrate | 结构体字段 | 115200 | DUT 模式下 HCI UART 波特率(ble_test_api.c 静态配置) |
配置入口分散在:apps/demo/hid/config/、apps/demo/transfer/config/ 下的 lib_btstack_config.c / lib_btctrler_config.c(协议栈与控制器裁剪),以及各 app 的 app_config.h(TCFG_* 系列)。公共层本身不持有这些宏的默认值,而是按调用方编译配置生效——这保证了不同 demo 可以差异化裁剪而不改公共代码。
API 参考
生命周期与事件
void btstack_ble_start_before_init(const ble_init_cfg_t *cfg, int param) 在控制器初始化前配置 BLE 参数。cfg 中的 same_address 必须在此阶段生效,因为地址分配发生在控制器初始化时。param 为保留扩展参数。
void btstack_ble_start_after_init(int param) 控制器初始化完成后启动 BLE 协议栈任务。必须在 btstack_ble_start_before_init 之后调用。
void btstack_ble_exit(int param) 退出 BLE:停止协议栈任务并释放相关资源,用于切换模式(如仅 EDR)或关机流程。
int bt_comm_ble_status_event_handler(struct bt_event *bt) BLE 状态事件分发入口。bt 指向协议栈填充的事件结构;返回非 0 表示事件已被消费。与 HCI 事件处理器配合完成连接/断开/配对状态机推进。
int bt_comm_ble_hci_event_handler(struct bt_event *bt) HCI 层事件分发入口,负责按 HCI_EVENT_* 宏分发到具体处理分支(连接完成、断开、SSP 确认、重连地址等)。
连接与配对控制
void bt_wait_phone_connect_control(u8 enable) 统一开关「等待手机连接」:enable 非 0 打开可发现与可连接,0 关闭。适合按键进入配对模式的简单场景。
void bt_wait_phone_connect_control_ext(u8 inquiry_en, u8 page_scan_en) 细分控制:inquiry_en 控制 Inquiry Scan(被发现),page_scan_en 控制 Page Scan(被连接)。可独立实现「可被发现但暂不接受连接」的窗口逻辑。
void __set_simple_pair_flag(bool flag) 简易配对(SSP)总开关。关闭后回退到传统配对流程(PIN Code 输入),用于兼容老旧设备。
void le_hogp_set_reconnect_adv_cfg(u8 adv_type, u32 adv_timeout) HOGP(HID over GATT)重连广播配置:adv_type 选择广播类型(可连接直连广播等),adv_timeout 限制重连广播的持续时间,超时后停止广播以省电。
DUT 测试(ble_test_api.c)
void ble_dut_mode_init(void) 初始化 DUT 测试会话:ll_hci_destory() 拆除链路层后经 __ble_dut_ops->init() 建立测试控制通道。静态句柄保证单实例,重复调用直接返回。
void ble_fix_fre_api() 进入定频连续发射:先 bt_ble_adv_enable(0) 停止广播,延时 10 tick 后以 PAYLOAD_TYPE_10101010、continuous_tx = 1 调用 ble_enter_dut_tx_mode。调用前必须退出睡眠模式。
void ble_enter_dut_tx_mode(void *param)(库导出,外部声明) 按 struct ble_dut_param_set 参数启动 DUT TX。ch_index 0~39 对应 2402~2480 MHz,payload_type/payload_len/continuous_tx 决定载荷与是否连续发射。
void bt_ble_adv_enable(u8 enable)(库导出,外部声明) 使能/禁止 BLE 广播,DUT 入口用它先关闭正常广播。
失败模式与边界情况
- Page 取消语义区分:
CUSTOM_BB_AUTO_CANCEL_PAGE(0xFD,应用发起)与BB_CANCEL_PAGE(0xFE,基带超时)必须分开处理——前者是用户主动行为(如按键停止搜索),后者是系统被动失败(如ERROR_CODE_PAGE_TIMEOUT)。混淆两者会导致 UI 状态与空口行为不一致。 - 配对失败码映射:
ERROR_CODE_AUTHENTICATION_FAILURE/PIN_OR_KEY_MISSING/CONNECTION_ACCEPT_TIMEOUT_EXCEEDED等错误码在事件处理器中应映射为不同的用户提示(PIN 错误、超时、对端拒绝),公共层只提供语义化常量,提示策略由应用决定。 - 断开时序:
WAIT_DISCONN_TIME_MS(1000ms)是断开动作的时间窗;若上层立即释放资源可能破坏正在进行的 L2CAP/SM 断链握手,公共层用它保证状态机在断链完成后才复位。 - DUT 与睡眠互斥:DUT 连续发射期间必须退出睡眠(源码注释明确警告)。若固件在 DUT 会话中进入睡眠,射频发射将被挂起,频谱测量失败且可能卡死测试流程。
- DUT 单实例约束:
ble_dut_hdl非空时ble_dut_mode_init不再重新初始化,重复进入 DUT 不会二次销毁链路层,避免悬挂指针。 - 并发/中断:
bt_test_status声明为volatile,因它可能被任务上下文与中断上下文同时读写;任何基于它的状态机判断都应视为弱同步(无原子保护),临界区需由调用方保证。 - 双模地址冲突:
ble_init_cfg_t.same_address = 0时 BLE 与 EDR 地址独立,若上层未同步管理两份地址,跨协议(如手机先连 BLE 再连 EDR)的绑定记录可能失配;same_address = 1可规避但限制地址自定义空间。
性能与运维注意
- Sniff 功耗:
check_timer_period与cnt_time控制 EDR 空闲后进入 Sniff 的时机;cnt_time越大空口越安静但省电越慢,timeout_slots越小 Sniff 唤醒越频繁。量产固件应按平均连接间隔调参,避免过度频繁的 Sniff 尝试影响连接保持。 - DUT 测试为独占模式:DUT 会话销毁正常链路层(
ll_hci_destory),测试后需完整重启协议栈才能恢复业务,产测固件通常设计为测试完成即复位。 - 日志裁剪:
LOG_TAG "[BT_DUT]"配合LOG_DUMP_ENABLE等宏,量产固件应关闭 DUMP 级日志以减小代码体积与日志吞吐开销。
扩展点
__ble_dut_ops操作表:DUT 控制通过函数指针表访问控制器能力,新芯片/库版本只需提供同签名实现即可复用ble_test_api.c全部逻辑。struct bt_event事件分发:两个 event handler 是公共层留给应用的状态机钩子,应用可在其中挂接自己的连接/配对状态机,而无需修改协议栈。edr_init_cfg_t/ble_init_cfg_t:通过指针字段(report_map、sniff_param)注入业务特有数据,HID 类应用可在不修改公共层的前提下提供自定义报告描述符与 Sniff 参数。- 编译期裁剪:
TCFG_NORMAL_SET_DUT_MODE_API、TCFG_USER_BLE_ENABLE、CONFIG_BT_MODE决定编入范围,同一份公共代码可服务产测固件与量产固件两种形态。
Related Links
- app_comm_bt.h 公共接口头文件
- ble_test_api.c DUT 测试实现
- btcontroller_modules.h 控制器模块声明
- btctrler_task.h 控制器任务/队列定义
- hci_transport.h HCI 传输层接口
- HID/Transfer demo 的协议栈裁剪配置(
apps/demo/hid/config/lib_btstack_config.c、apps/demo/transfer/config/lib_btctrler_config.c)属于各应用页面的范围
使用示例
以下示例仅使用本页已核实的头文件契约与实现片段进行组装,展示应用如何把公共层的配置结构与 API 串联起来(实际接入点位于各 demo 应用源码,如 apps/demo/hid、apps/demo/transfer)。
组装 BLE 初始化配置并启动
BLE 启动分两步走:先 before_init 让地址策略生效,后 after_init 拉起协议栈:
/* 按 app_comm_bt.h 中的 ble_init_cfg_t 契约组装 */
ble_init_cfg_t ble_cfg = {
.same_address = 1, /* BLE 与 EDR 共用地址,简化双模绑定 */
.appearance = 0x0040, /* 搜索时显示的图标(Audio Sink 类) */
.report_map_size = 0, /* 非 HOGP 场景可不提供报告描述符 */
.report_map = NULL,
};
btstack_ble_start_before_init(&ble_cfg, 0); /* 控制器初始化前配置 */
/* ... 控制器初始化由库完成 ... */
btstack_ble_start_after_init(0); /* 初始化完成后启动 BLE 任务 */
在事件处理器中按 HCI 事件码分发
事件处理器返回 int 表示是否消费,公共层用宏定义把裸事件码翻译成语义:
int app_bt_event_dispatch(struct bt_event *bt)
{
/* 先经公共层状态事件,再走 HCI 事件分发 */
bt_comm_ble_status_event_handler(bt);
switch (bt->event) {
case HCI_EVENT_CONNECTION_COMPLETE: /* 0x03 连接建立 */
/* 记录对端地址、更新 UI 为已连接 */
return 1;
case HCI_EVENT_DISCONNECTION_COMPLETE: /* 0x05 连接断开 */
/* 等待 WAIT_DISCONN_TIME_MS 后复位状态机 */
return 1;
case CUSTOM_BB_AUTO_CANCEL_PAGE: /* 0xFD 用户主动取消搜索 */
/* 区别于 BB_CANCEL_PAGE(0xFE) 被动取消 */
return 1;
}
return 0; /* 未消费,交由其他模块处理 */
}
产测固件进入 BLE 定频发射
在 TCFG_NORMAL_SET_DUT_MODE_API 开启的产测固件中,初始化 DUT 会话后即可定频连续发射:
/* 1. 建立 DUT 会话(销毁正常链路层,经 __ble_dut_ops 创建测试通道) */
ble_dut_mode_init();
/* 2. 进入定频连续发射:停广播 → 延时 → 注入 10101010 连续载荷 */
ble_fix_fre_api();
/* 内部等价于:
* bt_ble_adv_enable(0);
* os_time_dly(10);
* struct ble_dut_param_set p = { .ch_index=0, .payload_type=PAYLOAD_TYPE_10101010,
* .payload_len=0x20, .continuous_tx=1 };
* ble_enter_dut_tx_mode(&p);
*/
使用约束:上述 DUT 调用前必须确保已退出睡眠模式(源码注释的硬性要求),且测试完成后需复位系统才能恢复正常协议栈业务。