Getting HID Feature report for different Report IDs

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Getting HID Feature report for different Report IDs

6,085 Views
ssudhir
Contributor II

Hi,

Getting HID Feature report for different Report IDs

For Generic HID (LPC4357 – using ROM USB stack) when we have a report without different report

ID, and the count for all three reports are 64,  In the HID_GetReport Handler has the following code to get the feature report

*pBuffer = feature_report;

 *plength = 64;

At the Host end We are able to successfully get the feature report.

Some where in out EP Handler we are calling

USBD_API->hw->WriteEP(hUsb, pHidCtrl->epin_adr, inbuffer, 64);

 

Now when we change our report structure with 3 different report ID (separate ID for Input, Output & Feature),  and also changed the count (Feature is still 64 but changed the Input to 8) the get report fails.

Any material about how to get Feature reports or explanation will be helpful.

Thanks

0 Kudos
Reply
5 Replies

5,873 Views
ssudhir
Contributor II

Thanks TIC.

We made bit more progress and here is the description of our problem now. I have included the descriptor file, and also python code we use as a host in case you need.

When we don’t define report ID in our report descriptor, it takes the default ID that is ‘0’. In that case, we didn’t have to set report ID in the input or feature report we are sending. It looked like ROM stack was adding the report ID. For example, the input buffer looked like this
[20,21,22,23,24,25,26,27]
The host receives this
[0, 20,21,22,23,24,25,26,27]

However, when we specify a report ID say 1 for the input report, as per your suggestion we added the report ID as the first byte and now the host receives
For example, report ID with ‘1’ our input buffer at the device side looks like this
[1,20,21,22,23,24,25,26,27]
And the
The host receives this
[1, 20,21,22,23,24,25,26,27]
Now regarding Report Descriptor with multiple report IDs

Here are our descriptor and the code too.
Our understanding is, we can define different report ID so that we can utilize the bus efficiently. For example, if a feature Report with ID as 2 can have 2 bytes and another feature report with ID as 3 can have 64 bytes and report ID 2 results in 2 bytes transfer and report ID 3 results in 64 bytes transfer. Is that true? In our case, reports are sent padding. For example, if the HID_FEATURE_REPORT_BYTES is defined 64, then all feature reports are sent as 64 bytes.
For example, feature report with ID ‘2’ looks like this at the device side
[2,10,11]
Then the host receives this
[2,10,11,0,0------0] – Total 65 bytes – because as I mentioned HID_FEATURE_REPORT_BYTES is defined 64.
What is that we need to do if we want to send different length reports without padding?

Our descriptor

define HID_INPUT_REPORT_BYTES 8 /* size of report in Bytes */
#define HID_OUTPUT_REPORT_BYTES 64 /* size of report in Bytes */
#define HID_FEATURE_REPORT_BYTES 64 /* size of report in Bytes */
const uint8_t HID_ReportDescriptor[] = {
HID_UsagePageVendor(0x45),
HID_Usage(0x00), //name of hhe usage for the entire application
HID_Collection(HID_Application),
HID_Usage(0xA010), //name of the usage for the entire input report
HID_ReportID(0x01),
HID_Collection(HID_Logical),
HID_Usage(0xA011),
HID_Usage(0xA012),
HID_Usage(0xA013),
HID_LogicalMin(0), // value range: 0 - 0xFF
HID_LogicalMaxS(0xFF),
HID_ReportSize(8),
HID_ReportCount(3),
HID_Input(HID_Variable),
HID_Usage(0xA014),
HID_Usage(0xA015),
HID_LogicalMin(0), // value range: 0 - 0xFF
HID_LogicalMaxS(0xF),
HID_ReportSize(4),
HID_ReportCount(2),
HID_Input(HID_Variable),
HID_Usage(0xA016),
HID_LogicalMin(0), // value range: 0 - 0xFF
HID_LogicalMaxS(0xFF),
HID_ReportSize(8),
HID_ReportCount(4),
HID_Input(HID_Variable),
HID_EndCollection, //end of input collection
HID_ReportID(0x02),
HID_ReportSize(8),
HID_ReportCount(HID_OUTPUT_REPORT_BYTES),
HID_LogicalMin(0), // value range: 0 - 0xFF
HID_LogicalMaxS(0xFF),
HID_Usage(0xA020),
HID_Output(HID_Variable),
HID_Usage(0xA0001), //name of the usage for the entire feature report
HID_ReportID(0x03),
HID_Collection(HID_Logical),
HID_Usage(0xA0002),
HID_LogicalMin(0), // value range: 0 - 0xFF
HID_LogicalMaxS(0xFF),
HID_ReportSize(8),
HID_ReportCount(1),
HID_Feature(HID_Variable| HID_Volatile), //device might change
HID_Usage(0xA0003),
HID_Usage(0xA0004),
HID_LogicalMin(0), // value range: 0 - 0xF
HID_LogicalMaxS(0xF),
HID_ReportSize(4),
HID_ReportCount(2),
HID_Feature(HID_Variable| HID_Volatile), //device might change
HID_Usage(0xA0005),
HID_LogicalMin(0), // value range: 0 - 0xFF
HID_LogicalMaxS(0xFF),
HID_ReportSize(8),
HID_ReportCount(1),
HID_Feature(HID_Variable| HID_Volatile), //device might change
HID_Usage(0xA0006),
HID_LogicalMin(0), // value range: 0 - 0xFF
HID_LogicalMaxS(0xFF),
HID_ReportSize(8),
HID_ReportCount(61),
HID_Feature(HID_Variable| HID_Volatile), //device might change
HID_EndCollection, //end of feature
//testing another feature report with ID 4 format is the same
HID_Usage(0x30), //name of the usage for the entire feature report
HID_ReportID(0x04),
HID_Collection(HID_Logical),
HID_Usage(0x32),
HID_LogicalMin(0), // value range: 0 - 0xFF
HID_LogicalMaxS(0xFF),
HID_ReportSize(8),
HID_ReportCount(1),
HID_Feature(HID_Variable| HID_Volatile), //device might change
HID_Usage(0x33),
HID_Usage(0x34),
HID_LogicalMin(0), // value range: 0 - 0xF
HID_LogicalMaxS(0xF),
HID_ReportSize(4),
HID_ReportCount(2),
HID_Feature(HID_Variable| HID_Volatile), //device might change
HID_Usage(0x35),
HID_LogicalMin(0), // value range: 0 - 0xFF
HID_LogicalMaxS(0xFF),
HID_ReportSize(8),
HID_ReportCount(1),
HID_Feature(HID_Variable| HID_Volatile), //device might change
HID_Usage(0x36),
HID_LogicalMin(0), // value range: 0 - 0xFF
HID_LogicalMaxS(0xFF),
HID_ReportSize(8),
HID_ReportCount(5),
HID_Feature(HID_Variable| HID_Volatile), //device might change
HID_EndCollection, //end of feature


HID_EndCollection,
};

The initialization routine
/* HID init routine */
ErrorCode_t usb_hid_init(USBD_HANDLE_T hUsb,
USB_INTERFACE_DESCRIPTOR *pIntfDesc,
uint32_t *mem_base,
uint32_t *mem_size)
{
USBD_HID_INIT_PARAM_T hid_param;
USB_HID_REPORT_T reports_data[1];
ErrorCode_t ret = LPC_OK;
uint16_t count = 0;

memset((void *) &hid_param, 0, sizeof(USBD_HID_INIT_PARAM_T));
/* HID paramas */
hid_param.max_reports = 1;
/* Init reports_data */
reports_data[0].len = HID_ReportDescSize;
reports_data[0].idle_time = 0;
reports_data[0].desc = (uint8_t *) &HID_ReportDescriptor[0];

if ((pIntfDesc == 0) || (pIntfDesc->bInterfaceClass != USB_DEVICE_CLASS_HUMAN_INTERFACE)) {
return ERR_FAILED;
}

hid_param.mem_base = *mem_base;
hid_param.mem_size = *mem_size;
hid_param.intf_desc = (uint8_t *) pIntfDesc;
/* user defined functions */
hid_param.HID_GetReport = HID_GetReport;
hid_param.HID_SetReport = HID_SetReport;
hid_param.HID_EpIn_Hdlr = HID_Ep_Hdlr;
hid_param.HID_EpOut_Hdlr = HID_Ep_Hdlr;
hid_param.report_data = reports_data;

ret = USBD_API->hid->init(hUsb, &hid_param);
/* allocate USB accessable memory space for report data */
//loopback_report = (uint8_t *) hid_param.mem_base;
output_report = (uint8_t *) hid_param.mem_base;
//bns 3/8 - since we are using 64 bytes make it 64 - originally it was 4
hid_param.mem_base += 65;
hid_param.mem_size += 65;
//bns adding onout and out put
input_report = (uint8_t *) hid_param.mem_base;
memset((uint8_t*) input_report, 0, 65);
//bns 3/8 - since we are using 64 bytes make it 64 - originally it was 4
hid_param.mem_base += 65;
hid_param.mem_size += 65;

//bns adding feature
feature_report = (uint8_t *) hid_param.mem_base;
memset((uint8_t*) feature_report, 0, 65);
//bns 3/8 - since we are using 64 bytes make it 64 -
hid_param.mem_base += 65;
hid_param.mem_size += 65;
/* update memory variables */
/* update memory variables */

*mem_base = hid_param.mem_base;
*mem_size = hid_param.mem_size;
//bns 3/8 initlaize bit of inout so that we know what we are sending for test
for (int i = 0;i<10;i++)
input_report[i] =i+20;


//bns 3/14 initialize bit of feature so that we know what we are sending for test
for (int i = 0;i<10;i++)
feature_report[i] =i+10;

return LPC_OK;
}


And now the get report code
static ErrorCode_t HID_GetReport(USBD_HANDLE_T hHid, USB_SETUP_PACKET *pSetup, uint8_t * *pBuffer, uint16_t *plength)
{
uint8_t ReportID = pSetup->wValue.WB.L;
switch (pSetup->wValue.WB.H) {
case HID_REPORT_INPUT:
//now think if different report ID
switch (ReportID)
{
case 0: //when we don't define
//Can't assign explicitly 0 as report ID, but it is assigned default , in that case
// USB stack adds report ID as the first byte so not required to assign explicitly
//In general, we are using first byte as the report ID in the input buffer and second byte onwards data
//and due to what we mentioned earlier, just give data that is input_report second byte onwards
*pBuffer = input_report+1;
*plength = 8;
break;
case 1: //when we defined report ID as 1
//as we are testing different report ID etc add report ID here, much easier and no confusion
//after concluding about report ID can initialize as part of initialization routine
input_report[0] = 1;
input_report[1] = 11;
*pBuffer = input_report;
*plength = 8;
break;
case 4: //when we defined report ID as 1
//as we are testing different report ID etc add report ID here, much easier and no confusion
//after concluding about report ID can initialize as part of initialization routine
input_report[0] = 4;
//change data to test
input_report[1] = 44;
*pBuffer = input_report;
*plength = 8;
break;
}
break;

case HID_REPORT_OUTPUT:
//bns 3/19 shoudl never be here !
return ERR_USBD_STALL; // Not Supported
break;

case HID_REPORT_FEATURE:
switch (ReportID)
{
case 0: //when we don't define
//add report ID here no confusion
// feature_report[0] = 0;
*pBuffer = feature_report+1;
*plength = 64;
break;
case 1:
//as we are testing different report ID etc add report ID here, much easier and no confusion
//after concluding about report ID can initialize as part of initialization routine
feature_report[0] = 1;
*pBuffer = feature_report;
*plength = 64;
break;
case 3: // when we define report ID as 3
//as we are testing different report ID etc add report ID here, much easier and no confusion
//after concluding about report ID can initialize as part of initialization routine

feature_report[0] = 3;
//just to test different data
feature_report[1]=33;
*pBuffer = feature_report;
*plength = 64;
break;
case 4: // when we define report ID as 3
//as we are testing different report ID etc add report ID here, much easier and no confusion
//after concluding about report ID can initialize as part of initialization routine
feature_report[0] = 4;
//just to test different data
feature_report[1]=44;

*pBuffer = feature_report;
*plength = 8;
break;


}

break;
}
return LPC_OK;
}

Thanks

0 Kudos
Reply

5,873 Views
Alice_Yang
NXP TechSupport
NXP TechSupport

Hello  S S,

To my understanding, we need  refer to  the  "HID_ReportSize(x),  HID_ReportCount(x), " under each report ID, to define suitable "*plength" under GetReport() function also define the size of g_mouse.report[].

   case HID_REPORT_INPUT:
        Mouse_UpdateReport();

        *pBuffer = &g_mouse.report[0];
        *plength = 64;
        break;

And If you just want to change Report length, you can change the data of "*plength = ".

I haven't REPORT_FEATURE demo , also haven't a  good host tool like yours, so I just using

Bus Hound to test the report input,config *plength to 4 and 64, below is the result.

The Bus Hound sometimes doesn't show all the data, I think in your python code, you can see all the

64 bytes .

pastedImage_518.png

pastedImage_519.png


Have a great day,
TIC

0 Kudos
Reply

5,873 Views
ssudhir
Contributor II

Our code also looks very similar to yours and when we set a break point it does hit there.

As I mentioned earlier it works with the descriptor that has on Report ID, but doesn't work when it has more than more report ID. However, in both cases, when we set a break point it hits.

 

static ErrorCode_t HID_GetReport(USBD_HANDLE_T hHid, USB_SETUP_PACKET *pSetup, uint8_t * *pBuffer, uint16_t *plength)
{
/* ReportID = SetupPacket.wValue.WB.L; */
switch (pSetup->wValue.WB.H) {
case HID_REPORT_INPUT:


*pBuffer = input_report;
*plength = 64;
break;

case HID_REPORT_OUTPUT:

return ERR_USBD_STALL; // Not Supported

case HID_REPORT_FEATURE:

*pBuffer = feature_report;
*plength = 64;

break;
}
return LPC_OK;
}

0 Kudos
Reply

5,873 Views
Alice_Yang
NXP TechSupport
NXP TechSupport

Hello S S,

How about the input_report in your code, does input_report[0] is right report ID ?

*pBuffer = input_report;
*plength = 64;

and the plength should equal input data +1 (Report ID).

About more then one ID, how do you configure Report description? Also check the report ID in Get report request in PC,

the input_report[0] should also use this report ID.  And what's the appearance about your said "doesn't work" ?

Also you can send me a simple project that can reproduce the problem, I will test it on my side .


Have a great day,
TIC

0 Kudos
Reply

5,873 Views
Alice_Yang
NXP TechSupport
NXP TechSupport

Hello S S,

After finished the Report description, also Report data, then add the content in GetReport function as below:

pastedImage_16.png

set a breakpoint, check whether can run into it.

BR

TIC

0 Kudos
Reply