2025-03-22 4:51 AM - edited 2025-03-22 12:29 PM
I've read many posts here and on the web, even tried CoPilot, but I could not find how to get the USB controller to send data when the volume keys are pressed.
My Host keyboard driver works perfectly, but USBH_LL_GetURBState() is not returning with data for anything but "standard" key presses.
After many hours invested due to a total lack of documentation from STM, I found that the report descriptor of 146 bytes is read back by USBH_HID_GetHIDReportDescriptor() but the "consumer device" entry is not used.
But if STM had one support person publish a short guide it would save many developers many hours.
USBH_StatusTypeDef USBH_HID_KeybdInit(USBH_HandleTypeDef *phost)
{
uint32_t x;
HID_HandleTypeDef *HID_Handle = (HID_HandleTypeDef *) phost->pActiveClass->pData;
keybd_info.lctrl = 0U;
keybd_info.lshift = 0U;
keybd_info.lalt = 0U;
keybd_info.lgui = 0U;
keybd_info.rctrl = 0U;
keybd_info.rshift = 0U;
keybd_info.ralt = 0U;
keybd_info.rgui = 0U;
for (x = 0U; x < sizeof(keybd_report_data); x++)
{
keybd_report_data[x] = 0U;
keybd_rx_report_buf[x] = 0U;
}
if (HID_Handle->length > (sizeof(keybd_report_data)))
{
HID_Handle->length = (uint16_t)(sizeof(keybd_report_data));
}
HID_Handle->pData = keybd_rx_report_buf;
if ((HID_QUEUE_SIZE * sizeof(keybd_report_data)) > sizeof(phost->device.Data))
{
return USBH_FAIL;
}
else
{
** in the line below, I think it needs to point to the report table 65 bytes in for the "consumer devices" usage:-
USBH_HID_FifoInit(&HID_Handle->fifo, phost->device.Data, (uint16_t)(HID_QUEUE_SIZE * sizeof(keybd_report_data)));
}
return USBH_OK;
}
const char USB_CLASS_SPECIFIC_DESC[] = {
//hid report descriptor for interface 1 (keyboard)
0x05, 0x01, //usage page (generic desktop) //52, 53
0x09, 0x06, //usage (keyboard) //54, 55
0xA1, 0x01, //collection (application) //56, 57
0x85, 0x01, /* Report ID1 */
0x05, 0x07, //usage page (key codes) //58, 59
0x19, 0xE0, //usage min (224) //60, 61
0x29, 0xE7, //usage max (231) //62, 63
0x15, 0x00, //logical min (0) //64, 65
0x25, 0x01, //logical max (1) //66, 67
0x75, 0x01, //report size (1) //68, 69
0x95, 0x08, //report count (8) //70, 71
0x81, 0x02, //input (data, variable, absolute) [modifier byte] //72, 73
0x95, 0x01, //report count (1) //74, 75
0x75, 0x08, //report size (8) //76, 77
0x81, 0x01, //input (constant) [reserved byte] //78, 79
0x95, 0x05, //report count (5) //80, 81
0x75, 0x01, //report size (1) //82, 83
0x05, 0x08, //usage page (page# for leds) //84, 85
0x19, 0x01, //usage min (1) //86, 87
0x29, 0x05, //usage max (5) //88, 89
0x91, 0x02, //output (data, var, abs) [led report] //90, 91
0x95, 0x01, //report count (1) //92, 93
0x75, 0x03, //report size (3) //94, 95
0x91, 0x01, //output (constant) [led report padding] //96, 97
0x95, 0x05, //report count (5) //98, 99
0x75, 0x08, //report size (8) //100, 101
0x15, 0x00, //logical min (0) //102, 103
0x25, 0x65, //logical max (101) //104, 105
0x05, 0x07, //usage page (key codes) //106, 107
0x19, 0x00, //usage min (0) //108, 109
0x29, 0x65, //usage max (101) //110, 111
0x81, 0x00, //input (data, array) //112, 113
0xC0, //end collection //114
//
0x05, 0x0C, /* Usage Page (Consumer Devices) */
0x09, 0x01, /* Usage (Consumer Control) */
0xA1, 0x01, /* Collection (Application) */
0x85, 0x02, /* Report ID=2 */
0x05, 0x0C, /* Usage Page (Consumer Devices) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x01, /* Logical Maximum (1) */
0x75, 0x01, /* Report Size (1) */
0x95, 0x07, /* Report Count (7) */
0x09, 0xB5, /* Usage (Scan Next Track) */
0x09, 0xB6, /* Usage (Scan Previous Track) */
0x09, 0xB7, /* Usage (Stop) */
0x09, 0xCD, /* Usage (Play / Pause) */
0x09, 0xE2, /* Usage (Mute) */
0x09, 0xE9, /* Usage (Volume Up) */
0x09, 0xEA, /* Usage (Volume Down) */
0x81, 0x02, /* Input (Data, Variable, Absolute) */
0x95, 0x01, /* Report Count (1) */
0x81, 0x01, /* Input (Constant) */
0xC0,
2025-03-22 1:42 PM
The set idle call seems to be important to maintain dataflow, is this change going to be needed to get the volume key data to arrive?
case USBH_HID_REQ_SET_IDLE:
// First Set_Idle for standard keyboard Report ID (0x00)
classReqStatus = USBH_HID_SetIdle(phost, 0U, 0x00); // Send Set_Idle request
if (classReqStatus == USBH_OK) {
HID_Handle->ctl_state = USBH_HID_REQ_SET_IDLE_CONSUMER; // Move to next state
} else if (classReqStatus == USBH_NOT_SUPPORTED) {
HID_Handle->ctl_state = USBH_HID_REQ_SET_IDLE_CONSUMER; // Skip and continue
}
break;
case USBH_HID_REQ_SET_IDLE_CONSUMER:
// Second Set_Idle for Consumer Control Report ID (e.g., 0x02)
classReqStatus = USBH_HID_SetIdle(phost, 0U, 0x02);
if (classReqStatus == USBH_OK) {
HID_Handle->ctl_state = USBH_HID_REQ_SET_PROTOCOL; // Proceed to Set Protocol state
} else if (classReqStatus == USBH_NOT_SUPPORTED) {
HID_Handle->ctl_state = USBH_HID_REQ_SET_PROTOCOL; // Skip and continue
}
break;