USB Libraries Help > USB Device Libraries > USB HID Device Library > Using the Library > How the Library Works > Event Handling
MPLAB Harmony USB Stack
Event Handling
Registering a HID Function Driver Event Handler

While creating a USB HID Device-based application, an event handler must be registered with the Device Layer (the Device Layer Event Handler) and every HID Function Driver instance (HID Function Driver Event Handler). The HID Function Driver event handler receives HID events. This event handler should be registered before the USB Device Layer acknowledges the SET CONFIGURATION request from the USB Host. To ensure this, the event handler should be set in the USB_DEVICE_EVENT_CONFIGURED event that is generated by the device_layer. While registering the HID Function Driver event handler, the HID Function Driver allows the application to also pass a data object in the event handler register function. This data object gets associated with the instance of the HID Function Driver and is returned by the driver when a HID Function Driver event occurs. The following code shows an example of how this can be done.

/* This a sample Application Device Layer Event Handler
 * Note how the HID Function Driver event handler APP_USBDeviceHIDEventHandler()
 * is registered in the USB_DEVICE_EVENT_CONFIGURED event. The appData
 * object that is passed in the USB_DEVICE_HID_EventHandlerSet()
 * function will be returned as the userData parameter in the
 * when the APP_USBDeviceHIDEventHandler() function is invoked */

void APP_USBDeviceEventCallBack ( USB_DEVICE_EVENT event,
        void * eventData, uintptr_t context )
{
    uint8_t * configurationValue;
    switch ( event )
    {
        case USB_DEVICE_EVENT_RESET:
        case USB_DEVICE_EVENT_DECONFIGURED:

            // USB device is reset or device is deconfigured.
            // This means that USB device layer is about to deinitialize
            // all function drivers.

            break;

        case USB_DEVICE_EVENT_CONFIGURED:

            /* check the configuration */
            configurationValue = (uint8_t*)eventData;
            if ( *configurationValue == 1)
            {

                /* Register the HID Device application event handler here.
                 * Note how the appData object pointer is passed as the
                 * user data */

                USB_DEVICE_HID_EventHandlerSet(USB_DEVICE_HID_INDEX_0,
                        APP_USBDeviceHIDEventHandler, (uintptr_t)&appData);

                /* mark that set configuration is complete */
                appData.isConfigured = true;

            }
            break;

        case USB_DEVICE_EVENT_SUSPENDED:

            break;

        case USB_DEVICE_EVENT_RESUMED:
        case USB_DEVICE_EVENT_ATTACHED:
        case USB_DEVICE_EVENT_DETACHED:
        case USB_DEVICE_EVENT_ERROR:
        default:
            break;
    }
}

The HID Function Driver event handler executes in an interrupt context when the device stack is configured for Interrupt mode. 

In Polled mode, the event handler is invoked in the context of the SYS_Tasks function. The application should not call computationally intensive functions, blocking functions, functions that are not interrupt safe, or functions that poll on hardware conditions from the event handler. Doing so will affect the ability of the USB device stack to respond to USB events and could potentially make the USB device non-compliant. 

HID Function Driver Events: 

The HID Function Driver generates events to which the application must respond. Some of these events are control requests communicated through control transfers. The application must therefore complete the control transfer. Based on the generated event, the application may be required to:

  • Respond with a USB_DEVICE_ControlSend function, which completes the data stage of a Control Read Transfer
  • Respond with a USB_DEVICE_ControlReceive function, which provisions the data stage of a Control Write Transfer
  • Respond with a USB_DEVICE_ControlStatus function which completes the handshake stage of the Control Transfer. The application can either STALL or Acknowledge the handshake stage via the USB_DEVICE_HID_ControlStatus function.

The following table shows the HID Function Driver control transfer related events and the required application control transfer action.

HID Function Driver Control Transfer Event 
Required Application Action 
USB_DEVICE_HID_EVENT_GET_REPORT 
Call USB_DEVICE_ControlSend function with a buffer containing the requested report. 
USB_DEVICE_HID_EVENT_SET_REPORT 
Call USB_DEVICE_ControlReceive function with a buffer to receive the report. 
USB_DEVICE_HID_EVENT_SET_REPORT 
Call the USB_DEVICE_ControlSend function with the pointer to the current USB_HID_PROTOCOL_CODE type data. 
USB_DEVICE_HID_EVENT_SET_PROTOCOL 
Acknowledge or stall using the USB_DEVICE_ControlStatus function. 
USB_DEVICE_HID_EVENT_SET_IDLE 
Acknowledge or stall using the USB_DEVICE_ControlStatus function. 
USB_DEVICE_HID_EVENT_GET_IDLE 
Call the USB_DEVICE_ControlSend function to send the current idle rate. 
USB_DEVICE_HID_SET_DESCRIPTOR 
Call the USB_DEVICE_ControlReceive function with a buffer to receive the report. 
USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_SENT 
No action required. 
USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_RECEIVED 
Acknowledge or stall using the USB_DEVICE_ControlStatus function. 
USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_ABORTED 
No action required. 

The application can respond to HID Function Driver control transfer-related events in the function driver event handler. In a case where the data required for the response is not immediately available, the application can respond to the control transfer events after returning from the event handler. This defers the response to the control transfer event. However, please note that a USB host will typically wait for control transfer response for a finite time duration before timing out and canceling the transfer and associated transactions. Even when deferring response, the application must respond promptly if such timeouts have to be avoided. 

The application should analyze the pData member of the event handler and check for event specific data. The following table shows the pData parameter data type for each HID function driver event.

Event Type 
pData Parameter Data Type 
USB_DEVICE_HID_EVENT_GET_REPORT 
USB_DEVICE_HID_EVENT_SET_REPORT 
USB_DEVICE_HID_EVENT_GET_IDLE 
uint8_t* 
USB_DEVICE_HID_EVENT_SET_IDLE 
USB_DEVICE_HID_EVENT_SET_PROTOCOL 
USB_HID_PROTOCOL_CODE* 
USB_DEVICE_HID_EVENT_GET_PROTOCOL 
NULL 
USB_DEVICE_HID_EVENT_SET_DESCRIPTOR 
USB_DEVICE_HID_EVENT_DATA_SET_DESCRIPTOR * 
USB_DEVICE_HID_EVENT_REPORT_SENT 
USB_DEVICE_HID_EVENT_REPORT_RECEIVED 
USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_SENT 
NULL 
USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_RECEIVED 
NULL 
USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_ABORTED 
NULL 

The possible HID Function Driver events are described here along with the required application response, event specific data and likely follow up function driver event:

USB_DEVICE_HID_EVENT_GET_REPORT

Application Response: This event is generated when the USB HID Host is requesting a report over the control interface. The application must provide the report by calling the USB_DEVICE_HID_ControlSend function, either in the event handler, or in the application (after event handler function has exited). The application can use the USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_SENT event to track completion of the command. 

Event Specific Data (eventData): The application must interpret the pData parameter as a pointer to a 

USB_DEVICE_HID_EVENT_DATA_GET_REPORT data type, which contains details about the requested report. 

Likely Follow-up event: This event will likely be followed by the USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_SENT event. This indicates that the data was sent to the Host successfully. The application must acknowledge the handshake stage of the control transfer by calling the USB_DEVICE_HID_ControlStatus function with the USB_DEVICE_HID_CONTROL_STATUS_OK flag. 

USB_DEVICE_HID_EVENT_SET_REPORT

Application Response: This event is generated when the USB HID Host wants to send a report over the control interface. The application must provide a buffer to receive the report by calling the USB_DEVICE_HID_ControlReceive function either in the event handler or in the application (after the event handler function has exited). The application can use the USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_RECEIVED event to track completion of the command. 

Event Specific Data (eventData): The application must interpret the pData parameter as a pointer to a 

USB_DEVICE_HID_EVENT_DATA_SET_REPORT data type, which contains details about the report that the Host intends to send. 

Likely Follow-up event: This event will likely be followed by the 

USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_RECEIVED event. This indicates that the data was received successfully. The application must either acknowledge or stall the handshake stage of the control transfer by calling the USB_DEVICE_HID_ControlStatus function with the USB_DEVICE_HID_CONTROL_STATUS_OK or 

USB_DEVICE_HID_CONTROL_STATUS_ERROR flag, respectively.

USB_DEVICE_HID_EVENT_GET_IDLE

Application Response: This event is generated when the USB HID Host wants to read the current idle rate for the specified report. The application must provide the idle rate through the USB_DEVICE_HID_ControlSend function, either in the event handler, or in the application (after the event handler function has exited). The application must use the controlTransferHandle parameter provided in the event while calling the USB_DEVICE_HID_ControlSend function. The application can use the USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_SENT event to track completion of the command. 

Event Specific Data (eventData): The application must interpret the pData parameter as a pointer to a uint8_t data type, which contains a report ID of the report for which the idle rate is requested. 

Likely Follow-up event: This event will likely be followed by the 

USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_SENT event. This indicates that the data was sent to the Host successfully. The application must acknowledge the handshake stage of the control transfer by calling the USB_DEVICE_HID_ControlStatus function with the USB_DEVICE_HID_CONTROL_STATUS_OK flag.

USB_DEVICE_HID_EVENT_SET_IDLE

Application Response: This event is generated when the USB HID Host sends a Set Idle request to the device. The application must inspect the eventData and determine if the idle rate is to be supported. The application must either acknowledge (if the idle rate is supported) or stall the handshake stage of the control transfer (if the idle rate is not supported) by calling the USB_DEVICE_HID_ControlStatus function with the USB_DEVICE_HID_CONTROL_STATUS_OK or USB_DEVICE_HID_CONTROL_STATUS_ERROR flag, respectively. 

Event Specific Data (eventData): The application must interpret the pData parameter as a pointer to a USB_DEVICE_HID_EVENT_DATA_SET_IDLE data type that contains details about the report ID and the idle duration. 

Likely Follow-up event: None. 

USB_DEVICE_HID_EVENT_SET_PROTOCOL

Application Response: This event is generated when the USB HID Host sends a Set Protocol request to the device . The application must inspect the eventData and determine if the protocol is to be supported. The application must either acknowledge (if the protocol is supported) or stall the handshake stage of the control transfer (if the protocol is not supported) by calling USB_DEVICE_HID_ControlStatus function with SB_DEVICE_HID_CONTROL_STATUS_OK or USB_DEVICE_HID_CONTROL_STATUS_ERROR flag, respectively. 

Event Specific Data (eventData): The application must interpret the pData parameter as a pointer to a USB_HID_PROTOCOL_CODE data type that contains details about the protocol to be set. 

Likely Follow-up event: None. 

USB_DEVICE_HID_EVENT_GET_PROTOCOL

Application Response: This event is generated when the USB HID Host issues a Get Protocol Request. The application must provide the current protocol through the USB_DEVICE_HID_ControlSend function either in the event handler or in the application (after the event handler has exited). The application can use the USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_SENT event to track completion of the command. 

Event Specific Data (eventData): None. 

Likely Follow-up event: This event will likely be followed by the USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_SENT event. This indicates that the data was sent to the host successfully. The application must acknowledge the handshake stage of the control transfer by calling the USB_DEVICE_HID_ControlStatus function with the USB_DEVICE_HID_CONTROL_STATUS_OK flag. 

USB_DEVICE_HID_EVENT_SET_DESCRIPTOR

Application Response: This event is generated when the HID Host issues a Set Descriptor request. The application must provide a buffer to receive the descriptor through the USB_DEVICE_HID_ControlReceive function, either in the event handler, or in the application (after the event handler has exited). The application can use the USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_RECEIVED event to track completion of the command. 

Event Specific Data: None 

Likely Follow-up event: This event will likely be followed by the USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_RECEIVED event. This indicates that the data was received successfully. The application must either acknowledge or stall the handshake stage of the control transfer by calling USB_DEVICE_HID_ControlStatus function with USB_DEVICE_HID_CONTROL_STATUS_OK or the USB_DEVICE_HID_CONTROL_STATUS_ERROR flag, respectively. 

USB_DEVICE_HID_EVENT_REPORT_SENT

Application Response: This event occurs when a report send operation scheduled by calling the USB_DEVICE_HID_ReportSend function has completed. This event does not require the application to respond with any function calls. 

Event Specific Data (pData): The application must interpret the pData parameter as a pointer to a USB_DEVICE_HID_EVENT_DATA_REPORT_SENT data type that contains details about the report that was sent. 

Likely Follow-up event: None. 

USB_DEVICE_HID_EVENT_REPORT_RECEIVED

Application Response: This event occurs when a report receive operation scheduled by calling the USB_DEVICE_HID_ReportReceive function has completed. This event does not require the application to respond with any function calls. 

Event Specific Data (pData): The application must interpret the pData parameter as a pointer to a USB_DEVICE_HID_EVENT_DATA_REPORT_RECEIVED data type that contains details about the report that was received. 

Likely Follow-up event: None 

USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_SENT

Application Response: This event occurs when the data stage of a control read transfer has completed in response to the USB_DEVICE_HID_ControlSend function. The application must acknowledge the handshake stage of the control transfer by calling the USB_DEVICE_HID_ControlStatus function with the USB_DEVICE_HID_CONTROL_STATUS_OK flag. 

Event Specific Data (pData): None. 

Likely Follow-up event: None. 

USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_RECEIVED

Application Response: This event occurs when the data stage of a control write transfer has completed in response to the USB_DEVICE_HID_ControlReceive function. The application must either acknowledge or stall the handshake stage of the control transfer by calling USB_DEVICE_HID_ControlStatus function with the USB_DEVICE_HID_CONTROL_STATUS_OK or USB_DEVICE_HID_CONTROL_STATUS_ERROR flag, respectively. 

Event Specific Data (pData): None 

Likely Follow-up event: None. 

USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_ABORTED

Application Response: This event occurs when the a control transfer request is aborted by the Host. The application can use this event to update its HID class-specific control transfer state machine. 

Event Specific Data (pData): None 

Likely Follow-up event: None. The following code shows an example HID Function Driver event handling scheme. 

The following code shows an example HID Function Driver event handling scheme.

USB_DEVICE_HID_EVENT_RESPONSE USB_AppHIDEventHandler
(
    USB_DEVICE_HID_INDEX instanceIndex,
    USB_DEVICE_HID_EVENT event,
    void * pData,
    uintptr_t userData
)
{
    uint8_t currentIdleRate;

    switch(event)
    {
        case USB_DEVICE_HID_EVENT_GET_REPORT:
            // In this case, pData should be interpreted as a
            // USB_DEVICE_HID_EVENT_DATA_GET_REPORT pointer. The application
            // must send the requested report by using the
            // USB_DEVICE_ControlSend() function.
            // Example:
            // getReportEventData = (USB_DEVICE_HID_EVENT_DATA_GET_REPORT *)pData;
            // USB_DEVICE_ControlSend(usbDeviceHandle, someHIDReport, getReportEventData->reportLength);

            break;

         case USB_DEVICE_HID_EVENT_SET_REPORT:

            // In this case, pData should be interpreted as a
            // USB_DEVICE_HID_EVENT_DATA_SET_REPORT type pointer. The
            // application can analyze the request and then obtain the
            // report by using the USB_DEVICE_ControlReceive() function.
            // Example:
            // setReportEventData = (USB_DEVICE_HID_EVENT_DATA_SET_REPORT *)pData;
            // USB_DEVICE_ControlReceive(usbDeviceHandle, someHIDReport, setReportEventData->reportLength);

            break;

         case USB_DEVICE_HID_EVENT_GET_PROTOCOL:

            // In this case, pData will be NULL. The application
            // must send the current protocol to the host by using
            // the USB_DEVICE_ControlSend() function.
            // Example:
            // USB_DEVICE_ControlSend(usbDeviceHandle, &currentProtocol, sizeof(USB_HID_PROTOCOL_CODE));

            break;

         case USB_DEVICE_HID_EVENT_SET_PROTOCOL:

            // In this case, pData should be interpreted as a
            // USB_HID_PROTOCOL_CODE type pointer. The application can
            // analyze the data and decide to stall or accept the setting.
            // This shows an example of accepting the protocol setting.
            // Example:
            // *currentProtocol = *(USB_HID_PROTOCOL_CODE *)pData;
            // USB_DEVICE_ControlStatus(usbDeviceHandle, USB_DEVICE_CONTROL_STATUS_OK);

            break;

         case USB_DEVICE_HID_EVENT_GET_IDLE:

             // In this case, pData will be a uint8_t pointer type to the
             // report ID for which the idle rate is being requested. The
             // application must send the current idle rate to the host by
             // using the USB_DEVICE_ControlSend() function.
             USB_DEVICE_ControlSend(usbDeviceHandle, &currentIdleRate, 1);

            break;

         case USB_DEVICE_HID_EVENT_SET_IDLE:

            // In this case, pData should be interpreted as a
            // USB_DEVICE_HID_EVENT_DATA_SET_IDLE type pointer. The
            // application can analyze the data and decide to stall
            // or accept the setting. This shows an example of accepting
            // the protocol setting.
            currentIdleRate = ((USB_DEVICE_HID_EVENT_DATA_SET_IDLE*)pData)->duration;
            USB_DEVICE_ControlStatus(usbDeviceHandle, USB_DEVICE_CONTROL_STATUS_OK);


            break;

         case USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_RECEIVED:

            // In this case, control transfer data was received. The
            // application can inspect that data and then stall the
            // handshake stage of the control transfer or accept it
            // Example:
            // USB_DEVICE_ControlStatus(usbDeviceHandle, USB_DEVICE_CONTROL_STATUS_OK);

            break;

         case USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_DATA_SENT:

            // This means that control transfer data was sent. The
            // application would typically acknowledge the handshake
            // stage of the control transfer.

            break;

         case USB_DEVICE_HID_EVENT_CONTROL_TRANSFER_ABORTED:

             // This means that control transfer data was sent. The
             // application would typically acknowledge the handshake
             // stage of the control transfer.

            break;

         case USB_DEVICE_HID_EVENT_REPORT_RECEIVED:

            // This means a HID report receive request has completed.
            // The pData member should be interpreted as a
            // USB_DEVICE_HID_EVENT_DATA_REPORT_RECEIVED pointer type.

            break;

         case USB_DEVICE_HID_EVENT_REPORT_SENT:

            // This means a HID report send request has completed.
            // The pData member should be interpreted as a
            // USB_DEVICE_HID_EVENT_DATA_REPORT_SENT pointer type.

            break;
    }
    return USB_DEVICE_HID_EVENT_RESPONSE_NONE;
}