使用功能报告增加 HID 设备的音量

Increasing the volume of an HID device using feature reports

我需要向设备发送什么十六进制代码(以及什么报告索引)来触发音量变化?

我正在尝试使用 HID 功能报告来增加 Jabra 410 耳机的音量。 Jabra 提供以下界面和报告说明:

https://pastebin.com/ES8ivMym

Report Descriptor: (length is 273)
        Item(Global): Usage Page, data= [ 0x0c ] 12
                        Consumer
        Item(Local ): Usage, data= [ 0x01 ] 1
                        Consumer Control
        Item(Main  ): Collection, data= [ 0x01 ] 1
                        Application
        Item(Global): Report ID, data= [ 0x01 ] 1
        Item(Global): Usage Page, data= [ 0x0c ] 12
                        Consumer
        Item(Global): Logical Minimum, data= [ 0x00 ] 0
        Item(Global): Logical Maximum, data= [ 0x01 ] 1
        Item(Local ): Usage, data= [ 0xea ] 234
                        Volume Decrement
        Item(Local ): Usage, data= [ 0xe9 ] 233
                        Volume Increment
        Item(Local ): Usage, data= [ 0xe2 ] 226
                        Mute
        Item(Global): Report Size, data= [ 0x01 ] 1
        Item(Global): Report Count, data= [ 0x03 ] 3
        Item(Main  ): Input, data= [ 0x02 ] 2
                        Data Variable Absolute No_Wrap Linear
                        Preferred_State No_Null_Position Non_Volatile Bitfield
        Item(Global): Report Size, data= [ 0x01 ] 1
        Item(Global): Report Count, data= [ 0x05 ] 5
        Item(Main  ): Input, data= [ 0x01 ] 1
                        Constant Array Absolute No_Wrap Linear
                        Preferred_State No_Null_Position Non_Volatile Bitfield
        Item(Main  ): End Collection, data=none
        Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
                        (null)
        Item(Local ): Usage, data= [ 0x01 ] 1
                        (null)
        Item(Main  ): Collection, data= [ 0x01 ] 1
                        Application
        Item(Global): Report ID, data= [ 0x02 ] 2
        Item(Local ): Usage, data= [ 0x01 ] 1
                        (null)
        Item(Global): Logical Minimum, data= [ 0x00 ] 0
        Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
        Item(Global): Report Size, data= [ 0x08 ] 8
        Item(Global): Report Count, data= [ 0x20 ] 32
        Item(Main  ): Output, data= [ 0x02 0x01 ] 258
                        Data Variable Absolute No_Wrap Linear
                        Preferred_State No_Null_Position Non_Volatile Buffered Bytes
        Item(Local ): Usage, data= [ 0x01 ] 1
                        (null)
        Item(Global): Logical Minimum, data= [ 0x00 ] 0
        Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
        Item(Global): Report Size, data= [ 0x08 ] 8
        Item(Global): Report Count, data= [ 0x20 ] 32
        Item(Main  ): Input, data= [ 0x02 0x01 ] 258
                        Data Variable Absolute No_Wrap Linear
                        Preferred_State No_Null_Position Non_Volatile Buffered Bytes
        Item(Global): Report ID, data= [ 0x04 ] 4
        Item(Global): Usage Page, data= [ 0x30 0xff ] 65328
                        (null)
        Item(Global): Logical Minimum, data= [ 0x00 ] 0
        Item(Global): Logical Maximum, data= [ 0x01 ] 1
        Item(Local ): Usage, data= [ 0x20 ] 32
                        (null)
        Item(Local ): Usage, data= [ 0x97 ] 151
                        (null)
        Item(Local ): Usage, data= [ 0x2b ] 43
                        (null)
        Item(Global): Report Size, data= [ 0x01 ] 1
        Item(Global): Report Count, data= [ 0x03 ] 3
        Item(Main  ): Input, data= [ 0x23 ] 35
                        Constant Variable Absolute No_Wrap Linear
                        No_Preferred_State No_Null_Position Non_Volatile Bitfield
        Item(Local ): Usage, data= [ 0x2f ] 47
                        (null)
        Item(Local ): Usage, data= [ 0x21 ] 33
                        (null)
        Item(Local ): Usage, data= [ 0x24 ] 36
                        (null)
        Item(Local ): Usage, data= [ 0xfd 0xff ] 65533
                        (null)
        Item(Global): Report Size, data= [ 0x01 ] 1
        Item(Global): Report Count, data= [ 0x04 ] 4
        Item(Main  ): Input, data= [ 0x07 ] 7
                        Constant Variable Relative No_Wrap Linear
                        Preferred_State No_Null_Position Non_Volatile Bitfield
        Item(Global): Report Size, data= [ 0x01 ] 1
        Item(Global): Report Count, data= [ 0x09 ] 9
        Item(Main  ): Input, data= [ 0x01 ] 1
                        Constant Array Absolute No_Wrap Linear
                        Preferred_State No_Null_Position Non_Volatile Bitfield
        Item(Local ): Usage, data= [ 0xff 0xff ] 65535
                        (null)
        Item(Global): Report Size, data= [ 0x01 ] 1
        Item(Global): Report Count, data= [ 0x01 ] 1
        Item(Main  ): Feature, data= [ 0x22 ] 34
                        Data Variable Absolute No_Wrap Linear
                        No_Preferred_State No_Null_Position Non_Volatile Bitfield
        Item(Global): Report Size, data= [ 0x01 ] 1
        Item(Global): Report Count, data= [ 0x07 ] 7
        Item(Main  ): Feature, data= [ 0x01 ] 1
                        Constant Array Absolute No_Wrap Linear
                        Preferred_State No_Null_Position Non_Volatile Bitfield
        Item(Global): Usage Page, data= [ 0x40 0xff ] 65344
                        (null)
        Item(Global): Logical Minimum, data= [ 0x00 ] 0
        Item(Global): Logical Maximum, data= [ 0x01 ] 1
        Item(Local ): Usage, data= [ 0x17 ] 23
                        (null)
        Item(Local ): Usage, data= [ 0x1e ] 30
                        (null)
        Item(Local ): Usage, data= [ 0x09 ] 9
                        (null)
        Item(Local ): Usage, data= [ 0x18 ] 24
                        (null)
        Item(Local ): Usage, data= [ 0x20 ] 32
                        (null)
        Item(Local ): Usage, data= [ 0x21 ] 33
                        (null)
        Item(Global): Report Size, data= [ 0x01 ] 1
        Item(Global): Report Count, data= [ 0x06 ] 6
        Item(Main  ): Output, data= [ 0x22 ] 34
                        Data Variable Absolute No_Wrap Linear
                        No_Preferred_State No_Null_Position Non_Volatile Bitfield
        Item(Global): Usage Page, data= [ 0x30 0xff ] 65328
                        (null)
        Item(Global): Logical Minimum, data= [ 0x00 ] 0
        Item(Global): Logical Maximum, data= [ 0x01 ] 1
        Item(Local ): Usage, data= [ 0x9e ] 158
                        (null)
        Item(Global): Report Size, data= [ 0x01 ] 1
        Item(Global): Report Count, data= [ 0x01 ] 1
        Item(Main  ): Output, data= [ 0x22 ] 34
                        Data Variable Absolute No_Wrap Linear
                        No_Preferred_State No_Null_Position Non_Volatile Bitfield
        Item(Global): Report Size, data= [ 0x01 ] 1
        Item(Global): Report Count, data= [ 0x09 ] 9
        Item(Main  ): Output, data= [ 0x01 ] 1
                        Constant Array Absolute No_Wrap Linear
                        Preferred_State No_Null_Position Non_Volatile Bitfield
        Item(Main  ): End Collection, data=none
        Item(Global): Usage Page, data= [ 0x0b ] 11
                        Telephony
        Item(Local ): Usage, data= [ 0x05 ] 5
                        Headset
        Item(Main  ): Collection, data= [ 0x01 ] 1
                        Application
        Item(Global): Report ID, data= [ 0x03 ] 3
        Item(Global): Usage Page, data= [ 0x0b ] 11
                        Telephony
        Item(Global): Logical Minimum, data= [ 0x00 ] 0
        Item(Global): Logical Maximum, data= [ 0x01 ] 1
        Item(Local ): Usage, data= [ 0x20 ] 32
                        Hook Switch
        Item(Local ): Usage, data= [ 0x97 ] 151
                        Line Busy Tone
        Item(Local ): Usage, data= [ 0x2b ] 43
                        Speaker Phone
        Item(Global): Report Size, data= [ 0x01 ] 1
        Item(Global): Report Count, data= [ 0x03 ] 3
        Item(Main  ): Input, data= [ 0x23 ] 35
                        Constant Variable Absolute No_Wrap Linear
                        No_Preferred_State No_Null_Position Non_Volatile Bitfield
        Item(Local ): Usage, data= [ 0x2f ] 47
                        Phone Mute
        Item(Local ): Usage, data= [ 0x21 ] 33
                        Flash
        Item(Local ): Usage, data= [ 0x24 ] 36
                        Redial
        Item(Global): Report Size, data= [ 0x01 ] 1
        Item(Global): Report Count, data= [ 0x03 ] 3
        Item(Main  ): Input, data= [ 0x07 ] 7
                        Constant Variable Relative No_Wrap Linear
                        Preferred_State No_Null_Position Non_Volatile Bitfield
        Item(Local ): Usage, data= [ 0x07 ] 7
                        Programmable Button
        Item(Global): Usage Page, data= [ 0x09 ] 9
                        Buttons
        Item(Local ): Usage, data= [ 0x01 ] 1
                        Button 1 (Primary)
        Item(Global): Report Size, data= [ 0x01 ] 1
        Item(Global): Report Count, data= [ 0x01 ] 1
        Item(Main  ): Input, data= [ 0x02 ] 2
                        Data Variable Absolute No_Wrap Linear
                        Preferred_State No_Null_Position Non_Volatile Bitfield
        Item(Global): Report Count, data= [ 0x09 ] 9
        Item(Main  ): Input, data= [ 0x01 ] 1
                        Constant Array Absolute No_Wrap Linear
                        Preferred_State No_Null_Position Non_Volatile Bitfield
        Item(Global): Usage Page, data= [ 0x08 ] 8
                        LEDs
        Item(Global): Logical Minimum, data= [ 0x00 ] 0
        Item(Global): Logical Maximum, data= [ 0x01 ] 1
        Item(Local ): Usage, data= [ 0x17 ] 23
                        Off-Hook
        Item(Local ): Usage, data= [ 0x1e ] 30
                        Speaker
        Item(Local ): Usage, data= [ 0x09 ] 9
                        Mute
        Item(Local ): Usage, data= [ 0x18 ] 24
                        Ring
        Item(Local ): Usage, data= [ 0x20 ] 32
                        Hold
        Item(Local ): Usage, data= [ 0x21 ] 33
                        Microphone
        Item(Global): Report Size, data= [ 0x01 ] 1
        Item(Global): Report Count, data= [ 0x06 ] 6
        Item(Main  ): Output, data= [ 0x22 ] 34
                        Data Variable Absolute No_Wrap Linear
                        No_Preferred_State No_Null_Position Non_Volatile Bitfield
        Item(Global): Usage Page, data= [ 0x0b ] 11
                        Telephony
        Item(Global): Logical Minimum, data= [ 0x00 ] 0
        Item(Global): Logical Maximum, data= [ 0x01 ] 1
        Item(Local ): Usage, data= [ 0x9e ] 158
                        (null)
        Item(Global): Report Size, data= [ 0x01 ] 1
        Item(Global): Report Count, data= [ 0x01 ] 1
        Item(Main  ): Output, data= [ 0x22 ] 34
                        Data Variable Absolute No_Wrap Linear
                        No_Preferred_State No_Null_Position Non_Volatile Bitfield
        Item(Global): Report Size, data= [ 0x01 ] 1
        Item(Global): Report Count, data= [ 0x09 ] 9
        Item(Main  ): Output, data= [ 0x01 ] 1
                        Constant Array Absolute No_Wrap Linear
                        Preferred_State No_Null_Position Non_Volatile Bitfield
        Item(Main  ): End Collection, data=none

我已成功使用功能报告 #3 与设备交互,包括一些 LED 和呼叫状态的操作。但是,没有任何数据组合会改变音量,并且在与功能报告 #1 交互时我没有得到任何响应,如果我正确阅读报告,它应该负责音量。

例如,将十六进制值 05(如 00000101)发送到页面 #3 会导致设备进入静音状态。

我解码了报告描述符,似乎音量 increment/decrement 报告是使用 input[=22= 从设备(耳机)发送到主机(PC 或其他设备) ] 报告,而不是 feature 报告。也就是说,设备告诉主机 increment/decrement 音量 - 而不是相反。

顺便说一句,我只看到定义了一个功能报告,它使用 REPORT_ID 0x04。

具体来说,带REPORT_ID0x01的输入报告用于音量控制:

//--------------------------------------------------------------------------------
// Consumer Device Page inputReport 01 (Device --> Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x01 (1)
                                                     // Collection: ConsumerControl
  uint8_t  CD_ConsumerControlVolumeDecrement : 1;    // Usage 0x000C00EA: Volume Decrement, Value = 0 to 1
  uint8_t  CD_ConsumerControlVolumeIncrement : 1;    // Usage 0x000C00E9: Volume Increment, Value = 0 to 1
  uint8_t  CD_ConsumerControlMute : 1;               // Usage 0x000C00E2: Mute, Value = 0 to 1
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
} inputReport01_t;

完整的解码报告描述符如下所示...

hidrdd git:master ❯ rexx rd.rex --dump -dsa samples/headset-jabra410.rd

//--------------------------------------------------------------------------------
// Report descriptor data in hex (length 273 bytes)
//--------------------------------------------------------------------------------


// 050C0901 A1018501 050C1500 250109EA 09E909E2 75019503 81027501 95058101
// C00600FF 0901A101 85020901 150026FF 00750895 20920201 09011500 26FF0075
// 08952082 02018504 0630FF15 00250109 20099709 2B750195 03812309 2F092109
// 240AFDFF 75019504 81077501 95098101 0AFFFF75 019501B1 22750195 07B10106
// 40FF1500 25010917 091E0909 09180920 09217501 95069122 0630FF15 00250109
// 9E750195 01912275 01950991 01C0050B 0905A101 8503050B 15002501 09200997
// 092B7501 95038123 092F0921 09247501 95038107 09070509 09017501 95018102
// 95098101 05081500 25010917 091E0909 09180920 09217501 95069122 050B1500
// 2501099E 75019501 91227501 95099101 C0


//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------

/*
05 0C        (GLOBAL) USAGE_PAGE         0x000C Consumer Device Page
09 01        (LOCAL)  USAGE              0x000C0001 Consumer Control (CA=Application Collection)
A1 01        (MAIN)   COLLECTION         0x00000001 Application (Usage=0x000C0001: Page=Consumer Device Page, Usage=Consumer Control, Type=CA)
85 01          (GLOBAL) REPORT_ID          0x01 (1)
05 0C          (GLOBAL) USAGE_PAGE         0x000C Consumer Device Page <-- Redundant: USAGE_PAGE is already 0x000C
15 00          (GLOBAL) LOGICAL_MINIMUM    0x00 (0)  <-- Info: Consider replacing 15 00 with 14
25 01          (GLOBAL) LOGICAL_MAXIMUM    0x01 (1)
09 EA          (LOCAL)  USAGE              0x000C00EA Volume Decrement (RTC=Re-trigger Control)
09 E9          (LOCAL)  USAGE              0x000C00E9 Volume Increment (RTC=Re-trigger Control)
09 E2          (LOCAL)  USAGE              0x000C00E2 Mute (OOC=On/Off Control)
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field
95 03          (GLOBAL) REPORT_COUNT       0x03 (3) Number of fields
81 02          (MAIN)   INPUT              0x00000002 (3 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 05          (GLOBAL) REPORT_COUNT       0x05 (5) Number of fields
81 01          (MAIN)   INPUT              0x00000001 (5 fields x 1 bit) 1=Constant 0=Array 0=Absolute
C0           (MAIN)   END_COLLECTION     Application
*/

//--------------------------------------------------------------------------------
// Consumer Device Page inputReport 01 (Device --> Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x01 (1)
                                                     // Collection: ConsumerControl
  uint8_t  CD_ConsumerControlVolumeDecrement : 1;    // Usage 0x000C00EA: Volume Decrement, Value = 0 to 1
  uint8_t  CD_ConsumerControlVolumeIncrement : 1;    // Usage 0x000C00E9: Volume Increment, Value = 0 to 1
  uint8_t  CD_ConsumerControlMute : 1;               // Usage 0x000C00E2: Mute, Value = 0 to 1
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
} inputReport01_t;


//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------

/*
06 00FF      (GLOBAL) USAGE_PAGE         0xFF00 Vendor-defined
09 01        (LOCAL)  USAGE              0xFF000001 <-- Warning: Undocumented usage
A1 01        (MAIN)   COLLECTION         0x00000001 Application (Usage=0xFF000001: Page=Vendor-defined, Usage=, Type=)
85 02          (GLOBAL) REPORT_ID          0x02 (2)
09 01          (LOCAL)  USAGE              0xFF000001 <-- Warning: Undocumented usage
15 00          (GLOBAL) LOGICAL_MINIMUM    0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
26 FF00        (GLOBAL) LOGICAL_MAXIMUM    0x00FF (255)
75 08          (GLOBAL) REPORT_SIZE        0x08 (8) Number of bits per field
95 20          (GLOBAL) REPORT_COUNT       0x20 (32) Number of fields
92 0201        (MAIN)   OUTPUT             0x00000102 (32 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 1=Buffer
09 01          (LOCAL)  USAGE              0xFF000001 <-- Warning: Undocumented usage
15 00          (GLOBAL) LOGICAL_MINIMUM    0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
26 FF00        (GLOBAL) LOGICAL_MAXIMUM    0x00FF (255) <-- Redundant: LOGICAL_MAXIMUM is already 255
75 08          (GLOBAL) REPORT_SIZE        0x08 (8) Number of bits per field <-- Redundant: REPORT_SIZE is already 8
95 20          (GLOBAL) REPORT_COUNT       0x20 (32) Number of fields <-- Redundant: REPORT_COUNT is already 32
82 0201        (MAIN)   INPUT              0x00000102 (32 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 1=Buffer
85 04          (GLOBAL) REPORT_ID          0x04 (4)
06 30FF        (GLOBAL) USAGE_PAGE         0xFF30 Vendor-defined
15 00          (GLOBAL) LOGICAL_MINIMUM    0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 01          (GLOBAL) LOGICAL_MAXIMUM    0x01 (1)
09 20          (LOCAL)  USAGE              0xFF300020 <-- Warning: Undocumented usage
09 97          (LOCAL)  USAGE              0xFF300097 <-- Warning: Undocumented usage
09 2B          (LOCAL)  USAGE              0xFF30002B <-- Warning: Undocumented usage
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field
95 03          (GLOBAL) REPORT_COUNT       0x03 (3) Number of fields
81 23          (MAIN)   INPUT              0x00000023 (3 fields x 1 bit) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 1=NoPrefState 0=NoNull 0=NonVolatile 0=Bitmap
09 2F          (LOCAL)  USAGE              0xFF30002F <-- Warning: Undocumented usage
09 21          (LOCAL)  USAGE              0xFF300021 <-- Warning: Undocumented usage
09 24          (LOCAL)  USAGE              0xFF300024 <-- Warning: Undocumented usage
0A FDFF        (LOCAL)  USAGE              0xFF30FFFD <-- Warning: Undocumented usage
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 04          (GLOBAL) REPORT_COUNT       0x04 (4) Number of fields
81 07          (MAIN)   INPUT              0x00000007 (4 fields x 1 bit) 1=Constant 1=Variable 1=Relative 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 09          (GLOBAL) REPORT_COUNT       0x09 (9) Number of fields
81 01          (MAIN)   INPUT              0x00000001 (9 fields x 1 bit) 1=Constant 0=Array 0=Absolute
0A FFFF        (LOCAL)  USAGE              0xFF30FFFF <-- Warning: Undocumented usage
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 01          (GLOBAL) REPORT_COUNT       0x01 (1) Number of fields
B1 22          (MAIN)   FEATURE            0x00000022 (1 field x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 1=NoPrefState 0=NoNull 0=NonVolatile 0=Bitmap
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 07          (GLOBAL) REPORT_COUNT       0x07 (7) Number of fields
B1 01          (MAIN)   FEATURE            0x00000001 (7 fields x 1 bit) 1=Constant 0=Array 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
06 40FF        (GLOBAL) USAGE_PAGE         0xFF40 Vendor-defined
15 00          (GLOBAL) LOGICAL_MINIMUM    0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 01          (GLOBAL) LOGICAL_MAXIMUM    0x01 (1) <-- Redundant: LOGICAL_MAXIMUM is already 1
09 17          (LOCAL)  USAGE              0xFF400017 <-- Warning: Undocumented usage
09 1E          (LOCAL)  USAGE              0xFF40001E <-- Warning: Undocumented usage
09 09          (LOCAL)  USAGE              0xFF400009 <-- Warning: Undocumented usage
09 18          (LOCAL)  USAGE              0xFF400018 <-- Warning: Undocumented usage
09 20          (LOCAL)  USAGE              0xFF400020 <-- Warning: Undocumented usage
09 21          (LOCAL)  USAGE              0xFF400021 <-- Warning: Undocumented usage
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 06          (GLOBAL) REPORT_COUNT       0x06 (6) Number of fields
91 22          (MAIN)   OUTPUT             0x00000022 (6 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 1=NoPrefState 0=NoNull 0=NonVolatile 0=Bitmap
06 30FF        (GLOBAL) USAGE_PAGE         0xFF30 Vendor-defined
15 00          (GLOBAL) LOGICAL_MINIMUM    0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 01          (GLOBAL) LOGICAL_MAXIMUM    0x01 (1) <-- Redundant: LOGICAL_MAXIMUM is already 1
09 9E          (LOCAL)  USAGE              0xFF30009E <-- Warning: Undocumented usage
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 01          (GLOBAL) REPORT_COUNT       0x01 (1) Number of fields
91 22          (MAIN)   OUTPUT             0x00000022 (1 field x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 1=NoPrefState 0=NoNull 0=NonVolatile 0=Bitmap
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 09          (GLOBAL) REPORT_COUNT       0x09 (9) Number of fields
91 01          (MAIN)   OUTPUT             0x00000001 (9 fields x 1 bit) 1=Constant 0=Array 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
C0           (MAIN)   END_COLLECTION     Application
*/

//--------------------------------------------------------------------------------
// Vendor-defined featureReport 04 (Device <-> Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x04 (4)
  uint8_t  VEN_VendorDefinedFFFF : 1;                // Usage 0xFF30FFFF: , Value = 0 to 1
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
} featureReport04_t;


//--------------------------------------------------------------------------------
// Vendor-defined inputReport 02 (Device --> Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x02 (2)
  uint8_t  VEN_VendorDefined0001[32];                // Usage 0xFF000001: , Value = 0 to 255
} inputReport02_t;


//--------------------------------------------------------------------------------
// Vendor-defined inputReport 04 (Device --> Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x04 (4)
  uint8_t  VEN_VendorDefined0020 : 1;                // Usage 0xFF300020: , Value = 0 to 1
  uint8_t  VEN_VendorDefined0097 : 1;                // Usage 0xFF300097: , Value = 0 to 1
  uint8_t  VEN_VendorDefined002B : 1;                // Usage 0xFF30002B: , Value = 0 to 1
  uint8_t  VEN_VendorDefined002F : 1;                // Usage 0xFF30002F: , Value = 0 to 1
  uint8_t  VEN_VendorDefined0021 : 1;                // Usage 0xFF300021: , Value = 0 to 1
  uint8_t  VEN_VendorDefined0024 : 1;                // Usage 0xFF300024: , Value = 0 to 1
  uint8_t  VEN_VendorDefinedFFFD : 1;                // Usage 0xFF30FFFD: , Value = 0 to 1
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
} inputReport04_t;


//--------------------------------------------------------------------------------
// Vendor-defined outputReport 02 (Device <-- Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x02 (2)
  uint8_t  VEN_VendorDefined0001[32];                // Usage 0xFF000001: , Value = 0 to 255
} outputReport02_t;


//--------------------------------------------------------------------------------
// Vendor-defined outputReport 04 (Device <-- Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x04 (4)
  uint8_t  VEN_VendorDefined0017 : 1;                // Usage 0xFF400017: , Value = 0 to 1
  uint8_t  VEN_VendorDefined001E : 1;                // Usage 0xFF40001E: , Value = 0 to 1
  uint8_t  VEN_VendorDefined0009 : 1;                // Usage 0xFF400009: , Value = 0 to 1
  uint8_t  VEN_VendorDefined0018 : 1;                // Usage 0xFF400018: , Value = 0 to 1
  uint8_t  VEN_VendorDefined0020 : 1;                // Usage 0xFF400020: , Value = 0 to 1
  uint8_t  VEN_VendorDefined0021 : 1;                // Usage 0xFF400021: , Value = 0 to 1
  uint8_t  VEN_VendorDefined009E : 1;                // Usage 0xFF30009E: , Value = 0 to 1
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
} outputReport04_t;


//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------

/*
05 0B        (GLOBAL) USAGE_PAGE         0x000B Telephony Device Page
09 05        (LOCAL)  USAGE              0x000B0005 Headset (CL=Logical Collection)
A1 01        (MAIN)   COLLECTION         0x00000001 Application (Usage=0x000B0005: Page=Telephony Device Page, Usage=Headset, Type=CL) <-- Warning: USAGE type should be CA (Application)
85 03          (GLOBAL) REPORT_ID          0x03 (3)
05 0B          (GLOBAL) USAGE_PAGE         0x000B Telephony Device Page <-- Redundant: USAGE_PAGE is already 0x000B
15 00          (GLOBAL) LOGICAL_MINIMUM    0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 01          (GLOBAL) LOGICAL_MAXIMUM    0x01 (1) <-- Redundant: LOGICAL_MAXIMUM is already 1
09 20          (LOCAL)  USAGE              0x000B0020 Hook Switch (OOC=On/Off Control)
09 97          (LOCAL)  USAGE              0x000B0097 Line Busy Tone (MC=Momentary Control)
09 2B          (LOCAL)  USAGE              0x000B002B Speaker Phone (OOC=On/Off Control)
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 03          (GLOBAL) REPORT_COUNT       0x03 (3) Number of fields
81 23          (MAIN)   INPUT              0x00000023 (3 fields x 1 bit) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 1=NoPrefState 0=NoNull 0=NonVolatile 0=Bitmap
09 2F          (LOCAL)  USAGE              0x000B002F Phone Mute (OOC=On/Off Control)
09 21          (LOCAL)  USAGE              0x000B0021 Flash (MC=Momentary Control)
09 24          (LOCAL)  USAGE              0x000B0024 Redial (OSC=One Shot Control)
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 03          (GLOBAL) REPORT_COUNT       0x03 (3) Number of fields <-- Redundant: REPORT_COUNT is already 3
81 07          (MAIN)   INPUT              0x00000007 (3 fields x 1 bit) 1=Constant 1=Variable 1=Relative 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
09 07          (LOCAL)  USAGE              0x000B0007 Programmable Button (NAry=Named Array)
05 09          (GLOBAL) USAGE_PAGE         0x0009 Button Page
09 01          (LOCAL)  USAGE              0x00090001 Button 1 Primary/trigger (MULTI=Selector, On/Off, Momentary, or One Shot)
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 01          (GLOBAL) REPORT_COUNT       0x01 (1) Number of fields
81 02          (MAIN)   INPUT              0x00000002 (1 field x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
95 09          (GLOBAL) REPORT_COUNT       0x09 (9) Number of fields
81 01          (MAIN)   INPUT              0x00000001 (9 fields x 1 bit) 1=Constant 0=Array 0=Absolute
05 08          (GLOBAL) USAGE_PAGE         0x0008 LED Indicator Page
15 00          (GLOBAL) LOGICAL_MINIMUM    0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 01          (GLOBAL) LOGICAL_MAXIMUM    0x01 (1) <-- Redundant: LOGICAL_MAXIMUM is already 1
09 17          (LOCAL)  USAGE              0x00080017 Off-Hook (OOC=On/Off Control)
09 1E          (LOCAL)  USAGE              0x0008001E Speaker (OOC=On/Off Control)
09 09          (LOCAL)  USAGE              0x00080009 Mute (OOC=On/Off Control)
09 18          (LOCAL)  USAGE              0x00080018 Ring (OOC=On/Off Control)
09 20          (LOCAL)  USAGE              0x00080020 Hold (OOC=On/Off Control)
09 21          (LOCAL)  USAGE              0x00080021 Microphone (OOC=On/Off Control)
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 06          (GLOBAL) REPORT_COUNT       0x06 (6) Number of fields
91 22          (MAIN)   OUTPUT             0x00000022 (6 fields x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 1=NoPrefState 0=NoNull 0=NonVolatile 0=Bitmap
05 0B          (GLOBAL) USAGE_PAGE         0x000B Telephony Device Page
15 00          (GLOBAL) LOGICAL_MINIMUM    0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 01          (GLOBAL) LOGICAL_MAXIMUM    0x01 (1) <-- Redundant: LOGICAL_MAXIMUM is already 1
09 9E          (LOCAL)  USAGE              0x000B009E Ringer (OOC=On/Off Control)
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 01          (GLOBAL) REPORT_COUNT       0x01 (1) Number of fields
91 22          (MAIN)   OUTPUT             0x00000022 (1 field x 1 bit) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 1=NoPrefState 0=NoNull 0=NonVolatile 0=Bitmap
75 01          (GLOBAL) REPORT_SIZE        0x01 (1) Number of bits per field <-- Redundant: REPORT_SIZE is already 1
95 09          (GLOBAL) REPORT_COUNT       0x09 (9) Number of fields
91 01          (MAIN)   OUTPUT             0x00000001 (9 fields x 1 bit) 1=Constant 0=Array 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
C0           (MAIN)   END_COLLECTION     Application
*/

//--------------------------------------------------------------------------------
// Telephony Device Page inputReport 03 (Device --> Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x03 (3)
                                                     // Collection: Headset
  uint8_t  TEL_HeadsetHookSwitch : 1;                // Usage 0x000B0020: Hook Switch, Value = 0 to 1
  uint8_t  TEL_HeadsetLineBusyTone : 1;              // Usage 0x000B0097: Line Busy Tone, Value = 0 to 1
  uint8_t  TEL_HeadsetSpeakerPhone : 1;              // Usage 0x000B002B: Speaker Phone, Value = 0 to 1
  uint8_t  TEL_HeadsetPhoneMute : 1;                 // Usage 0x000B002F: Phone Mute, Value = 0 to 1
  uint8_t  TEL_HeadsetFlash : 1;                     // Usage 0x000B0021: Flash, Value = 0 to 1
  uint8_t  TEL_HeadsetRedial : 1;                    // Usage 0x000B0024: Redial, Value = 0 to 1
  uint8_t  TEL_HeadsetProgrammableButton : 1;        // Usage 0x000B0007: Programmable Button, Value = 0 to 1
                                                     // Usage 0x00090001 Button 1 Primary/trigger (MULTI=Selector, On/Off, Momentary, or One Shot) Value = 0 to 1 <-- Ignored: REPORT_COUNT (1) is too small
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
} inputReport03_t;


//--------------------------------------------------------------------------------
// LED Indicator Page outputReport 03 (Device <-- Host)
//--------------------------------------------------------------------------------

typedef struct
{
  uint8_t  reportId;                                 // Report ID = 0x03 (3)
                                                     // Collection: Headset
  uint8_t  LED_HeadsetOffHook : 1;                   // Usage 0x00080017: Off-Hook, Value = 0 to 1
  uint8_t  LED_HeadsetSpeaker : 1;                   // Usage 0x0008001E: Speaker, Value = 0 to 1
  uint8_t  LED_HeadsetMute : 1;                      // Usage 0x00080009: Mute, Value = 0 to 1
  uint8_t  LED_HeadsetRing : 1;                      // Usage 0x00080018: Ring, Value = 0 to 1
  uint8_t  LED_HeadsetHold : 1;                      // Usage 0x00080020: Hold, Value = 0 to 1
  uint8_t  LED_HeadsetMicrophone : 1;                // Usage 0x00080021: Microphone, Value = 0 to 1
  uint8_t  TEL_HeadsetRinger : 1;                    // Usage 0x000B009E: Ringer, Value = 0 to 1
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
  uint8_t  : 1;                                      // Pad
} outputReport03_t;