HID规范
+ -

HID报告描述符教程 手把手教你编写HID报告描述符

2022-03-08 6334 37
翻译原文:https://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/

USB HID报告描述符是USB主机可以从USB设备请求获取的描述符之一。HID 设备使用报告向主机发送数据,HID报告描述符告诉主机如何解释数据。这里我们将尝试向您展示如何编写这些描述符。

什么是USB HID 报告描述符

HID 协议使设备的实现非常简单。设备定义它们的数据包,然后向主机提供一个“HID报告描述符”。HID报告描述符是一个硬编码的字节数组,用于描述设备的数据包。这包括:设备支持多少数据包,数据包有多大,以及数据包中每个字节和位的用途。

例如,带有计算器程序按钮的键盘可以告诉主机按钮的按下/释放状态存储为数据包ID为4的第 6 个字节中的第 2 位(注意:这些位置仅用于说明,并且是特定于设备的)。设备通常将 HID报告描述符存储在 ROM 中,并且不需要本质上理解或解析 HID 描述符。当今市场上的一些鼠标和键盘硬件仅使用 8 位 CPU 实现。

HID报告描述符入门编写

作为一个简单的起点,让我们制作一个标准鼠标。只需三个按钮,并在 X 和 Y 轴上移动。所以我们想发送有关按钮和移动的数据。用一位来表示每个按钮,用一个字节将一个轴上的运动表示为有符号整数。所以我们可以说我们希望数据结构看起来像这样。
标准鼠标

然后我们可以说我们在 C 中的数据结构看起来像

struct mouse_report_t
{
    uint8_t buttons;
    int8_t x;
    int8_t y;
}

所以现在在我们的描述符中,我们的第一项必须描述按钮,其中三个

USAGE_PAGE (Button)
USAGE_MINIMUM (Button 1)
USAGE_MAXIMUM (Button 3)

每个按钮状态由一个位表示,0 或 1

LOGICAL_MINIMUM (0)
LOGICAL_MAXIMUM (1)

这些有三位

REPORT_COUNT (3)
REPORT_SIZE (1)

将此可变数据发送到主机

INPUT (Data,Var,Abs)

最终结果看起来像

USAGE_PAGE (Button)
USAGE_MINIMUM (Button 1)
USAGE_MAXIMUM (Button 3)
LOGICAL_MINIMUM (0)
LOGICAL_MAXIMUM (1)
REPORT_COUNT (3)
REPORT_SIZE (1)
INPUT (Data,Var,Abs)

这将代表按键
但是五个无用的填充位呢?

REPORT_COUNT (1)
REPORT_SIZE (5)
INPUT (Cnst,Var,Abs)

现在我们进行 X 轴运动

USAGE_PAGE (Generic Desktop)
USAGE (X)

我们希望它是一个占用一个字节的有符号整数,因此它的值介于 -127 和 +127 之间(实际上是 -128 和 +127,但我想保持平衡)

LOGICAL_MINIMUM (-127)
LOGICAL_MAXIMUM (127)

我们希望它占用一个 8 位的整个字节

REPORT_SIZE (8)
REPORT_COUNT (1)

并将其作为可变相对坐标发送到计算机

INPUT (Data,Var,Rel)

你最终会得到这样的东西来代表 X 轴运动

USAGE_PAGE (Generic Desktop)
USAGE (X)
LOGICAL_MINIMUM (-127)
LOGICAL_MAXIMUM (127)
REPORT_SIZE (8)
REPORT_COUNT (1)
INPUT (Data,Var,Rel)

Y轴呢?你可以试试

USAGE_PAGE (Generic Desktop)
USAGE (X)
LOGICAL_MINIMUM (-127)
LOGICAL_MAXIMUM (127)
REPORT_SIZE (8)
REPORT_COUNT (1)
INPUT (Data,Var,Rel)
USAGE_PAGE (Generic Desktop)
USAGE (Y)
LOGICAL_MINIMUM (-127)
LOGICAL_MAXIMUM (127)
REPORT_SIZE (8)
REPORT_COUNT (1)

这会起作用,但为了节省内存,我们可以这样做

USAGE_PAGE (Generic Desktop)
USAGE (X)
USAGE (Y)
LOGICAL_MINIMUM (-127)
LOGICAL_MAXIMUM (127)
REPORT_SIZE (8)
REPORT_COUNT (2)
INPUT (Data,Var,Rel)

所以你所有的数据最终看起来像

USAGE_PAGE (Button)
USAGE_MINIMUM (Button 1)
USAGE_MAXIMUM (Button 3)
LOGICAL_MINIMUM (0)
LOGICAL_MAXIMUM (1)
REPORT_COUNT (3)
REPORT_SIZE (1)
INPUT (Data,Var,Abs)
REPORT_COUNT (1)
REPORT_SIZE (5)
INPUT (Cnst,Var,Abs)
USAGE_PAGE (Generic Desktop)
USAGE (X)
USAGE (Y)
LOGICAL_MINIMUM (-127)
LOGICAL_MAXIMUM (127)
REPORT_SIZE (8)
REPORT_COUNT (2)
INPUT (Data,Var,Rel

啊但是我们还没做完,为了让电脑知道这是鼠标,我们做

USAGE_PAGE (Generic Desktop)
USAGE (Mouse)
COLLECTION (Application)
    USAGE (Pointer)
    COLLECTION (Physical)

    ... 我们上面写的内容

    END COLLECTION
END COLLECTION

所以最后,这是标准鼠标的 USB HID 报告描述符

0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
0x09, 0x02,                    // USAGE (Mouse)
0xa1, 0x01,                    // COLLECTION (Application)
0x09, 0x01,                    //   USAGE (Pointer)
0xa1, 0x00,                    //   COLLECTION (Physical)
0x05, 0x09,                    //     USAGE_PAGE (Button)
0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
0x29, 0x03,                    //     USAGE_MAXIMUM (Button 3)
0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
0x95, 0x03,                    //     REPORT_COUNT (3)
0x75, 0x01,                    //     REPORT_SIZE (1)
0x81, 0x02,                    //     INPUT (Data,Var,Abs)
0x95, 0x01,                    //     REPORT_COUNT (1)
0x75, 0x05,                    //     REPORT_SIZE (5)
0x81, 0x03,                    //     INPUT (Cnst,Var,Abs)
0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
0x09, 0x30,                    //     USAGE (X)
0x09, 0x31,                    //     USAGE (Y)
0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
0x75, 0x08,                    //     REPORT_SIZE (8)
0x95, 0x02,                    //     REPORT_COUNT (2)
0x81, 0x06,                    //     INPUT (Data,Var,Rel)
0xc0,                          //   END_COLLECTION
0xc0                           // END_COLLECTION

这实际上是 USB HID 文档提供的示例描述符,您也可以将其作为 HID 工具提供的示例。

以上就是我们完成的鼠标报告描述符内容编写,现在我们将遇到一些可能有疑问的概念,并给出说明和解释:

USAGE_PAGE

我认为文档中没有很好地解释一件事,USAGE、USAGE_PAGE、USAGE_MINIMUM 和 USAGE_MAXIMUM。在描述符中,您首先设置一个 USAGE_PAGE,并且某些 USAGE 可用。在鼠标示例中,USAGE_PAGE(通用桌面)允许您使用 USAGE(鼠标),当使用页面更改为 USAGE_PAGE(按钮)时,USAGE_MINIMUM 和 USAGE_MAXIMUM 允许您指定按钮,然后才能使用 USAGE (X) 和 USAGE (Y),使用页面更改回 USAGE_PAGE(通用桌面)。使用页面就像一个命名空间,更改使用页面会影响可用的“使用”。阅读名为“HID 使用表”的文档以获取更多信息。

Collections

阅读有关官方正确使用集合的文档。用我自己的话来说,集合可以用来组织你的数据,例如,一个键盘可能有一个内置的触摸板,那么键盘的数据应该保存在一个应用程序集合中,而触摸板数据保存在另一个应用程序集合中。我们可以为每个集合分配一个“报告 ID”,稍后我将向您展示。


嘿,这是你可以做的,通过将“USAGE (Mouse)”变成“USAGE (Gamepad)”,你可以让计算机认为它是一个带有一个操纵杆和 3 个按钮的游戏手柄。将 Playstation 2 控制器转换为 USB 游戏手柄怎么样?控制器有 16 个按钮和两个拇指棒,所以我们希望数据看起来像
Gamepad报告描述

所以我们的数据结构看起来像

struct gamepad_report_t
{
    uint16_t buttons;
    int8_t left_x;
    int8_t left_y;
    int8_t right_x;
    int8_t right_y;
}

我们让电脑明白它是一个游戏手柄

USAGE_PAGE (Generic Desktop)
USAGE (Game Pad)
COLLECTION (Application)
    COLLECTION (Physical)

    ...

    END COLLECTION
END COLLECTION

对于按钮

USAGE_PAGE (Button)
USAGE_MINIMUM (Button 1)
USAGE_MAXIMUM (Button 16)
LOGICAL_MINIMUM (0)
LOGICAL_MAXIMUM (1)
REPORT_COUNT (16)
REPORT_SIZE (1)
INPUT (Data,Var,Abs)

用于四个拇指杆轴

USAGE_PAGE (Generic Desktop)
USAGE (X)
USAGE (Y)
USAGE (Z)
USAGE (Rx)
LOGICAL_MINIMUM (-127)
LOGICAL_MAXIMUM (127)
REPORT_SIZE (8)
REPORT_COUNT (4)
INPUT (Data,Var,Abs)

注意:Z 用于表示右摇杆的 X 轴,Rx 用于表示右摇杆的 Y 轴。这没有任何意义,但这就是大多数现有 USB 游戏手柄的工作方式。我已经使用 Battlefield Bad Company 2 对此进行了测试,它可以工作。

注意:对于像操纵杆这样的东西使用“绝对”,而对于像鼠标这样的东西使用“相对”。

所以现在你最终得到

USAGE_PAGE (Generic Desktop)
USAGE (Game Pad)
COLLECTION (Application)
    COLLECTION (Physical)
        USAGE_PAGE (Button)
        USAGE_MINIMUM (Button 1)
        USAGE_MAXIMUM (Button 16)
        LOGICAL_MINIMUM (0)
        LOGICAL_MAXIMUM (1)
        REPORT_COUNT (16)
        REPORT_SIZE (1)
        INPUT (Data,Var,Abs)
        USAGE_PAGE (Generic Desktop)
        USAGE (X)
        USAGE (Y)
        USAGE (Z)
        USAGE (Rx)
        LOGICAL_MINIMUM (-127)
        LOGICAL_MAXIMUM (127)
        REPORT_SIZE (8)
        REPORT_COUNT (4)
        INPUT (Data,Var,Abs)
    END COLLECTION
END COLLECTION

嘿,怎么样?这里是Collection派用场的地方

USAGE_PAGE (Generic Desktop)
USAGE (Game Pad)
COLLECTION (Application)
    COLLECTION (Physical)
        REPORT_ID (1)
        ...
    END COLLECTION
END COLLECTION
USAGE_PAGE (Generic Desktop)
USAGE (Game Pad)
COLLECTION (Application)
    COLLECTION (Physical)
        REPORT_ID (2)
        ...
    END COLLECTION
END COLLECTION

填写数据区域,你最终得到

USAGE_PAGE (Generic Desktop)
USAGE (Game Pad)
COLLECTION (Application)
    COLLECTION (Physical)
        REPORT_ID (1)
        USAGE_PAGE (Button)
        USAGE_MINIMUM (Button 1)
        USAGE_MAXIMUM (Button 16)
        LOGICAL_MINIMUM (0)
        LOGICAL_MAXIMUM (1)
        REPORT_COUNT (16)
        REPORT_SIZE (1)
        INPUT (Data,Var,Abs)
        USAGE_PAGE (Generic Desktop)
        USAGE (X)
        USAGE (Y)
        USAGE (Z)
        USAGE (Rx)
        LOGICAL_MINIMUM (-127)
        LOGICAL_MAXIMUM (127)
        REPORT_SIZE (8)
        REPORT_COUNT (4)
        INPUT (Data,Var,Abs)
    END COLLECTION
END COLLECTION
USAGE_PAGE (Generic Desktop)
USAGE (Game Pad)
COLLECTION (Application)
    COLLECTION (Physical)
        REPORT_ID (2)
        USAGE_PAGE (Button)
        USAGE_MINIMUM (Button 1)
        USAGE_MAXIMUM (Button 16)
        LOGICAL_MINIMUM (0)
        LOGICAL_MAXIMUM (1)
        REPORT_COUNT (16)
        REPORT_SIZE (1)
        INPUT (Data,Var,Abs)
        USAGE_PAGE (Generic Desktop)
        USAGE (X)
        USAGE (Y)
        USAGE (Z)
        USAGE (Rx)
        LOGICAL_MINIMUM (-127)
        LOGICAL_MAXIMUM (127)
        REPORT_SIZE (8)
        REPORT_COUNT (4)
        INPUT (Data,Var,Abs)
    END COLLECTION
END COLLECTION

这非常重要:您必须更改数据结构以包含ReportId
ReportId

struct multiplayer_gamepad_report_t
{
    uint8_t report_id;
    uint16_t buttons;
    int8_t left_x;
    int8_t left_y;
    int8_t right_x;
    int8_t right_y;
}

必须在将数据发送到计算机之前手动设置ReportId,以便计算机了解数据属于哪个player数据包。

multiplayer_gamepad_report_t player1_report;
multiplayer_gamepad_report_t player2_report;
player1_report.report_id = 1;
player2_report.report_id = 2;

您还可以使用集合和报告 ID 来制作复合设备。到目前为止,我已经向您展示了键盘、鼠标和游戏手柄。这里描述了一个复合设备,它是一个键盘、鼠标和两个玩家游戏手柄。

SAGE_PAGE (Generic Desktop)
USAGE (Keyboard)
COLLECTION (Application)
    REPORT_ID (1)
    ...
END COLLECTION
USAGE_PAGE (Generic Desktop)
USAGE (Mouse)
COLLECTION (Application)
    USAGE (Pointer)
    COLLECTION (Physical)
        REPORT_ID (2)
        ...
    END COLLECTION
END COLLECTION
USAGE_PAGE (Generic Desktop)
USAGE (Game Pad)
COLLECTION (Application)
    COLLECTION (Physical)
        REPORT_ID (3)
        ...
    END COLLECTION
END COLLECTION
USAGE_PAGE (Generic Desktop)
USAGE (Game Pad)
COLLECTION (Application)
    COLLECTION (Physical)
        REPORT_ID (4)
        ...
    END COLLECTION
END COLLECTION

当然,您的数据结构与添加的报告 ID。

struct keyboard_report_t
{
    uint8_t report_id;
    uint8_t modifier;
    uint8_t reserved;
    uint8_t keycode[6];
}

struct mouse_report_t
{
    uint8_t report_id;
    uint8_t buttons;
    int8_t x;
    int8_t y;
}

struct gamepad_report_t
{
    uint8_t report_id;
    uint16_t buttons;
    int8_t left_x;
    int8_t left_y;
    int8_t right_x;
    int8_t right_y;
}

但是由于我们更改了数据结构,您的设备不再支持启动协议,因此您不需要定义协议。因此,请确保相应地更改 usbconfig.h。

想看看这个在行动吗?将此示例项目加载到项目中,让 Windows 的“设备和打印机”向您展示!
设备描述

HID人机交互QQ群:564808376    UAC音频QQ群:218581009    UVC相机QQ群:331552032    BOT&UASP大容量存储QQ群:258159197    STC-USB单片机QQ群:315457461    USB技术交流QQ群2:580684376    USB技术交流QQ群:952873936   

0 篇笔记 写笔记

USB复合HID设备报告描述符的区分
在USB规范中,设备的功能是通过接口来承载的,在USB规格书中就是接口描述符。对于一般的设备,一般一个接口就是一个功能,这个功能可以是鼠标,键盘或其它设备类型。当然这个只是对USB简易设备而言的,对于一些USB复杂设备如UVC摄像头,UAC音频等是多接口相互配合来实现其功能的,为了整合这么多接口使......
HID报告描述符详解
HID的报告描述符和其它描述符不一样,不是具有固定的数据结构,而是由固件开发商根据上报的数据自行组装的。这个组装的原材料是HID规范定义的ITEM。所以说HID报告描述符就像搭积木一样,其最终的数据结构和设计图纸是什么,都是由固件开发商决定的,但是其最终的产品又是由HID规范提供的各个标准积木模块搭......
USB键盘报告描述符数据格式分析
USB键盘的HID报表描述符的内容参见下表。数据的输入端点为中断方式,当有键盘敲击事件时,会上报数据长度为8字节的数据报告。0x05,0x01,// Global Generic Desktop0x09,0x06,// Local KeyBoard 0xA1,0x01,// Main app col......
USB鼠标HID报告描述符数据格式分析
注意:这里的鼠标为普通鼠标报告描述符的信息解释,其并不适用于全鼠标报表描述符。一个示例如下:0x05,0x01, // Global Generic Desktop0x09,0x02, // Local Mouse0xa1,0x01, // Main app collection0x09,......
USB中文网出品-HID报告描述符分析工具
HidReportParser.exe工具已经网页化,可访问http://www.usbzh.com/tool/usb.html 在线分析USB-HID报告描述符USB HID规范中有一个很重要的概念,就是HID的报告描述符。本人搞了这么久的HID设备开发,其中一项最头疼的是HID报告描述符的......
为什么Windows7重新安装系统后插在USB3.0端口的鼠标不能使用?
在 Windows 7 及更早版本的操作系统中,USB 3.0 驱动程序堆栈由第三方提供,操作系统不提供USB3.0驱动栈。 因此,Windows7重新安装系统后插在USB3.0端口上的所有设备都无法工作,需要安装第三方提供的USB控制器和集线器驱动,这样才能识别出挂接在该USB总线下的设备。从Wi......
HID 报表描述符/报告描述符
报表描述符用于描述USB HID设备与主机之间数据交互的格式。根据数据的传输方向,分为输入报告和输出报告。输入报告是USB设备发送数据给主机的。大部分的USB HID设备主要实现的是输入报告。如我们平常使用的USB鼠标,就是通过我们点击鼠标按键或滑动鼠标流轮实现给主机上报鼠标的报告信息。输出报告......
HID报告描述符协议
HID报告描述符通过报告描述符的条目定义了HID报告数据的格式。对于大部分的HID设备来说,数据的传输方向都是输入的,即使用输入端点数据从设备端到主机端,并且使用的是中断的方式。当然HID设备不仅仅为数据的输入,有时也需要数据的输出。这时就需要一个输出中断端点来实现。报告描述符包含了属于特定Rep......
HID 报表描述符鼠标实例
USAGE_PAGE (Generic Desktop) 05 01USAGE (Mouse) 09 02COLLECTION (Application) A1 01 ......
USB官网HID报告描述符生成工具
USB规范官网提供了一个HID报告描述符生成工具,https://www.usb.org/document-library/hid-descriptor-tool 使用我们此工具,我们可以:创建、编辑和验证HID报告描述符。输出多种输出(.txt、.inc、.h等)查看一些标准的设备报告描述符......
VS2019分析HID报告描述符解析源代码
常有人问,有没有HID解析的工具,好像除了usb官网提供的dt.exe,没有其它的好的东东了。Linux下有相关的工具,在本站的社区里:http://www.usbzh.com/zone/detail-12.html 可以查看做HID开发,其实最麻烦的就是HID报表描述符了。这里本人移植了Reac......
Win10使用虚拟USB鼠标实现自动挂机测试功能
昨天要测试一个软件不停的整机的功能:在整机软件中需要不停地点击某个软件的按钮,启动会议功能,然后隔一段时间后,需要再次呼出关闭按钮,并点击将该按钮停止会议,如此往复的操作。当然这些操作是需要人工操作点击软件界面的某些按钮实现的。本以为是一个很简单的东西,没想到还是弄出了花样。初始版本 - 脚本方......
USB鼠标HID全局坐标报表描述符
常用的USB HID鼠标是相对的描述符,鼠标的移动是相对当前位置的相对移动。如相对当前位置左移,右移等。这种相对的坐标描述符有的时候在使用上有一定麻烦的,最重要的原因就是需要计算鼠标指针的当前位置。如本人之前做的一个USB鼠标挂机测试脚本,内容详见:http://www.usbzh.com/ar......
HID复合设备(键盘、鼠标)的实现
在使用一些USB键盘或鼠标的时候,特别是一些电竟高档HID设备时,经常发现这些设备会额外定义一些特别的快捷键,使得这些设备不仅有基础设备(如键盘,鼠标)的功能,也有一些特别的快捷功能(如系统声音的放大放小)。甚至更有一些复杂的设备,只需要一个USB接口,就同时支持鼠标键盘功能或在键盘的额外区域支持触......
Windows10下开发虚拟USB鼠标之枚举子设备失败(STATUS_DEVICE_DATA_ERROR)
之前发过一篇文章:Win10使用虚拟USB鼠标实现自动挂机测试功能(文章地址:http://www.usbzh.com/article/detail-476.html ) 使用的是虚拟驱动实现的一个虚拟USB鼠标,实现了产品的自动测试功能。生成的设备在设备管理器中如下:但在开发过程中,并不是一帆......
关注公众号
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!