USB HID Report ID

Hello,

I am useing an SAM7S256 controller. I want to implement a USB HID communication. I have already succeded to some degree with the Keil sample code for HID.

My problem is the Report descriptor.
I want to be able to transmit 1 to 1024 bytes from HOST to DEVICE and DEVICE to HOST. I could define a report descriptor for 1026 bytes and use 2 bytes for the length of the actual data. However I don't want to waste so much bandwidth if there is only a few bytes actual information to send.
I came up with the idea to use report IDs and to define say 17 report IDs with sizes from 64-bytes to 1026 bytes.
My problem is I don't know how to specify this so it works correctly.
Are you aware of a tool to test the descriptors in depth. The Tools I have found on the usb.org page only tell me how many errors there are in my report descriptor but not what exactly the problem is?

My descriptor so far ...

/* HID Report Descriptor */
const BYTE HID_ReportDescriptor[] = {
  HID_UsagePageVendor(0x00),
  HID_Usage(          0x01),
  HID_Collection(     HID_Application),

    // INPUT (DEVICE -> HOST)
  HID_Collection(     HID_Logical),
        HID_ReportID(     1),
        HID_Usage(        0x01),
    HID_LogicalMin(   0),
    HID_LogicalMax(   255),
    HID_ReportCount(  64),
    HID_ReportSize(   8),
    HID_Input(        HID_Data | HID_Variable | HID_Absolute),
  HID_EndCollection,


  HID_Collection(     HID_Logical),
        HID_ReportID(     2),
        HID_Usage(        0x01),
    HID_LogicalMin(   0),
    HID_LogicalMax(   255),
    HID_ReportCount(  128),
    HID_ReportSize(   8),
    HID_Input(        HID_Data | HID_Variable | HID_Absolute),
  HID_EndCollection,

        // INPUT (HOST -> DEVICE)
  HID_Collection(     HID_Logical),
        HID_ReportID(     1),
        HID_UsagePage(HID_USAGE_PAGE_GENERIC),
    HID_Usage(HID_USAGE_GENERIC_COUNTED_BUFFER),
    HID_LogicalMin(0),
    HID_LogicalMax(255),
    HID_ReportCount(64),
    HID_ReportSize(8),
    HID_Output(HID_Data | HID_Variable | HID_Absolute),
  HID_EndCollection,

 HID_Collection(     HID_Logical),
        HID_ReportID(     2),
        HID_UsagePage(HID_USAGE_PAGE_GENERIC),
    HID_Usage(HID_USAGE_GENERIC_COUNTED_BUFFER),
    HID_LogicalMin(0),
    HID_LogicalMax(255),
    HID_ReportCount(128),
    HID_ReportSize(8),
    HID_Output(HID_Data | HID_Variable | HID_Absolute),
  HID_EndCollection,

 HID_Collection(     HID_Logical),
        HID_ReportID(     3),
        HID_UsagePage(HID_USAGE_PAGE_GENERIC),
    HID_Usage(HID_USAGE_GENERIC_COUNTED_BUFFER),
    HID_LogicalMin(0),
    HID_LogicalMax(255),
    HID_ReportCount(192),
    HID_ReportSize(8),
    HID_Output(HID_Data | HID_Variable | HID_Absolute),
  HID_EndCollection,

  HID_EndCollection,
};

Parents
  • 1) sub-collections are not required
    In your report descriptor, you declare sub-collection to each report ID, like

      HID_Collection(     HID_Logical),
      ...
      HID_EndCollection,
    


    Just to declare report ID, these sub-collections are not required.
    Delete them all.

    Just the top-level collection is required.

      HID_Collection(     HID_Application),
      HID_EndCollection,
    

    2) Declaration of duplicated report ID is not allowed throughout entire report descriptor.
    Rather, combine the Input and Output under the same report ID.

    3) For Global items, one time declaration is enough
    You don't need to declare these global items every time, unless you assign another value to them. The value is held once declared.
    - LogicalMin
    - LogicalMax
    - ReportSize

    4) Detailed usage is not required
    For vendor specific HID, there isn't so much advantage to specify the detailed usage.

    /* HID Report Descriptor */
    const BYTE HID_ReportDescriptor[] = {
        0x06, 0x00, 0xff,              // USAGE_PAGE (Vendor Defined Page 1)
        0xa1, 0x01,                    // COLLECTION (Application)
        0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
        0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
        0x75, 0x08,                    //   REPORT_SIZE (8)
    
        0x85, 0x01,                    //   REPORT_ID (1)
        0x95, 0x40,                    //   REPORT_COUNT (64)
        0x09, 0x01,                    //   USAGE (Vendor Usage 1)
        0x81, 0x02,                    //   INPUT (Data,Var,Abs)
        0x09, 0x01,                    //   USAGE (Vendor Usage 1)
        0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
    
        0x85, 0x02,                    //   REPORT_ID (2)
        0x95, 0x80,                    //   REPORT_COUNT (128)
        0x09, 0x01,                    //   USAGE (Vendor Usage 1)
        0x81, 0x02,                    //   INPUT (Data,Var,Abs)
        0x09, 0x01,                    //   USAGE (Vendor Usage 1)
        0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
    
        0x85, 0x03,                    //   REPORT_ID (3)
        0x95, 0xc0,                    //   REPORT_COUNT (192)
        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
    };
    

    Tsuneo

Reply
  • 1) sub-collections are not required
    In your report descriptor, you declare sub-collection to each report ID, like

      HID_Collection(     HID_Logical),
      ...
      HID_EndCollection,
    


    Just to declare report ID, these sub-collections are not required.
    Delete them all.

    Just the top-level collection is required.

      HID_Collection(     HID_Application),
      HID_EndCollection,
    

    2) Declaration of duplicated report ID is not allowed throughout entire report descriptor.
    Rather, combine the Input and Output under the same report ID.

    3) For Global items, one time declaration is enough
    You don't need to declare these global items every time, unless you assign another value to them. The value is held once declared.
    - LogicalMin
    - LogicalMax
    - ReportSize

    4) Detailed usage is not required
    For vendor specific HID, there isn't so much advantage to specify the detailed usage.

    /* HID Report Descriptor */
    const BYTE HID_ReportDescriptor[] = {
        0x06, 0x00, 0xff,              // USAGE_PAGE (Vendor Defined Page 1)
        0xa1, 0x01,                    // COLLECTION (Application)
        0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
        0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
        0x75, 0x08,                    //   REPORT_SIZE (8)
    
        0x85, 0x01,                    //   REPORT_ID (1)
        0x95, 0x40,                    //   REPORT_COUNT (64)
        0x09, 0x01,                    //   USAGE (Vendor Usage 1)
        0x81, 0x02,                    //   INPUT (Data,Var,Abs)
        0x09, 0x01,                    //   USAGE (Vendor Usage 1)
        0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
    
        0x85, 0x02,                    //   REPORT_ID (2)
        0x95, 0x80,                    //   REPORT_COUNT (128)
        0x09, 0x01,                    //   USAGE (Vendor Usage 1)
        0x81, 0x02,                    //   INPUT (Data,Var,Abs)
        0x09, 0x01,                    //   USAGE (Vendor Usage 1)
        0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)
    
        0x85, 0x03,                    //   REPORT_ID (3)
        0x95, 0xc0,                    //   REPORT_COUNT (192)
        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
    };
    

    Tsuneo

Children
More questions in this forum