Custom HID device HID report descriptor report count - usb

I simply want to send from device to host with two report ID.These reports must have different Report Count(First report id has 4 report count, second report id has 40).This is what I have done so far:
//14 bytes
0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined Page 1)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xa1, 0x01, // COLLECTION (Application)
// -------- common global items ---------
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
// 10 bytes | Input message 1 (sent from device to host)
0x85, 5, // Global Report ID (cannot be 0)
0x95, 4, // Global Report Count (number of Report Size fields)
0x19, 0x01, // USAGE_MINIMUM (Vendor Usage 1)
0x29, 5, // USAGE_MAXIMUM (Vendor Usage 64)
0x81, 0x02, // Main Input (data, array, absolute)
// 10 bytes | Input message 1 (sent from device to host)
0x85, 6, // Global Report ID (cannot be 0)
0x95, 40, // Global Report Count (number of Report Size fields)
0x19, 0x01, // USAGE_MINIMUM (Vendor Usage 1)
0x29, 41, // USAGE_MAXIMUM (Vendor Usage 64)
0x81, 0x02, // Main Input (data, array, absolute)
0xC0
But first report id is sending 40 bayt.Where is my mistake?
HID Terminal output:
R 02 0C 16 20 2A 34 3E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
R 01 0B 15 1F 29 34 3E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

I believe #Nipo has given you the correct answer: the report descriptor indicates what each report should look like, but it is still the responsibility of your code to send reports with the correct length specified.
For report id 5 that would be 5 (1 for the report id + 4 for the payload), and
for report it 6 it would be 41 (1 for the report id + 40 for the payload).
BTW, your report descriptor may need a little tweaking. As it stands, it decodes as:
//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------
PROGMEM char usbHidReportDescriptor[] =
{
0x06, 0x00, 0xFF, // (GLOBAL) USAGE_PAGE 0xFF00 Vendor-defined
0x09, 0x01, // (LOCAL) USAGE 0xFF000001 <-- Warning: Undocumented usage
0xA1, 0x01, // (MAIN) COLLECTION 0x00000001 Application (Usage=0xFF000001: Page=Vendor-defined, Usage=, Type=)
0x15, 0x00, // (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
0x26, 0xFF, 0x00, // (GLOBAL) LOGICAL_MAXIMUM 0x00FF (255)
0x75, 0x08, // (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
0x85, 0x05, // (GLOBAL) REPORT_ID 0x05 (5)
0x95, 0x04, // (GLOBAL) REPORT_COUNT 0x04 (4) Number of fields
0x19, 0x01, // (LOCAL) USAGE_MINIMUM 0xFF000001 <-- Warning: Undocumented usage
0x29, 0x05, // (LOCAL) USAGE_MAXIMUM 0xFF000005 <-- Warning: Undocumented usage
0x81, 0x02, // (MAIN) INPUT 0x00000002 (4 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
0x85, 0x06, // (GLOBAL) REPORT_ID 0x06 (6)
0x95, 0x28, // (GLOBAL) REPORT_COUNT 0x28 (40) Number of fields
0x19, 0x01, // (LOCAL) USAGE_MINIMUM 0xFF000001 <-- Warning: Undocumented usage
0x29, 0x29, // (LOCAL) USAGE_MAXIMUM 0xFF000029 <-- Warning: Undocumented usage
0x81, 0x02, // (MAIN) INPUT 0x00000002 (40 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
0xC0, // (MAIN) END_COLLECTION Application
};
//--------------------------------------------------------------------------------
// Vendor-defined inputReport 05 (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x05 (5)
uint8_t VEN_VendorDefined0001; // Usage 0xFF000001: , Value = 0 to 255
uint8_t VEN_VendorDefined0002; // Usage 0xFF000002: , Value = 0 to 255
uint8_t VEN_VendorDefined0003; // Usage 0xFF000003: , Value = 0 to 255
uint8_t VEN_VendorDefined0004; // Usage 0xFF000004: , Value = 0 to 255
// Usage 0xFF000005 Value = 0 to 255 <-- Ignored: REPORT_COUNT (4) is too small
} inputReport05_t;
//--------------------------------------------------------------------------------
// Vendor-defined inputReport 06 (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x06 (6)
uint8_t VEN_VendorDefined0001; // Usage 0xFF000001: , Value = 0 to 255
uint8_t VEN_VendorDefined0002; // Usage 0xFF000002: , Value = 0 to 255
uint8_t VEN_VendorDefined0003; // Usage 0xFF000003: , Value = 0 to 255
uint8_t VEN_VendorDefined0004; // Usage 0xFF000004: , Value = 0 to 255
uint8_t VEN_VendorDefined0005; // Usage 0xFF000005: , Value = 0 to 255
uint8_t VEN_VendorDefined0006; // Usage 0xFF000006: , Value = 0 to 255
uint8_t VEN_VendorDefined0007; // Usage 0xFF000007: , Value = 0 to 255
uint8_t VEN_VendorDefined0008; // Usage 0xFF000008: , Value = 0 to 255
uint8_t VEN_VendorDefined0009; // Usage 0xFF000009: , Value = 0 to 255
uint8_t VEN_VendorDefined000A; // Usage 0xFF00000A: , Value = 0 to 255
uint8_t VEN_VendorDefined000B; // Usage 0xFF00000B: , Value = 0 to 255
uint8_t VEN_VendorDefined000C; // Usage 0xFF00000C: , Value = 0 to 255
uint8_t VEN_VendorDefined000D; // Usage 0xFF00000D: , Value = 0 to 255
uint8_t VEN_VendorDefined000E; // Usage 0xFF00000E: , Value = 0 to 255
uint8_t VEN_VendorDefined000F; // Usage 0xFF00000F: , Value = 0 to 255
uint8_t VEN_VendorDefined0010; // Usage 0xFF000010: , Value = 0 to 255
uint8_t VEN_VendorDefined0011; // Usage 0xFF000011: , Value = 0 to 255
uint8_t VEN_VendorDefined0012; // Usage 0xFF000012: , Value = 0 to 255
uint8_t VEN_VendorDefined0013; // Usage 0xFF000013: , Value = 0 to 255
uint8_t VEN_VendorDefined0014; // Usage 0xFF000014: , Value = 0 to 255
uint8_t VEN_VendorDefined0015; // Usage 0xFF000015: , Value = 0 to 255
uint8_t VEN_VendorDefined0016; // Usage 0xFF000016: , Value = 0 to 255
uint8_t VEN_VendorDefined0017; // Usage 0xFF000017: , Value = 0 to 255
uint8_t VEN_VendorDefined0018; // Usage 0xFF000018: , Value = 0 to 255
uint8_t VEN_VendorDefined0019; // Usage 0xFF000019: , Value = 0 to 255
uint8_t VEN_VendorDefined001A; // Usage 0xFF00001A: , Value = 0 to 255
uint8_t VEN_VendorDefined001B; // Usage 0xFF00001B: , Value = 0 to 255
uint8_t VEN_VendorDefined001C; // Usage 0xFF00001C: , Value = 0 to 255
uint8_t VEN_VendorDefined001D; // Usage 0xFF00001D: , Value = 0 to 255
uint8_t VEN_VendorDefined001E; // Usage 0xFF00001E: , Value = 0 to 255
uint8_t VEN_VendorDefined001F; // Usage 0xFF00001F: , Value = 0 to 255
uint8_t VEN_VendorDefined0020; // Usage 0xFF000020: , Value = 0 to 255
uint8_t VEN_VendorDefined0021; // Usage 0xFF000021: , Value = 0 to 255
uint8_t VEN_VendorDefined0022; // Usage 0xFF000022: , Value = 0 to 255
uint8_t VEN_VendorDefined0023; // Usage 0xFF000023: , Value = 0 to 255
uint8_t VEN_VendorDefined0024; // Usage 0xFF000024: , Value = 0 to 255
uint8_t VEN_VendorDefined0025; // Usage 0xFF000025: , Value = 0 to 255
uint8_t VEN_VendorDefined0026; // Usage 0xFF000026: , Value = 0 to 255
uint8_t VEN_VendorDefined0027; // Usage 0xFF000027: , Value = 0 to 255
uint8_t VEN_VendorDefined0028; // Usage 0xFF000028: , Value = 0 to 255
// Usage 0xFF000029 Value = 0 to 255 <-- Ignored: REPORT_COUNT (40) is too small
} inputReport06_t;
You may want to try the following instead:
//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------
PROGMEM char usbHidReportDescriptor[] =
{
0x06, 0x00, 0xFF, // (GLOBAL) USAGE_PAGE 0xFF00 Vendor-defined
0x09, 0x01, // (LOCAL) USAGE 0xFF000001 <-- Warning: Undocumented usage
0xA1, 0x01, // (MAIN) COLLECTION 0x00000001 Application (Usage=0xFF000001: Page=Vendor-defined, Usage=, Type=)
0x15, 0x00, // (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
0x26, 0xFF, 0x00, // (GLOBAL) LOGICAL_MAXIMUM 0x00FF (255)
0x75, 0x08, // (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
0x85, 0x05, // (GLOBAL) REPORT_ID 0x05 (5)
0x95, 0x04, // (GLOBAL) REPORT_COUNT 0x04 (4) Number of fields
0x19, 0x01, // (LOCAL) USAGE_MINIMUM 0xFF000001 <-- Warning: Undocumented usage
0x29, 0x04, // (LOCAL) USAGE_MAXIMUM 0xFF000004 <-- Warning: Undocumented usage
0x81, 0x00, // (MAIN) INPUT 0x00000000 (4 fields x 8 bits) 0=Data 0=Array 0=Absolute 0=Ignored 0=Ignored 0=PrefState 0=NoNull
0x85, 0x06, // (GLOBAL) REPORT_ID 0x06 (6)
0x95, 0x28, // (GLOBAL) REPORT_COUNT 0x28 (40) Number of fields
0x19, 0x01, // (LOCAL) USAGE_MINIMUM 0xFF000001 <-- Warning: Undocumented usage
0x29, 0x28, // (LOCAL) USAGE_MAXIMUM 0xFF000028 <-- Warning: Undocumented usage
0x81, 0x00, // (MAIN) INPUT 0x00000000 (40 fields x 8 bits) 0=Data 0=Array 0=Absolute 0=Ignored 0=Ignored 0=PrefState 0=NoNull
0xC0, // (MAIN) END_COLLECTION Application
};
//--------------------------------------------------------------------------------
// Vendor-defined inputReport 05 (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x05 (5)
uint8_t VEN_VendorDefined[4]; // Value = 0 to 255
} inputReport05_t;
//--------------------------------------------------------------------------------
// Vendor-defined inputReport 06 (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x06 (6)
uint8_t VEN_VendorDefined[40]; // Value = 0 to 255
} inputReport06_t;

Related

Compute a signature with private key in Server Key Exchange

On https://tls.ulfheim.net/ there is an example showing how to compute a signature in the section of " Server Key Exchange ".
https://i.ibb.co/Y7fbkDw/1.jpg (This image shows the Server Key Exchange section on the website that I refer to. Could not embed the image in this post.)
Whatever I try I dont get the same output as the one on that website, I dont understand why.
I've tried storing the same data in two different ways, then use the same openssl command that they use on their example. None of the methods gave the same output.
Method 1.
char hex[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x20, 0x9f, 0xd7, 0xad, 0x6d, 0xcf, 0xf4, 0x29, 0x8d, 0xd3, 0xf9, 0x6d, 0x5b, 0x1b, 0x2a, 0xf9, 0x10, 0xa0, 0x53, 0x5b, 0x14, 0x88, 0xd7, 0xf8, 0xfa, 0xbb, 0x34, 0x9a, 0x98, 0x28, 0x80, 0xb6, 0x15 };
ofstream myfile("c:/hex1.txt", ios::binary);
myfile.write(hex, sizeof hex);
then:
openssl dgst -hex -sign server.key -sha256 hex1.txt
Method 2.
I had this data stored in hex2.txt (as ASCII):
\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x20\x9f\xd7\xad\x6d\xcf\xf4\x29\x8d\xd3\xf9\x6d\x5b\x1b\x2a\xf9\x10\xa0\x53\x5b\x14\x88\xd7\xf8\xfa\xbb\x34\x9a\x98\x28\x80\xb6\x15
then:
openssl dgst -hex -sign server.key -sha256 hex2.txt
Method 1
You left out curve_info. The applicable RFC 4492 section 5.4 updated for TLS1.2 by RFC 5246 appendix A.7 actually defines the signature to be over in effect client_random + server_random + SKX_params where SKX_params is type ServerECDHParams and consists of ECParameters curve_params and ECPoint public -- these are what ulfheim labels Curve Info and Public Key.
With the correct data I get the correct result:
$ od -tx1 70148855.bin
0000000 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
0000020 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
0000040 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f
0000060 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f
0000100 03 00 1d 20 9f d7 ad 6d cf f4 29 8d d3 f9 6d 5b
0000120 1b 2a f9 10 a0 53 5b 14 88 d7 f8 fa bb 34 9a 98
0000140 28 80 b6 15
$ openssl sha256 <70148855.bin -sign $privkey -hex
(stdin)= 0402b661f7c191ee59be45376639bdc3d4bb81e115ca73c8348b525b0d2338aa144667ed9431021412cd9b844cba29934aaacce873414ec11cb02e272d0ad81f767d33076721f13bf36020cf0b1fd0ecb078de1128beba0949ebece1a1f96e209dc36e4fffd36b673a7ddc1597ad4408e485c4adb2c873841249372523809e4312d0c7b3522ef983cac1e03935ff13a8e96ba681a62e40d3e70a7ff35866d3d9993f9e26a634c81b4e71380fcdd6f4e835f75a6409c7dc2c07410e6f87858c7b94c01c2e32f291769eacca71643b8b98a963df0a329bea4ed6397e8cd01a110ab361ac5bad1ccd840a6c8a6eaa001a9d7d87dc3318643571226c4dd2c2ac41fb
Added: BTW this only works because the signature scheme used for RSA in TLS1.2 and below, namely the scheme that was 'block type 1' in PKCS1v1 and now is RSASSA-PKCS1-v1_5 in PKCS1v2, is deterministic. Most digital signature schemes are not, including the RSA-PSS scheme used in TLS1.3, and you cannot check or test a signature by comparing it to another signature. You can only use the verification method provided by the scheme.
Method 2
is completely incorrect. \x00 etc is a notation used in source code for C and C++ (as you did in Method 1) and a few other languages like Java, JS/ES, and Python, as well as certain tools like the printf command in Unix and the awk program. But it does not work other places, and in particular does not work in files read by OpenSSL (at least for data; it might work in the config file, I'd have to check). Your method two (hashes and) signs the bytes 0x5c 0x78 0x30 0x30 0x5c 0x78 0x30 0x31 which represent the characters \ x 0 0 \ x 0 1 etc, not the bytes 0x00 0x01 etc, and unsurprisingly this is completely different and wrong.

Accessing USB device data based only on DESCRIPTOR HID Report

I have a Digital Sound Level Meter (sonometer) GM1356 with USB. There is some software to handle it on Windows, however I don't have CD and it's not available on the internet. What I want do to is to read it's data about current noise level on Linux.
I found already a library that allows me to do this in a language I know (ruby, libusb). In next step I installed wireshark to check out what it sends do the pc. It doesn't send too much. The most interesting packet I found is DESCRIPTOR HID Report. I wonder what next steps should I take to read data that is interesting for me. How can I determine what requests I should send to get it?
HID Report
Global item (Usage)
Header
.... ..10 = bSize: 2 bytes (2)
.... 01.. = bType: Global (1)
0000 .... = bTag: Usage (0x0)
Usage page: [Vendor-defined] (0xffa0)
Local item (Usage)
Header
.... ..01 = bSize: 1 byte (1)
.... 10.. = bType: Local (2)
0000 .... = bTag: Usage (0x0)
Usage: [Vendor-defined] (0xffa00001)
Main item (Collection)
Header
.... ..01 = bSize: 1 byte (1)
.... 00.. = bType: Main (0)
1010 .... = bTag: Collection (0xa)
Collection type: Application (0x01)
Local item (Usage)
Header
.... ..01 = bSize: 1 byte (1)
.... 10.. = bType: Local (2)
0000 .... = bTag: Usage (0x0)
Usage: [Vendor-defined] (0xffa00002)
Main item (Collection)
Header
.... ..01 = bSize: 1 byte (1)
.... 00.. = bType: Main (0)
1010 .... = bTag: Collection (0xa)
Collection type: Physical (0x00)
Global item (Usage)
Header
.... ..10 = bSize: 2 bytes (2)
.... 01.. = bType: Global (1)
0000 .... = bTag: Usage (0x0)
Usage page: [Vendor-defined] (0xffa1)
Local item (Usage)
Header
.... ..01 = bSize: 1 byte (1)
.... 10.. = bType: Local (2)
0000 .... = bTag: Usage (0x0)
Usage: [Vendor-defined] (0xffa10003)
Local item (Usage)
Header
.... ..01 = bSize: 1 byte (1)
.... 10.. = bType: Local (2)
0000 .... = bTag: Usage (0x0)
Usage: [Vendor-defined] (0xffa10004)
Global item (Logical minimum)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0001 .... = bTag: Logical minimum (0x1)
Logical minimum: 128
Global item (Logical maximum)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0010 .... = bTag: Logical maximum (0x2)
Logical maximum: 127
Global item (Physical minimum)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0011 .... = bTag: Physical minimum (0x3)
Physical minimum: 0
Global item (Physical maximum)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0100 .... = bTag: Physical maximum (0x4)
Physical maximum: 255
Global item (Report size)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0111 .... = bTag: Report size (0x7)
Report size: 8
Global item (Report count)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
1001 .... = bTag: Report count (0x9)
Report count: 8
Main item (Input)
Header
.... ..01 = bSize: 1 byte (1)
.... 00.. = bType: Main (0)
1000 .... = bTag: Input (0x8)
.... .... 0 = Data/constant: Data
.... ...1 . = Data type: Variable
.... ..0. . = Coordinates: Absolute
.... .0.. . = Min/max wraparound: No Wrap
.... 0... . = Physical relationship to data: Linear
...0 .... . = Preferred state: Preferred State
..0. .... . = Has null position: No Null position
.0.. .... . = [Reserved]: False
0... .... . = Bits or bytes: Buffered bytes (default, no second byte present)
Local item (Usage)
Header
.... ..01 = bSize: 1 byte (1)
.... 10.. = bType: Local (2)
0000 .... = bTag: Usage (0x0)
Usage: [Vendor-defined] (0xffa10005)
Local item (Usage)
Header
.... ..01 = bSize: 1 byte (1)
.... 10.. = bType: Local (2)
0000 .... = bTag: Usage (0x0)
Usage: [Vendor-defined] (0xffa10006)
Global item (Logical minimum)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0001 .... = bTag: Logical minimum (0x1)
Logical minimum: 128
Global item (Logical maximum)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0010 .... = bTag: Logical maximum (0x2)
Logical maximum: 127
Global item (Physical minimum)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0011 .... = bTag: Physical minimum (0x3)
Physical minimum: 0
Global item (Physical maximum)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0100 .... = bTag: Physical maximum (0x4)
Physical maximum: 255
Global item (Report size)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
0111 .... = bTag: Report size (0x7)
Report size: 8
Global item (Report count)
Header
.... ..01 = bSize: 1 byte (1)
.... 01.. = bType: Global (1)
1001 .... = bTag: Report count (0x9)
Report count: 8
Main item (Output)
Header
.... ..01 = bSize: 1 byte (1)
.... 00.. = bType: Main (0)
1001 .... = bTag: Output (0x9)
.... .... 0 = Data/constant: Data
.... ...1 . = Data type: Variable
.... ..0. . = Coordinates: Absolute
.... .0.. . = Min/max wraparound: No Wrap
.... 0... . = Physical relationship to data: Linear
...0 .... . = Preferred state: Preferred State
..0. .... . = Has null position: No Null position
.0.. .... . = (Non)-volatile: Non Volatile
0... .... . = Bits or bytes: Buffered bytes (default, no second byte present)
Main item (End collection)
Header
.... ..00 = bSize: 0 bytes (0)
.... 00.. = bType: Main (0)
1100 .... = bTag: End collection (0xc)
Main item (End collection)
Header
.... ..00 = bSize: 0 bytes (0)
.... 00.. = bType: Main (0)
1100 .... = bTag: End collection (0xc)
When you decode the HID descriptor it will show the packet formats. Unfortunately, in this case the usage pages are vendor-defined so it is not possible to say exactly how each usage is to be interpreted.
I decoded it using hidrdd (disclaimer: I wrote it, but it is free open source so I have no conflict of interest) as:
//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------
/*
06 A0FF (GLOBAL) USAGE_PAGE 0xFFA0 Vendor-defined
09 01 (LOCAL) USAGE 0xFFA00001 <-- Warning: Undocumented usage (document it by inserting 0001 into file FFA0.conf)
A1 01 (MAIN) COLLECTION 0x01 Application (Usage=0xFFA00001: Page=Vendor-defined, Usage=, Type=) <-- Error: COLLECTION must be preceded by a known USAGE
09 02 (LOCAL) USAGE 0xFFA00002 <-- Warning: Undocumented usage (document it by inserting 0002 into file FFA0.conf)
A1 00 (MAIN) COLLECTION 0x00 Physical (Usage=0xFFA00002: Page=Vendor-defined, Usage=, Type=) <-- Error: COLLECTION must be preceded by a known USAGE
06 A1FF (GLOBAL) USAGE_PAGE 0xFFA1 Vendor-defined
09 03 (LOCAL) USAGE 0xFFA10003 <-- Warning: Undocumented usage (document it by inserting 0003 into file FFA1.conf)
09 04 (LOCAL) USAGE 0xFFA10004 <-- Warning: Undocumented usage (document it by inserting 0004 into file FFA1.conf)
15 80 (GLOBAL) LOGICAL_MINIMUM 0x80 (-128)
25 7F (GLOBAL) LOGICAL_MAXIMUM 0x7F (127)
35 00 (GLOBAL) PHYSICAL_MINIMUM 0x00 (0) <-- Info: Consider replacing 35 00 with 34
45 FF (GLOBAL) PHYSICAL_MAXIMUM 0xFF (-1)
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
95 08 (GLOBAL) REPORT_COUNT 0x08 (8) Number of fields
81 02 (MAIN) INPUT 0x00000002 (8 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap <-- Error: PHYSICAL_MAXIMUM (-1) is less than PHYSICAL_MINIMUM (0)
09 05 (LOCAL) USAGE 0xFFA10005 <-- Warning: Undocumented usage (document it by inserting 0005 into file FFA1.conf)
09 06 (LOCAL) USAGE 0xFFA10006 <-- Warning: Undocumented usage (document it by inserting 0006 into file FFA1.conf)
15 80 (GLOBAL) LOGICAL_MINIMUM 0x80 (-128) <-- Redundant: LOGICAL_MINIMUM is already -128
25 7F (GLOBAL) LOGICAL_MAXIMUM 0x7F (127) <-- Redundant: LOGICAL_MAXIMUM is already 127
35 00 (GLOBAL) PHYSICAL_MINIMUM 0x00 (0) <-- Redundant: PHYSICAL_MINIMUM is already 0 <-- Info: Consider replacing 35 00 with 34
45 FF (GLOBAL) PHYSICAL_MAXIMUM 0xFF (-1) <-- Redundant: PHYSICAL_MAXIMUM is already -1
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field <-- Redundant: REPORT_SIZE is already 8
95 08 (GLOBAL) REPORT_COUNT 0x08 (8) Number of fields <-- Redundant: REPORT_COUNT is already 8
91 02 (MAIN) OUTPUT 0x00000002 (8 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap <-- Error: PHYSICAL_MAXIMUM (-1) is less than PHYSICAL_MINIMUM (0)
C0 (MAIN) END_COLLECTION Physical <-- Warning: Physical units are still in effect PHYSICAL(MIN=0,MAX=-1) UNIT(0x,EXP=0)
C0 (MAIN) END_COLLECTION Application <-- Warning: Physical units are still in effect PHYSICAL(MIN=0,MAX=-1) UNIT(0x,EXP=0)
*/
//--------------------------------------------------------------------------------
// Vendor-defined inputReport (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
// No REPORT ID byte
// Collection: CA: CP:
int8_t VEN_0003; // Usage 0xFFA10003: , Value = -128 to 127, Physical = (Value + 128) x -1 / 255
int8_t VEN_0004[7]; // Usage 0xFFA10004: , Value = -128 to 127, Physical = (Value + 128) x -1 / 255
} inputReport_t;
//--------------------------------------------------------------------------------
// Vendor-defined outputReport (Device <-- Host)
//--------------------------------------------------------------------------------
typedef struct
{
// No REPORT ID byte
// Collection: CA: CP:
int8_t VEN_0005; // Usage 0xFFA10005: , Value = -128 to 127, Physical = (Value + 128) x -1 / 255
int8_t VEN_0006[7]; // Usage 0xFFA10006: , Value = -128 to 127, Physical = (Value + 128) x -1 / 255
} outputReport_t;
As you can see, the above HID descriptor has some issues (for example, physical maximum 45 FF is -1, but I think they meant 255 - which should be represented as 46 FF 00) but the problem remains that it tells you nothing about the meaning of the usages. BTW, even Wireshark has not reported the logical minimum correctly: 15 80 is -128 not 128.
All we can tell from it is that the reports are 8-bytes long and that the first byte seems to be some kind of id (well, its usage is different from the remaining 7 bytes).
Only the vendor's driver knows how to interpret the reports, but with a sufficient number of Wireshark packet captures obtained under controlled conditions you may be able reverse engineer a workable interpretation.
Sorry, but that's the best I can do with this.
I bought a decibelimeter too, which happens to be compatible with your model. I am currently trying to port this code to a bash script: https://github.com/dobra-noc/gm1356 which works fine for me with my device (which btw isn't even the gm1356) and I'm guessing it will work for you too.

Increasing the volume of an HID device using feature reports

What hex code do I need to send to the device (and what report index) to trigger a volume change?
I'm trying to use HID feature reports to increase the volume of a Jabra 410 headset. The Jabra provides the following interface and report description:
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
I have successfully used feature report #3 to interact with the device, including the manipulation of some LEDs and call states. However, no combination of data changes the volume, and I get no response whatsoever when interacting with feature report #1, which should be responsible for volume if I'm reading the report properly.
For example, sending a hex value of 05 (as in 00000101) to page #3 results in the device going to a muted state.
I decoded the report descriptor and it appears that the volume increment/decrement reports are sent from the device (headset) to the host (PC or whatever) using an input report, not a feature report. That is, the device tells the host to increment/decrement the volume - not the other way around.
BTW, I only see one feature report defined and it uses REPORT_ID 0x04.
Specifically, the input report with REPORT_ID 0x01 is used for volume control:
//--------------------------------------------------------------------------------
// 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;
The full decoded report descriptor is shown below...
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;

Non-application top-level collection?

The USB HID spec states
Each top level collection must be an application collection and reports may not
span more than one top level collection.
However, one of the examples provided in the USB HID report descriptor tool, namely the display example, has a top-level collection of type logical with no application collection:
0x05, 0x14, // USAGE_PAGE (Alphnumeric Display)
0x09, 0x01, // USAGE (Alphanumeric Display)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0xa1, 0x02, // COLLECTION (Logical)
0x09, 0x20, // USAGE (Display Attributes Report)
0xa1, 0x02, // COLLECTION (Logical)
0x09, 0x35, // USAGE (Rows)
0x09, 0x36, // USAGE (Columns)
0x09, 0x3d, // USAGE (Character Width)
0x09, 0x3e, // USAGE (Character Height)
0x85, 0x01, // REPORT_ID (1)
0x25, 0x1f, // LOGICAL_MAXIMUM (31)
0x75, 0x05, // REPORT_SIZE (5)
0x95, 0x04, // REPORT_COUNT (4)
0xb1, 0x03, // FEATURE (Cnst,Var,Abs)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x03, // REPORT_COUNT (3)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x09, 0x21, // USAGE (ASCII Character Set)
0x09, 0x22, // USAGE (Data Read Back)
0x09, 0x29, // USAGE (Vertical Scroll)
0xb1, 0x03, // FEATURE (Cnst,Var,Abs)
0x95, 0x03, // REPORT_COUNT (3)
0xb1, 0x03, // FEATURE (Cnst,Var,Abs)
0xc0, // END_COLLECTION
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0x25, 0x02, // LOGICAL_MAXIMUM (2)
0x09, 0x2d, // USAGE (Display Status)
0xa1, 0x02, // COLLECTION (Logical)
0x09, 0x2e, // USAGE (Stat Not Ready)
0x09, 0x2f, // USAGE (Stat Ready)
0x09, 0x30, // USAGE (Err Not a loadable character)
0x81, 0x40, // INPUT (Data,Ary,Abs,Null)
0xc0, // END_COLLECTION
0x09, 0x32, // USAGE (Cursor Position Report)
0xa1, 0x02, // COLLECTION (Logical)
0x85, 0x02, // REPORT_ID (2)
0x75, 0x04, // REPORT_SIZE (4)
0x95, 0x01, // REPORT_COUNT (1)
0x25, 0x0f, // LOGICAL_MAXIMUM (15)
0x09, 0x34, // USAGE (Column)
0xb1, 0x22, // FEATURE (Data,Var,Abs,NPrf)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x09, 0x33, // USAGE (Row)
0xb1, 0x22, // FEATURE (Data,Var,Abs,NPrf)
0xc0, // END_COLLECTION
0x09, 0x2b, // USAGE (Character Report)
0xa1, 0x02, // COLLECTION (Logical)
0x85, 0x03, // REPORT_ID (3)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x04, // REPORT_COUNT (4)
0x25, 0x7e, // LOGICAL_MAXIMUM (126)
0x09, 0x2c, // USAGE (Display Data)
0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf)
0xc0, // END_COLLECTION
0x85, 0x04, // REPORT_ID (4)
0x09, 0x3b, // USAGE (Font Report)
0xa1, 0x02, // COLLECTION (Logical)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x7e, // LOGICAL_MAXIMUM (126)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0x09, 0x2c, // USAGE (Display Data)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0x95, 0x05, // REPORT_COUNT (5)
0x09, 0x3c, // USAGE (Font Data)
0x92, 0x02, 0x01, // OUTPUT (Data,Var,Abs,Buf)
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION
Is this allowed?
No, it is not allowed.
The example given seems to be quite similar to the example in "Appendix A.8 A Device with a Display" in the HID Usage Tables v1.12 specification which does have a top level application collection defined.
I'd say the example you posted may have some transcription errors - especially since the top level Usage selected (0x00140001) has Usage Type of CA and so is intended to be used on an Application Collection item rather than a Logical Collection (see page 109 of the Usage Tables document).
The first logical collection should be changed to:
0xa1, 0x01, // COLLECTION (Application)
It will then be parsed (albeit with bit alignment issues due to sections having been omitted from the original example) as:
//--------------------------------------------------------------------------------
// Decoded Application Collection
//--------------------------------------------------------------------------------
/*
05 14 (GLOBAL) USAGE_PAGE 0x0014 Alphanumeric Display Page
09 01 (LOCAL) USAGE 0x00140001 Alphanumeric Display (CA=Application Collection)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
A1 01 (MAIN) COLLECTION 0x00000001 Application (Usage=0x00140001: Page=Alphanumeric Display Page, Usage=Alphanumeric Display, Type=CA)
09 20 (LOCAL) USAGE 0x00140020 Display Attributes Report (CL=Logical Collection)
A1 02 (MAIN) COLLECTION 0x00000002 Logical (Usage=0x00140020: Page=Alphanumeric Display Page, Usage=Display Attributes Report, Type=CL)
09 35 (LOCAL) USAGE 0x00140035 Rows (SV=Static Value)
09 36 (LOCAL) USAGE 0x00140036 Columns (SV=Static Value)
09 3D (LOCAL) USAGE 0x0014003D Character Width (SV=Static Value)
09 3E (LOCAL) USAGE 0x0014003E Character Height (SV=Static Value)
85 01 (GLOBAL) REPORT_ID 0x01 (1)
25 1F (GLOBAL) LOGICAL_MAXIMUM 0x1F (31)
75 05 (GLOBAL) REPORT_SIZE 0x05 (5) Number of bits per field
95 04 (GLOBAL) REPORT_COUNT 0x04 (4) Number of fields
B1 03 (MAIN) FEATURE 0x00000003 (4 fields x 5 bits) 1=Constant 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
95 03 (GLOBAL) REPORT_COUNT 0x03 (3) Number of fields
25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1)
09 21 (LOCAL) USAGE 0x00140021 ASCII Character Set (SF=Static Flag)
09 22 (LOCAL) USAGE 0x00140022 Data Read Back (SF=Static Flag)
09 29 (LOCAL) USAGE 0x00140029 Vertical Scroll (SFDF=Static Flag or Dynamic Flag)
B1 03 (MAIN) FEATURE 0x00000003 (3 fields x 1 bit) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
95 03 (GLOBAL) REPORT_COUNT 0x03 (3) Number of fields <-- Redundant: REPORT_COUNT is already 3
B1 03 (MAIN) FEATURE 0x00000003 (3 fields x 1 bit) 1=Constant 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
C0 (MAIN) END_COLLECTION Logical
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
25 02 (GLOBAL) LOGICAL_MAXIMUM 0x02 (2)
09 2D (LOCAL) USAGE 0x0014002D Display Status (CL=Logical Collection)
A1 02 (MAIN) COLLECTION 0x00000002 Logical (Usage=0x0014002D: Page=Alphanumeric Display Page, Usage=Display Status, Type=CL)
09 2E (LOCAL) USAGE 0x0014002E Stat Not Ready (Sel=Selector)
09 2F (LOCAL) USAGE 0x0014002F Stat Ready (Sel=Selector)
09 30 (LOCAL) USAGE 0x00140030 Err Not a loadable character (Sel=Selector)
81 40 (MAIN) INPUT 0x00000040 (1 field x 8 bits) 0=Data 0=Array 0=Absolute
C0 (MAIN) END_COLLECTION Logical
09 32 (LOCAL) USAGE 0x00140032 Cursor Position Report (CL=Logical Collection)
A1 02 (MAIN) COLLECTION 0x00000002 Logical (Usage=0x00140032: Page=Alphanumeric Display Page, Usage=Cursor Position Report, Type=CL)
85 02 (GLOBAL) REPORT_ID 0x02 (2)
75 04 (GLOBAL) REPORT_SIZE 0x04 (4) Number of bits per field
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields <-- Redundant: REPORT_COUNT is already 1
25 0F (GLOBAL) LOGICAL_MAXIMUM 0x0F (15)
09 34 (LOCAL) USAGE 0x00140034 Column (DV=Dynamic Value)
B1 22 (MAIN) FEATURE 0x00000022 (1 field x 4 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 1=NoPrefState 0=NoNull 0=NonVolatile 0=Bitmap
25 01 (GLOBAL) LOGICAL_MAXIMUM 0x01 (1)
09 33 (LOCAL) USAGE 0x00140033 Row (DV=Dynamic Value)
B1 22 (MAIN) FEATURE 0x00000022 (1 field x 4 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 1=NoPrefState 0=NoNull 0=NonVolatile 0=Bitmap
C0 (MAIN) END_COLLECTION Logical
09 2B (LOCAL) USAGE 0x0014002B Character Report (CL=Logical Collection)
A1 02 (MAIN) COLLECTION 0x00000002 Logical (Usage=0x0014002B: Page=Alphanumeric Display Page, Usage=Character Report, Type=CL)
85 03 (GLOBAL) REPORT_ID 0x03 (3)
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
95 04 (GLOBAL) REPORT_COUNT 0x04 (4) Number of fields
25 7E (GLOBAL) LOGICAL_MAXIMUM 0x7E (126)
09 2C (LOCAL) USAGE 0x0014002C Display Data (DV=Dynamic Value)
B2 0201 (MAIN) FEATURE 0x00000102 (4 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 1=Buffer
C0 (MAIN) END_COLLECTION Logical
85 04 (GLOBAL) REPORT_ID 0x04 (4)
09 3B (LOCAL) USAGE 0x0014003B Font Report (CL=Logical Collection)
A1 02 (MAIN) COLLECTION 0x00000002 Logical (Usage=0x0014003B: Page=Alphanumeric Display Page, Usage=Font Report, Type=CL)
15 00 (GLOBAL) LOGICAL_MINIMUM 0x00 (0) <-- Redundant: LOGICAL_MINIMUM is already 0 <-- Info: Consider replacing 15 00 with 14
25 7E (GLOBAL) LOGICAL_MAXIMUM 0x7E (126) <-- Redundant: LOGICAL_MAXIMUM is already 126
75 08 (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field <-- Redundant: REPORT_SIZE is already 8
95 01 (GLOBAL) REPORT_COUNT 0x01 (1) Number of fields
09 2C (LOCAL) USAGE 0x0014002C Display Data (DV=Dynamic Value)
91 02 (MAIN) OUTPUT 0x00000002 (1 field x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
95 05 (GLOBAL) REPORT_COUNT 0x05 (5) Number of fields
09 3C (LOCAL) USAGE 0x0014003C Font Data (BB=Buffered Bytes)
92 0201 (MAIN) OUTPUT 0x00000102 (5 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 1=Buffer
C0 (MAIN) END_COLLECTION Logical
C0 (MAIN) END_COLLECTION Application
*/
//--------------------------------------------------------------------------------
// Alphanumeric Display Page featureReport 01 (Device <-> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x01 (1)
// Collection: AlphanumericDisplay DisplayAttributesReport
uint8_t AD_AlphanumericDisplayDisplayAttributesReportRows : 5; // Usage 0x00140035: Rows, Value = 0 to 31
uint8_t AD_AlphanumericDisplayDisplayAttributesReportColumns : 5; // Usage 0x00140036: Columns, Value = 0 to 31
uint8_t AD_AlphanumericDisplayDisplayAttributesReportCharacterWidth : 5; // Usage 0x0014003D: Character Width, Value = 0 to 31
uint8_t AD_AlphanumericDisplayDisplayAttributesReportCharacterHeight : 5; // Usage 0x0014003E: Character Height, Value = 0 to 31
uint8_t AD_AlphanumericDisplayDisplayAttributesReportAsciiCharacterSet : 1; // Usage 0x00140021: ASCII Character Set, Value = 0 to 1
uint8_t AD_AlphanumericDisplayDisplayAttributesReportDataReadBack : 1; // Usage 0x00140022: Data Read Back, Value = 0 to 1
uint8_t AD_AlphanumericDisplayDisplayAttributesReportVerticalScroll : 1; // Usage 0x00140029: Vertical Scroll, Value = 0 to 1
uint8_t : 1; // Pad
uint8_t : 1; // Pad
uint8_t : 1; // Pad
} featureReport01_t;
//--------------------------------------------------------------------------------
// Alphanumeric Display Page featureReport 02 (Device <-> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x02 (2)
// Collection: AlphanumericDisplay CursorPositionReport
uint8_t AD_AlphanumericDisplayCursorPositionReportColumn : 4; // Usage 0x00140034: Column, Value = 0 to 15
uint8_t AD_AlphanumericDisplayCursorPositionReportRow : 4; // Usage 0x00140033: Row, Value = 0 to 1
} featureReport02_t;
//--------------------------------------------------------------------------------
// Alphanumeric Display Page featureReport 03 (Device <-> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x03 (3)
// Collection: AlphanumericDisplay CharacterReport
uint8_t AD_AlphanumericDisplayCharacterReportDisplayData[4]; // Usage 0x0014002C: Display Data, Value = 0 to 126
} featureReport03_t;
//--------------------------------------------------------------------------------
// Alphanumeric Display Page inputReport 01 (Device --> Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x01 (1)
// Collection: AlphanumericDisplay DisplayStatus
uint8_t AD_AlphanumericDisplayDisplayStatus; // Value = 0 to 2
// Value 0 = Usage 0x0014002E: Stat Not Ready
// Value 1 = Usage 0x0014002F: Stat Ready
// Value 2 = Usage 0x00140030: Err Not a loadable character
} inputReport01_t;
//--------------------------------------------------------------------------------
// Alphanumeric Display Page outputReport 04 (Device <-- Host)
//--------------------------------------------------------------------------------
typedef struct
{
uint8_t reportId; // Report ID = 0x04 (4)
// Collection: AlphanumericDisplay FontReport
uint8_t AD_AlphanumericDisplayFontReportDisplayData; // Usage 0x0014002C: Display Data, Value = 0 to 126
uint8_t AD_AlphanumericDisplayFontReportFontData[5]; // Usage 0x0014003C: Font Data, Value = 0 to 126
} outputReport04_t;

objdump showing wrong start and end address for functions

For testing purposes, I modified the PLT stub that is generated by the llvm linker, lld.
The stub before was:
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *got(%rip)
0x68, 0x00, 0x00, 0x00, 0x00, // pushq <relocation index>
0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[0]
Linking a program with this (original) stub and inspecting it with objdump yields something like this:
00000000002012d0 <printf#plt>:
2012d0: ff 25 62 0d 00 00 jmpq *0xd62(%rip) # 202038 <__TMC_END__+0x28>
2012d6: 68 02 00 00 00 pushq $0x2
2012db: e9 c0 ff ff ff jmpq 2012a0 <_fini+0x10>
I modified the PLT stub by simply adding a NOP at the end:
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *got(%rip)
0x68, 0x00, 0x00, 0x00, 0x00, // pushq <relocation index>
0xe9, 0x00, 0x00, 0x00, 0x00, // jmpq plt[0]
0x0f, 0x1f, 0x40, 0x00 // nop
I made sure to modify the PltEntrySize variable so that it reflects the change in size. Linking and running programs with this modification seems to work just fine.
However, when I try to inspect the disassembly of a linked program with objdump, I see something strange:
00000000002012d0 <printf#plt>:
2012d0: cc int3
2012d1: ff (bad)
2012d2: ff (bad)
2012d3: ff 0f decl (%rdi)
2012d5: 1f (bad)
2012d6: 40 00 ff add %dil,%dil
2012d9: 25 5a 0d 00 00 and $0xd5a,%eax
2012de: 68 02 00 00 00 pushq $0x2
2012e3: e9 b8 ff ff ff jmpq 2012a0 <_fini+0x10>
2012e8: 0f 1f 40 00 nopl 0x0(%rax)
The PLT stub's address is interpreted by objdump to be at 0x2012d0, but the real printf#plt address is at 0x2012d8! This is confirmed by readelf -s:
Symbol table '.dynsym' contains 7 entries:
Num: Value Size Type Bind Vis Ndx Name
...
6: 00000000002012d8 0 FUNC GLOBAL DEFAULT UND printf#GLIBC_2.2.5 (2)
Where does objdump get its information from? It could very well be that I forgot to modify something in the linker.
For testing purposes, I modified the PLT stub that is generated by the llvm linker, lld.
The size and layout of the plt entry is set in stone by the ABI (see pg. 79), and can not be changed.
Linking and running programs with this modification seems to work just fine.
I doubt any non-trivial program will run correctly with your modification -- the dynamic loader assumes ABI plt layout, and should crash and burn when given bogus plt.