This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

UsageMin/UsageMax

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

Parents
  • You'll see a good example in the report descriptor for USB keyboard.

    "Device Class Definition for HID 1.11"
    www.usb.org/.../HID1_11.pdf
    E.6 Report Descriptor (Keyboard) (HID1_11.pdf p69)

    This excerpt shows the definition of modifier keys (CTRL, ALT, SHIFT and GUI)

    // ------- Input for the Modifier byte -----------
    05 07   Usage Page (Key Codes)   -- usage is defined in the Keyboard page (0x07)
    19 E0   Usage Minimum (224)      -- the first item is "Keyboard LeftControl"
    29 E7   Usage Maximum (231)      -- the last item is "Keyboard Right GUI"
    15 00   Logical Minimum (0)      -- the value is 0 or 1
    25 01   Logical Maximum (1)
    75 01   Report Size (1)          -- each item has a bit
    95 08   Report Count (8)         -- 8 bits, as a whole
    81 02   Input (Data, Variable, Absolute) -- the modifier byte
    

    - First, looking at the "Usage Page", you'll know the "Usage" is defined in the Keyboard page (0x07).
    - Then, you'll open the "HID Usage Tables" and look into the long table on
    "10 Keyboard/Keypad Page (0x07)" chapter.

    "HID Usage Tables 1.12"
    www.usb.org/.../Hut1_12.pdf

    At the end of the table, you'll see these values.

    Table 12: Keyboard/Keypad Page (Hut1_12.pdf p60)
    
    224 E0   Keyboard LeftControl  -- Usage Minimum
    225 E1   Keyboard LeftShift
    226 E2   Keyboard LeftAlt
    227 E3   Keyboard Left GUI
    228 E4   Keyboard RightControl
    229 E5   Keyboard RightShift
    230 E6   Keyboard RightAlt
    231 E7   Keyboard Right GUI    -- Usage Maximum
    

    This pair of Usage Minimum/ Maximum specifies eight "Usages", from "Keyboard LeftControl" to "Keyboard Right GUI". It gives the "name" (or attribute) to each bit.

    Bit    Key
     0   LEFT CTRL
     1   LEFT SHIFT
     2   LEFT ALT
     3   LEFT GUI
     4   RIGHT CTRL
     5   RIGHT SHIFT
     6   RIGHT ALT
     7   RIGHT GUI
    

    .

    This kind of detailed HID "grammar" is useful when you make up an established HID, like keyboard or mouse. When you handle a vendor-specific HID, you can do without such a detail :-)

    For example, this report descriptor shows a vender-specific HID with IN and OUT endpoints. 64 bytes Input and Output report are defined, respectively.

        0x06, 0x00, 0xff,       // USAGE_PAGE (Vendor Defined Page 1)
        0x09, 0x01,             // USAGE (Vendor Usage 1)
        0xa1, 0x01,             // COLLECTION (Application)
        0x15, 0x00,             //  LOGICAL_MINIMUM (0)
        0x26, 0xff, 0x00,       //  LOGICAL_MAXIMUM (255)
        0x75, 0x08,             //  REPORT_SIZE  (8)    - bits
        0x95, 0x40,             //  REPORT_COUNT (64)   - Bytes
        0x09, 0x01,             //  USAGE (Vendor Usage 1)
        0x81, 0x02,             //  INPUT (Data,Var,Abs)
        0x09, 0x01,             //  USAGE (Vendor Usage 1)
        0x91, 0x02,             //  OUTPUT (Data,Var,Abs)
        0xc0                    // END_COLLECTION
    

    This one is the same one that I've advised to fix the bug of the report descriptor of ULINK2, in this post.

    "ULINK2 slow performance on USB 2.0"
    http://www.keil.com/forum/docs/thread11783.asp

    That is, a vendor-specific HID like ULINK2, this simple report descriptor is enough. You don't need to define the usage of each items precisely.

    Tsuneo

Reply
  • You'll see a good example in the report descriptor for USB keyboard.

    "Device Class Definition for HID 1.11"
    www.usb.org/.../HID1_11.pdf
    E.6 Report Descriptor (Keyboard) (HID1_11.pdf p69)

    This excerpt shows the definition of modifier keys (CTRL, ALT, SHIFT and GUI)

    // ------- Input for the Modifier byte -----------
    05 07   Usage Page (Key Codes)   -- usage is defined in the Keyboard page (0x07)
    19 E0   Usage Minimum (224)      -- the first item is "Keyboard LeftControl"
    29 E7   Usage Maximum (231)      -- the last item is "Keyboard Right GUI"
    15 00   Logical Minimum (0)      -- the value is 0 or 1
    25 01   Logical Maximum (1)
    75 01   Report Size (1)          -- each item has a bit
    95 08   Report Count (8)         -- 8 bits, as a whole
    81 02   Input (Data, Variable, Absolute) -- the modifier byte
    

    - First, looking at the "Usage Page", you'll know the "Usage" is defined in the Keyboard page (0x07).
    - Then, you'll open the "HID Usage Tables" and look into the long table on
    "10 Keyboard/Keypad Page (0x07)" chapter.

    "HID Usage Tables 1.12"
    www.usb.org/.../Hut1_12.pdf

    At the end of the table, you'll see these values.

    Table 12: Keyboard/Keypad Page (Hut1_12.pdf p60)
    
    224 E0   Keyboard LeftControl  -- Usage Minimum
    225 E1   Keyboard LeftShift
    226 E2   Keyboard LeftAlt
    227 E3   Keyboard Left GUI
    228 E4   Keyboard RightControl
    229 E5   Keyboard RightShift
    230 E6   Keyboard RightAlt
    231 E7   Keyboard Right GUI    -- Usage Maximum
    

    This pair of Usage Minimum/ Maximum specifies eight "Usages", from "Keyboard LeftControl" to "Keyboard Right GUI". It gives the "name" (or attribute) to each bit.

    Bit    Key
     0   LEFT CTRL
     1   LEFT SHIFT
     2   LEFT ALT
     3   LEFT GUI
     4   RIGHT CTRL
     5   RIGHT SHIFT
     6   RIGHT ALT
     7   RIGHT GUI
    

    .

    This kind of detailed HID "grammar" is useful when you make up an established HID, like keyboard or mouse. When you handle a vendor-specific HID, you can do without such a detail :-)

    For example, this report descriptor shows a vender-specific HID with IN and OUT endpoints. 64 bytes Input and Output report are defined, respectively.

        0x06, 0x00, 0xff,       // USAGE_PAGE (Vendor Defined Page 1)
        0x09, 0x01,             // USAGE (Vendor Usage 1)
        0xa1, 0x01,             // COLLECTION (Application)
        0x15, 0x00,             //  LOGICAL_MINIMUM (0)
        0x26, 0xff, 0x00,       //  LOGICAL_MAXIMUM (255)
        0x75, 0x08,             //  REPORT_SIZE  (8)    - bits
        0x95, 0x40,             //  REPORT_COUNT (64)   - Bytes
        0x09, 0x01,             //  USAGE (Vendor Usage 1)
        0x81, 0x02,             //  INPUT (Data,Var,Abs)
        0x09, 0x01,             //  USAGE (Vendor Usage 1)
        0x91, 0x02,             //  OUTPUT (Data,Var,Abs)
        0xc0                    // END_COLLECTION
    

    This one is the same one that I've advised to fix the bug of the report descriptor of ULINK2, in this post.

    "ULINK2 slow performance on USB 2.0"
    http://www.keil.com/forum/docs/thread11783.asp

    That is, a vendor-specific HID like ULINK2, this simple report descriptor is enough. You don't need to define the usage of each items precisely.

    Tsuneo

Children
  • Tsuneo;
    Thank you very much for your reply. I have the referenced specs. You have made the subject somewhat more clear for me. I will study the specs with a better understanding.
    But I still don't understand why the Keil examples have these two items. From your examples they are not used and not required. I have no idea what ranges these two items represent. Just another bug or they just using them for a place keeper in case they later want to make these items have meaning?
    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

  • 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