MPLAB Harmony USB Stack
|
While creating a USB Audio 2.0 Device application, an event handler must be registered with the Device Layer (the Device Layer Event Handler) and every Audio 2.0 Function Driver instance (Audio 2.0 Function Driver Event Handler). The application needs to register the event handler with the Audio 2.0 Function Driver:
The event handler should be registered before the USB device layer_acknowledges the SET CONFIGURATION request from the USB Host. To ensure this, the callback function should be set in the USB_DEVICE_EVENT_CONFIGURED event that is generated by the device_layer. The following code example shows how this can be done.
/* This a sample Application Device Layer Event Handler * Note how the USB Audio 2.0 Device Driver callback function * USB_DEVICE_AUDIO_2_0_EventHandlerSet() * is registered in the USB_DEVICE_EVENT_CONFIGURED event. */ void APP_UsbDeviceEventCallBack( USB_DEVICE_EVENT event, void * pEventData, uintptr_t context ) { uint8_t * configuredEventData; switch( event ) { case USB_DEVICE_EVENT_RESET: break; case USB_DEVICE_EVENT_DECONFIGURED: // USB device is reset or device is de-configured. // This means that USB device layer is about to de-initialize // all function drivers. So close handles to previously opened // function drivers. break; case USB_DEVICE_EVENT_CONFIGURED: /* check the configuration */ /* Initialize the Application */ configuredEventData = pEventData; if(*configuredEventData == 1) { USB_DEVICE_AUDIO_V2_EventHandlerSet ( 0, APP_USBDeviceAudioEventHandler , (uintptr_t)NULL ); /* mark that set configuration is complete */ appData.isConfigured = true; } break; case USB_DEVICE_EVENT_SUSPENDED: break; case USB_DEVICE_EVENT_POWER_DETECTED: /* Attach the device */ USB_DEVICE_Attach (appData.usbDevHandle); break; case USB_DEVICE_EVENT_POWER_REMOVED: /* VBUS is not available. We can detach the device */ USB_DEVICE_Detach(appData.usbDevHandle); break; case USB_DEVICE_EVENT_RESUMED: case USB_DEVICE_EVENT_ERROR: default: break; } }
The Audio 2.0 Function Driver provides events to the application through the event handler function registered by the application. These events indicate:
The Audio 2.0 Control Interface Request events and the related control transfer events typically require the application to respond with the Device Layer Control Transfer routines to complete the control transfer. Based on the generated event, the application may be required to:
The following table shows the Audio 2.0 Function Driver Control Transfer related events and the required application control transfer actions.
Audio 2.0 Function Driver Control Transfer Event |
Required Application Action |
USB_DEVICE_AUDIO_V2_CUR_ENTITY_SETTINGS_RECEIVED |
Identify the control type using the associated event data. If a data stage is expected, use the USB_DEVICE_ControlReceive function to receive expected data. If a data stage is not required or if the request is not supported, use the USB_DEVICE_ControlStatus function to Acknowledge or Stall the request. |
USB_DEVICE_AUDIO_V2_RANGE_ENTITY_SETTINGS _RECEIVED |
Identify the control type using the associated event data. If a data stage is expected, use the USB_DEVICE_ControlReceive function to receive expected data. If a data stage is not required or if the request is not supported, use the USB_DEVICE_ControlStatus function to Acknowledge or Stall the request. |
USB_DEVICE_AUDIO_V2_EVENT_CONTROL_TRANSFER _DATA_RECEIVED |
Acknowledge or stall using the USB_DEVICE_ControlStatus function. |
USB_DEVICE_AUDIO_V2_EVENT_CONTROL_TRANSFER _DATA_SENT |
Action not required. |
The application must analyze the wIndex field of the event data (received with the control transfer event) to identify the entity that is being addressed. The application must be aware of all entities included in the application and their IDs. Once identified, the application can then type cast the event data to entity type the specific control request type. For example, if the Host sends a control request to set the clock source for the Audio 2.0 device, the following occurs in this order:
Based on the type of event, the application should analyze the event data parameter 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 event data member is not required for all events.
Audio 2.0 Function Driver Event |
Related Event Data Type |
USB_DEVICE_AUDIO_V2_CUR_ENTITY_SETTINGS_RECEIVED |
USB_AUDIO_V2_CONTROL_INTERFACE_REQUEST* |
USB_DEVICE_AUDIO_V2_RANGE_ENTITY_SETTINGS _RECEIVED |
USB_AUDIO_V2_CONTROL_INTERFACE_REQUEST* |
USB_DEVICE_AUDIO_V2_EVENT_CONTROL_TRANSFER _DATA_RECEIVED |
NULL |
USB_DEVICE_AUDIO_V2_EVENT_CONTROL_TRANSFER _DATA_SENT |
NULL |
USB_DEVICE_AUDIO_V2_EVENT_INTERFACE_SETTING_CHANGED | |
USB_DEVICE_AUDIO_V2_EVENT_READ_COMPLETE | |
USB_DEVICE_AUDIO_V2_EVENT_WRITE_COMPLETE |
When the Audio 2.0 Function Driver receives an Audio 2.0 Class Specific Control Transfer Request, it passes this control transfer to the application as a Audio 2.0 Function Driverevent. The following code example shows how to handle an Audio 2.0 Control request.
void APP_USBDeviceAudioEventHandler ( USB_DEVICE_AUDIO_V2_INDEX iAudio , USB_DEVICE_AUDIO_V2_EVENT event , void * pData, uintptr_t context ) { USB_DEVICE_AUDIO_V2_EVENT_DATA_SET_ALTERNATE_INTERFACE * interfaceInfo; USB_DEVICE_AUDIO_V2_EVENT_DATA_READ_COMPLETE * readEventData; USB_DEVICE_AUDIO_V2_EVENT_DATA_WRITE_COMPLETE * writeEventData; USB_AUDIO_V2_CONTROL_INTERFACE_REQUEST* controlRequest; if ( iAudio == 0 ) { switch (event) { case USB_DEVICE_AUDIO_V2_EVENT_READ_COMPLETE: readEventData = (USB_DEVICE_AUDIO_V2_EVENT_DATA_READ_COMPLETE *)pData; //We have received an audio frame from the Host. //Now send this audio frame to Audio Codec for Playback. break; case USB_DEVICE_AUDIO_V2_EVENT_WRITE_COMPLETE: break; case USB_DEVICE_AUDIO_V2_EVENT_INTERFACE_SETTING_CHANGED: //We have received a request from USB host to change the Interface- //Alternate setting. interfaceInfo = (USB_DEVICE_AUDIO_V2_EVENT_DATA_SET_ALTERNATE_INTERFACE *)pData; appData.activeInterfaceAlternateSetting = interfaceInfo->interfaceAlternateSetting; appData.state = APP_USB_INTERFACE_ALTERNATE_SETTING_RCVD; break; case USB_DEVICE_AUDIO_V2_CUR_ENTITY_SETTINGS_RECEIVED: controlRequest = (USB_AUDIO_V2_CONTROL_INTERFACE_REQUEST*) setupPkt; USB_AUDIO_V2_CLOCKSOURCE_CONTROL_REQUEST* clockSourceRequest; switch(controlRequest->entityID) { case APP_ID_CLOCK_SOURCE: clockSourceRequest = (USB_AUDIO_V2_CLOCKSOURCE_CONTROL_REQUEST*) controlRequest; switch(clockSourceRequest->controlSelector) { case AUDIO_V2_CS_SAM_FREQ_CONTROL: { if ((controlRequest->bmRequestType & 0x80) == 0) { //A control write transfer received from Host. Now receive data from Host. USB_DEVICE_ControlReceive(appData.usbDevHandle, (void *) &(appData.clockSource), 4 ); appData.currentAudioControl = APP_USB_AUDIO_CLOCKSOURCE_CONTROL; } else { /*Handle Get request*/ USB_DEVICE_ControlSend(appData.usbDevHandle, (void *)&(appData.clockSource), 4 ); appData.currentAudioControl = APP_USB_CONTROL_NONE; } } } break; case USB_DEVICE_AUDIO_V2_RANGE_ENTITY_SETTINGS_RECEIVED: break; case USB_DEVICE_AUDIO_V2_EVENT_CONTROL_TRANSFER_DATA_RECEIVED: USB_DEVICE_ControlStatus(appData.usbDevHandle, USB_DEVICE_CONTROL_STATUS_OK ); switch (appData.currentAudioControl) { case APP_USB_AUDIO_MUTE_CONTROL: { appData.state = APP_MUTE_AUDIO_PLAYBACK; appData.currentAudioControl = APP_USB_CONTROL_NONE; } break; case APP_USB_AUDIO_CLOCKSOURCE_CONTROL: { // Handle Clock Source Control here. appData.state = APP_CLOCKSOURCE_SET; appData.currentAudioControl = APP_USB_CONTROL_NONE; } break; case APP_USB_AUDIO_CLOCKSELECT_CONTROL: { // Handle Clock Source Control here. appData.currentAudioControl = APP_USB_CONTROL_NONE; } break; } break; case USB_DEVICE_AUDIO_V2_EVENT_CONTROL_TRANSFER_DATA_SENT: break; default: SYS_ASSERT ( false , "Invalid callback" ); break; } //end of switch ( callback ) }//end of if if ( iAudio == 0 ) }//end of function APP_AudioEventCallback
MPLAB Harmony USB Stack
|