1. Home
  2. 博客

    HID Report Map

HID Report Map 2025-01-21

HID (The Human Interface Device) 定义了人机接口设备中的协议,特征,和使用规范,典型的应用包括鼠标,键盘,pad,以及游戏手柄,通信方式包括USB 和 蓝牙。

HID (The Human Interface Device) 定义了人机接口设备中的协议,特征,和使用规范,典型的应用包括鼠标,键盘,pad,以及游戏手柄,通信方式包括USB 和 蓝牙。

HID协议定义了一系列标准化的命令和数据格式,使得各种设备可以通过共同的协议来进行通信,外部设备可以向计算机发送各种数据,例如按键信息,鼠标移动信息,传感器数据等等,计算机解析这些数据,并进行相应的响应。

  • 蓝牙HID协议的最大特点是低功耗,因为人机交互需要长时间工作,因此对于电池的续航能力有很高要求,蓝牙HID在设计的时候考虑到了这一点,采用了一系列低功耗的技术,使得人机交互设备可以长时间工作而不需要频繁充电,另外蓝牙HID协议还支持休眠和唤醒功能,不使用的时候设备可以自动进入休眠,以节约电量。
  • 蓝牙HID还具有很好的稳定性和可靠性,蓝牙HID协议采用了一系列信号处理和纠错技术,能有效减少信号干扰和数据丢失,保证了信号的稳定和可靠。
  • 蓝牙HID还有一个很大的特性就是可以设备自动重连,此特性被很多应用场景所使用。

HID Report Protocol 数据包格式需求-Report Map

要实现HID数据的传输,两者必须协商好一个数据包格式。而HID设备多种多样,所要上报的数据格式/长度各不相同,如只有3个按键的键盘,或者全功能键盘,其所需发送的数据格式是不同的。HID设备要满足各种稀奇古怪的需求。

在HID中是通过report map来定义数据包格式:

code char MouseReportDescriptor[63] = {
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)

……

0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data, Array, Abs)

0xc0 // END_COLLECTION

};

我们一眼就能看出双斜线后面的文字,是对前面数字的说明,即:0x05,0x01所表达的是USAGE_PAGE (Generic Desktop) 的含义,但是,为何如此表达,则描述的不太清楚, 本文主要针对report map进行解说。

我们参考 Device Class Definition for Human Interface Devices (HID) E.6和E.10里面的键盘和鼠标。

hid report map

 

hid report map 2

根据HID协议,该描述符内部的数据组,如{0x05,0x01},称为条目(目前我们用的都是两个字节的短条目)。条目由一个字节的前缀和可选的数据字节组成,可选的数据字节最大为4,最小为0.

前缀是如下三段数据组成的一个字节:

hid report map

bType表示该条目的类型。类型有三种:0为主条目,1为全局条目,2为局部条目。
bSize用来表示条目的数据字节数量0表示0个字节,1表示1个字节,2表示2个字节,3表示4个字节。
bTag表示该条目的功能。

我们查找 Device Class Definition for Human Interface Devices (HID) 6.2.2.4 Main Items,6.2.2.7 Global Items和6.2.2.8 Local Items,并在这里做一个摘抄。

Main item tag

One-Byte Prefix (nn represents size value)

Valid Data

Input

1000 00 nn

Bit 0--{Data (0) | Constant (1)}…..... Bit 1--{Array (0) | Variable (1)}….....

Output

1001 00 nn

Bit 2--{Absolute (0) | Relative (1)}…..... Bit 3--{No Wrap (0) | Wrap (1)}…...

Feature

1011 00 nn

Bit 4--{Linear (0) | Non Linear (1)}…….. Bit 5--{Preferred State (0) | No Preferred (1)}….....

Collection

1010 00 nn

0x00--Physical (group of axes)…….. 0x01--Application (mouse, keyboard)….....

End Collection

1100 00 nn

Global item tag

One-Byte Prefix (nn represents
Global item tag size value)

Description

Usage Page

0000 01 nn

Unsigned integer specifying the current Usage

Logical Minimum

0001 01 nn

Extent value in logical units. This is the minimum value that a variable or array item will report.

Logical Maximum

0010 01 nn

Extent value in logical units. This is the maximum value that a variable or array item will report

Physical Minimum

0011 01 nn

Minimum value for the physical extent of a variable item. This represents the Logical Minimum with units applied to it.

Physical Maximum

0100 01 nn

Maximum value for the physical extent of a
variable item

Report Size

0111 01 nn

Unsigned integer specifying the size of the report fields in bits.

Report ID

1000 01 nn

Unsigned value that specifies the Report ID.

Report Count

1001 01 nn

Unsigned integer specifying the number of data
fields for the item;

Local Items Tag

Usage

0000 10 nn

Usage index for an item usage; represents a
suggested usage for the item or collection.

Usage Minimum

0001 10 nn

Defines the starting usage associated with an array or bitmap.

Usage Maximum

0010 10 nn

Defines the ending usage associated with an array or bitmap.

表格-A

我们下面解读一下各个条目:

HID Report Map

表格—B

Usage Page (Generic Desktop), 05 01里面:0x05-----0000 01 nn, bType为01,表示此条目为主条目,nn (bSize) 为01,表示后面1个字节用来表示Page ID,此处为0x01,我们需要查找Universal Serial Bus HID Usage Tables 第三章节 Usage Pages:代表的意思就是Generic desktop controls。

0x01对应的Usage需要查找Universal Serial Bus HID Usage Tables 第四章节,见表格—C。

从此表也可以看到07表示的是keyboard,08表示的是LED,09表示的是Button。

对应在E.6表格和E.10表格,我们可以找到对应的数据:

Usage Page (Key Codes), 05 07

Usage Page (Page# for LEDs), 05 08

Usage Page (Buttons), 05 09

------ 当Usage page使用的是Page ID为00FF—FFFF,就不是0x05来表示,而是用0x06,0x06的后两位是2,表明用两个字节来Page ID:

Usage Page (Vendor Define), 06 FF FF

HID Report Map

表格—C

Usage (Mouse), 09 02的解读为:0x09-----0000 10 nn, bType 为10,表明这个条目为局部条目,nn (bSize) 为01,表示后面1个字节用来表示Usage ID,此处为0x02,表示mouse,表示report map后面的数据都是对应mouse的描述,直到下一个Usage ID。

从表格--C我们也可以看到0x30 表示X,0x31表示Y,0x01表示指针设备,0x02表示鼠标,0x06表示键盘,对应在E.6表格和E.10表格,我们可以找到对应的数据:

Usage (Mouse), 09 02

Usage (Pointer), 09 01

Usage (X), 09 30

Usage (Y), 09 31

Usage (Keyboard), 09 06

Usage Minimum (224) , 19 E0 解读为:0x19-----0001 10 nn, 局部条目,nn (bSize) 为01,表示后面1个字节用来表示value,此处为0xE0。

Usage Maximum (231) , 29 E7 解读为:0x29-----0010 10 nn, 局部条目,nn (bSize) 为01,表示后面1个字节用来表示value,此处为0xE7。

usage min和max设置了该usage page下值的范围,比如按键的值范围为0-101。

与此相似的还有:

Usage Minimum (0), 19 00

Usage Maximum (101), 29 65

Usage Minimum (1), 19 01

Usage Maximum (5), 29 05

Logical Minimum (0), 15 00 解读为:0x15-----0011 01 nn, 全局条目,nn (bSize) 为01,表示后面1个字节用来表示value,此处为0x00。

Logical Maximum (1), 25 01解读为:0x25-----0010 01 nn, 全局条目,nn (bSize) 为01,表示后面1个字节用来表示value,此处为0x01。

Logical Minimum和Logical Maxinum用于说明每个报告字段的数值范围,这是纯数值,所以称为逻辑数值。

对应在E.6表格和E.10表格,我们可以找到对应的数据:

Logical Minimum (0), 15 00 逻辑最小值为0

Logical Maximum (101), 25 65 逻辑最大值为101

Logical Minimum (-127), 15 81 逻辑最小值为-127

Logical Maximum (127), 25 7F 逻辑最大值为+127

--------那么如果逻辑值超过1个字节,应该用什么格式来表示呢,请看如下示例:

Logical maximum (2047) //0x16, 0xFF, 0x07,

Logical minimum (-2047) // 0x26, 0x01, 0xF8,

在这里,0x16和0x26的最低两位为10,就是2,表明后面用两个字节来表示logical min 和max的值,在这里就是0xF801和0x07FF。

Report Count (1), 75 01

Report Size (8), 95 08

这里就表示每一位表示一个意义,用8个bit位,总共一个字节来表示这8个bit。

Report Count (6), 95 06

Report Size (8), 75 08

这里就表示每一个字节表示一个输入或者输出,总共有6个字节用来表示这个报告。

Hid发送数据我们称之为输入输出报告,input或者output都是相对于host来说的,比如pc,输入到pc的数据称之为input,pc输出的数据称之为output,feature用来主机传送给设备的信息,或是主机从设备读取Feature数据。一个特征报表包含一个或多个Feature。

Input在report map里面用0x81 0xXX来表示。

output在report map里面用0x91 0xXX来表示。

feature在report map里面用0xB1 0xXX来表示。

对应的数据有:

0x81, 0x06 // Input (Data, Variable, Relative)

0x81, 0x01 // Input (Constant) for padding

0x81, 0x02 // Input (Data, Variable, Absolute)

0x81, 0x00 // Input (Data, Array) Key array(6 bytes)

0xB1, 0x02 // Feature (Data, Variable, Absolute)

0x91, 0x01 // Output (Data, Variable, Absolute), Led report padding

Data, Variable, Relative,请参考 Device Class Definition for Human Interface Devices (HID) 6.2.2.4 Main Items Valid bit的定义。

汇总一下我们的keyboard report map

下面这一段表明要用1个字节来表示Modifier byte,作为input输入给电脑:

HID Report Map

各个bit位的定义如下:

HID Report Map

下面这一段表明要用1个字节是保留字节,作为input输入给电脑,没有实际意义:

HID Report Map

下面这一段表明PC输出一个字节给设备,使用里面的5个bit位,空余3个bit位不用:

HID Report Map

具体bit位定义如下图:

HID Report Map

最后定义了6个字节数数据作为input,用来表示键盘按键的值输入给PC:

HID Report Map

一个键盘report map,发送的数据总结如下:

HID Report Map

第一个字节表示8个特殊的按键,第二个字节保留,后面6个字节的每个字节都可以表示一个按键的状态,可以同时有多个按键按下。

需要说明的是,一个字节来表示modifier byte功能键我们可以按位来表示,也可以用E0—E7来表示,尽管E0---E7是在Usage Table里面说明了,但是它并不是跟按键0-101一样,在array byte里面发送。

按键对应的字母请查找Universal Serial Bus HID Usage Table 第10章节 Keyboard/keypad Page(07): 部分表格如下:

HID Report Map

‘A’和’a’是同一个字母编码4,当我们键盘先按下cap lock 按键之后,再按下’a’键,那么host会将’a’识别成为’A’,或者当我们shift按键按下同时按下’a’键,host将’a’识别为’A’, 过程如下:

我们按住left shift 发送的数据为02 00 00 00 00 00 00 00

我们按住’a’ 发送的数据为02 00 04 00 00 00 00 00

我们松开’a’ 发送的数据为02 00 00 00 00 00 00 00

我们松开left shift 发送的数据为00 00 00 00 00 00 00 00

至此一个‘A’将会输入到host上面。

下图展示了,输入ALT+CTRL+DEL在modifier byte和 array bytes上面的bitmap。

HID Report Map

键盘里面还有输出报告:

在我们输入Cap Lock/Scroll lock/Num lock按键之后,我们可以看到host给我们发送了一个output数据为0x07,表示led1,2,3都点亮。

1.输入Cap Lock给PC:

HID Report Map

HID Report Map

2.输入Scroll lock给PC:

HID Report Map

HID Report Map

3.输入Num lock给PC:

HID Report Map

HID Report Map

4.收到PC输出的7:

HID Report Map

此时键盘上面的3个led灯(Cap Lock/Scroll lock/Num lock)应该点亮。

我们再看鼠标的report map ,发送的数据为:

HID Report Map

上报有4个字节,bit 0 鼠标左键,bit 1鼠标右键,bit 2鼠标中键,第二字节鼠标X轴移动,第三字节鼠标Y轴移动,第四字节滚轮移动。

在此例中,X,Y移动范围都定义为-127-------+127,实际上很多鼠标可以定义为-2048--------—+2048,那么我们就需要用12bit来表示一个指针移动,那么需要改为:

0x75, 0x0C // Report Size (12)

0x95, 0x02 // Report Count (2)

0x05, 0x01 // Usage Page (Generic Desktop)

0x09, 0x30 // Usage (X)

0x09, 0x31 // Usage (Y)

0x16, 0x01, 0xF8 // Logical maximum (2047)

0x26, 0xFF, 0x07 // Logical minimum (-2047)

0x81, 0x06 // Input (Data, Variable, Relative)

最后我们再看看自定义的output是如何编写的的吧:

可以看到这里自定义的output发送和接收都是64字节的数组。

HID Report Map

接收报告如下:

HID Report Map

发送报告如下:

HID Report Map

订阅Nordic新闻简报

了解最新信息!订阅后即可获取最新Nordic及物联网资讯

立即订阅