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.625msmin 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)实际时间适用场景
0x002020 ms高速率连接(低延迟,耗电高)
0x00A0100 ms典型可连接广播
0x06401 s功耗优先的信标广播
0x400010.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...

验证步骤:

  1. 使用nRF Connect或LightBlue扫描,确认广播包可见。
  2. 检查广播数据中的Flags字段(0x06表示可发现、非BR/EDR)。
  3. 测量实际广播间隔:使用逻辑分析仪或Sniffer对比配置值。
  4. 主动扫描时,验证扫描响应数据是否完整返回。

2.7 广播状态机与流程

GAP广播状态机与数据流 闲置 广播参数配置 广播进行中 扫描响应回复 连接建立 / 停止 主动扫描请求 继续广播 广播数据:31字节TLV 扫描响应数据:31字节TLV 总限制:广播+扫描响应 ≤ 62字节 广播间隔:可配置20ms ~ 10.24s 注意:非连接广播无扫描响应

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之间