您现在的位置是:主页 > HID规范 >

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

发布时间:2022-12-03 05:12:16所属栏目:HID规范 已帮助编辑作者:【USB接口百科】

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 的“设备和打印机”向您展示!
设备描述

     以上就是USB接口百科为您提供HID报告描述符教程 手把手教你编写HID报告描述符的解读,本文章链接: http://www.usb-hub.cn/hidgf/42337.html 欢迎分享转载,更多婚礼相关资讯请前往HID规范