Skip to content

BLE 协议栈、角色与工作流程

1. 开发者需要看到哪几层

BLE 协议栈看起来层次很多,但在常见芯片 SDK 中,底层控制器、无线收发和大部分协议已经实现。开发者通常通过事件和 API 与 Host 交互。

可以用下面的方式记忆:

  • GAP 解决“设备如何被发现、如何连接、以什么安全级别交互”;
  • GATT 解决“连接后有哪些数据、能怎样访问”;
  • ATT 是 GATT 使用的属性传输机制;
  • SMP 处理配对、认证、密钥分发等安全过程;
  • L2CAP、Link Layer、PHY 更多由协议栈和控制器负责,但 MTU、连接参数、PHY 等会影响应用表现。

2. 不要把所有“角色”混在一起

BLE 中有几组处于不同层次的角色,它们可以组合,但不是同义词。

2.1 GAP 角色

  • Broadcaster:发送不可连接广播;
  • Observer:扫描广播;
  • Peripheral:发送可连接广播,并接受连接;
  • Central:扫描并发起连接。

手机通常是 Central,嵌入式设备通常是 Peripheral,但这只是常见组合,不是硬性规定。

2.2 GATT 角色

  • GATT Server:维护属性数据库,提供服务与特征值;
  • GATT Client:发现并访问 Server 的属性。

在“手机连接温度计”的场景中,温度计通常是 Peripheral + GATT Server,手机通常是 Central + GATT Client。

关键点

Central 不等于 GATT Client,Peripheral 也不等于 GATT Server。GAP 角色描述连接如何建立,GATT 角色描述属性数据由谁提供、由谁访问。在一条连接中,双方甚至可以同时各自拥有 GATT Server。

3. 广播与扫描

设备尚未连接时,通常通过广播宣布自己的存在。扫描端会依据广播内容进行过滤和展示。

常见广播内容包括:

  • Flags;
  • Local Name,完整或缩短的设备名;
  • Service UUID 列表;
  • Service Data;
  • Manufacturer Specific Data;
  • Appearance;
  • 发射功率等信息。

传统广播的主广播数据空间很紧张,不应把它当作任意长度的数据包。扩展广播提供了更大的能力,但是否能使用取决于控制器、协议栈、手机系统和产品兼容目标。

广播里的设备名不是唯一身份

多个设备可以拥有相同名称,名称也可能被固件修改或截断。App 应优先使用 Service UUID、Manufacturer Data 中的产品字段等信息进行筛选,不能只靠名称判断产品型号,更不应把名称当作安全凭据。

4. 从上电到业务通信的完整流程

具体系统可能调整部分步骤顺序,例如连接参数更新和 MTU 交换也可能由任意一方稍后发起。业务层不应假设“连接成功”就代表 GATT 已可立即使用。

5. 连接参数控制了延迟与功耗

5.1 Connection Interval

连接双方只在约定的连接事件附近唤醒。间隔较短通常能降低交互延迟、提高可用吞吐量,但会增加唤醒频率。

5.2 Peripheral Latency

允许 Peripheral 在没有数据时跳过一定数量的连接事件,以降低功耗。它会增加最坏情况下的响应延迟。

5.3 Supervision Timeout

在一段时间没有收到有效链路数据后,认为连接丢失。设置过短可能在干扰环境下频繁掉线,设置过长则会让应用较晚感知断线。

这些参数相互约束,操作系统也可能拒绝或调整设备提出的值。产品应定义“低延迟工作态”和“低功耗空闲态”的策略,而不是只配置一组参数。

6. 配对、绑定和加密的区别

  • Pairing(配对):双方协商安全能力、建立密钥的过程;
  • Encryption(加密):当前链路使用密钥保护空中数据;
  • Bonding(绑定):双方保存长期密钥,以便下次重连恢复受信关系;
  • Authentication(认证):提供一定程度的对端身份确认,能力取决于配对方式和输入输出条件。

“连接成功”不代表已加密,“已加密”也不必然代表能够抵抗中间人攻击。没有屏幕和按键的设备采用 Just Works 时,产品应明确其安全边界,并考虑二维码、按键确认、应用层认证或出厂密钥等补充机制。

7. 设备工作状态

从固件角度看,“已连接”只是链路建立成功,并不一定已经可以交换业务数据。一个依赖 Notify 上报数据的 Peripheral,可以使用下面的状态机:

各状态的职责如下:

状态设备正在做什么可以处理业务吗
Init初始化控制器、Host、GATT 服务和广播数据不可以
Advertising周期发送广播,等待 Central 连接不可以
LinkConnected链路已建立,保存 connection handle 和连接参数通常还不可以
Securing配对、恢复绑定关系或等待链路加密不可以
AwaitSubscribe等待客户端订阅 Notify/Indicate,或完成应用握手视产品协议而定
ReadyMTU、权限、订阅等前置条件满足可以
Busy处理命令、采样或发送一组数据只接受状态允许的操作

并非所有产品都需要完整复制这些状态。例如只提供 Read/Write 的简单设备不必等待 CCCD,可以在连接和安全条件满足后直接进入 Ready。关键是不要只使用一个 connected 布尔值描述所有阶段。

7.1 事件驱动,而不是延时驱动

状态切换应该由协议栈事件触发:

  • 收到连接完成事件后进入 LinkConnected;
  • 收到加密状态事件后结束 Securing;
  • 收到 CCCD 写入事件后记录该连接的订阅状态;
  • 收到断开事件后释放本连接的 MTU、订阅、分包和业务上下文;
  • 确认服务与广播参数仍有效后重新进入 Advertising。

固定等待 500 ms 再假设订阅成功,只适合作为临时兼容措施,不应替代对完成事件和状态的判断。

8. 本篇小结

GAP 负责相遇与建立关系,GATT 负责连接后的结构化数据访问。对业务代码而言,BLE 是异步事件系统:扫描、连接、服务发现、订阅、安全和断开都应按状态推进,而不是把 API 调用当作同步串行函数。

参考资料