USB Libraries Help > USB Device Libraries > Generic USB Device Library > Using the Library > How the Library Works > Event Handling > Control Transfer Events
MPLAB Harmony USB Stack
Control Transfer Events

These events occur when the Device Layer has received a control transfer that is targeted to an interface or an endpoint which is managed by the Generic USB Device Application. The USB_DEVICE_EVENT_CONTROL_TRANSFER_SETUP_REQUEST event is generated when the Setup stage of the control transfer has been received. The application must investigate the 8-byte setup command that accompanies this event. The following flowchart explains the interaction. 

 

The application can then either choose to continue the control transfer or stall it. The control transfer is stalled by calling the USB_DEVICE_ControlStatus function with the USB_DEVICE_CONTROL_STATUS_ERROR flag. In case of zero data stage control transfers, the application can complete the control transfer by calling the USB_DEVICE_ControlStatus function with the USB_DEVICE_CONTROL_STATUS_OK flag. In case of control transfers that contain a data stage, the application must use the USB_DEVICE_ControlSend or the USB_DEVICE_ControlReceive function to send and receive data from the Host, respectively. 

In a case where data is to be received from the host, the device layer generates USB_DEVICE_EVENT_CONTROL_TRANSFER_DATA_RECEIVED event when the data stage has completed. The application can analyze the received data and can then either choose to acknowledge or stall the control transfer by the calling the USB_DEVICE_ControlStatus function with the USB_DEVICE_CONTROL_STATUS_ERROR flag. This is shown in the following flow chart. 

 

The following code shows an example of handling control transfer in a Generic USB Device. Note that the control transfer events are generated by the Device Layer.

/* This code shows an example of how the control transfer events
 * can be handled in a Generic USB Device. The example device will accepts the
 * Set Interface Control Request and replies to the Get Interface Control Request
 * with the current alternate setting. */
case USB_DEVICE_EVENT_CONTROL_TRANSFER_SETUP_REQUEST:
    /* This means we have received a setup packet */
       setupPacket = (USB_SETUP_PACKET *)eventData;
    if(setupPacket->bRequest == USB_REQUEST_SET_INTERFACE)
    {
        /* If we have got the SET_INTERFACE request, we just acknowledge
         * for now. In this example, there is one alternate setting which
         * is already active. */
        USB_DEVICE_ControlStatus(appData.usbDevHandle,USB_DEVICE_CONTROL_STATUS_OK);
    }
    else if(setupPacket->bRequest == USB_REQUEST_GET_INTERFACE)
    {
        /* We have only one alternate setting and this setting 0. So
        * we send this information to the host. */
        USB_DEVICE_ControlSend(appData.usbDevHandle, &appData.altSetting, 1);
    }
    else
    {
        /* We have received a request that we cannot handle. Stall it*/
        USB_DEVICE_ControlStatus(appData.usbDevHandle, USB_DEVICE_CONTROL_STATUS_ERROR);
    }
    break;
case USB_DEVICE_EVENT_CONTROL_TRANSFER_DATA_SENT:
    /* This is a notification event which the application can use to free
     * buffer that was used in a USB_DEVICE_ControlSend() function. */
    break;
case USB_DEVICE_EVENT_CONTROL_TRANSFER_DATA_RECEIVED:
    /* This event means that data has been received in the control transfer
     * and the application must either stall or acknowledge the data stage
     * by calling the USB_DEVICE_ControlStatus() function. Here we simply
     * acknowledge the received data. This is an example only. */
    USB_DEVICE_ControlStatus(appData.usbDevHandle, USB_DEVICE_CONTROL_STATUS_OK);
    break;