USB Libraries Help > USB Host Libraries > USB Host Layer Library > Using the Library > How the Library Works > Host Layer - Application Interaction
MPLAB Harmony USB Stack
Host Layer - Application Interaction

The Host Layer in the MPLAB Harmony USB Host stack provides the user application with API methods to operate the USB Host. The following sections discuss these API methods.

Registering the Event Handler

The application must register an event handler to receive device related USB Host events. The application sets the events handler by using the USB_HOST_EventHandlerSet function. An application defined context can also be provided. This context is returned along with the event handler and helps the application to identify the context in case of a dynamic application use cases. The host layer provides events when a connected device requires more current than can be provided or when a unsupported device was attached. The following code shows an example of registering the event handler.

/* This code shows an example of registering an event handler with the
 * Host Layer */

USB_HOST_EVENT_RESPONSE APP_USBHostEventHandler
(
    USB_HOST_EVENT event,
    void * eventData,
    uintptr_t context
)
{
    /* This is the event handler implementation */
    switch (event)
    {
        case USB_HOST_EVENT_DEVICE_UNSUPPORTED:
            break;
        case USB_HOST_EVENT_DEVICE_REJECTED_INSUFFICIENT_POWER:
            break;
        case USB_HOST_EVENT_HUB_TIER_LEVEL_EXCEEDED:
            break;
        case USB_HOST_EVENT_PORT_OVERCURRENT_DETECTED:
            break;
        default:
            break;
    }

    return(USB_HOST_EVENT_RESPONSE_NONE);
}

void APP_Tasks(void)
{
    /* This shows an example app state machine implementation in which the event
     * handler is set and the bus is then enabled. */

    switch(appData.state)
    {
        case APP_STATE_BUS_ENABLE:

            /* Set the event handler and enable the bus */
            USB_HOST_EventHandlerSet(APP_USBHostEventHandler, 0);
            USB_HOST_BusEnable(0);
            appData.state = APP_STATE_WAIT_FOR_BUS_ENABLE_COMPLETE;
            break;

        default:
            break;
    }
}
Enabling the Bus

The user application must call the USB_HOST_BusEnable function to enable the bus. This function enables the 5V VBUS supply to root hub port thus powering up the bus powered device that are attached to the bus. The attached devices will then indicate attach. The root hub will provide these attach events to the Host layer which in turn starts the enumeration process. The application can call other Host Layer functions only after the bus has been enabled. The USB_HOST_BusIsEnabled function must be called to check if the enable process has completed. The following code shows an example application state machine that enables the bus.

void APP_Tasks ( void )
{
   /* The application shows an example of how the USB bus is enabled and how the
    * application must wait for the bus to enabled */

    switch(appData.state)
    {
        case APP_STATE_BUS_ENABLE:

           /* Set the event handler and enable the bus */
            USB_HOST_EventHandlerSet(APP_USBHostEventHandler, 0);
            USB_HOST_BusEnable(0);
            appData.state = APP_STATE_WAIT_FOR_BUS_ENABLE_COMPLETE;
            break;

        case APP_STATE_WAIT_FOR_BUS_ENABLE_COMPLETE:
            /* Check if the bus is enabled */
            if(USB_HOST_BusIsEnabled(0))
            {
                appData.state = APP_STATE_WAIT_FOR_DEVICE_ATTACH;
            }
            break;

        default:
            break;
    }
}
Attached Device Information

The application can use the USB_HOST_DeviceFirstGet and the USB_HOST_DeviceNextGet function to query for attached devices. The USB_HOST_DeviceFirstGet function will provide information on the first device that was attached to the bus. Information is returned in application specified USB_HOST_DEVICE_INFO object. The USB_HOST_DeviceFirstGet function will return the following information in the USB_HOST_DEVICE_INFO object:

  • A Device Object Handle of the type USB_HOST_DEVICE_OBJ_HANDLE. The application can use this device object handle to perform operations on the device.
  • The address of the device on the USB
  • The bus to which this device belongs

The application can access the contents of the USB_HOST_DEVICE_INFO object but should not alter it contents. The same object is passed to the USB_HOST_DeviceNextGet function to get the information about the next device attached on the bus. Each call to this function defines the point at which the USB_HOST_DeviceNextGet function will start searching. If the device that is represented by the USB_HOST_DEVICE_INFO object has been disconnected, calling the USB_HOST_DeviceNextGet function will return an error. The search must be reset by calling the USB_HOST_DeviceFirstGet function. The application can define multiple USB_HOST_DEVICE_INFO objects to search on different busses or maintain different search points.

void APP_Tasks(void)
{
    USB_HOST_DEVICE_INFO deviceInfo;
    USB_HOST_RESULT result;

    /* Get information about the first device on Bus 0 */
    result = USB_HOST_DeviceGetFirst(0, &deviceInfo);

    while(result != USB_HOST_RESULT_END_OF_DEVICE_LIST)
    {
        /* deviceInfo.address has the address of the bus */
        /* deviceInfo.deviceObjHandle will have the device object handle */

        /* Now we can get the information about the next device on the bus. */
        result = USB_HOST_DeviceGetNext(&deviceInfo);
    }
}
Suspend and Resume

The USB Host Layer allows the application to suspend and resume a device. The USB_HOST_DeviceSuspend and the USB_HOST_DeviceResume function are provided for this purpose. The application must use the device object handles, obtained from the USB_HOST_DeviceFirstGet or USB_HOST_DeviceNextGet function, to specify the device to suspend or resume when calling USB_HOST_DeviceSuspend and the USB_HOST_DeviceResume() function. The USB_HOST_DeviceIsSuspended function can be called to check the suspend status of the device. 

In a case where the entire bus (and hence all device connected on the bus) need to be suspended or resumed, the application must call USB_HOST_BusSuspend and USB_HOST_BusResume functions to suspend or resume the entire bus. The USB_HOST_BusIsSuspended function can be called to check the suspend status of the bus.

Device String Descriptors

The application may want to obtain the string descriptors of a device. Sting descriptors are optionally provided by the USB device manufacturer and provide device information. The USB_HOST_DeviceStringDescriptorGet function is available to read the string descriptors. Calling this function will cause the Host Layer to invoke a control transfer request to read the string descriptor. The string descriptor will be available when the control transfer completes. The host layer calls the USB_HOST_STRING_REQUEST_COMPLETE_CALLBACK type callback function, that is provided in the USB_HOST_DeviceStringDescriptorGet function, when the control transfer has completed. The completion status of the request and the size of the string descriptor are available in the callback. 

The function allows the application to obtain the supported string language IDs. The language ID of the string can be specified or a default can be used.

typedef struct
{
    /* This is an application specific data structure */
    char string[APP_STRING_SIZE];
    USB_HOST_REQUEST_HANDLE requestHandle;
    uintptr_t context;

} APP_DATA;

APP_DATA appData;

void APP_USBHostSringDescriptorGetCallBack
(
    USB_HOST_REQUEST_HANDLE requestHandle,
    size_t size,
    uintptr_t context
)
{
    /* This function is called when the string descriptor get function has
     * completed. */

    if(size != 0)
    {
        /* This means the function executed successfully and we have a string.
         * An application function prints the string to the console. */
        APP_PrintStringToConsole(appData.string, size);
    }
}

void APP_Tasks(void)
{
    USB_HOST_DEVICE_INFO deviceInfo;
    USB_HOST_RESULT result;

    /* Get information about the first device on Bus 0 */
    result = USB_HOST_DeviceGetFirst(0, &deviceInfo);

    if(result != USB_HOST_RESULT_END_OF_DEVICE_LIST)
    {
        /* deviceInfo.deviceObjHandle will have the device object handle. Use
         * this device object handle along with the
         * USB_HOST_DeviceStringDescriptorGet() function to read the product
         * string ID using the default Language ID. */

        USB_HOST_DeviceStringDescriptorGet(deviceInfo.deviceObjHandle, USB_HOST_DEVICE_STRING_PRODUCT,
                USB_HOST_DEVICE_STRING_LANG_ID_DEFAULT, appData.string, APP_STRING_SIZE,
                &appData.requestHandle, APP_USBHostSringDescriptorGetCallBack, appData.context );
    }
}