4、链路层(LL)基础:状态机、数据包与过滤策略
链路层,也就是咱们常说的 LL 层,是蓝牙协议栈里最核心的模块之一。它直接跑在物理层之上,负责设备之间的连接建立、数据收发和功耗控制。说白了,没有 LL 层,两个蓝牙设备连最基本的“握手”都做不到。
我个人习惯把 LL 层看作一个“有限状态机”——设备在任一时刻只能处于一种状态,状态之间通过特定事件跳转。理解了这个状态机,你就掌握了蓝牙通信的骨架。
4.1 链路层状态机
蓝牙 LL 层定义了 5 种基本状态:Standby、Advertising、Scanning、Initiating 和 Connection。它们之间的关系可以用下面这张图来概括。
核心要点:所有蓝牙通信都从 Standby 开始,最终要么回到 Standby,要么进入 Connection。
4.2 各状态详解
4.2.1 Standby(待机状态)
这是设备的初始状态和默认状态。此时设备不发送任何数据,也不接收任何数据。功耗最低,但什么也干不了。所有其他状态都可以直接回到 Standby。
4.2.2 Advertising(广播状态)
设备在广播信道上周期性发送广播包。广播包可以包含设备名称、服务 UUID、厂商自定义数据等。我遇到过不少初学者把广播包塞得满满当当,结果导致连接建立变慢——广播包越长,被其他设备扫描到的概率越低。
经验之谈:广播间隔建议在 20ms 到 10.24s 之间。间隔越短,被发现越快,但功耗也越高。做低功耗产品时,我一般把间隔设在 100ms 以上。
4.2.3 Scanning(扫描状态)
扫描设备在广播信道上监听广播包。扫描分为两种:
- 被动扫描:只收不发,不回复任何内容。
- 主动扫描:收到广播包后,会发送扫描请求,获取更详细的广播数据。
嗯,这里要注意:主动扫描会多一次空中交互,功耗更高,但能拿到更多信息。做 Beacon 类产品时,我通常用被动扫描就够了。
4.2.4 Initiating(发起连接状态)
设备在广播信道上监听特定设备的广播包,一旦收到就发送连接请求。这个状态是连接建立的“临门一脚”。
4.2.5 Connection(连接状态)
连接建立后,设备进入连接状态。此时双方在数据信道上按约定的时序收发数据。连接状态又分为:
- Master Role(主设备):决定连接时序,控制数据发送时机。
- Slave Role(从设备):跟随主设备的时序,在指定时间窗口内收发数据。
4.3 空中数据包格式
蓝牙 LL 层的数据包结构非常固定。每个包由 4 个部分组成:
| 字段 | 长度 | 说明 |
|---|---|---|
| Preamble | 1 字节 | 前导码,用于接收端同步时钟。固定为 0xAA 或 0x55 |
| Access Address | 4 字节 | 接入地址。广播包固定为 0x8E89BED6;数据包使用随机生成的地址 |
| PDU | 2~257 字节 | 协议数据单元,包含实际数据和控制信息 |
| CRC | 3 字节 | 循环冗余校验,用于检测数据完整性 |
避坑指南:我曾经在一个项目中,因为 Access Address 配置错误,导致两个设备明明在同一个房间,却死活连不上。后来用抓包工具一看,数据包的 Access Address 和广播包的完全不一样——接收端直接丢弃了所有包。记住:广播包的 Access Address 是固定的,数据包的必须由主设备在连接建立时分配。
4.3.1 PDU 详解
PDU 是数据包的核心。它又分为:
- 广播信道 PDU:用于广播、扫描和发起连接。包含 ADV_IND、SCAN_REQ、CONNECT_REQ 等类型。
- 数据信道 PDU:用于连接状态下的数据收发。包含 LL_DATA 和 LL_CONTROL 两种。
一个典型的广播包 PDU 结构如下:
广播信道 PDU 格式:
+--------+--------+------------------+
| 头(2B) | 负载 | 可选(如扫描响应) |
+--------+--------+------------------+
头字段:
- PDU 类型 (4 bit)
- RFU (2 bit)
- ChSel (1 bit)
- TxAdd (1 bit)
- RxAdd (1 bit)
- 长度 (8 bit)
- RFU (3 bit)
4.4 白名单与过滤策略
白名单是 LL 层提供的一种硬件级过滤机制。说白了,就是告诉蓝牙芯片:我只跟名单里的设备通信,其他的统统忽略。
4.4.1 白名单的作用
- 减少干扰:只处理目标设备的包,降低 CPU 负载。
- 提升安全性:防止未授权设备接入。
- 降低功耗:不需要的包直接丢弃,芯片不用唤醒。
4.4.2 白名单的配置
白名单可以基于设备地址(BD_ADDR)或地址类型(Public/Random)进行过滤。配置时通常需要:
- 将目标设备的地址写入白名单列表。
- 设置过滤策略(如:只接受白名单内的广播包)。
- 启动广播或扫描时启用白名单。
实际案例:我在做智能门锁项目时,门锁作为从设备,只接受手机 App 的连接。我把手机的蓝牙地址写入门锁的白名单,其他设备发来的连接请求全部被 LL 层自动丢弃。这样既省电又安全。
4.4.3 过滤策略对比
| 策略 | 描述 | 适用场景 |
|---|---|---|
| 无过滤 | 处理所有收到的包 | 调试阶段、通用扫描器 |
| 白名单过滤 | 只处理白名单内的设备 | 配对设备、私有网络 |
| 地址类型过滤 | 只处理 Public 或 Random 地址 | 区分设备类型 |
| RSSI 过滤 | 只处理信号强度高于阈值的包 | 近距离触发、防误触 |
小技巧:白名单的条目数有限(通常 8~32 条)。如果你的设备需要连接多个设备,可以考虑用软件层做二次过滤,或者使用 Resolvable Private Address(可解析私有地址)配合 IRK 进行动态匹配。
好了,链路层的基础就讲到这里。记住状态机的流转、数据包的格式、白名单的用法,后面讲连接建立和 LE Audio 时,你会反复用到这些知识。