蓝牙HID协议基础:HID报告描述符、协议栈分层与HOGP简介
蓝牙HID(Human Interface Device)驱动开发的核心在于理解HID协议如何通过蓝牙无线链路传输。本章从HID报告描述符的语法结构出发,逐层剖析蓝牙HID协议栈的分工,并重点介绍面向低功耗蓝牙的HID Over GATT Profile(HOGP)。掌握这些基础,才能正确配置设备树并完成数据收发测试。
2.1 HID报告描述符
HID报告描述符(Report Descriptor)是一段二进制数据,用于描述设备发送/接收的数据格式、用途和物理范围。主机通过解析描述符,无需预知设备类型即可正确解释输入/输出报告。
2.1.1 描述符结构
描述符由一系列Item(项)组成,每个Item包含一个字节的头部和若干字节的数据。Item分为短项和长项,常用的是短项,格式如下:
| 位域 | 宽度(bit) | 说明 |
|---|---|---|
| bSize | 2 | 数据长度:0=0字节,1=1字节,2=2字节,3=4字节 |
| bType | 2 | 项类型:0=Main,1=Global,2=Local,3=Reserved |
| bTag | 4 | 功能标签,如Input/Output/Collection/Usage Page等 |
典型的HID键盘描述符片段如下:
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
0x05, 0x07, // Usage Page (Key Codes)
0x19, 0xE0, // Usage Minimum (224)
0x29, 0xE7, // Usage Maximum (231)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data,Var,Abs)
0xC0 // End Collection
2.1.2 报告描述符解析流程
关键概念:主机通过Usage Page和Usage确定设备类型(键盘/鼠标/游戏杆),通过Report ID区分多份报告,通过Logical Minimum/Maximum和Report Size/Count计算数据位宽。
下图展示了HID报告描述符的解析与报告生成流程:
2.2 蓝牙HID协议栈分层
蓝牙HID协议栈采用分层架构,每一层封装特定的功能,上层依赖下层提供的服务。理解分层有助于定位驱动开发中的问题。
2.2.1 分层模型
| 层编号 | 协议层名称 | 主要职责 | 典型数据单元 |
|---|---|---|---|
| 4 | HID Service / Profile | 报告描述符管理、报告收发、协议控制 | HID报告、控制命令 |
| 3 | GATT / ATT | 属性操作(读/写/通知)、服务发现 | Attribute PDU |
| 2 | L2CAP | 数据分段重组、多路复用、MTU协商 | L2CAP帧 |
| 1 | HCI + Link Layer | 蓝牙物理传输、ACL数据包、事件上报 | HCI命令/事件、ACL数据 |
2.2.2 各层交互关系
下图展示了蓝牙HID协议栈的层次结构及数据流向:
开发要点:在嵌入式Linux中,HID Profile层通常由BlueZ的
bluetoothd或btgatt实现;GATT层通过ioctl或dbus接口与用户态交互;L2CAP和HCI由内核蓝牙子系统(bluetooth.ko)提供。设备树配置主要影响HCI底层(UART/USB绑定)和中断引脚。
2.3 蓝牙HID Profile (HOGP)
HOGP(HID Over GATT Profile)是蓝牙低功耗(BLE)上的HID实现标准,定义在Bluetooth Core Specification的HID Service和HID Profile中。它取代了传统BR/EDR的HID Profile,成为BLE HID设备的唯一规范。
2.3.1 HOGP核心特征
| 特征(Characteristic) | UUID | 属性 | 说明 |
|---|---|---|---|
| Report Map | 0x2A4B | Read | 存放HID报告描述符 |
| Report | 0x2A4D | Read/Write/Notify | 输入/输出/特征报告数据 |
| Boot Keyboard Input Report | 0x2A22 | Read/Notify | 兼容BIOS的键盘输入 |
| Boot Mouse Input Report | 0x2A33 | Read/Notify | 兼容BIOS的鼠标输入 |
| HID Information | 0x2A4A | Read | HID版本、国家代码等 |
| Protocol Mode | 0x2A4E | Read/Write | 切换报告模式/启动模式 |
| HID Control Point | 0x2A4C | Write | 发送控制命令(如挂起/恢复) |
2.3.2 HOGP设备角色与数据流
HOGP定义了两种角色:
- HID Host(GATT Client):通常是手机、平板、PC,负责读取报告描述符、接收输入报告、发送输出报告。
- HID Device(GATT Server):键盘、鼠标、游戏手柄,负责提供HID Service,通过Notify发送输入报告,通过Write接收输出报告。
下图展示了HOGP设备与主机之间的典型交互流程:
2.3.3 HOGP与传统蓝牙HID对比
| 对比项 | 传统蓝牙HID (BR/EDR) | HOGP (BLE) |
|---|---|---|
| 传输层 | L2CAP + RFCOMM | GATT + ATT |
| 功耗 | 较高(持续连接) | 极低(广播+连接事件) |
| 报告传输 | 中断通道(独立L2CAP信道) | GATT Notify/Indicate |
| 描述符获取 | HID控制通道 | Read Report Map特征 |
| 多报告支持 | 通过Report ID | 多个Report特征实例 |
| 兼容性 | 需配对+认证 | 支持Just Works配对 |
常见误区:HOGP设备必须实现Report Map特征,且描述符内容必须与Report特征的数据格式严格一致。如果描述符声明了8字节键盘输入报告,但Notify只发送6字节,主机将解析错误或丢弃数据。开发时建议使用
hidrd工具验证描述符合法性。
2.4 本章小结
- HID报告描述符是设备与主机之间的数据契约,通过Item序列定义报告格式和用途。
- 蓝牙HID协议栈分为HID Profile、GATT/ATT、L2CAP、HCI四层,每层职责清晰,驱动开发需关注HCI和GATT接口。
- HOGP是BLE HID的唯一标准,基于GATT特征实现报告映射、输入通知和输出写入,功耗低且兼容性好。
- 设备树配置主要影响HCI底层(UART/USB引脚、中断、时钟),而HID报告描述符和GATT服务由固件或用户态协议栈管理。