2.9.2.3.2 Event Handling

Registering a Printer Function Driver Event Handler

While creating an USB Printer Device-based application, an event handler must be registered with the Device Layer (the Device Layer Event Handler) and every Printer Function Driver instance (Printer Function Driver Event Handler). The Printer Function Driver event handler receives Printer 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 Printer Function Driver event handler, the Printer 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 Printer Function Driver and is returned by the Printer Function Driver when a Printer Function Driver event occurs. The following code shows an example of how this can be done.

This below code is a sample of Application Device Layer Event Handler.

Note how the Printer Function Driver event handler APP_USBDevicePrinterEventHandler is registered in the USB_DEVICE_EVENT_CONFIGURED event.

The appData object that is passed in the USB_DEVICE_PRINTER_EventHandlerSet function will be returned as the userData parameter in the when the APP_USBDevicePrinterEventHandler function is invoked.

/***********************************************
 * Application USB Device Layer Event Handler.
 ***********************************************/
void APP_USBDeviceEventHandler
(
    USB_DEVICE_EVENT event,
    void * eventData,
    uintptr_t context
)
{
    USB_DEVICE_EVENT_DATA_CONFIGURED *configuredEventData;

    switch(event)
    {
        case USB_DEVICE_EVENT_CONFIGURED:

            /* Check the configuration. We only support configuration 1 */
            configuredEventData = (USB_DEVICE_EVENT_DATA_CONFIGURED*)eventData;

            if ( configuredEventData->configurationValue == 1)
            {
                /* Update LED to show configured state */
                LED_On();

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

USB_DEVICE_PRINTER_EventHandlerSet(USB_DEVICE_PRINTER_INDEX_0,
          APP_USBDevicePrinterEventHandler, (uintptr_t)&appData);

                /* Mark that the device is now configured */
                appData.isConfigured = true;
            }
        break;
    }
}

The Printer 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.

Printer Function Driver Events

The Printer Function Driver generates events to which the application must respond. Some of these events are management requests communicated through control transfers. Therefore, the application must use the Device Layer Control Transfer routines to complete the control transfer. Based on the generated event, the application may be required to:

  • Respond with a USB_DEVICE_ControlSend function, which is 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_ControlStatus function. The following table shows the Printer Function Driver Control Transfer related events and the required application control transfer actions.

Printer Function Driver Control Transfer Event Required Application Action
USB_DEVICE_PRINTER_GET_PORT_STATUS Call USB_DEVICE_ControlSend() function to send the response data for GET_PORT_STATUS request.

Based on the type of event, the application should analyze the pData member of the event handler. This data member should be type cast to an event specific data type. The following table shows the event and the data type to use while type casting.

Note that the pData member is not required for all events.

Printer Function Driver Event Related pData type
USB_DEVICE_PRINTER_EVENT_WRITE_COMPLETE USB_DEVICE_PRINTER_EVENT_DATA_WRITE_COMPLETE
USB_DEVICE_PRINTER_EVENT_READ_COMPLETE USB_DEVICE_PRINTER_EVENT_DATA_READ_COMPLETE

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

USB_DEVICE_PRINTER_EVENT_WRITE_COMPLETE

Application Response: This event occurs when a write operation scheduled by calling the USB_DEVICE_PRINTER_Write() function has completed. This event does not require the application to respond with any function calls.

Event Specific Data (pData): The pData member in the event handler will point to the USB_DEVICE_PRINTER_EVENT_DATA_WRITE_COMPLETE data type.

Likely Follow-up event: None.

USB_DEVICE_PRINTER_EVENT_READ_COMPLETE

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

Event Specific Data (pData): The pData member in the event handler will point to the USB_DEVICE_PRINTER_EVENT_DATA_READ_COMPLETE type.

Likely Follow-up event: None.

Printer Function Driver Event Handling

The following code shows an event handling scheme example. The application always returns from the event handler with a USB_DEVICE_PRINTER_EVENT_RESPONSE_NONE value.

The below code example shows all Printer Function Driver possible events and a possible scheme for handling these events. In this case event responses are not deferred.

/*******************************************************
 * USB PRINTER Device Events - Application Event Handler
 *******************************************************/

USB_DEVICE_PRINTER_EVENT_RESPONSE APP_USBDevicePrinterEventHandler
(
    USB_DEVICE_PRINTER_INDEX index,
    USB_DEVICE_PRINTER_EVENT event,
    void * pData,
    uintptr_t userData
)
{
  APP_DATA * appDataObject;
  USB_DEVICE_PRINTER_EVENT_DATA_READ_COMPLETE * eventDataRead;
  uint8_t prntrStatus;
  appDataObject = (APP_DATA *)userData;
  switch(event)
  {
    case USB_DEVICE_PRINTER_GET_PORT_STATUS:
       /* This means the host wants to know the printer's current status,
        * in a format which is compatible with the status register of a
        * standard PC parallel port. This is a control transfer request.
        * Use the USB_DEVICE_ControlSend() function to send the data to
        * host. */
       prntrStatus = (uint8_t)(((appDataObject->portStatus.errorStatus << 3) & 0x08) |
                ((appDataObject->portStatus.selectStatus << 4) & 0x10) |
                ((appDataObject->portStatus.paperEmptyStatus << 5) & 0x20));

       USB_DEVICE_ControlSend( appDataObject->deviceHandle, &prntrStatus, 1 );
       break;

    case USB_DEVICE_PRINTER_EVENT_READ_COMPLETE:
       /* This means that the host has sent some data*/
       eventDataRead = (USB_DEVICE_PRINTER_EVENT_DATA_READ_COMPLETE *)pData;
       appDataObject->isReadComplete = true;
       appDataObject->numBytesRead = eventDataRead->length;
       break;

    case USB_DEVICE_PRINTER_EVENT_WRITE_COMPLETE:
       /* This means that the data write got completed */
       appDataObject->isWriteComplete = true;
       break;
    default:
       break;
    }
    return USB_DEVICE_PRINTER_EVENT_RESPONSE_NONE;
}

Refer to the USB_DEVICE_PRINTER_EVENT enumeration for more details on each event.