In all of Keil's USBHID examples, there are two items in the Report Descriptor called UsageMin and UsageMax. Thy are set to 1 and 3. I have reviewed the USB Usage Spec and several other examples and I still don't understand the need for these two items of range. I can find no other example of these two items. In MSDN2, I find the HIDP_Value_CAPS structure that includes the RANGE.UsageMin and RANGE.UsageMax that tells about the bounds but what is their use? In Keil's HIDClient code, I see no place where the two items are used. Of course when I comment out the two lines of code, the code fails. Probably I'm breaking an array count somewhere when I comment out the code. I'm hoping that someone like Tsuneo can educate me on the two items. I have sent a query to Keil Support but it will be awhile before I expect an answer. Al Bradford
"I have no idea what ranges these two items represent."
Find the Usage Page just before the Usage Minimum/ Maximum. Look at the KEIL HID example,
#define HID_USAGE_PAGE_BUTTON 0x09 HID_UsagePage(HID_USAGE_PAGE_BUTTON), -- On the Button page, HID_UsageMin(1), -- from Button 1 HID_UsageMax(3), -- to Button 3 HID_LogicalMin(0), -- the value is 0 or 1 HID_LogicalMax(1), HID_ReportCount(3), -- three items HID_ReportSize(1), -- each item has one bit HID_Input(HID_Data | HID_Variable | HID_Absolute), -- apply above format to the Input report HID_ReportCount(1), -- 5 bits padding for the Input report HID_ReportSize(5), HID_Input(HID_Constant),
HID_UsagePage declares HID_USAGE_PAGE_BUTTON (0x09) just before HID_UsageMin/ HID_UsageMax. On the "HID Usage Tables 1.12", "12 Button Page (0x09)" (Hut1_12.pdf p69) chapter describes the each Usage.
Table 14: Button Usage Page Usage ID Usage Name 00 No button pressed 01 Button 1 (primary/trigger) -- Usage Minimum 02 Button 2 (secondary) 03 Button 3 (tertiary) -- Usage Maximum 04 Button 4 ... ... FFFF Button 65535
The Usage Minimum/ Maximum represents three buttons, Button 1-3. The bitmap is as follows.
Bit Attribute 0 Button 1 1 Button 2 2 Button 3 3 --- (padding) 4 --- 5 --- 6 --- 7 ---
.
"But I still don't understand why the Keil examples have these two items. From your examples they are not used and not required."
As we reviewed in this discussion, HID report descriptor defines the format of the HID reports. HID 'grammar' has been developed to provide an universal way to describe the report format. If you would have great ambition to spread your 'format' all over the world, on every desktop, like USB mouse or keyboard, it should be worth to pour your time and effort to your precise HID report descriptor. When your project is just for your specific device without open feature, however, much simpler descriptor will do. You can exchange the 'format' between the device and host app development by common header files, or precise documents, or even by your memory :-) You can code the direct parser in C/C++ or other programming language as you like, on both of device/ host app coding.
That's why you don't need to define the usage of each items precisely in your vendor-specific HID.
This is the original report descriptor of the KEIL HID example.
/* HID Report Descriptor */ const BYTE HID_ReportDescriptor[] = { HID_UsagePageVendor(0x00), HID_Usage(0x01), HID_Collection(HID_Application), HID_UsagePage(HID_USAGE_PAGE_BUTTON), HID_UsageMin(1), HID_UsageMax(3), HID_LogicalMin(0), HID_LogicalMax(1), HID_ReportCount(3), HID_ReportSize(1), HID_Input(HID_Data | HID_Variable | HID_Absolute), HID_ReportCount(1), HID_ReportSize(5), HID_Input(HID_Constant), HID_UsagePage(HID_USAGE_PAGE_LED), HID_Usage(HID_USAGE_LED_GENERIC_INDICATOR), HID_LogicalMin(0), HID_LogicalMax(1), HID_ReportCount(8), HID_ReportSize(1), HID_Output(HID_Data | HID_Variable | HID_Absolute), HID_EndCollection, };
It is simplified as follows. This report descriptor defines just one byte for Input and Output report, respectively. You'll document the precise bitmap of the report elsewhere.
/* HID Report Descriptor */ const BYTE HID_ReportDescriptor[] = { HID_UsagePageVendor(0x00), HID_Usage(0x01), HID_Collection(HID_Application), HID_LogicalMin(0), // value range: 0 - 0xFF HID_LogicalMaxS(0xFF), HID_ReportSize(8), // 8 bits HID_ReportCount(1), // one byte HID_Usage(0x01), HID_Input(HID_Data | HID_Variable | HID_Absolute), HID_Usage(0x01), HID_Output(HID_Data | HID_Variable | HID_Absolute), HID_EndCollection, };
To make up your report descriptor, or to confirm its integrity, "HID Descriptor Tool" will help you.
"HID Descriptor Tool" www.usb.org/.../dt2_4.zip
This tool also provides example descriptors for popular HID, such as keyboard/ mouse, joystick, display / monitor, telephony, etc.
To save your custom report descriptor on this tool, save it to the application (Dt.exe) folder. Otherwise, this tool will complain "dt.ini is not found". The app searches just current working directory for "dt.ini", not in the original application folder. A minor bug :-)
Tsuneo
I'll show a little more generalized form. In the simplified report descriptor, it just defines the number of bytes of each report. This numbers are extracted with #define as follows. Then, you don't need to worry about the report descriptor any more. When you add more reports using report ID, this code works as the template for the modification.
//----------------------------------------- // HID Report Descriptor //----------------------------------------- // // Bit Input Output // 0 Button 1 LED1 // 1 Button 2 LED2 // 2 Button 3 LED3 // 3 (padding) LED4 // 4 --- LED5 // 5 --- LED6 // 6 --- LED7 // 7 --- LED8 // #define HID_INPUT_REPORT_BYTES 1 // up to 127 bytes #define HID_OUTPUT_REPORT_BYTES 1 // up to 127 bytes #define HID_FEATURE_REPORT_BYTES 1 // up to 127 bytes const BYTE HID_ReportDescriptor[] = { HID_UsagePageVendor( 0x00 ), HID_Usage ( 0x01 ), HID_Collection ( HID_Application ), HID_LogicalMin ( 0 ), // value range: 0 - 0xFF HID_LogicalMaxS ( 0xFF ), HID_ReportSize ( 8 ), // 8 bits HID_ReportCount ( HID_INPUT_REPORT_BYTES ), HID_Usage ( 0x01 ), HID_Input ( HID_Data | HID_Variable | HID_Absolute ), HID_ReportCount ( HID_OUTPUT_REPORT_BYTES ), HID_Usage ( 0x01 ), HID_Output ( HID_Data | HID_Variable | HID_Absolute ), HID_ReportCount ( HID_FEATURE_REPORT_BYTES ), HID_Usage ( 0x01 ), HID_Feature ( HID_Data | HID_Variable | HID_Absolute ), HID_EndCollection, }; const WORD HID_ReportDescSize = sizeof(HID_ReportDescriptor);
Tsuneo; Thank you for your effort in my education. You have been a great help to me and I'm sure others that monitor this forum. I have the DT tool you referenced. It also was a help until I stumbled and fell on the point of UsageMin/UsageMax. Actually your description of the keyboard code was also a great help in defining how to handle my 12 buttons of input with the Usage range items. I have USB communication between my target and HID Client working and I was attempting to finalize my report formats. This education has saved me several more days of effort. Thanks again. Al Bradford