3、链路层(LL)基础:状态机、设备角色与数据包结构

链路层,简称 LL,是 BLE 协议栈里最核心的一层。说白了,它负责两件事:什么时候发数据,以及数据长什么样。我刚开始接触 BLE 时,总觉得 LL 就是个调度器,后来踩了几个坑才明白——不理解 LL,你连连接都建不起来。

3.1 链路层状态机——设备在干什么?

BLE 设备在任何时刻都处于五种状态之一。这五种状态构成了链路层的状态机,也是整个 BLE 通信的基础。

五种状态:待机(Standby)、广播(Advertising)、扫描(Scanning)、发起连接(Initiating)、连接(Connection)。

状态之间的跳转有严格规则。你不能从广播直接跳到扫描,也不能从连接直接跳到发起。我画了一张图,帮你理清这个关系。

BLE 链路层状态机 BLE 链路层状态机 待机 (Standby) 广播 (Advertising) 扫描 (Scanning) 发起连接 (Initiating) 连接 (Connection) 进入广播 进入扫描 停止广播 停止扫描 收到广播 连接请求成功 断开连接 可连接广播 虚线表示非直接跳转,需经过特定事件触发

嗯,这里要注意:待机状态是唯一一个可以从任何状态进入的状态。你想想看,设备上电后默认就在待机,然后根据应用需求决定下一步做什么。

3.2 设备角色——谁在说话,谁在听?

状态机定义了设备在干什么,但设备在通信中扮演什么角色,是由设备角色决定的。BLE 4.0/4.1 定义了四种角色,我习惯把它们分成两组:

角色 对应状态 典型设备 一句话描述
广播者 (Advertiser) 广播 传感器、信标 我在这,快来连我
扫描者 (Scanner) 扫描 手机、网关 谁在广播?我看看
主机 (Master) 连接(发起方) 手机、中心设备 我来控制连接节奏
从机 (Slave) 连接(被发起方) 手环、耳机 听主机安排

我的经验:一个设备可以同时是广播者和扫描者吗?可以。比如手机在扫描周围设备的同时,也可以广播自己的信息。但注意,同一时刻只能处于一个状态,角色是时分复用的。

我记得有一次做项目,客户要求一个设备既能被手机连接,又能扫描其他传感器。我一开始想当然地让设备同时做两件事,结果发现广播间隔和扫描窗口冲突了。后来我用了交替调度——广播 30ms,扫描 30ms,再广播 30ms……虽然吞吐量降了,但功能都跑通了。

3.3 链路层数据包结构——数据长什么样?

链路层的数据包,官方叫 PDU(Protocol Data Unit)。不管你是广播包还是数据包,底层都遵循同一套结构。我把它拆成三部分:

  • 前导码 (Preamble):1 字节,用于接收端同步时钟。固定为 0xAA 或 0x55。
  • 访问地址 (Access Address):4 字节。广播包固定为 0x8E89BED6,数据包是随机生成的。
  • PDU:2~257 字节,包含实际数据。
  • CRC:3 字节,校验数据完整性。

你想想看,为什么广播包的访问地址是固定的?因为扫描者不知道谁会广播,必须用一个大家都认识的地址来监听。而连接后的数据包,地址是随机生成的,这样别的设备就不会误收你的数据。

3.3.1 广播信道 PDU

广播包有两种类型:

类型 PDU 长度 用途
广播指示 (ADV_IND) 6~37 字节 可连接的非定向广播
扫描请求 (SCAN_REQ) 12 字节 扫描者请求更多信息
扫描响应 (SCAN_RSP) 6~37 字节 广播者回复扫描请求
连接请求 (CONNECT_REQ) 34 字节 发起连接,包含连接参数

避坑指南:我曾经在广播包里塞了太多厂商自定义数据,结果超过 31 字节的载荷上限。扫描者收到后直接丢弃了整个包。后来我才知道,广播包 PDU 的载荷最大 31 字节,超过就得用扫描响应来补充。

3.3.2 数据信道 PDU

连接建立后,数据在数据信道上传送。数据 PDU 分为两种:

  • LL 数据 PDU:承载上层(L2CAP)数据,最大 251 字节。
  • LL 控制 PDU:用于链路层管理,比如更新连接参数、加密等。

数据 PDU 的头部只有 2 字节,但包含了很多信息:

LL 数据 PDU 头部(2 字节):
  - LLID (2 bits):标识是数据还是控制包
  - NESN (1 bit):下一个期望的序列号
  - SN (1 bit):当前包的序列号
  - MD (1 bit):是否还有更多数据要发
  - RFU (3 bits):保留
  - Length (8 bits):载荷长度

嗯,这里 SN 和 NESN 是 BLE 可靠传输的关键。每次发送一个包,SN 翻转一次;接收端用 NESN 告诉对方“我收到了,请发下一个”。如果丢包了,NESN 不变,发送端就会重传。

3.4 链路层的关键机制

除了状态机和数据包,链路层还有几个机制,我挑两个最重要的说说。

3.4.1 白名单 (White List)

白名单是一组设备地址。只有在白名单里的设备,才能收到你的广播,或者才能连接你。我习惯用白名单来做设备过滤,避免无关设备干扰。

我的习惯:在量产项目中,我会把白名单放在 OTP(一次性可编程)区域。这样设备出厂后,白名单就不能改了,安全性高很多。

3.4.2 连接参数更新

连接建立后,主机和从机可以协商更新连接参数,包括:

  • 连接间隔 (Connection Interval):7.5ms ~ 4s
  • 从机延迟 (Slave Latency):0~499 个事件
  • 监督超时 (Supervision Timeout):100ms ~ 32s

我记得有一次做低功耗项目,把连接间隔设成了 400ms,从机延迟设成了 9。结果设备在大部分时间都在睡觉,功耗降到了 10μA 以下。但代价是响应延迟变大了——按个按钮,要等 4 秒才有反应。所以低功耗和低延迟是矛盾的,你得根据应用场景做取舍。

3.5 本章小结

链路层是 BLE 的基石。你理解了状态机,就知道设备在干什么;理解了角色,就知道谁控制谁;理解了数据包结构,就能读懂空中飞过的每一帧数据。我个人觉得,LL 是 BLE 协议栈里最值得花时间啃的部分——啃透了,后面的 L2CAP、ATT、GATT 都会轻松很多。