天天看点

HID 报告描述 2

1、样例解读

下面是一个伪代码描述的样例,其中涉及到的页码可查看第 5 段用途表:

Usage Page (Generic Desktop), //定位到Generic Desktop页,这个相当于指针跳转一样的东西

Usage (Mouse), //指定Generic Desktop里的mouse,表示这是一个鼠标

Collection (Application), // Collection Application,是对Mouse的解释

 Usage (Pointer), //表示指针形式

Collection (Physical), // Collection Physical,是对Pointer的解释

  Report ID (0A), //id为0x0A的报告

  Usage (X), Usage (Y), //上报X,Y两个数据

  Logical Minimum (-127), //Report data values range from -127

  Logical Maximum (127), //X,Y的取值范围是-127~127

  Report Size (8), Report Count (2), //总共要上报2个字节,即x一个字节,y一个字节

  Input (Data, Variable, Relative), //将X,Y这两个字节添加到0x0A的报告里,且这两个值是可写并且是相对的

  Logical Minimum (0),

  Logical Maximum (1), //下面Button的取值范围是0~1

  Report Size (1), Report Count (3), //3个1位的数据

  Usage Page (Button Page),//是一个BUTTON

  Usage Minimum (1),

  Usage Maximum (3),//共有 BUTTON1~BUTTON3,即总共有 3 个 BUTTON

Input (Data, Variable, Absolute),//将3个分别代表的BUTTON1,BUTTON2,BUTTON3的位添加到0x0A的报告

Report Size (5),

Input (Constant), //增加5个无效的位与上面3位凑成一个字节

End Collection,

End Collection

综上所示,上面样例所表达的意思就是下图所示的:

HID 报告描述 2

这里先简单介绍用图表(鼠标):具体看 HID Usage Tables 1.12(用图表).pdf ,或下一章

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

HID 报告描述 2

0x09, 0x02, // Usage (Mouse)

HID 报告描述 2

再 举 一 个 实 际 的 例 子 进 行 解 读 , 下 面 是 摘 自 TI CC2540/CC2541 SDK 里 的BLE-CC254x_v1.4.0\Projects\ble\Profiles\HIDDevKbM\hidkbmservice.c

static CONST uint8 hidReportMap[] =

{

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

0x09, 0x02, // Usage (Mouse)

0xA1, 0x01, // Collection (Application)

0x85, 0x01, // Report Id (1)

0x09, 0x01, // Usage (Pointer)

0xA1, 0x00, // Collection (Physical)

0x05, 0x09, // Usage Page (Buttons)

0x19, 0x01, // Usage Minimum (01) - Button 1

0x29, 0x03, // Usage Maximum (03) - Button 3

0x15, 0x00, // Logical Minimum (0)

0x25, 0x01, // Logical Maximum (1)

0x75, 0x01, // Report Size (1)

0x95, 0x03, // Report Count (3)

0x81, 0x02, // Input (Data, Variable,Absolute) - Button states

0x75, 0x05, // Report Size (5)

0x95, 0x01, // Report Count (1)

0x81, 0x01, // Input (Constant) - Padding or Reserved bits

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

0x09, 0x30, // Usage (X)

0x09, 0x31, // Usage (Y)

0x09, 0x38, // Usage (Wheel)

0x15, 0x81, // Logical Minimum (-127)

0x25, 0x7F, // Logical Maximum (127)

0x75, 0x08, // Report Size (8)

0x95, 0x03, // Report Count (3)

0x81, 0x06, // Input (Data, Variable, Relative) - X & Y coordinate

0xC0, // End Collection

0xC0, // End Collection

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

0x09, 0x06, // Usage (Keyboard)

0xA1, 0x01, // Collection: (Application)

0x85, 0x02, // Report Id (2)

0x05, 0x07, // Usage Pg (Key Codes)

0x19, 0xE0, // Usage Min (224)

0x29, 0xE7, // Usage Max (231)

0x15, 0x00, // Log Min (0)

0x25, 0x01, // Log Max (1)

// Modifier byte

0x75, 0x01, // Report Size (1)

0x95, 0x08, // Report Count (8)

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

// Reserved byte

0x95, 0x01, // Report Count (1)

0x75, 0x08, // Report Size (8)

0x81, 0x01, // Input: (Constant)

// LED report

0x95, 0x05, // Report Count (5)

0x75, 0x01, // Report Size (1)

0x05, 0x08, // Usage Pg (LEDs)

0x19, 0x01, // Usage Min (1)

0x29, 0x05, // Usage Max (5)

0x91, 0x02, // Output: (Data, Variable,Absolute)

// LED report padding

0x95, 0x01, // Report Count (1)

0x75, 0x03, // Report Size (3)

0x91, 0x01, // Output: (Constant)

// Key arrays (6 bytes)

0x95, 0x06, // Report Count (6)

0x75, 0x08, // Report Size (8)

0x15, 0x00, // Log Min (0)

0x25, 0x65, // Log Max (101)

0x05, 0x07, // Usage Pg (Key Codes)

0x19, 0x00, // Usage Min (0)

0x29, 0x65, // Usage Max (101)

0x81, 0x00, // Input: (Data, Array)

0xC0, // End Collection

0x05, 0x0C, // Usage Pg (Consumer Devices)

0x09, 0x01, // Usage (Consumer Control)

0xA1, 0x01, // Collection (Application)

0x85, 0x03, // Report Id (3)

0x09, 0x02, // Usage (Numeric Key Pad)

0xA1, 0x02, // Collection (Logical)

0x05, 0x09, // Usage Pg (Button)

0x19, 0x01, // Usage Min (Button 1)

0x29, 0x0A, // Usage Max (Button 10)

0x15, 0x01, // Logical Min (1)

0x25, 0x0A, // Logical Max (10)

0x75, 0x04, // Report Size (4)

0x95, 0x01, // Report Count (1)

0x81, 0x00, // Input (Data,Ary,Abs)

0xC0, // End Collection

0x05, 0x0C, // Usage Pg (Consumer Devices)

0x09, 0x86, // Usage (Channel)

0x15, 0xFF, // Logical Min (-1)

0x25, 0x01, // Logical Max (1)

0x75, 0x02, // Report Size (2)

0x95, 0x01, // Report Count (1)

0x81, 0x46, // Input (Data, Var, Rel, Null)

0x09, 0xE9, // Usage (Volume Up)

0x09, 0xEA, // Usage (Volume Down)

0x15, 0x00, // Logical Min (0)

0x75, 0x01, // Report Size (1)

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

0x81, 0x02, // Input (Data, Var,Abs)

0x09, 0xE2, // Usage (Mute)

0x09, 0x30, // Usage (Power)

0x09, 0x40, // Usage (Menu)

0x09, 0xB1, // Usage (Pause)

0x09, 0xB2, // Usage (Record)

0x0a, 0x23, 0x02, // Usage (Home)

0x0a, 0x24, 0x02, // Usage (Back)

0x09, 0xB3, // Usage (Fast Forward)

0x09, 0xB4, // Usage (Rewind)

0x09, 0xB5, // Usage (Scan Next)

0x09, 0xB6, // Usage (Scan Prev)

0x09, 0xB7, // Usage (Stop)

0x15, 0x01, // Logical Min (1)

0x25, 0x0C, // Logical Max (12)

0x75, 0x04, // Report Size (4)

0x95, 0x01, // Report Count (1)

0x81, 0x00, // Input (Data, Ary,Abs)

0x09, 0x80, // Usage (Selection)

0xA1, 0x02, // Collection (Logical)

0x05, 0x09, // Usage Pg (Button)

0x19, 0x01, // Usage Min (Button 1)

0x29, 0x03, // Usage Max (Button 3)

0x15, 0x01, // Logical Min (1)

0x25, 0x03, // Logical Max (3)

0x75, 0x02, // Report Size (2)

0x81, 0x00, // Input (Data,Ary,Abs)

0xC0, // End Collection

0x81, 0x03, // Input (Const, Var,Abs)

0xC0 // End Collection

};

上面用红蓝绿区分出三大应用功能,分别鼠标、键盘和 Consumer,每个应用功能都是用CollectionApplication 括起来的。

HID 报告描述 2
HID 报告描述 2

我们先来解析鼠标的报告描述:

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

0x04 代表是 Global 类的 Usage Page 功能,最位 2 位表示带多少个字节的数据,因为只带1 个数据,所以是 1,跟 0x04 组合起来就是 0x05 了。其他名称的意思都差不多,数值可以参照上一章的Generic Item Format

0x09, 0x02, // Usage (Mouse)

表示这是一个鼠标, Usage 是为了给对方解析数据时有个参照

0xA1, 0x01, // Collection (Application)

0xA1, 0x01 表示 CollectionApplication ; 0xA1, 0x00 表示 Collection Physical.表示下面所包含的是对 Mouse 的解释

0x85, 0x01, // Report Id (1)

该报告对应的 ID 是 1

0x09, 0x01, // Usage (Pointer)

这是个指针形式

0xA1, 0x00, // Collection (Physical)

下面所包含的是对指针的解释

0x05, 0x09, // Usage Page (Buttons)

下面定义的是按键

0x19, 0x01, // Usage Minimum (01) - Button 1

0x29, 0x03, // Usage Maximum (03) - Button 3

总共有 3 个按键

0x15, 0x00, // Logical Minimum (0)

0x25, 0x01, // Logical Maximum (1)

按键的值是 0 和 1,表示放开和按下

0x75, 0x01, // Report Size (1)

0x95, 0x03, // Report Count (3)

有 3 个 1 位,即用 3bits 分别对应三个按键

0x81, 0x02, // Input (Data, Variable,Absolute) - Button states

将这三个位加入本报告的数据中,这三位是可读写的绝对值

0x75, 0x05, // Report Size (5)

0x95, 0x01, // Report Count (1)

定义 1 个 5 位的数据

0x81, 0x01, // Input (Constant) - Padding or Reserved bits

将这个数据添加到本报告的数据中,主要是与前面 3 位组成一个字节,这 5 位是 Constant数据

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

0x09, 0x30, // Usage (X)

0x09, 0x31, // Usage (Y)

0x09, 0x38, // Usage (Wheel)

下面定义的是 X,Y,Wheel 三个功能

0x15, 0x81, // Logical Minimum (-127)

0x25, 0x7F, // Logical Maximum (127)

X,Y,Wheel 的取值范围是-127~127

0x75, 0x08, // Report Size (8)

0x95, 0x03, // Report Count (3)

用三个字节来表示 x,y,wheel

0x81, 0x06, // Input (Data, Variable, Relative) - X & Y coordinate

将这三个字节添加到本报告中

0xC0, // End Collection

0xC0, // End Collection

上面解析出来的数据格式如下:

HID 报告描述 2

我们来看一下,如果要发一个鼠标的坐标,该如何发:

static void hidEmuKbdSendMouseReport( uint8 buttons )

{

uint8 buf[HID_MOUSE_IN_RPT_LEN];

buf[0] = buttons; // Buttons

buf[1] = 0; // X

buf[2] = 0; // Y

buf[3] = 0; // Wheel

HidDev_Report( HID_RPT_ID_MOUSE_IN, HID_REPORT_TYPE_INPUT,

HID_MOUSE_IN_RPT_LEN, buf );

}

从上面函数可以看到,X,Y 在第 2、3 个字节,结合上面的数据格式图可以看出,正好是对应的。

我们接着解析键盘的报告描述:

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

0x09, 0x06, // Usage (Keyboard)

这是一个键盘

0xA1, 0x01, // Collection: (Application)

0x85, 0x02, // Report Id (2)

本报告的 ID 是 2

0x05, 0x07, // Usage Pg (Key Codes)

下面定义的是按键码

0x19, 0xE0, // Usage Min (224)

0x29, 0xE7, // Usage Max (231)

按键码分别是 224~231,共总有 8 个按键码

0x15, 0x00, // Log Min (0)

0x25, 0x01, // Log Max (1)

按键码的值是 0 和 1,分别代表放开和按下

// Modifier byte

0x75, 0x01, // Report Size (1)

0x95, 0x08, // Report Count (8)

用 8 个 bit 分别表示 8 个按键的状态

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

将这 8 个 bit 添加到本报告中

// Reserved byte

0x95, 0x01, // Report Count (1)

0x75, 0x08, // Report Size (8)

0x81, 0x01, // Input: (Constant)

另外再预留 8 个 bit 备用,暂时没用

// LED report

0x95, 0x05, // Report Count (5)

0x75, 0x01, // Report Size (1)

定义 5 个 1bit

0x05, 0x08, // Usage Pg (LEDs)

这是 LED

0x19, 0x01, // Usage Min (1)

0x29, 0x05, // Usage Max (5)

5 个 bit 分别对应 LED1~LED5

0x91, 0x02, // Output: (Data, Variable,Absolute)

将这 5 个 bit 添加到本报告中,LED 需要作为 OUT

// LED report padding

0x95, 0x01, // Report Count (1)

0x75, 0x03, // Report Size (3)

0x91, 0x01, // Output: (Constant)

再增加 3 个 bit,与上面 5 个 bit 组成一个字节

// Key arrays (6 bytes)

0x95, 0x06, // Report Count (6)

0x75, 0x08, // Report Size (8)

定义 6 个字节

0x15, 0x00, // Log Min (0)

0x25, 0x65, // Log Max (101)

每个字节的取值范围是 0~101

0x05, 0x07, // Usage Pg (Key Codes)

这个也是键盘码

0x19, 0x00, // Usage Min (0)

0x29, 0x65, // Usage Max (101)

分别是键盘码 0~键盘码 101

0x81, 0x00, // Input: (Data, Array)

将这 6 个字节添加到本报告中,表示同时可产生 6 个键值。

0xC0, // End Collection

上面解析出来的数据格式如下:

HID 报告描述 2

Input 和 Out 是不同的两条通道。现在我们来看一下,如果要发一个按键 K0~K101,需要怎么发,如下:

static void hidEmuKbdSendReport( uint8 keycode )

{

uint8 buf[HID_KEYBOARD_IN_RPT_LEN];

buf[0] = 0; // Modifier keys

buf[1] = 0; // Reserved

buf[2] = keycode; // Keycode 1

buf[3] = 0; // Keycode 2

buf[4] = 0; // Keycode 3

buf[5] = 0; // Keycode 4

buf[6] = 0; // Keycode 5

buf[7] = 0; // Keycode 6

HidDev_Report( HID_RPT_ID_KEY_IN, HID_REPORT_TYPE_INPUT,

HID_KEYBOARD_IN_RPT_LEN, buf );

}

上面函数可以看到,它是放在第 3 个字节,结合数据格式图可以看出,第 3 个字节开始,刚好是在 K0~K101 的按键区。

我们最后来解析 Consumer 的报告描述:

0x05, 0x0C, // Usage Pg (Consumer Devices)

0x09, 0x01, // Usage (Consumer Control)

这是个 Consumer 控制

0xA1, 0x01, // Collection (Application)

0x85, 0x03, // Report Id (3)

本报告 ID 为 3

0x09, 0x02, // Usage (Numeric Key Pad)

下面定义的是数字键盘

0xA1, 0x02, // Collection (Logical)

0x05, 0x09, // Usage Pg (Button)

下面定义的是按键

0x19, 0x01, // Usage Min (Button 1)

0x29, 0x0A, // Usage Max (Button 10)

分别是 Button1~Button10

0x15, 0x01, // Logical Min (1)

0x25, 0x0A, // Logical Max (10)

每个按键的取值范围为 1~10

0x75, 0x04, // Report Size (4)

0x95, 0x01, // Report Count (1)

1 个 4bit 的值,来表示键值 1~10,这个值是哪个就表示哪个键按下。

0x81, 0x00, // Input (Data,Ary,Abs)

将这 4bit 添加到本报告中

0xC0, // End Collection

0x05, 0x0C, // Usage Pg (Consumer Devices)

0x09, 0x86, // Usage (Channel)

这里定义的是频道

0x15, 0xFF, // Logical Min (-1)

0x25, 0x01, // Logical Max (1)

频道值范围是-1~1,这里应该只用到-1 和 1,表示频道+和-

0x75, 0x02, // Report Size (2)

0x95, 0x01, // Report Count (1)

用一个 2bit 来表示,第 1 个 bit 表示频道+,第二个表示频道-

0x81, 0x46, // Input (Data, Var, Rel, Null)

将这个 2bit 加到本报告中

0x09, 0xE9, // Usage (Volume Up)

0x09, 0xEA, // Usage (Volume Down)

定义两个按键,音量加和音量减

0x15, 0x00, // Logical Min (0)

按键值为 0~1,这里少了 Logical Max,继承上面的 Logical Max=1

0x75, 0x01, // Report Size (1)

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

定义 2 个 1bit,每个 bit 代表一个键

0x81, 0x02, // Input (Data, Var,Abs)

将 2 个 1bit 添加到本报告中

0x09, 0xE2, // Usage (Mute)

0x09, 0x30, // Usage (Power)

0x09, 0x40, // Usage (Menu)

0x09, 0xB1, // Usage (Pause)

0x09, 0xB2, // Usage (Record)

0x0a, 0x23, 0x02, // Usage (Home)

0x0a, 0x24, 0x02, // Usage (Back)

0x09, 0xB3, // Usage (Fast Forward)

0x09, 0xB4, // Usage (Rewind)

0x09, 0xB5, // Usage (Scan Next)

0x09, 0xB6, // Usage (Scan Prev)

0x09, 0xB7, // Usage (Stop)

定义 12 个按键

0x15, 0x01, // Logical Min (1)

0x25, 0x0C, // Logical Max (12)

0x75, 0x04, // Report Size (4)

0x95, 0x01, // Report Count (1)

用一个 4 位来存储 1~12,1 表示 Mute … 12 表示 Stop

0x81, 0x00, // Input (Data, Ary,Abs)

将这个 4bit 添加到报告中

0x09, 0x80, // Usage (Selection)

0xA1, 0x02, // Collection (Logical)

0x05, 0x09, // Usage Pg (Button)

这是按键

0x19, 0x01, // Usage Min (Button 1)

0x29, 0x03, // Usage Max (Button 3)

分别是 Button1~Button3

0x15, 0x01, // Logical Min (1)

0x25, 0x03, // Logical Max (3)

每个按键取值范围是 1~3

0x75, 0x02, // Report Size (2)

这里缺少了 Report Count,继承上面的 Report Count =1,也就是用 1 个 2bit 来存储 1~3

0x81, 0x00, // Input (Data,Ary,Abs)

将 1 个字节添加到本报告中

0xC0, // End Collection

0x81, 0x03, // Input (Const, Var,Abs)

再补充 2 个 bit 将上面的凑成一个字节,Report Size=2 和 Report Count =1 继承上面的。

0xC0 // End Collection

修改后,解析出来的数据格式如下:

HID 报告描述 2

我们来看一下,如果要发音量+/-键该怎么发:

static void hidCCSendReport( uint8 cmd, bool keyPressed )

{

// Only send the report if something meaningful to report

uint8 buf[HID_CC_IN_RPT_LEN] = { 0, 0 };

// No need to include Report Id

if ( keyPressed )

{

hidCCBuildReport( buf, cmd );

}

HidDev_Report( HID_RPT_ID_CC_IN, HID_REPORT_TYPE_INPUT,

HID_CC_IN_RPT_LEN, buf );

}

在 hidCCBuildReport 对音量加减解析出来是:

音量加是:buf[0] = 0x40, buf[1] = 0x00

音量减是:buf[0] = 0x80, buf[1] = 0x00

正好与数据格式图中第一个字节的第 6 位和第 7 位相对应。

继续阅读