NOTICE: The Processors Wiki will End-of-Life on January 15, 2021. It is recommended to download any files or other content you may need that are hosted on processors.wiki.ti.com. The site is now set to read only.
Template:RemoTI-1.4.0 ZRC Dongle Voice
Contents
Detailed guide to add Voice support for the ZRC Dongle project[edit]
This section describes all steps required to add the Voice remote functionality to RemoTI-1.4.0. There are several aspects and gotchas to consider. Each code snippet that is added comes with a brief comment of why it is added.
Project options update[edit]
- Add
$PROJ_DIR$\..\..\..\..\COMPONENTS\audio\include
to the include paths - Add to the pre-compiler options the following two defines
- We need to link with the audio library, in addition to the network library. Instead of adding the path to the compile options, we add a folder in the project, and then place both libraries there.
- Uncheck the box which includes command line arguments for the linker. This is required since we add the library to the project in a new folder.
- To improve throughput and processing time we need to use compiler optimization settings for speed
- Add USB audio files
usb_aud.c/h
|
![]() |
Source files update[edit]
Application[edit]
In the main application code, zrc_dongle.c
- Include headers
- Add defines for audio buffer management, and audio decoding configuration structure
- Add function prototype to handle stop event. Also add a global counter, which is used to count audio frames to toggle LED in a pattern based on received data
- In the function
Dongle_Init()
add code to initialize and configure Audio Target library - Add processing of Audio events to
Dongle_ProcessEvent()
- Add received data processing in
RTI_ReceiveDataInd()
. This includes detecting whether or not we are already receiving audio data, and if not already receiving disable Frequency Agility. - Implement function to handle stop stream event
#ifdef VOICE_STREAM
#include "usb_aud.h"
#include "ratl_lib.h"
#endif
#ifdef VOICE_STREAM
#define USB_AUDIO_NB_FRAME_TO_BUF 3
#define USB_MAX_AUDIO_RX_QUEUE_SIZE 13
#define AUDIO_DEAD_LINK_TIMER 1000 //if no packet is received during this time, link is dead, so stop everything.
ratl_Config_t UsbDecodeconfig;
#endif
#ifdef VOICE_STREAM
static void audio_EventStop( void );
uint8 kk;
#endif
#ifdef VOICE_STREAM
// Want Audio buffer initialized as early as possible, so do it here
extern void RATL_DecodeInit( void );
extern CBAudioBuf_t pUsbAudioTxBuffer;
RATL_DecodeInit();
pUsbAudioTxBuffer.usbSamples = usbDataBuf;
pUsbAudioTxBuffer.size = MAX_USB_AUDIO_BUFFER_SIZE;
UsbDecodeconfig.CircBuf = &pUsbAudioTxBuffer;
UsbDecodeconfig.MaxNbByteToDecode = USB_NB_BYTES_TO_DECODE;
UsbDecodeconfig.MaxRxQueueSize = USB_MAX_AUDIO_RX_QUEUE_SIZE;
UsbDecodeconfig.BufferingSize = USB_AUDIO_NB_FRAME_TO_BUF;
RATL_decodeCfg( &UsbDecodeconfig);
#endif
#ifdef VOICE_STREAM
if (events & ZRC_DONGLE_EVT_DEAD_LINK )
{
audio_EventStop();
return (events ^ ZRC_DONGLE_EVT_DEAD_LINK );
}
if ( events & ZRC_DONGLE_EVT_AUD_DECODE )
{
if (RATL_DecodeAudioSamples())
{
return events;
}
else
{
return (events ^ ZRC_DONGLE_EVT_AUD_DECODE );
}
}
#endif
#if defined VOICE_STREAM
else if (len > 0 && profileId == RTI_PROFILE_ZRC && (rxFlags & RTI_RX_FLAGS_VENDOR_SPECIFIC) )
{
if (pData[0] == RTI_PROTOCOL_RAS)
{
uint8 res;
halIntState_t intState;
audioDataEvent_t audData;
audData.len = len-1;
audData.pData = (pData+1);
HAL_ENTER_CRITICAL_SECTION(intState);
uint8 temp = usbStatus;
HAL_EXIT_CRITICAL_SECTION(intState);
osal_start_timerEx(zrcDongleTaskId, ZRC_DONGLE_EVT_DEAD_LINK, AUDIO_DEAD_LINK_TIMER);
if ( RATL_COPY_ALLOWED == (res = RATL_ProcessDataPacket( &audData, temp)))
{
streamStatus = STREAM_START_COPY;
}
else if (RATL_STOPPED == res)
{
//Stop Cmd Receive
audio_EventStop();
}
else if (RATL_DECODING_ALLOWED == res)
{
//Start Decoding (needed for buffering...)
osal_set_event(zrcDongleTaskId, ZRC_DONGLE_EVT_AUD_DECODE);
}
//Play LED:
if (temp == USB_START)
{
if (kk++ == 50)
HalLedSet(HAL_LED_1, HAL_LED_MODE_ON);
if (kk >= 100)
{
HalLedSet(HAL_LED_1, HAL_LED_MODE_OFF);
HalLedSet(HAL_LED_2, HAL_LED_MODE_OFF);
kk = 0;
}
}
else
{
if (kk++ == 50)
HalLedSet(HAL_LED_2, HAL_LED_MODE_ON);
if (kk >= 100)
{
HalLedSet(HAL_LED_1, HAL_LED_MODE_OFF);
HalLedSet(HAL_LED_2, HAL_LED_MODE_OFF);
kk = 0;
}
}
}
}
#endif
#ifdef VOICE_STREAM
static void audio_EventStop( void )
{
streamStatus = STREAM_STOP;
RATL_audioStop();
osal_clear_event(zrcDongleTaskId, ZRC_DONGLE_EVT_AUD_DECODE);
osal_stop_timerEx(zrcDongleTaskId, ZRC_DONGLE_EVT_DEAD_LINK);
osal_clear_event(zrcDongleTaskId, ZRC_DONGLE_EVT_DEAD_LINK);
}
#endif
In zrc_dongle.h
- Add audio stream events to the list
#ifdef VOICE_STREAM
#define ZRC_DONGLE_EVT_AUD_DECODE 0x0010 // event to decode audio frame
#define ZRC_DONGLE_EVT_DEAD_LINK 0x0020 // timed event to detect dead link
#endif
Profile[edit]
Audio data are sent as Texas Instruments vendor specific ZRC data. TI use the first byte of the payload to indicate the specific TI protocol. For Audio, add:
#define RTI_PROTOCOL_RAS 0x50
Driver[edit]
USB[edit]
In zrc_usb.h
- Add audio interface enumeration macros
- Modify endpoint macros to better reflect endpoint direction. Also update code to use these new macros.
#ifdef VOICE_STREAM
#define INTERFACE_NUMBER_AUDIO_CONTROL 0x02
#define INTERFACE_NUMBER_AUDIO_STREAM 0x03
#define INTERFACE_NUMBER_ZRC 0x04
#else
#define INTERFACE_NUMBER_ZRC 0x02
#endif
//#define ZRC_PROXY_RNP_EP_OUT_ADDR 0x03
//#define ZRC_PROXY_RNP_EP_IN_ADDR ZRC_PROXY_RNP_EP_OUT_ADDR
//#define ZRC_PROXY_ZRC_EP_OUT_ADDR 0x04
//#define ZRC_PROXY_ZRC_EP_IN_ADDR 0x05
#define CE_ENPOINT_ADDR 0x02
#define RNP_ENPOINT_ADDR 0x03
#define ZRC_ENPOINT_ADDR 0x04
#define AUD_ENPOINT_ADDR 0x05
#define IN_ENPOINT_ADDR 0x80
#define OUT_ENPOINT_ADDR 0x00
#define CE_EP_IN_ADDR IN_ENPOINT_ADDR | CE_ENPOINT_ADDR
#define CE_EP_OUT_ADDR OUT_ENPOINT_ADDR | CE_ENPOINT_ADDR
#define RNP_EP_IN_ADDR IN_ENPOINT_ADDR | RNP_ENPOINT_ADDR
#define RNP_EP_OUT_ADDR OUT_ENPOINT_ADDR | RNP_ENPOINT_ADDR
#define ZRC_EP_IN_ADDR IN_ENPOINT_ADDR | ZRC_ENPOINT_ADDR
#define ZRC_EP_OUT_ADDR OUT_ENPOINT_ADDR | ZRC_ENPOINT_ADDR
#define AUDIO_EP_IN_ADDR IN_ENPOINT_ADDR | AUD_ENPOINT_ADDR
#define AUDIO_EP_OUT_ADDR OUT_ENPOINT_ADDR | AUD_ENPOINT_ADDR
#define RNP_EP_OUT_PACKET_LEN ZRC_DONGLE_OUTBUF_SIZE
In zrc_usb.c
- Update macros to account for the extended USB descriptor, now that audio is added
- Add audio descriptors
- Update Product String
- Update all macros to define endpoint enumeration, and also update descriptors to use it
- Add USB audio descriptor components offset defines
- Add to total length calculation
- Add interfaces to the dynamically built descriptor
- There are two additional USB interfaces if
VOICE_STREAM
is defined - Add endpoint configuration for audio interfaces
#ifdef VOICE_STREAM
#define ZRC_USB_NUM_INTERFACES 5
#else
#define ZRC_USB_NUM_INTERFACES 3
#endif
...
#ifdef VOICE_STREAM
#define DBLBUF_LUT_INFO_SIZE (sizeof(DBLBUF_LUT_INFO) * 6)
#else //VOICE_STREAM
#define DBLBUF_LUT_INFO_SIZE (sizeof(DBLBUF_LUT_INFO) * 3)
#endif //VOICE_STREAM
#ifdef VOICE_STREAM
// Interface Descriptor for audio control
const uint8 usb_iface_desc_audio_control[] = {
DESC_SIZE_INTERFACE, // bLength
DESC_TYPE_INTERFACE, // bDescriptorType
INTERFACE_NUMBER_AUDIO_CONTROL, // bInterfaceNumber
0x00, // bAlternateSetting (none)
0x00, // bNumEndpoints (none)
0x01, // bInterfaceClass (AUDIO)
0x01, // bInterfaceSubClass (AUDIO CONTROL)
0x00, // bInterfaceProcotol (N/A)
0x00 // iInterface
};
//Audio Descriptor: HEADER
const uint8 usb_audio_desc_header[] = {
DESC_SIZE_AUDIO_HEADER, // bLength
DESC_TYPE_CS_INTERFACE, // bDescriptorType
DESC_AUDIO_TYPE_HEADER, // bDescriptorSubType
0x01, 0x00, // bcdADC (1.0)
// wTotalLength //SIZE EQUAL TO SUM OF DESCRIPTOR of the audio control descriptor, including tis header:
// == size of (usb_audio_desc_input_term) +
// == size of (usb_audio_desc_feat_unit) +
0x27, 0x00, // == size of (usb_audio_desc_out_term)
0x01, // bInCollection (1 stream interface)
0x03, // bInterfaceNr (interface 4 is stream)
};
//Audio Descriptor: INPUT TERMINAL
const uint8 usb_audio_desc_input_term[] = {
DESC_SIZE_AUDIO_INPUT_TERM, // bLength
DESC_TYPE_CS_INTERFACE, // bDescriptorType
DESC_AUDIO_TYPE_INPUT_TERM, // bDescriptorSubType
0x01, // bTerminalID
0x01, 0x02, // wTerminalType
0x00, // bAssocTerminal (none)
0x01, // bNrChannel
0x00, 0x00, // wChannelConfig //No predifined spatial position
0x00, //iChannelNames
0x00, //iTerminal (none)
};
//Audio Descriptor: FEATURE UNIT
const uint8 usb_audio_desc_feat_unit[] = {
DESC_SIZE_AUDIO_FEAT_UNIT, // bLength (9)
DESC_TYPE_CS_INTERFACE, // bDescriptorType (CS_INTERFACE)
DESC_AUDIO_TYPE_FEAT_UNIT, // bDescriptorSubtype (FEATURE_UNIT)
0x02, // bUnitID (2)
0x01, // bSourceID (input terminal 1)
0x01, // bControlSize (2 bytes)
0x03, 0x00, // Master controls (volume and mute supported)
0x00 // iFeature (none)
};
//Audio Descriptor: OUTPUT TERMINAL
const uint8 usb_audio_desc_out_term[] = {
DESC_SIZE_AUDIO_OUTPUT_TERM, // bLength
DESC_TYPE_CS_INTERFACE, // bDescriptorType
DESC_AUDIO_TYPE_OUTPUT_TERM, // bDescriptorSubType
0x03, // bTerminalID
0x01, 0x01, // wTerminalType
0x00, // bAssocTerminal (none)
0x02, // bSourceID (feature unit 2)
0x00 // iTerminal (none)
};
// Interface Descriptor for audio stream
const uint8 usb_iface_desc_audio_stream0[] = {
DESC_SIZE_INTERFACE, // bLength
DESC_TYPE_INTERFACE, // bDescriptorType
INTERFACE_NUMBER_AUDIO_STREAM , // bInterfaceNumber
0x00, // bAlternateSetting (0)
0x00, // bNumEndpoints (none)
0x01, // bInterfaceClass (AUDIO)
0x02, // bInterfaceSubClass (AUDIO STREAM)
0x00, // bInterfaceProcotol (N/A)
0x00 // iInterface
};
// Interface Descriptor for audio stream, ALTERNATE SETTING
const uint8 usb_iface_desc_audio_stream1[] = {
DESC_SIZE_INTERFACE, // bLength
DESC_TYPE_INTERFACE, // bDescriptorType
INTERFACE_NUMBER_AUDIO_STREAM , // bInterfaceNumber
0x01, // bAlternateSetting (1)
0x01, // bNumEndpoints (1)
0x01, // bInterfaceClass (AUDIO)
0x02, // bInterfaceSubClass (AUDIO STREAM)
0x00, // bInterfaceProcotol (N/A)
0x00 // iInterface
};
//Audio Descriptor: aduio Stream, general
const uint8 usb_audio_desc_AS_general[] = {
DESC_SIZE_AUDIO_STREAM, // bLength
DESC_TYPE_CS_INTERFACE, // bDescriptorType
DESC_AUDIO_TYPE_GENERAL, // bDescriptorSubType
0x03, // bTerminalLink (terminal 3)
0x00, // bDelay (none)
0x01, 0x00 // wFormatTag (PCM format)
};
//Audio Descriptor: FORMAT TYPE
const uint8 usb_audio_desc_AS_format_type[] = {
DESC_SIZE_AUDIO_FORMAT_TYPEI, // bLength
DESC_TYPE_CS_INTERFACE, // bDescriptorType
DESC_AUDIO_TYPE_FORMAT_TYPE, // bDescriptorSubType
0x01, // bFormatType (TYPE_I)
0x01, // bNrChannels (1)
0x02, // bSubFrameSize (2)
0x10, // bBitResolution (16)
0x01, // bSamFreqType (1 sampling frequency)
0x80, // 16,000 Hz (byte 0)
0x3E, // 16,000 Hz (byte 1)
0x00 // 16,000 Hz (byte 2)
};
//Audio Descriptor: Audio Stream endpoint
const uint8 usb_audio_desc_AS_endpoint[] = {
DESC_SIZE_AUDIO_ENDPOINT, // bLength
DESC_TYPE_ENDPOINT, // bDescriptorType
AUDIO_EP_IN_ADDR, // bEndpointAddress (EP1 in)
0x05, // bmAttributes (isochronous + asynchronous)
0x20, 0x00, // wMaxPacketSize (256)
0x01, // bInterval (1 millisecond)
0x00, // bRefresh (0)
0x00 // bSynchAddress (no synchronization)
};
//Audio Descriptor: Isochronous endpoint
const uint8 usb_audio_desc_AS_isoendpoint[] = {
DESC_SIZE_AUDIO_ISO_ENDPOINT, // bLength
DESC_TYPE_CS_ENDPOINT, // bDescriptorType
DESC_AUDIO_TYPE_EP_GENERAL, // bDescriptorSubType
0x00, // bmAttributes (none)
0x02, // bLockDelayUnits (PCM samples)
0x00, 0x00 // wLockDelay (0)
};
#endif
const uint8 string2Product[] = {
#ifdef VOICE_STREAM
38, // bLength
#else
30, // bLength
#endif
DESC_TYPE_STRING, // bDescriptorType
'U', 0, // unicode string
...
'C', 0,
#ifdef VOICE_STREAM
' ', 0,
'A', 0,
'U', 0,
'D', 0
#endif
};
|
--> |
|
|
--> |
|
|
--> |
|
|
--> |
|
- 0x85, // bEndpointAddress
+ ZRC_EP_IN_ADDR, // bEndpointAddress
...
- 0x04, // bEndpointAddress
+ ZRC_EP_OUT_ADDR, // bEndpointAddress
...
- 0x83, // bEndpointAddress
+ RNP_EP_IN_ADDR, // bEndpointAddress
...
- 0x82, // bEndpointAddress
+ CE_EP_IN_ADDR, // bEndpointAddress
#ifdef VOICE_STREAM
#define ZRC_AUD_CTRL_IFACE_DESC (ZRC_CE_IN_EP_DESC + DESC_SIZE_ENDPOINT)
#define ZRC_AUD_CTRL_HDR_DESC (ZRC_AUD_CTRL_IFACE_DESC + DESC_SIZE_INTERFACE)
#define ZRC_AUD_CTRL_IN_TERM_DESC (ZRC_AUD_CTRL_HDR_DESC + DESC_SIZE_AUDIO_HEADER)
#define ZRC_AUD_CTRL_FEAT_DESC (ZRC_AUD_CTRL_IN_TERM_DESC + DESC_SIZE_AUDIO_INPUT_TERM)
#define ZRC_AUD_CTRL_OUT_TERM_DESC (ZRC_AUD_CTRL_FEAT_DESC + DESC_SIZE_AUDIO_FEAT_UNIT)
//#define ZRC_AUD_CTRL_OUT_TERM_DESC (ZRC_AUD_CTRL_IN_TERM_DESC + DESC_SIZE_AUDIO_INPUT_TERM)
#define ZRC_AUD_STREAM_IFACE0_DESC (ZRC_AUD_CTRL_OUT_TERM_DESC + DESC_SIZE_AUDIO_OUTPUT_TERM)
#define ZRC_AUD_STREAM_IFACE1_DESC (ZRC_AUD_STREAM_IFACE0_DESC + DESC_SIZE_INTERFACE)
#define ZRC_AUD_STREAM_GENERAL_DESC (ZRC_AUD_STREAM_IFACE1_DESC + DESC_SIZE_INTERFACE)
#define ZRC_AUD_STREAM_FORMAT_DESC (ZRC_AUD_STREAM_GENERAL_DESC + DESC_SIZE_AUDIO_STREAM)
#define ZRC_AUD_STREAM_EP_DESC (ZRC_AUD_STREAM_FORMAT_DESC + DESC_SIZE_AUDIO_FORMAT_TYPEI)
#define ZRC_AUD_STREAM_ISO_EP_DESC (ZRC_AUD_STREAM_EP_DESC + DESC_SIZE_AUDIO_ENDPOINT)
#define ZRC_IFACE_DESC (ZRC_AUD_STREAM_ISO_EP_DESC + DESC_SIZE_AUDIO_ISO_ENDPOINT)
#else //VOICE STREAM
#define ZRC_IFACE_DESC (ZRC_CE_IN_EP_DESC + DESC_SIZE_AUDIO_ISO_ENDPOINT)
#endif //VOICE STREAM
#ifdef VOICE_STREAM
// Add Audio class descriptor to the total length.
wTotalLength += DESC_SIZE_INTERFACE; // Audio Control interface
wTotalLength += DESC_SIZE_AUDIO_HEADER; // Audio Control Header descriptor
wTotalLength += DESC_SIZE_AUDIO_INPUT_TERM; // Audio Control input terminal descriptor
wTotalLength += DESC_SIZE_AUDIO_FEAT_UNIT; // Audio Control feature unit descriptor
wTotalLength += DESC_SIZE_AUDIO_OUTPUT_TERM; // Audio Control output terminal descriptor
wTotalLength += DESC_SIZE_INTERFACE; // Audio Stream interface, alternate 0
wTotalLength += DESC_SIZE_INTERFACE; // Audio Stream interface, alternate 1
wTotalLength += DESC_SIZE_AUDIO_STREAM; // Audio Stream, general descriptor
wTotalLength += DESC_SIZE_AUDIO_FORMAT_TYPEI; // Audio Stream, format type descriptor
wTotalLength += DESC_SIZE_AUDIO_ENDPOINT; // Audio Stream, endpoint descriptor
wTotalLength += DESC_SIZE_AUDIO_ISO_ENDPOINT; // Audio Stream, isochronous endpoint descriptor
#endif
#ifdef VOICE_STREAM
//Add Voice descriptor and interface
ptr = osal_memcpy(ptr, usb_iface_desc_audio_control, sizeof(usb_iface_desc_audio_control));
ptr = osal_memcpy(ptr, usb_audio_desc_header, sizeof(usb_audio_desc_header));
ptr = osal_memcpy(ptr, usb_audio_desc_input_term, sizeof(usb_audio_desc_input_term));
ptr = osal_memcpy(ptr, usb_audio_desc_feat_unit, sizeof(usb_audio_desc_feat_unit));
ptr = osal_memcpy(ptr, usb_audio_desc_out_term, sizeof(usb_audio_desc_out_term));
ptr = osal_memcpy(ptr, usb_iface_desc_audio_stream0, sizeof(usb_iface_desc_audio_stream0));
ptr = osal_memcpy(ptr, usb_iface_desc_audio_stream1, sizeof(usb_iface_desc_audio_stream1));
ptr = osal_memcpy(ptr, usb_audio_desc_AS_general, sizeof(usb_audio_desc_AS_general));
ptr = osal_memcpy(ptr, usb_audio_desc_AS_format_type, sizeof(usb_audio_desc_AS_format_type));
ptr = osal_memcpy(ptr, usb_audio_desc_AS_endpoint, sizeof(usb_audio_desc_AS_endpoint));
ptr = osal_memcpy(ptr, usb_audio_desc_AS_isoendpoint, sizeof(usb_audio_desc_AS_isoendpoint));
#endif
#ifdef VOICE_STREAM
*ptr = 4; // bNumInterfaces
#else
*ptr = 2; // bNumInterfaces
#endif
#ifdef VOICE_STREAM
usbDescriptorMarker.pUsbDblbufLut[2].pInterface = (USB_INTERFACE_DESCRIPTOR *)ZRC_AUD_CTRL_IFACE_DESC;
usbDescriptorMarker.pUsbDblbufLut[2].inMask = 0;
usbDescriptorMarker.pUsbDblbufLut[2].outMask = 0;
usbDescriptorMarker.pUsbDblbufLut[3].pInterface = (USB_INTERFACE_DESCRIPTOR *)ZRC_AUD_STREAM_IFACE0_DESC;
usbDescriptorMarker.pUsbDblbufLut[3].inMask = 0;
usbDescriptorMarker.pUsbDblbufLut[3].outMask = 0;
usbDescriptorMarker.pUsbDblbufLut[4].pInterface = (USB_INTERFACE_DESCRIPTOR *)ZRC_AUD_STREAM_IFACE1_DESC;
usbDescriptorMarker.pUsbDblbufLut[4].inMask = (1<<AUD_ENPOINT_ADDR ); //0x02; // Set EP1 to double buffering on IN
usbDescriptorMarker.pUsbDblbufLut[4].outMask = 0;
usbDescriptorMarker.pUsbDblbufLut[5].pInterface = (USB_INTERFACE_DESCRIPTOR *)ZRC_IFACE_DESC;
usbDescriptorMarker.pUsbDblbufLut[5].inMask = 0;
usbDescriptorMarker.pUsbDblbufLut[5].outMask = 0;
#else
usbDescriptorMarker.pUsbDblbufLut[2].pInterface = (USB_INTERFACE_DESCRIPTOR *)ZRC_IFACE_DESC;
usbDescriptorMarker.pUsbDblbufLut[2].inMask = 0;
usbDescriptorMarker.pUsbDblbufLut[2].outMask = 0;
#endif
In usb_zrc.h
- Add audio events
#ifdef VOICE_STREAM
#define AUDIOD_CMD_START 0x04
#define AUDIOD_CMD_STOP 0x08
#define AUDIOD_STREAM_STARTED 0x10
#define AUDIOD_STREAM_REQUESTED 0x20
#endif
In the usb_zrc_class_request.c
- Add USB audio class request handles
#if defined VOICE_STREAM
uint8 audioCVolumeMin[2]={0x00,0x80};
uint8 audioCVolumeMax[2]={0x00,0x06};
uint8 audioCVolumeRes[2]={0x00,0x01};
uint8 audioCVolumeCur[2]={0x00,0x00};
uint8 audioMuteValue = 0;
void usbcrGetMin(void)
{
if (usbfwData.ep0Status == EP_IDLE)
{
// Is the length stall correct?
if ( (usbSetupHeader.length == 0) || (HI_UINT16(usbSetupHeader.index) > 2))
{
usbfwData.ep0Status = EP_STALL;
}
else
{
switch (HI_UINT16(usbSetupHeader.value))
{
case 2: //Volume
usbSetupData.pBuffer = (uint8 *)&audioCVolumeMin;
usbSetupData.bytesLeft = 2;
usbfwData.ep0Status = EP_TX;
break;
default:
usbfwData.ep0Status = EP_STALL;
break;
}
}
}
}// usbcrGetReport
void usbcrGetMax(void)
{
if (usbfwData.ep0Status == EP_IDLE)
{
// Is the length stall correct?
if ( (usbSetupHeader.length == 0) || (HI_UINT16(usbSetupHeader.index) > 2))
{
usbfwData.ep0Status = EP_STALL;
}
else
{
switch (HI_UINT16(usbSetupHeader.value))
{
case 2: //Volume
usbSetupData.pBuffer = (uint8 *)&audioCVolumeMax;
usbSetupData.bytesLeft = 2;
usbfwData.ep0Status = EP_TX;
break;
default:
usbfwData.ep0Status = EP_STALL;
break;
}
}
}
}// usbcrGetReport
void usbcrGetRes(void)
{
if (usbfwData.ep0Status == EP_IDLE)
{
// Is the length stall correct?
if ( (usbSetupHeader.length == 0) || (HI_UINT16(usbSetupHeader.index) > 2))
{
usbfwData.ep0Status = EP_STALL;
} else
{
switch (HI_UINT16(usbSetupHeader.value))
{
case 2:
usbSetupData.pBuffer = (uint8 *)&audioCVolumeRes;
usbSetupData.bytesLeft = 2;
usbfwData.ep0Status = EP_TX;
break;
default:
usbfwData.ep0Status = EP_STALL;
break;
}
}
}
}// usbcrGetReport
void usbcrGetCur(void)
{
if (usbfwData.ep0Status == EP_IDLE)
{
// Is the length stall correct?
if ( (usbSetupHeader.length == 0) || (HI_UINT16(usbSetupHeader.index) > 2))
{
usbfwData.ep0Status = EP_STALL;
}
else
{
switch (HI_UINT16(usbSetupHeader.value))
{
case 1:
usbSetupData.pBuffer = (uint8 *)&audioMuteValue;
usbSetupData.bytesLeft = 1;
usbfwData.ep0Status = EP_TX;
break;
case 2:
usbSetupData.pBuffer = (uint8 *)&audioCVolumeCur;
usbSetupData.bytesLeft = 2;
usbfwData.ep0Status = EP_TX;
break;
default:
usbfwData.ep0Status = EP_STALL;
break;
}
}
}
}// usbcrGetReport
uint8 *pVolumeCur;
uint8 *pMuteCur;
void usbcrSetCur(void)
{
// Received header
if (usbfwData.ep0Status == EP_IDLE)
{
// Is the length stall correct?
if ( (usbSetupHeader.length == 0) || (HI_UINT16(usbSetupHeader.index) > 2))
{
usbfwData.ep0Status = EP_STALL;
}
else
{
switch (HI_UINT16(usbSetupHeader.value))
{
case 1: //Mute
pMuteCur = (uint8 *)osal_mem_alloc(usbSetupHeader.length);
usbfwData.ep0Status = EP_RX;
usbSetupData.bytesLeft = usbSetupHeader.length;
usbSetupData.pBuffer = pMuteCur;
break;
case 2: //Volume
pVolumeCur = (uint8 *)osal_mem_alloc(usbSetupHeader.length);
usbfwData.ep0Status = EP_RX;
usbSetupData.bytesLeft = usbSetupHeader.length;
usbSetupData.pBuffer = pVolumeCur;
break;
default:
usbfwData.ep0Status = EP_STALL;
break;
}
}
}
else if (usbfwData.ep0Status == EP_RX)
{
switch (HI_UINT16(usbSetupHeader.value))
{
case 1: //Mute
// Send OUT report up to Application
//zrcPxyServeHIDClassRequests(usbSetupHeader.request, zrcClassRequestDataOut);
audioMuteValue = *pMuteCur;
osal_mem_free(pMuteCur);
break;
case 2: //Volume
// Send OUT report up to Application
//zrcPxyServeHIDClassRequests(usbSetupHeader.request, zrcClassRequestDataOut);
audioCVolumeCur[0] = pVolumeCur[0];
audioCVolumeCur[1] = pVolumeCur[1];
osal_mem_free(pVolumeCur);
break;
default:
break;
}
}
}// usbcrSetReport
uint8 *pVolumeRes;
void usbcrSetRes(void)
{
// Received header
if (usbfwData.ep0Status == EP_IDLE)
{
// Is the length stall correct?
if ( (usbSetupHeader.length == 0) || (HI_UINT16(usbSetupHeader.index) > 2))
{
usbfwData.ep0Status = EP_STALL;
}
else
{
switch (HI_UINT16(usbSetupHeader.value))
{
// case 2: //Volume
//#ifdef IO_BENCHMARK
// HAL_BM_TURN_ON_IO1 (); //RF4CE task on
//#endif
// pVolumeRes = (uint8 *)osal_mem_alloc(usbSetupHeader.length);
//
// usbfwData.ep0Status = EP_RX;
//
// usbSetupData.bytesLeft = usbSetupHeader.length;
// usbSetupData.pBuffer = pVolumeRes;
// break;
default:
usbfwData.ep0Status = EP_STALL;
break;
}
}
}
else if (usbfwData.ep0Status == EP_RX)
{
// Send OUT report up to Application
//zrcPxyServeHIDClassRequests(usbSetupHeader.request, zrcClassRequestDataOut);
audioCVolumeRes[0] = pVolumeRes[0];
audioCVolumeRes[1] = pVolumeRes[1];
osal_mem_free(pVolumeRes);
}
}
void usbcrSetMin(void)
{
if (usbfwData.ep0Status == EP_IDLE)
{
if ( (usbSetupHeader.value & 0xFFFE) ||
(usbSetupHeader.length != 0) ||
(usbSetupHeader.index > INTERFACE_NUMBER_AUDIO_STREAM))
{
usbfwData.ep0Status = EP_STALL;
}
else
{
}
}
}// usbcrSetProtocol
#endif
In usb_zrc_class_requests.h
- Add audio class requests macros
- And add audio class requests function prototypes
#ifdef VOICE_STREAM
// Audio Request Codes
#define GET_CUR 0x81 // Code for Get Current Value
#define GET_MIN 0x82
#define GET_MAX 0x83
#define GET_RES 0x84
#define SET_CUR 0x01 // Code for Get Current Value
#define SET_MIN 0x02
#define SET_MAX 0x03
#define SET_RES 0x04
#endif
#ifdef VOICE_STREAM
void usbcrSetCur(void);
void usbcrSetRes(void);
void usbcrGetCur(void);
void usbcrGetMin(void);
void usbcrGetMax(void);
void usbcrGetRes(void);
#endif
In the usb_zrc_hooks.c
- Add include files
- In
usbcrHookProcessOut()
- In
usbcrHookProcessIn()
- Define start and stop streaming functions as extern hooks. These are defined in
usb_aud.c
#ifdef VOICE_STREAM
#include "usb_zrc.h"
#include "zrc_common.h"
#include "zrc_usb.h"
#endif
#ifdef VOICE_STREAM
case SET_CUR:
usbcrSetCur();
break;
case SET_RES:
usbcrSetRes();
break;
#endif //VOICE_STREAM
#ifdef VOICE_STREAM
case GET_CUR:
usbcrGetCur(); break;
case GET_MIN:
usbcrGetMin(); break;
case GET_MAX:
usbcrGetMax(); break;
case GET_RES:
usbcrGetRes(); break;
#endif //VOICE_STREAM
#ifdef VOICE_STREAM
//extern void InitBuffer(void);
extern void StartAudioStreamingCommand(void);
extern void StopAudioStreamingCommand(void);
#endif
// ************************ USB standard request event processing *************************
void usbsrHookProcessEvent(uint8 event, uint8 index)
{
...
// Process relevant events, one at a time.
switch (event) {
...
#ifdef VOICE_STREAM
// interface 3 and alternate Setting 1 ==> start audio
if ( (index == INTERFACE_NUMBER_AUDIO_STREAM) && (usbfwData.pAlternateSetting[usbSetupHeader.index] == 1) )
{
StartAudioStreamingCommand();
}
else if ( (index == INTERFACE_NUMBER_AUDIO_STREAM) && (usbfwData.pAlternateSetting[usbSetupHeader.index] == 0) )
{
StopAudioStreamingCommand();
}
#endif
In usb_descriptor.h
- Add audio descriptor macros
#define DESC_TYPE_CS_INTERFACE 0x24
#define DESC_TYPE_CS_ENDPOINT 0x25
#define DESC_AUDIO_TYPE_HEADER 0x01
#define DESC_AUDIO_TYPE_INPUT_TERM 0x02
#define DESC_AUDIO_TYPE_OUTPUT_TERM 0x03
#define DESC_AUDIO_TYPE_FEAT_UNIT 0x06
//Audio Stream
#define DESC_AUDIO_TYPE_GENERAL 0x01
#define DESC_AUDIO_TYPE_FORMAT_TYPE 0x02
#define DESC_AUDIO_TYPE_EP_GENERAL 0x01
#define DESC_SIZE_DEVICE 0x12
#define DESC_SIZE_CONFIG 0x09
#define DESC_SIZE_INTERFACE 0x09
#define DESC_SIZE_ENDPOINT 0x07
#define DESC_SIZE_AUDIO_HEADER 0x09
#define DESC_SIZE_AUDIO_INPUT_TERM 0x0C
#define DESC_SIZE_AUDIO_OUTPUT_TERM 0x09
#define DESC_SIZE_AUDIO_FEAT_UNIT 0x09
#define DESC_SIZE_AUDIO_STREAM 0x07
#define DESC_SIZE_AUDIO_FORMAT_TYPEI 0x0B //for one discrete Fs
#define DESC_SIZE_AUDIO_ENDPOINT 0x09
#define DESC_SIZE_AUDIO_ISO_ENDPOINT 0x07
In usb_interrupt.c
- Add files to include
- Add hooks for isochronous interrupt service routines, implemented in
usb_aud.c
- In
usbirqHandler()
add#ifdef VOICE_STREAM uint8 usbiif; #endif ... #ifdef VOICE_STREAM usbiif = USBIIF; #endif ... #ifdef VOICE_STREAM if (usbcif & USBCIF_SOFIF) { usbSofIsr(); } if ( (usbiif & (1<<AUDIO_ENPOINT_ADDR) /*USBIIF_INEP1IF*/) ) //|| (usbcif & USBCIF_SOFIF) { // Handle Audio stream usbIsoInIsr(); if (usbiif & (1<<AUDIO_ENPOINT_ADDR)) { usbiif &= ~((1<<AUDIO_ENPOINT_ADDR)); } } #endif eventMask = usbcif; #ifdef VOICE_STREAM eventMask |= (uint16)usbiif << 4; #else eventMask |= (uint16)USBIIF << 4; #endif
#ifdef VOICE_STREAM
#include "usb_aud.h"
#endif
#ifdef VOICE_STREAM
extern void usbIsoInIsr(void);
extern void usbSofIsr(void);
#endif
DMA[edit]
In the DMA driver file hal_dma.c
, add hooks for the audio library.
- Include header
- Add
HAL_USB_DMA
to precompiler clause to enable DMA interrupt, and to implement interrupt handler - Add call to usb audio driver
usb_aud.c
DMA interrupt handler - Add macro to check if DMA has started in
hal_dma.h
#if (defined HAL_USB_DMA) && (HAL_USB_DMA == TRUE)
#include "usb_aud.h"
#endif
void HalDmaInit( void )
{
...
#if (HAL_UART_DMA || \
((defined HAL_SPI) && (HAL_SPI == TRUE)) || \
((defined HAL_USB_DMA) && (HAL_USB_DMA == TRUE)) || \
((defined HAL_IRGEN) && (HAL_IRGEN == TRUE)))
DMAIE = 1;
#endif
}
#if (HAL_UART_DMA || \
((defined HAL_SPI) && (HAL_SPI == TRUE)) || \
((defined HAL_USB_DMA) && (HAL_USB_DMA == TRUE)) || \
((defined HAL_IRGEN) && (HAL_IRGEN == TRUE)))
/******************************************************************************
* @fn HalDMAInit
#if (defined HAL_USB_DMA) && (HAL_USB_DMA == TRUE)
if ( HAL_DMA_CHECK_IRQ( HAL_DMA_CH_RX ) )
{
usbDmaIsr();
HAL_DMA_CLEAR_IRQ( HAL_DMA_CH_RX );
}
#endif
#define HAL_DMA_CHECK_STARTED( ch ) (DMAREQ & ( 1 << (ch) ))