【问题标题】:ReportID in a HID report descriptorHID 报告描述符中的 ReportID
【发布时间】:2021-10-10 08:58:31
【问题描述】:

我对 ReportID 的工作方式有些困惑。根据 HID 文档,只有主要项目“生成”数据。所有其他项目定义了这些数据的特征。但是定义为全局项的 ReportID 似乎工作方式不同:看看这个操纵杆的报告描述符:

Usage Page (Generic Desktop)    05 01 
Usage (Joystick)    09 04 
Collection (Application)    A1 01 
    Collection (Logical)    A1 02 
        Report ID (1)   85 01 
        Report Size (8)     75 08 
        Report Count (1)    95 01 
        Logical Minimum (0)     15 00 
        Logical Maximum (255)   26 FF 00 
        Input (Cnst,Var,Abs,NWrp,Lin,Pref,NNul,Bit)     81 03 
        Report Size (1)     75 01 
        Report Count (19)   95 13 
        Logical Minimum (0)     15 00 
        Logical Maximum (1)     25 01 
        Physical Minimum (0)    35 00 
        Physical Maximum (1)    45 01 
        Usage Page (Button)     05 09 
        Usage Minimum (Button 1)    19 01 
        Usage Maximum (Button 19)   29 13 
        Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit)     81 02 

当设备发送他的报告时,我希望报告 id 有一个字节,然后是按钮状态的 3 个字节。但情况并非如此:我收到一个字节作为报告 ID,然后是一个空字节,然后是按钮状态的 3 个字节。

这是否意味着我应该威胁 ReportID 作为主要项目而不是全局项目?

谢谢,

威利。

【问题讨论】:

    标签: usb hid descriptor


    【解决方案1】:

    GLOBAL 和 LOCAL 项的区别在于,在解析过程中顺序遇到下一个 MAIN 项时会保留 GLOBAL 项的值,但不保留 LOCAL 项的值。当遇到下一个 MAIN 项时,所有 LOCAL 项的值都将重置为其默认状态。 REPORT_ID 是一个 GLOBAL 项目,这意味着一旦您设置它,它的值将保持不变,直到您将其设置为另一个值。

    您发布的示例将被解析为以下结构(使用C语言语法):

    //--------------------------------------------------------------------------------
    // Generic Desktop Page inputReport 01 (Device --> Host)
    //--------------------------------------------------------------------------------
    
    typedef struct
    {
      uint8_t  reportId;                                 // Report ID = 0x01 (1)
                                                         // Collection: CA:Joystick
      uint8_t  pad_1;                                    // Pad
      uint8_t  BTN_JoystickButton1 : 1;                  // Usage 0x00090001: Button 1 Primary/trigger, Value = 0 to 1
      uint8_t  BTN_JoystickButton2 : 1;                  // Usage 0x00090002: Button 2 Secondary, Value = 0 to 1
      uint8_t  BTN_JoystickButton3 : 1;                  // Usage 0x00090003: Button 3 Tertiary, Value = 0 to 1
      uint8_t  BTN_JoystickButton4 : 1;                  // Usage 0x00090004: Button 4, Value = 0 to 1
      uint8_t  BTN_JoystickButton5 : 1;                  // Usage 0x00090005: Button 5, Value = 0 to 1
      uint8_t  BTN_JoystickButton6 : 1;                  // Usage 0x00090006: Button 6, Value = 0 to 1
      uint8_t  BTN_JoystickButton7 : 1;                  // Usage 0x00090007: Button 7, Value = 0 to 1
      uint8_t  BTN_JoystickButton8 : 1;                  // Usage 0x00090008: Button 8, Value = 0 to 1
      uint8_t  BTN_JoystickButton9 : 1;                  // Usage 0x00090009: Button 9, Value = 0 to 1
      uint8_t  BTN_JoystickButton10 : 1;                 // Usage 0x0009000A: Button 10, Value = 0 to 1
      uint8_t  BTN_JoystickButton11 : 1;                 // Usage 0x0009000B: Button 11, Value = 0 to 1
      uint8_t  BTN_JoystickButton12 : 1;                 // Usage 0x0009000C: Button 12, Value = 0 to 1
      uint8_t  BTN_JoystickButton13 : 1;                 // Usage 0x0009000D: Button 13, Value = 0 to 1
      uint8_t  BTN_JoystickButton14 : 1;                 // Usage 0x0009000E: Button 14, Value = 0 to 1
      uint8_t  BTN_JoystickButton15 : 1;                 // Usage 0x0009000F: Button 15, Value = 0 to 1
      uint8_t  BTN_JoystickButton16 : 1;                 // Usage 0x00090010: Button 16, Value = 0 to 1
      uint8_t  BTN_JoystickButton17 : 1;                 // Usage 0x00090011: Button 17, Value = 0 to 1
      uint8_t  BTN_JoystickButton18 : 1;                 // Usage 0x00090012: Button 18, Value = 0 to 1
      uint8_t  BTN_JoystickButton19 : 1;                 // Usage 0x00090013: Button 19, Value = 0 to 1
    } inputReport01_t;
    

    在内存中如下所示:

       Bit:    7    6    5    4    3    2    1    0  
            .---------------------------------------.
    Byte 0  |     Report ID (0x01)                  |
            |---------------------------------------|
    Byte 1  |     Pad                               |
            |---------------------------------------|
    Byte 2  |  8 |  7 |  6 |  5 |  4 |  3 |  2 |  1 | Buttons 1 to 8
            |---------------------------------------|
    Byte 3  | 16 | 15 | 14 | 13 | 12 | 11 | 10 |  9 | Buttons 9 to 16
            |---------------------------------------|
    Byte 4  |    |    |    |    |    | 19 | 18 | 17 | Buttons 17 to 19
            '---------------------------------------'
    

    换句话说,您看到的是指定报告描述符的正确布局。您可能误解了Input (Cnst,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 03 项的意义——它定义了一个“常量”字节——即一个不包含任何信息但在网络上传输的报告中占用空间的字节。

    【讨论】:

    • 感谢您的回复 我的困惑来自文档。查看“人机接口设备 (HID) 的设备类定义”文档。第 28 页,您可以阅读:“Datatype Main items are used to create a field within a report ...”和第 35 页,您可以阅读:“Global items describe 而不是定义 ...”因为 TargetID 不是主要项目,我没想到它会像输入项那样在报告中创建空间。
    • 是的,USB 规范很难理解。其中的重要信息很容易被遗漏。在这种情况下,该文档的第 5.6 节有这个 gem:“如果设备有多个报告结构,则所有数据传输都以 1 字节标识符前缀开头,指示哪个报告结构适用于传输。这允许类驱动程序区分传入通过检查传输前缀从键盘数据中获取指针数据。”
    猜你喜欢
    • 1970-01-01
    • 2011-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多