链路层状态机与连接建立

BLE 链路层(Link Layer)是蓝牙核心协议栈中直接控制射频收发、状态转换和连接维护的实体。本章围绕链路层的五种基本状态、广播与扫描的时序机制、连接参数协商流程以及通过 HCI 命令对连接进行精确控制展开,为后续实现本地持久化中的连接管理与数据同步打下基础。

链路层角色与状态机

BLE 链路层定义了五种互斥状态:待机(Standby)、广播(Advertising)、扫描(Scanning)、发起(Initiating)和连接(Connection)。每个时刻链路层只能处于其中一种状态,状态转换由主机通过 HCI 命令或内部定时事件触发。

状态角色说明
Standby空闲不发送或接收任何数据包,最低功耗
Advertising广播者(Advertiser)周期性发送广播包,可携带扫描响应数据
Scanning扫描者(Scanner)监听广播信道,接收广播包与扫描响应
Initiating发起者(Initiator)针对特定广播者发送连接请求,建立连接
Connection主设备/从设备在已建立的连接中按锚点时间收发数据

状态转换的典型路径:Standby → Advertising(开启广播),Standby → Scanning(开始扫描),Scanning → Initiating(匹配到目标后发起连接),Initiating → Connection(收到连接响应后进入连接态)。

要点:链路层状态机是 BLE 协议栈中最核心的有限状态机,所有连接建立与数据通信都以此为基础。理解状态转换条件,是调试连接失败问题的第一步。
BLE 链路层状态机及连接建立路径 Standby Advertising Scanning Initiating Connection HCI_LE_Set_Advertising_Enable HCI_LE_Set_Scan_Enable HCI_LE_Create_Connection 禁用广播 禁用扫描 发现目标 CONNECT_REQ + 响应 断开 / 超时 连接建立关键路径:Standby → Advertising(广播) ↔ Scanning(扫描) → Initiating → Connection 虚线表示可选或条件转换;实线为典型主动连接流程

广播与扫描过程

广播和扫描是连接建立的前置步骤。广播者在三个广播信道(37/38/39)上交替发送 ADV_IND 或 ADV_DIRECT_IND 等 PDU;扫描者在相同信道上监听并接收广播包,可选择发送扫描请求以获取额外数据。

广播时序参数

参数范围说明
advInterval20 ms – 10.24 s连续广播事件间的间隔,步进 0.625 ms
advDelay0 – 10 ms每个广播事件前的随机延迟,防碰撞
advChannelMapbit 0-2启用哪些广播信道(37/38/39)

扫描时序参数

参数范围说明
scanInterval2.5 ms – 10.24 s两次扫描间的间隔
scanWindow2.5 ms – scanInterval每次扫描的监听时长
scanType被动 / 主动被动只接收;主动可发送扫描请求
实践建议:广播间隔越短,被发现越快,但功耗越高。对于本地持久化场景(如信标数据采集),推荐使用 100–200 ms 广播间隔,扫描窗设置为 scanInterval 的 50%–80%,以平衡发现延迟和功耗。

连接参数协商

当发起者发送 CONNECT_REQ PDU 后,连接参数在连接请求中一次性确定,随后可通过 连接参数更新请求(LL_CONNECTION_PARAM_REQ)在连接建立后进行协商。核心参数包括:

参数典型范围说明
connInterval7.5 ms – 4 s两个连接事件之间的间隔
connLatency0 – 499从设备可跳过的最大连接事件数
supervisionTimeout100 ms – 32 s连接超时时间,超过未收到数据则判定断开

协商流程通常由从设备发起(例如需要更低的延迟传输数据):

  1. 从设备发送 LL_CONNECTION_PARAM_REQ,包含期望的参数范围。
  2. 主设备收到后,根据自身能力与当前负载决定接受或拒绝。
  3. 若接受,主设备回复 LL_CONNECTION_PARAM_RSP;若拒绝,可提出替代值。
  4. 双方应用新参数从下一个连接事件开始生效。
注意:连接参数更新请求不应过于频繁(建议每次请求间隔 > 5 秒),否则可能被主设备视为无效请求而忽略,甚至触发 supervision timeout。

使用 HCI 命令控制连接

主机(Host)通过 Host-Controller Interface(HCI)向链路层发送命令。建立连接最常用的 HCI 命令序列如下:

1. 设置广播参数并开启广播

# HCI 命令示例 (使用 hcitool/btmgmt 或直接发送 HCI 数据包)
# 设置广播参数:间隔 100ms,类型为可连接广播
hcitool -i hci0 cmd 0x08 0x0006 0xA0 0x00 0xA0 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x07 0x00
# 开启广播
hcitool -i hci0 cmd 0x08 0x000A 0x01

2. 设置扫描参数并开启扫描

# 设置扫描间隔 60ms,扫描窗口 60ms,主动扫描
hcitool -i hci0 cmd 0x08 0x000C 0x60 0x00 0x60 0x00 0x01 0x00
# 开启扫描
hcitool -i hci0 cmd 0x08 0x000D 0x01 0x00

3. 发起连接(指定目标 MAC)

# 发起连接:目标地址 11:22:33:44:55:66,连接间隔 30ms,延迟 0,超时 4s
hcitool -i hci0 cmd 0x08 0x000D 0x00 0x60 0x00 0x60 0x00 0x00 0x00 0x11 0x22 0x33 0x44 0x55 0x66 0x00 0x00 0x30 0x00 0x00 0x00 0x10 0x00

实际开发中通常使用 BlueZ 提供的 hcitool lecc 或 bluetoothctl connect 等高层工具,但底层均映射为上述 HCI 命令。在嵌入式环境中(如 Zephyr、NimBLE),则直接调用 HCI API:

/* Zephyr 中发起连接示例 */
struct bt_le_conn_param *param = BT_LE_CONN_PARAM(24, 40, 0, 400);
struct bt_conn *conn;
int err = bt_conn_le_create(&peer_addr, BT_CONN_LE_CREATE_CONN, param, &conn);
if (err) {
    printk("连接创建失败: %d\n", err);
}

常见错误与修复

现象可能原因解决方案
扫描不到广播包广播信道被禁用;扫描窗过短;射频冲突检查 advChannelMap;增大 scanWindow;检查天线匹配
连接请求无响应目标设备已进入连接态;广播类型不可连接确认广播类型为 ADV_IND 或 ADV_DIRECT_IND;重置目标状态
连接频繁断开supervisionTimeout 过小;连接间隔不匹配增大超时值;确保主从设备连接参数兼容
参数更新被拒绝请求参数超出主设备能力范围读取主设备支持的参数范围,调整至合理区间

调试时建议开启蓝牙芯片的 HCI 日志(如 Zephyr 的 CONFIG_BT_HCI_RAW_LOG),实时观察 HCI 命令与事件流:

# 开启 btmon 监控 HCI 流量(Linux)
btmon -w hci_log.pklg
# 实时查看
btmon -r

性能与稳定性优化

  • 广播拥塞控制:在广播密集型场景(如数十个设备同时广播),将 advDelay 随机化范围适当增大到 5–10 ms,降低碰撞概率。
  • 扫描窗口适配:若扫描功耗敏感,可采用 间歇扫描 策略:扫描 100 ms、休眠 900 ms,而非持续全速扫描。
  • 连接参数自适应:在本地持久化场景中,批量数据传输时使用短间隔(15–30 ms),空闲时切换回长间隔(200–500 ms)并增大 latency,降低功耗。
  • 超时冗余:设置 supervisionTimeout 为连接间隔的 10–20 倍以上,防止瞬时射频干扰导致意外断开。
  • 信道规避:在 2.4 GHz 干扰严重的环境中,通过 advChannelMap 避开拥堵信道(如仅使用 38、39 信道)。
调优指标:在项目中可以通过统计 连接建立成功率(成功连接 / 发起连接总数)和 平均连接建立时间(从发起连接请求到收到连接完成事件)来量化状态机与参数配置的合理性。建议在本地持久化模块中记录这两项指标,用于长期稳定性监控。