2. GAP层核心概念与广播模式
2.1 原理与设计模式意图
GAP(Generic Access Profile)是BLE协议栈的顶层控制层,负责设备发现、连接建立和广播行为管理。GAP定义了四种角色:Broadcaster(仅发送广播)、Observer(仅扫描)、Peripheral(发送广播并接受连接)、Central(扫描并发起连接)。本章聚焦于广播模式的核心要素。
设计模式意图:GAP层采用“状态机+观察者”复合模式。广播状态机管理设备在可发现、可连接、非连接等状态间的迁移;观察者模式将广播事件(如扫描结果、广播数据更新)通知上层应用,实现解耦。
2.2 核心概念与关键属性
| 概念 | 说明 | 典型参数 |
|---|---|---|
| 广播角色 | 设备在广播中扮演的角色(仅广播 / 可连接广播 / 定向广播) | BLE_GAP_ADV_TYPE_NONCONN, BLE_GAP_ADV_TYPE_CONNECTABLE |
| 广播数据格式 | 遵循AD Structure(AD Type + AD Data)格式,最大31字节 | AD Type: Flags, Tx Power, Local Name 等 |
| 广播间隔 | 两次广播事件之间的时间间隔,单位0.625ms | min 20ms, max 10.24s(具体受限) |
| 扫描响应 | 主动扫描时,设备可回复额外的AD数据(最多31字节) | SCAN_RSP data独立设置 |
2.3 广播数据格式详解
广播数据包(Advertising Data)和扫描响应数据包(Scan Response Data)都使用TLV结构:
- Length:1字节,后续AD Data长度(不含Length自身)
- AD Type:1字节,标识数据类型(0x01 Flags, 0x09 Complete Local Name等)
- AD Data:可变长度,具体数据内容
示例:广播包含“本地名称”和“Tx Power Level”:
// 准备广播数据:长度0x02 + AD Type 0x01 + Flags 0x06 (LE General Discoverable + BR/EDR Not Supported)
// 长度0x05 + AD Type 0x09 + "BT-100" 前5字节
uint8_t adv_data[] = {
0x02, 0x01, 0x06, // Flags
0x05, 0x09, 'B','T','-','1','0' // Complete Local Name 实际全名 "BT-100" 应填完
};
// 注意:长度字段是AD Data长度,不包含自身;实际编码时需严格计算
2.4 核心代码实现流程
以下代码使用nRF5 SDK的API展示广播初始化、数据配置与启动:
static void advertising_init(void)
{
ret_code_t err_code;
// 1. 配置广播参数结构体
ble_gap_adv_params_t adv_params;
memset(&adv_params, 0, sizeof(adv_params));
adv_params.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED;
adv_params.p_peer_addr = NULL; // 未指定对端地址
adv_params.fp = BLE_GAP_ADV_FP_ANY;
adv_params.interval = 0x00A0; // 160 * 0.625ms = 100ms
adv_params.timeout = 0; // 无超时
// 2. 设置广播数据(31字节限制)
ble_gap_adv_data_t adv_data;
adv_data.adv_data.p_data = m_adv_manuf_data; // 自定义数据缓冲
adv_data.adv_data.len = sizeof(m_adv_manuf_data);
adv_data.scan_rsp_data.p_data = m_scan_rsp_data;
adv_data.scan_rsp_data.len = sizeof(m_scan_rsp_data);
// 3. 启动广播
err_code = sd_ble_gap_adv_set_configure(&m_adv_handle, &adv_data, &adv_params);
APP_ERROR_CHECK(err_code);
err_code = sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG);
APP_ERROR_CHECK(err_code);
}
2.5 配置/参数/命令
常见广播间隔参数映射表(基于nRF5 SDK):
| interval值(单位0.625ms) | 实际时间 | 适用场景 |
|---|---|---|
| 0x0020 | 20 ms | 高速率连接(低延迟,耗电高) |
| 0x00A0 | 100 ms | 典型可连接广播 |
| 0x0640 | 1 s | 功耗优先的信标广播 |
| 0x4000 | 10.24 s | 极低功耗装置(受规范上限) |
扫描响应配置:与广播数据接口相同,但使用独立的缓冲区。SDK中通过 ble_gap_adv_data_t.scan_rsp_data 设置。
2.6 调试日志分析
典型的广播调试日志(基于RTT或UART输出):
<info> app: Advertising started (interval 100ms, type CONNECTABLE)
<debug> gap: sd_ble_gap_adv_set_configure: handle=0x01
<debug> gap: adv data set: len=12, type=0x06
<debug> gap: scan resp set: len=10, type=0x09
<warning> app: advertising timeout after 180s, restarting...
验证步骤:
- 使用nRF Connect或LightBlue扫描,确认广播包可见。
- 检查广播数据中的Flags字段(0x06表示可发现、非BR/EDR)。
- 测量实际广播间隔:使用逻辑分析仪或Sniffer对比配置值。
- 主动扫描时,验证扫描响应数据是否完整返回。
2.7 广播状态机与流程
2.8 易错点与优化建议
常见错误:
- 广播数据长度超标:广播数据+扫描响应总长度超过31+31=62字节(部分芯片广播数据单独不超过31字节)。
- AD Type未按规范放置:Flags字段必须放在第一个AD Structure,否则扫描设备可能忽略广播包。
- 广播间隔过短导致功耗飙升:非必要不要低于50ms,低频应用建议使用1s以上。
- 扫描响应未配置却期望收到:主动扫描仅能触发扫描响应,若扫描响应数据长度为0,则不会回复。
- 未设置可连接标志导致无法连接:如果广播类型是非连接型(NON_CONN),即使Central发起连接也会失败。
优化建议:
- 使用广播负载合并:将多个短AD Type合并到一个AD Structure(如把Tx Power和Local Name放在同一段)。
- 对于信标或广播应用,关闭扫描响应以省电并减少空口冲突。
- 动态调整广播间隔:连接时降低非必要广播频率,断开后恢复。
- 利用定向广播(Directed Advertising)减少连接延迟:需要指定对端地址,仅适用于已知设备快速重连。
- 在调试阶段开启Stack的Logging(例如nRF5 SDK的
NRF_LOG_DEBUG)实时观察广播事件。
2.9 部署验证清单
| 检查项 | 验证方法 | 预期结果 |
|---|---|---|
| 广播设备可见 | 使用Sniffer或手机APP扫描 | 设备名称正确显示,无乱码 |
| 广播间隔准确 | Sniffer测量两次广播事件间隔 | 偏差≤±20% |
| 扫描响应可获取 | 主动扫描后查看scan resp数据 | 包含额外数据(如服务UUID) |
| 连接建立正常 | 使用Central连接并订阅服务 | 连接成功,广播自动停止 |
| 功耗符合预期 | 电流测量仪监测 | 广播态平均电流在50µA~500µA之间 |