4. HCI协议详解

HCI(Host Controller Interface)是蓝牙协议栈中主机(Host)与控制器(Controller)之间的通信桥梁。理解 HCI 数据包的结构是进行蓝牙驱动调试和日志分析的基础。本章将深入剖析 HCI 的四种核心数据包类型及其格式。

4.1 HCI Packet 类型概览

HCI 定义了四种不同的数据包类型,每种类型通过特定的 Packet Indicator 字节进行区分。主机通过 UART、USB 或 SDIO 等物理总线发送这些数据包。

Packet 类型 指示符 (Byte) 方向 用途
HCI Command 0x01 Host → Controller 主机下发指令,如扫描、连接、配置参数
HCI ACL Data 0x02 双向 承载面向连接的异步数据(如 A2DP 音频、ATT 协议)
HCI SCO Data 0x03 双向 承载同步面向连接数据(如传统语音通话)
HCI Event 0x04 Controller → Host 控制器向主机报告事件,如命令完成、连接建立、断开
调试要点:在 HCI 日志(如 btsnoop、hcidump)中,第一个字节就是 Packet Indicator。例如,看到 01 开头,立即知道这是一个 Command 包。

4.2 HCI Command 格式详解

HCI Command 是主机驱动控制器行为的核心手段。每个 Command 包由 OpCode、Parameter Total Length 和 Parameters 三部分组成。

+--------+--------+--------+--------+--------+--------+--------+
| 0x01   | OpCode (2B)   | Length (1B) | Parameters (0-255B) |
+--------+--------+--------+--------+--------+--------+--------+
         | OpCode Group | OpCode Cmd  |                       |
         |    (OGF)     |    (OCF)    |                       |
         +--------------+-------------+                       +
  • OpCode (2 字节):由高 6 位的 OGF(OpCode Group Field)和低 10 位的 OCF(OpCode Command Field)组成。OGF 用于分组命令类型(如链路控制、控制器配置),OCF 标识具体命令。
  • Parameter Total Length (1 字节):指示 Parameters 字段的字节数,不包含 OpCode 和 Length 本身。
  • Parameters (可变):命令特有的参数,长度由 Length 字段指定。
示例:HCI_Reset 命令的 OpCode 为 0x0C03(OGF=0x03, OCF=0x0003),无参数,因此 Length=0。日志中表现为:01 03 0C 00。

4.3 HCI Event 格式详解

HCI Event 是控制器向主机异步报告状态变化的机制。每个 Event 包由 Event Code、Parameter Total Length 和 Parameters 组成。

+--------+--------+--------+--------+--------+--------+--------+
| 0x04   | Event Code(1B)| Length (1B) | Parameters (0-255B) |
+--------+--------+--------+--------+--------+--------+--------+
  • Event Code (1 字节):标识事件类型。例如 0x0E 表示 Command Complete,0x0F 表示 Command Status。
  • Parameter Total Length (1 字节):Parameters 字段的字节数。
  • Parameters (可变):事件特有的数据,如命令返回的 Status、连接句柄等。
常见陷阱:Command Complete 事件(0x0E)的 Parameters 中第一个字节是 Num_HCI_Command_Packets,表示控制器还能接收多少个 Command。如果该值为 0,主机必须等待,不能继续下发命令。

4.4 HCI ACL 与 SCO 数据包格式

ACL 和 SCO 数据包用于传输实际的应用数据。它们的头部结构相似,但用途不同。

4.4.1 HCI ACL Data Packet

+--------+--------+--------+--------+--------+--------+--------+
| 0x02   | Handle (2B)   | PB Flag | BC Flag | Data Total Length |
+--------+--------+--------+--------+--------+--------+--------+
         | Connection Handle (12b) | Flags (4b) | Length (2B)   |
         +-------------------------+------------+---------------+
  • Connection Handle (12 位):标识该数据包属于哪个 ACL 连接。
  • PB Flag (2 位):Packet Boundary Flag,用于分段重组。例如 10 表示数据包起始,01 表示中间或末尾片段。
  • BC Flag (2 位):Broadcast Flag,用于广播包。
  • Data Total Length (2 字节):后续数据的长度。

4.4.2 HCI SCO Data Packet

+--------+--------+--------+--------+--------+--------+--------+
| 0x03   | Handle (2B)   | Reserved | Data Total Length (1B) |
+--------+--------+--------+--------+--------+--------+--------+
         | Connection Handle (12b) | Flags (4b) | Length (1B)   |
         +-------------------------+------------+---------------+
  • Connection Handle (12 位):标识 SCO 连接。
  • Flags (4 位):通常保留或用于指示 SCO 状态。
  • Data Total Length (1 字节):SCO 数据长度通常较小(如 60 字节),因此只用 1 字节表示。

4.5 HCI 数据包交互流程(SVG)

下图展示了主机与控制器之间通过 HCI 数据包进行交互的典型流程:

HCI 数据包交互流程 蓝牙主机 (Host) 蓝牙控制器 (Controller) HCI 传输层 (UART/USB/SDIO) HCI Command (0x01) HCI Event (0x04) HCI ACL Data (0x02) HCI SCO Data (0x03) HCI 数据包交互说明 1. 主机下发 HCI_Reset (Command) → 控制器执行并返回 Command Complete (Event) 2. 主机下发 HCI_Inquiry (Command) → 控制器返回 Inquiry Result (Event) 3. 连接建立后,ACL/SCO 数据包双向传输 4. 连接断开时,控制器发送 Disconnection Complete (Event)

4.6 关键事件与命令对照表

在调试过程中,以下命令和事件组合最为常见:

操作 HCI Command (OpCode) 对应 HCI Event 调试关注点
重置控制器 0x0C03 (Reset) 0x0E (Command Complete) 检查 Status 是否为 0x00
查询设备 0x0401 (Inquiry) 0x02 (Inquiry Result) / 0x01 (Inquiry Complete) 观察返回的设备地址和 RSSI
创建连接 0x0405 (Create Connection) 0x0F (Command Status) → 0x03 (Connection Complete) 确认连接句柄和链路类型
断开连接 0x0406 (Disconnect) 0x05 (Disconnection Complete) 分析 Reason 字段(如 0x13 表示远程用户终止)
读取本地版本 0x1001 (Read Local Version Info) 0x0E (Command Complete) 获取 HCI 版本、LMP 版本、制造商信息

4.7 实战:解析一段 HCI 日志

以下是一段真实的 HCI 日志片段(十六进制),我们逐字节解析:

01 03 0C 00
04 0E 04 01 03 0C 00
  • 第一行:
    • 01 → HCI Command 包
    • 03 0C → OpCode(小端序),实际为 0x0C03,即 HCI_Reset
    • 00 → Parameter Total Length = 0,无参数
  • 第二行:
    • 04 → HCI Event 包
    • 0E → Event Code = Command Complete
    • 04 → 参数长度 = 4 字节
    • 01 → Num_HCI_Command_Packets = 1(可以继续发命令)
    • 03 0C → 对应命令的 OpCode
    • 00 → Status = Success
日志分析技巧:使用 hcidump -X 或 Wireshark 的蓝牙嗅探功能,可以自动解析这些字节。但手动解析能帮助你深入理解协议栈的底层行为,尤其在驱动开发阶段。

4.8 本章小结