3、链路层基础:状态机、角色、连接建立与数据包格式
链路层(Link Layer)是 BLE 协议栈里最核心的一层,没有之一。它直接控制着射频的收发、状态切换、连接管理。说白了,你上层再怎么花哨,最终都得靠链路层把数据变成无线信号发出去。
我个人习惯把链路层理解成一个“有限状态机”——它永远只处于某一种状态,收到特定事件后才会跳转到下一个状态。搞懂了状态机,你就搞懂了 BLE 设备在干什么。
3.1 链路层状态机
BLE 链路层定义了 5 种基本状态:
- Standby(待机)—— 啥也不干,射频关闭。
- Advertising(广播)—— 向外发送广播包,让别人发现我。
- Scanning(扫描)—— 监听广播包,看看周围有没有设备。
- Initiating(发起连接)—— 收到广播后主动发起连接请求。
- Connection(连接)—— 已经建立连接,按固定间隔收发数据。
状态之间的跳转关系,我画了一张图,你一看就明白:
嗯,这里要注意:Connection 状态是终点。一旦进入连接,就只能断开回到 Standby,不能直接跳到广播或扫描。为什么?因为连接是点对点的,已经占用了固定的射频资源,不能再干别的事。
3.2 设备角色:Master 与 Slave
连接建立后,两个设备就有了明确的分工:
| 角色 | 职责 | 典型设备 |
|---|---|---|
| Master(主设备) | 决定连接时序,发起数据包交换 | 手机、平板、PC |
| Slave(从设备) | 跟随主设备的时序,响应数据包 | 手环、传感器、耳机 |
说白了,Master 是“发令枪”,Slave 是“跟跑者”。Master 在每个连接事件(Connection Event)开始时先发一个包,Slave 收到后才能回复。如果 Slave 没收到,那就得等下一个连接事件。
我记得刚做 BLE 项目时,有个同事把 Master 和 Slave 搞反了——从设备一直主动发数据,结果主设备根本不收。折腾了两天才发现是角色配置错了。你想想看,如果连谁先说话都没定好,通信肯定乱套。
3.3 连接建立过程
连接建立不是一蹴而就的,它分三步走:
- 广播阶段:Slave(通常是外设)在广播信道上发送 ADV_IND 或 ADV_DIRECT_IND 包。
- 扫描阶段:Master 在广播信道上扫描,收到广播包后,如果感兴趣,就进入 Initiating 状态。
- 连接请求:Master 发送 CONNECT_REQ 包,里面包含了连接参数(连接间隔、延迟、超时时间等)。
一旦 Slave 收到 CONNECT_REQ 并确认,双方就进入 Connection 状态。从这一刻起,它们不再使用广播信道,而是切换到数据信道(37 个数据信道之一)进行通信。
关键点:CONNECT_REQ 包里的连接参数是 Master 决定的。Slave 只能接受或拒绝(拒绝就是不理它)。所以,如果你想让从设备有更多话语权,可以在广播数据里带上自己期望的连接参数,让 Master 参考。
3.4 数据包格式
BLE 链路层的数据包结构非常简洁。我直接给你看格式:
| 字段 | 长度(字节) | 说明 |
|---|---|---|
| Preamble | 1 | 同步序列,固定为 0xAA 或 0x55 |
| Access Address | 4 | 连接唯一标识,广播时为 0x8E89BED6 |
| PDU | 2~257 | 协议数据单元,包含头部和有效载荷 |
| CRC | 3 | 24 位循环冗余校验 |
PDU 内部又分两种:
- 广播信道 PDU:用于广播、扫描、发起连接。头部包含 PDU 类型、发送地址类型、接收地址类型等。
- 数据信道 PDU:用于连接后的数据交换。头部包含 LLID(链路层标识)、NESN/SN(序列号)、MD(更多数据)等。
这里有个坑,我踩过:Access Address 在广播阶段是固定的 0x8E89BED6,但连接建立后,Master 会在 CONNECT_REQ 里分配一个新的 Access Address。如果你在抓包时发现数据信道上的 Access Address 不是这个值,别慌,那是正常的。
3.5 数据包示例
给你看一个实际的广播包 PDU 结构(十六进制):
广播信道 PDU 示例:
02 00 00 00 01 02 03 04 05 06
解析:
- 第一个字节 0x02:PDU 类型 = ADV_IND(可连接的非定向广播)
- 第二个字节 0x00:发送地址类型 = 公共地址
- 第三~八字节:广播地址 = 00:00:01:02:03:04
- 后续字节:广播数据(本例中为 05 06)
数据信道 PDU 稍微复杂一点,因为它要处理流控和重传:
数据信道 PDU 示例(带 LLID 和数据):
1E 08 00 01 02 03 04 05
解析:
- 第一个字节 0x1E:LLID=01(数据 PDU 继续),NESN=1,SN=1,MD=0
- 第二个字节 0x08:有效载荷长度 = 8 字节
- 后续字节:实际数据
你想想看,如果没有这些序列号和确认机制,丢包了怎么办?BLE 的链路层通过 NESN/SN 实现了简单的停止等待 ARQ(自动重传请求)。Slave 收到包后,如果 CRC 校验通过,就翻转 NESN 表示确认;如果没通过,就不翻转,Master 会重传。
好了,链路层的基础就这些。状态机决定了设备的行为,角色决定了谁控制时序,连接建立是广播到连接的桥梁,数据包格式则是通信的“语法”。把这些搞明白,后面讲 GAP 和 GATT 时你会觉得轻松很多。