This page shows the unique attributes for an MPLAB® Harmony USB Human Interface Device (HID) project. To get the most out of this page it is useful to have reviewed the USB Device Page showing the Harmony features common to all device projects. After finishing this page you should be able to more easily follow the step-by-step description of Developer Help's example HID project.
HID Report
HIDs respond to host requests by returning a data element called an HID Report. The length and format of the HID Report are set by the HID Report Descriptor. It is the responsibility of the application to format the HID Report in compliance with the HID Report Descriptor.
The sample Harmony USB projects use some of the most common HID Report examples including a mouse, a keyboard, and a user-defined protocol. The examples below are the HID Report formats for a simple three-button mouse and a gamepad controller.
bit 7 | bit 6 | bit 5 | bit 4 | bit 3 | bit 3 | bit 1 | bit 0 | |
---|---|---|---|---|---|---|---|---|
Byte 0 | - - - | - - - | - - - | - - - | - - - | Left Button | Middle Button | Right Button |
Byte 1 | X axis relative movement as signed char | |||||||
Byte 2 | Y axis relative movement as signed char |
bit 7 | bit 6 | bit 5 | bit 4 | bit 3 | bit 3 | bit 1 | bit 0 | |
---|---|---|---|---|---|---|---|---|
Byte 0 | Button | Button | Button | Button | Button | Button | Button | Button |
Byte 1 | Button | Button | Button | Button | Button | Button | Button | Button |
Byte 2 | Left X axis as signed char | |||||||
Byte 3 | Left Y as signed char | |||||||
Byte 4 | Right X axis as signed char | |||||||
Byte 5 | Right Y as signed char |
HID Report Descriptor
The HID Report Descriptor resides in the device and defines the format in which the device will send messages to the host. This information is shared with the host during enumeration.
The example below shows the code defining an HID Report Descriptor for a simple three-button mouse. The report indicates three bytes will be sent:
- The first byte contains three single elements which are input variables and five 1-bit inputs which are constants (i.e. padding).
- The second and third bytes each have a range of -127 to +127 and their input is variable (set by the applications).
Device Descriptor Table
The device descriptor table is the mechanism by which a device informs the host of the communication expectations of the device. The descriptor table is read from the device by the host during the enumeration process. There is very little room for a variance with the descriptor table for an HID. The USB standard for HID dictates much of the descriptor table contents. All HID Descriptor tables have these common attributes:
- At least one interface must exist with the class code for an HID.
- The HID interface will have exactly two data endpoints (Endpoint1 IN and Endpoint1 OUT).
- Both endpoints will have Interrupt Transfer types, be 64-bytes in length, and be scheduled to be polled every frame.
USB specifications allow the developer to select the Vendor/Product ID numbers, power consumption figures, as well as any identification text strings used.
Below is an example of a device descriptor for a single configuration HID. The device configuration has a maximum power consumption of 50 ma, and a Vendor ID/Product ID (VID/PID) of 0x0480/0x0000. There are two identifying text strings for this device.
Driver Event Handler
Harmony USB projects schedule a HID Driver Task (either DRV_USBFS_Tasks or DRV_USBHS_Tasks) to run on each iteration of the main while loop. When the device is enumerated, a user-written function is designated as the HID Driver Event Handler by USB_DEVICE_HID_EventHandlerSet().
The Driver Task monitors the communication between the host and the device. When certain events are detected, the user-written event handler is called. The event handler will then process the following events:
HID Events Detected by Driver Function | Description |
---|---|
USB_DEVICE_HID_EVENT_GET_REPORT | A GET REPORT command received from the host. |
USB_DEVICE_HID_EVENT_SET_REPORT | A SET REPORT command received from the host. |
USB_DEVICE_HID_EVENT_REPORT_SENT | The data in Endpoint1 IN has successfully been sent to the host. |
USB_DEVICE_HID_EVENT_REPORT_RECEIVED | A data packet has been received from the host and has been placed in Endpoint 1 OUT. |
USB_DEVICE_HID_EVENT_SET_IDLE | A SET IDLE command received from the host. The device will set the new idle rate. |
USB_DEVICE_HID_EVENT_GET_IDLE | A GET IDLE command received from host. The device responds by sending the current idle rate value. |
USB_DEVICE_HID_EVENT_SET_PROTOCOL | A SET PROTOCOL command received from host device will accept the new protocol value. |
USB_DEVICE_HID_EVENT_GET_PROTOCOL | A GET PROTOCOL command received. The device returns the value of the current protocol. |
USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_SENT | The host has sent a control packet to the device. |
USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_RECEIVED | The host has a received a control packet response from the device. |
USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_ABORTED | The host has aborted a control transfer. |
How is the Driver Event Handler used in an Application?
One of the most common usages of the HID Event Handler is to inform the application of either the receipt or the successful transmission of an HID Report. The code below shows an application program working with the sample event handler to track the transmission of a report.
Sample HID Event Handler:
// Application HID Event Handler Code
void APP_USBDeviceHIDEventHandler(USB_DEVICE_HID_INDEX hidInstance,
USB_DEVICE_HID_EVENT event, void * eventData, uintptr_t userData)
{
switch(event)
{
…
case USB_DEVICE_HID_EVENT_REPORT_SENT:
appdata.SendBufferEmpty = TRUE ; // Set a flag for the application program.
break ;
…
}
}
…
// Registering the HID Event Handler
USB_DEVICE_HID_EventHandlerSet(USB_DEVICE_HID_INDEX_0,
APP_USBDeviceHIDEventHandler, (uintptr_t)&appdata) ;
…
An Application Communicating with the Sample HID Event Handler:
void APP_MyCommuncationTask(void)
{
switch(commdata.state)
{
…
case SEND_DATA_TO_HOST:
if (appdata.SendBufferEmpty == TRUE) // Can the data be sent?
{
USB_DEVICE_HID_ReportSend(
USB_DEVICE_HID_INDEX_0,
&hidTransferHandle ,
&appReport[0], sizeof(appReport)); // initiate sending the HID Report.
appdata.SendBufferEmpty = FALSE ; // Clear the flag
commdata.state = WAIT_FOR_HID_REPORT_TO_BE_SENT ;
}
break;
case WAIT_FOR_HID_REPORT_TO_BE_SENT:
if (appdata.SendbufferEmpty == TRUE) // Did EventHandler Set the flag?
commdata.state = DATA_SENT: // If so, the data was sent
break ;
case DATA_SENT:
…
}
}