Search code examples
c++windowsusbhidhidapi

HID USB control transfer (Windows)


Recently, I started to learn about communicating with HID devices on Windows 10.

But I got a few questions.

According to the Window's document, HidD_SetOutputReport must set the first byte of the ReportBuffer parameter to a report ID or 0x00.

Since my device's HID Report Descriptor has declared some report id, so I have to set the report id when I use HidD_setoutputreport instead of 0x00?

When I used the report id 0x80 as the buf[0], ex: 0x80 0x02 0x00 ....... 0x00 (my Capabilities.OutputReportByteLength is 64)

And my code is ret = HidD_SetOutputReport(handle->device_handle, buf2, 65)

But I always send the data like this (on Bus Hound):

64 OUT 80 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 4.1.0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 4.1.16

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 4.1.32

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 4.1.48

I thought that it should send buf[1] to buf[64] instead of buf[0] to buf[63] , so I tried ret = HidD_SetOutputReport(handle->device_handle, buf2, 64), but the result was same.

Here is my HID report descriptor of INPUT and OUTPUT:

Usage Page (Generic Desktop) 05 01

Logical Minimum (0) 15 00

Usage (Joystick) 09 04

Collection (Application) A1 01

Report ID (48) 85 30

Usage Page (Generic Desktop) 05 01

Usage Page (Button) 05 09

Usage Minimum (Button 1) 19 01

Usage Maximum (Button 10) 29 0A

Logical Minimum (0) 15 00

Logical Maximum (1) 25 01

Report Size (1) 75 01

Report Count (10) 95 0A

Unit Exponent (0) 55 00

Unit (None) 65 00

Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02

Usage Page (Button) 05 09

Usage Minimum (Button 11) 19 0B

Usage Maximum (Button 14) 29 0E

Logical Minimum (0) 15 00

Logical Maximum (1) 25 01

Report Size (1) 75 01

Report Count (4) 95 04

Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02

Report Size (1) 75 01

Report Count (2) 95 02

Input (Cnst,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 03

Usage (Generic Desktop:Pointer) 0B 01 00 01 00

Collection (Physical) A1 00

   Usage (Generic Desktop:X)    0B 30 00 01 00

   Usage (Generic Desktop:Y)    0B 31 00 01 00

   Usage (Generic Desktop:Z)    0B 32 00 01 00

   Usage (Generic Desktop:Rz)    0B 35 00 01 00

   Logical Minimum (0)    15 00

   Logical Maximum (65535)    27 FF FF 00 00

   Report Size (16)    75 10

   Report Count (4)    95 04

   Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit)    81 02

End Collection C0

Usage (Generic Desktop:Hat Switch) 0B 39 00 01 00

Logical Minimum (0) 15 00

Logical Maximum (7) 25 07

Physical Minimum (0) 35 00

Physical Maximum (315) 46 3B 01

Unit (Eng Rot: Degree) 65 14

Report Size (4) 75 04

Report Count (1) 95 01

Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02

Usage Page (Button) 05 09

Usage Minimum (Button 15) 19 0F

Usage Maximum (Button 18) 29 12

Logical Minimum (0) 15 00

Logical Maximum (1) 25 01

Report Size (1) 75 01

Report Count (4) 95 04

Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02

Report Size (8) 75 08

Report Count (52) 95 34

Input (Cnst,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 03

Usage Page (Vendor-Defined 1) 06 00 FF

Report ID (33) 85 21

Usage (Vendor-Defined 1) 09 01

Report Size (8) 75 08

Report Count (63) 95 3F

Input (Cnst,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 03

Report ID (129) 85 81

Usage (Vendor-Defined 2) 09 02

Report Size (8) 75 08

Report Count (63) 95 3F

Input (Cnst,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 03

Report ID (1) 85 01

Usage (Vendor-Defined 3) 09 03

Report Size (8) 75 08

Report Count (63) 95 3F

Output (Cnst,Var,Abs,NWrp,Lin,Pref,NNul,Vol,Bit) 91 83

Report ID (16) 85 10

Usage (Vendor-Defined 4) 09 04

Report Size (8) 75 08

Report Count (63) 95 3F

Output (Cnst,Var,Abs,NWrp,Lin,Pref,NNul,Vol,Bit) 91 83

Report ID (128) 85 80

Usage (Vendor-Defined 5) 09 05

Report Size (8) 75 08

Report Count (63) 95 3F

Output (Cnst,Var,Abs,NWrp,Lin,Pref,NNul,Vol,Bit) 91 83

Report ID (130) 85 82

Usage (Vendor-Defined 6) 09 06

Report Size (8) 75 08

Report Count (63) 95 3F

Output (Cnst,Var,Abs,NWrp,Lin,Pref,NNul,Vol,Bit) 91 83

End Collection C0


Solution

  • I can't really comment on the Windows API (I've never used it), but I know that if you specify a report id in your HID report descriptor then the report id occupies the first byte of your packet and the rest of the packet is your payload otherwise your packet is all payload and no REPORT_ID is sent. In your case, your RD specifies a REPORT_ID and 63 byte payload, so I would specify a length of 64, and put the REPORT_ID in the first byte.

    The report id is transmitted to the end point so that it can know how to interpret each report

    I've checked your report descriptor and I can suggest a few tweaks that may reduce the chance of future grief.

    • Remove the 52-bytes of pad from the input report. It'll only be ignored by the host anyway so there is no need to send it from your device.
    • Use shorter usage codes to reduce size of the report descriptor. This could be important if your device is short on memory.
    • Reset physical units when not needed. If you don't do that, then the physical units apply to all subsequent items - which may not be appropriate (for example, an on/off switch having a length in inches). I've done this by using PUSH to save the global variables and POP to restore them at a convenient point later.
    • Specify DATA (not CONSTANT) on your OUTPUT reports. I'm really not sure if this makes any difference, but you never know, some future USB driver may choose to set any CONSTANT fields to nulls before sending the packet which would cause pain.

    The report descriptor size reduced from 203 bytes to just 133 bytes after doing the above:

    //--------------------------------------------------------------------------------
    // Report descriptor data in hex (length 133 bytes)
    //--------------------------------------------------------------------------------
    
    
    // 05011409 04A10185 30050925 017501A4 1901290A 950A8102 190B290E 95048102
    // 95028103 05010901 A0093009 31093209 3527FFFF 00007510 95048102 C0093925
    // 0734463B 01651475 04950181 02B4190F 29129504 810226FF 00750895 3F0600FF
    // 85210901 81028581 09028102 85010903 91828510 09049182 85800905 91828582
    // 09069182 C0      
    
    
    //--------------------------------------------------------------------------------
    // Decoded Application Collection
    //--------------------------------------------------------------------------------
    
    /*
    05 01        (GLOBAL) USAGE_PAGE         0x0001 Generic Desktop Page 
    14           (GLOBAL) LOGICAL_MINIMUM    (0) <-- Redundant: LOGICAL_MINIMUM is already 0 
    09 04        (LOCAL)  USAGE              0x00010004 Joystick (CA=Application Collection) 
    A1 01        (MAIN)   COLLECTION         0x00000001 Application (Usage=0x00010004: Page=Generic Desktop Page, Usage=Joystick, Type=CA)
    85 30          (GLOBAL) REPORT_ID          0x30 (48) '0' 
    05 09          (GLOBAL) USAGE_PAGE         0x0009 Button Page 
    25 01          (GLOBAL) LOGICAL_MAXIMUM    0x01 (1)  
    75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field  
    A4             (GLOBAL) PUSH               USAGE_PAGE=0x0009 LOGICAL(MIN=0,MAX=1) PHYSICAL(MIN=0,MAX=0) UNIT(0x0,EXP=0) REPORT(ID=0x30,SIZE=1,COUNT=0)
    19 01          (LOCAL)  USAGE_MINIMUM      0x00090001 Button 1 Primary/trigger (MULTI=Selector, On/Off, Momentary, or One Shot) 
    29 0A          (LOCAL)  USAGE_MAXIMUM      0x0009000A Button 10 (MULTI=Selector, On/Off, Momentary, or One Shot) 
    95 0A          (GLOBAL) REPORT_COUNT       0x0A (10) Number of fields  
    81 02          (MAIN)   INPUT              0x00000002 (10 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 
    19 0B          (LOCAL)  USAGE_MINIMUM      0x0009000B Button 11 (MULTI=Selector, On/Off, Momentary, or One Shot) 
    29 0E          (LOCAL)  USAGE_MAXIMUM      0x0009000E Button 14 (MULTI=Selector, On/Off, Momentary, or One Shot) 
    95 04          (GLOBAL) REPORT_COUNT       0x04 (4) Number of fields  
    81 02          (MAIN)   INPUT              0x00000002 (4 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 
    95 02          (GLOBAL) REPORT_COUNT       0x02 (2) Number of fields  
    81 03          (MAIN)   INPUT              0x00000003 (2 fields x 1 bit) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 
    05 01          (GLOBAL) USAGE_PAGE         0x0001 Generic Desktop Page 
    09 01          (LOCAL)  USAGE              0x00010001 Pointer (CP=Physical Collection) 
    A0             (MAIN)   COLLECTION         0x00000000 Physical (Usage=0x00010001: Page=Generic Desktop Page, Usage=Pointer, Type=CP)
    09 30            (LOCAL)  USAGE              0x00010030 X (DV=Dynamic Value) 
    09 31            (LOCAL)  USAGE              0x00010031 Y (DV=Dynamic Value) 
    09 32            (LOCAL)  USAGE              0x00010032 Z (DV=Dynamic Value) 
    09 35            (LOCAL)  USAGE              0x00010035 Rz (DV=Dynamic Value) 
    27 FFFF0000      (GLOBAL) LOGICAL_MAXIMUM    0x0000FFFF (65535)  
    75 10            (GLOBAL) REPORT_SIZE        0x10 (16) Number of bits per field  
    95 04            (GLOBAL) REPORT_COUNT       0x04 (4) Number of fields  
    81 02            (MAIN)   INPUT              0x00000002 (4 fields x 16 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 
    C0             (MAIN)   END_COLLECTION     Physical 
    09 39          (LOCAL)  USAGE              0x00010039 Hat switch (DV=Dynamic Value) 
    25 07          (GLOBAL) LOGICAL_MAXIMUM    0x07 (7)  
    34             (GLOBAL) PHYSICAL_MINIMUM   (0) <-- Redundant: PHYSICAL_MINIMUM is already 0 
    46 3B01        (GLOBAL) PHYSICAL_MAXIMUM   0x013B (315)  
    65 14          (GLOBAL) UNIT               0x00000014 Rotation in degrees [1° units] (4=System=English Rotation, 1=Rotation=Degrees) 
    75 04          (GLOBAL) REPORT_SIZE        0x04 (4) Number of bits per field  
    95 01          (GLOBAL) REPORT_COUNT       0x01 (1) Number of fields  
    81 02          (MAIN)   INPUT              0x00000002 (1 field x 4 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 
    B4             (GLOBAL) POP                USAGE_PAGE=0x0009 LOGICAL(MIN=0,MAX=1) PHYSICAL(MIN=0,MAX=0) UNIT(0x0,EXP=0) REPORT(ID=0x30,SIZE=1,COUNT=0)
    19 0F          (LOCAL)  USAGE_MINIMUM      0x0009000F Button 15 (MULTI=Selector, On/Off, Momentary, or One Shot) 
    29 12          (LOCAL)  USAGE_MAXIMUM      0x00090012 Button 18 (MULTI=Selector, On/Off, Momentary, or One Shot) 
    95 04          (GLOBAL) REPORT_COUNT       0x04 (4) Number of fields  
    81 02          (MAIN)   INPUT              0x00000002 (4 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 
    26 FF00        (GLOBAL) LOGICAL_MAXIMUM    0x00FF (255)  
    75 08          (GLOBAL) REPORT_SIZE        0x08 (8) Number of bits per field  
    95 3F          (GLOBAL) REPORT_COUNT       0x3F (63) Number of fields  
    06 00FF        (GLOBAL) USAGE_PAGE         0xFF00 Vendor-defined 
    85 21          (GLOBAL) REPORT_ID          0x21 (33) 
    09 01          (LOCAL)  USAGE              0xFF000001 <-- Warning: Undocumented usage
    81 02          (MAIN)   INPUT              0x00000002 (63 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 
    85 81          (GLOBAL) REPORT_ID          0x81 (129) 
    09 02          (LOCAL)  USAGE              0xFF000002 <-- Warning: Undocumented usage
    81 02          (MAIN)   INPUT              0x00000002 (63 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap 
    85 01          (GLOBAL) REPORT_ID          0x01 (1) 
    09 03          (LOCAL)  USAGE              0xFF000003 <-- Warning: Undocumented usage
    91 82          (MAIN)   OUTPUT             0x00000082 (63 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 1=Volatile 0=Bitmap 
    85 10          (GLOBAL) REPORT_ID          0x10 (16) 
    09 04          (LOCAL)  USAGE              0xFF000004 <-- Warning: Undocumented usage
    91 82          (MAIN)   OUTPUT             0x00000082 (63 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 1=Volatile 0=Bitmap 
    85 80          (GLOBAL) REPORT_ID          0x80 (128) 
    09 05          (LOCAL)  USAGE              0xFF000005 <-- Warning: Undocumented usage
    91 82          (MAIN)   OUTPUT             0x00000082 (63 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 1=Volatile 0=Bitmap 
    85 82          (GLOBAL) REPORT_ID          0x82 (130) 
    09 06          (LOCAL)  USAGE              0xFF000006 <-- Warning: Undocumented usage
    91 82          (MAIN)   OUTPUT             0x00000082 (63 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 1=Volatile 0=Bitmap 
    C0           (MAIN)   END_COLLECTION     Application 
    */
    
    //--------------------------------------------------------------------------------
    // Button Page inputReport 30 (Device --> Host)
    //--------------------------------------------------------------------------------
    
    typedef struct
    {
      uint8_t  reportId;                                 // Report ID = 0x30 (48) '0'
                                                         // Collection: Joystick
      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  : 1;                                      // Pad
      uint8_t  : 1;                                      // Pad
                                                         // Collection: Joystick Pointer
      uint16_t GD_JoystickPointerX;                      // Usage 0x00010030: X, Value = 0 to 65535
      uint16_t GD_JoystickPointerY;                      // Usage 0x00010031: Y, Value = 0 to 65535
      uint16_t GD_JoystickPointerZ;                      // Usage 0x00010032: Z, Value = 0 to 65535
      uint16_t GD_JoystickPointerRz;                     // Usage 0x00010035: Rz, Value = 0 to 65535
                                                         // Collection: Joystick
      uint8_t  GD_JoystickHatSwitch : 4;                 // Usage 0x00010039: Hat switch, Value = 0 to 7, Physical = Value x 45 in degrees
      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
    } inputReport30_t;
    
    
    //--------------------------------------------------------------------------------
    // Vendor-defined inputReport 21 (Device --> Host)
    //--------------------------------------------------------------------------------
    
    typedef struct
    {
      uint8_t  reportId;                                 // Report ID = 0x21 (33)
      uint8_t  VEN_Joystick0001[63];                     // Usage 0xFF000001: , Value = 0 to 255
    } inputReport21_t;
    
    
    //--------------------------------------------------------------------------------
    // Vendor-defined inputReport 81 (Device --> Host)
    //--------------------------------------------------------------------------------
    
    typedef struct
    {
      uint8_t  reportId;                                 // Report ID = 0x81 (129)
      uint8_t  VEN_Joystick0002[63];                     // Usage 0xFF000002: , Value = 0 to 255
    } inputReport81_t;
    
    
    //--------------------------------------------------------------------------------
    // Vendor-defined outputReport 01 (Device <-- Host)
    //--------------------------------------------------------------------------------
    
    typedef struct
    {
      uint8_t  reportId;                                 // Report ID = 0x01 (1)
                                                         // Collection: Joystick
      uint8_t  VEN_Joystick0003[63];                     // Usage 0xFF000003: , Value = 0 to 255
    } outputReport01_t;
    
    
    //--------------------------------------------------------------------------------
    // Vendor-defined outputReport 10 (Device <-- Host)
    //--------------------------------------------------------------------------------
    
    typedef struct
    {
      uint8_t  reportId;                                 // Report ID = 0x10 (16)
      uint8_t  VEN_Joystick0004[63];                     // Usage 0xFF000004: , Value = 0 to 255
    } outputReport10_t;
    
    
    //--------------------------------------------------------------------------------
    // Vendor-defined outputReport 80 (Device <-- Host)
    //--------------------------------------------------------------------------------
    
    typedef struct
    {
      uint8_t  reportId;                                 // Report ID = 0x80 (128)
      uint8_t  VEN_Joystick0005[63];                     // Usage 0xFF000005: , Value = 0 to 255
    } outputReport80_t;
    
    
    //--------------------------------------------------------------------------------
    // Vendor-defined outputReport 82 (Device <-- Host)
    //--------------------------------------------------------------------------------
    
    typedef struct
    {
      uint8_t  reportId;                                 // Report ID = 0x82 (130)
      uint8_t  VEN_Joystick0006[63];                     // Usage 0xFF000006: , Value = 0 to 255
    } outputReport82_t;