Rework audio driver

This commit is contained in:
Reinhard Panhuber 2021-01-31 19:08:23 +01:00
parent f1551d7a5f
commit 84406f1654
6 changed files with 442 additions and 363 deletions

View File

@ -32,8 +32,6 @@
* *
* */ * */
// TODO: Rename CFG_TUD_AUDIO_EPSIZE_IN to CFG_TUD_AUDIO_EP_IN_BUFFER_SIZE
#include "tusb_option.h" #include "tusb_option.h"
#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_AUDIO) #if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_AUDIO)
@ -49,30 +47,17 @@
// MACRO CONSTANT TYPEDEF // MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE
#ifndef CFG_TUD_AUDIO_TX_FIFO_COUNT
#define CFG_TUD_AUDIO_TX_FIFO_COUNT CFG_TUD_AUDIO_N_CHANNELS_TX
#endif
#endif
#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE
#ifndef CFG_TUD_AUDIO_RX_FIFO_COUNT
#define CFG_TUD_AUDIO_RX_FIFO_COUNT CFG_TUD_AUDIO_N_CHANNELS_RX
#endif
#endif
typedef struct typedef struct
{ {
uint8_t rhport; uint8_t rhport;
uint8_t const * p_desc; // Pointer pointing to Standard AC Interface Descriptor(4.7.1) - Audio Control descriptor defining audio function uint8_t const * p_desc; // Pointer pointing to Standard AC Interface Descriptor(4.7.1) - Audio Control descriptor defining audio function
#if CFG_TUD_AUDIO_EPSIZE_IN #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE
uint8_t ep_in; // Outgoing (out of uC) audio data EP. uint8_t ep_in; // TX audio data EP.
uint16_t epin_buf_cnt; // Count filling status of EP in buffer - this is a shared state currently and is intended to be removed once EP buffers can be implemented as FIFOs!
uint8_t ep_in_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to output terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) uint8_t ep_in_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to output terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero)
#endif #endif
#if CFG_TUD_AUDIO_EPSIZE_OUT #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE
uint8_t ep_out; // Incoming (into uC) audio data EP. uint8_t ep_out; // Incoming (into uC) audio data EP.
uint8_t ep_out_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to input terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero) uint8_t ep_out_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to input terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero)
@ -89,25 +74,51 @@ typedef struct
#if CFG_TUD_AUDIO_N_AS_INT #if CFG_TUD_AUDIO_N_AS_INT
uint8_t altSetting[CFG_TUD_AUDIO_N_AS_INT]; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP! uint8_t altSetting[CFG_TUD_AUDIO_N_AS_INT]; // We need to save the current alternate setting this way, because it is possible that there are AS interfaces which do not have an EP!
#endif #endif
/*------------- From this point, data is not cleared by bus reset -------------*/ /*------------- From this point, data is not cleared by bus reset -------------*/
// Buffer for control requests // Buffer for control requests
CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf[CFG_TUD_AUDIO_CTRL_BUF_SIZE]; CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf[CFG_TUD_AUDIO_CTRL_BUF_SIZE];
// FIFO // EP Transfer buffers and FIFOs
#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE
tu_fifo_t tx_ff[CFG_TUD_AUDIO_TX_FIFO_COUNT]; CFG_TUSB_MEM_ALIGN uint8_t ep_out_buf[CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE];
CFG_TUSB_MEM_ALIGN uint8_t tx_ff_buf[CFG_TUD_AUDIO_TX_FIFO_COUNT][CFG_TUD_AUDIO_TX_FIFO_SIZE]; tu_fifo_t ep_out_ff;
#if CFG_FIFO_MUTEX #if CFG_FIFO_MUTEX
osal_mutex_def_t tx_ff_mutex[CFG_TUD_AUDIO_TX_FIFO_COUNT]; osal_mutex_def_t ep_out_ff_mutex;
#endif
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
uint32_t fb_val; // Feedback value for asynchronous mode (in 16.16 format).
#endif
#endif
#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE
CFG_TUSB_MEM_ALIGN uint8_t ep_in_buf[CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE];
tu_fifo_t ep_in_ff;
#if CFG_FIFO_MUTEX
osal_mutex_def_t ep_in_ff_mutex;
#endif
#endif
// Support FIFOs
#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
tu_fifo_t tx_ff[CFG_TUD_AUDIO_N_CHANNELS_TX];
CFG_TUSB_MEM_ALIGN uint8_t tx_ff_buf[CFG_TUD_AUDIO_N_CHANNELS_TX][CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE];
#if CFG_FIFO_MUTEX
osal_mutex_def_t tx_ff_mutex[CFG_TUD_AUDIO_N_CHANNELS_TX];
#endif #endif
#endif #endif
#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE #if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
tu_fifo_t rx_ff[CFG_TUD_AUDIO_RX_FIFO_COUNT]; tu_fifo_t rx_ff[CFG_TUD_AUDIO_N_CHANNELS_RX];
CFG_TUSB_MEM_ALIGN uint8_t rx_ff_buf[CFG_TUD_AUDIO_RX_FIFO_COUNT][CFG_TUD_AUDIO_RX_FIFO_SIZE]; CFG_TUSB_MEM_ALIGN uint8_t rx_ff_buf[CFG_TUD_AUDIO_N_CHANNELS_RX][CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE];
#if CFG_FIFO_MUTEX #if CFG_FIFO_MUTEX
osal_mutex_def_t rx_ff_mutex[CFG_TUD_AUDIO_RX_FIFO_COUNT]; osal_mutex_def_t rx_ff_mutex[CFG_TUD_AUDIO_N_CHANNELS_RX];
#endif #endif
#endif #endif
@ -119,21 +130,6 @@ typedef struct
#endif #endif
#endif #endif
// Endpoint Transfer buffers
#if CFG_TUD_AUDIO_EPSIZE_OUT
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_AUDIO_EPSIZE_OUT]; // Bigger makes no sense for isochronous EP's (but technically possible here)
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
uint32_t fb_val; // Feedback value for asynchronous mode (in 16.16 format).
#endif
#endif
#if CFG_TUD_AUDIO_EPSIZE_IN
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_AUDIO_EPSIZE_IN]; // Bigger makes no sense for isochronous EP's (but technically possible here)
tu_fifo_t epin_ff;
#endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN]; CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN];
#endif #endif
@ -149,11 +145,11 @@ CFG_TUSB_MEM_SECTION audiod_interface_t _audiod_itf[CFG_TUD_AUDIO];
extern const uint16_t tud_audio_desc_lengths[]; extern const uint16_t tud_audio_desc_lengths[];
#if CFG_TUD_AUDIO_EPSIZE_OUT #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE
static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t * buffer, uint16_t bufsize); static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t * buffer, uint16_t bufsize);
#endif #endif
#if CFG_TUD_AUDIO_EPSIZE_IN #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE
static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio); static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio);
#endif #endif
@ -167,34 +163,23 @@ static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *idxDriver);
bool tud_audio_n_mounted(uint8_t itf) bool tud_audio_n_mounted(uint8_t itf)
{ {
TU_VERIFY(itf < CFG_TUD_AUDIO);
audiod_interface_t* audio = &_audiod_itf[itf]; audiod_interface_t* audio = &_audiod_itf[itf];
#if CFG_TUD_AUDIO_EPSIZE_OUT #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE
if (audio->ep_out == 0) if (audio->ep_out == 0) return false;
{
return false;
}
#endif #endif
#if CFG_TUD_AUDIO_EPSIZE_IN #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE
if (audio->ep_in == 0) if (audio->ep_in == 0) return false;
{
return false;
}
#endif #endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
if (audio->ep_int_ctr == 0) if (audio->ep_int_ctr == 0) return false;
{
return false;
}
#endif #endif
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
if (audio->ep_fb == 0) if (audio->ep_fb == 0) return false;
{
return false;
}
#endif #endif
return true; return true;
@ -204,43 +189,58 @@ bool tud_audio_n_mounted(uint8_t itf)
// READ API // READ API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE
#if CFG_TUD_AUDIO_RX_FIFO_COUNT > 1
uint16_t tud_audio_n_available(uint8_t itf, uint8_t channelId)
{
TU_VERIFY(channelId < CFG_TUD_AUDIO_N_CHANNELS_RX);
return tu_fifo_count(&_audiod_itf[itf].rx_ff[channelId]);
}
uint16_t tud_audio_n_read(uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize)
{
TU_VERIFY(channelId < CFG_TUD_AUDIO_N_CHANNELS_RX);
return tu_fifo_read_n(&_audiod_itf[itf].rx_ff[channelId], buffer, bufsize);
}
void tud_audio_n_read_flush (uint8_t itf, uint8_t channelId)
{
TU_VERIFY(channelId < CFG_TUD_AUDIO_N_CHANNELS_RX, );
tu_fifo_clear(&_audiod_itf[itf].rx_ff[channelId]);
}
#else
uint16_t tud_audio_n_available(uint8_t itf) uint16_t tud_audio_n_available(uint8_t itf)
{ {
return tu_fifo_count(&_audiod_itf[itf].rx_ff[0]); TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, );
return tu_fifo_count(&_audiod_itf[itf].ep_out_ff);
} }
uint16_t tud_audio_n_read(uint8_t itf, void* buffer, uint16_t bufsize) uint16_t tud_audio_n_read(uint8_t itf, void* buffer, uint16_t bufsize)
{ {
return tu_fifo_read_n(&_audiod_itf[itf].rx_ff[0], buffer, bufsize); TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, );
return tu_fifo_read_n(&_audiod_itf[itf].ep_out_ff, buffer, bufsize);
} }
void tud_audio_n_read_flush (uint8_t itf) void tud_audio_n_clear_ep_out_ff(uint8_t itf)
{ {
tu_fifo_clear(&_audiod_itf[itf].rx_ff[0]); TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, );
return tu_fifo_clear(&_audiod_itf[itf].ep_out_ff);
}
#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
// Delete all content in the support RX FIFOs
void tud_audio_n_clear_rx_support_ff(uint8_t itf, uint8_t channelId)
{
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX, );
tu_fifo_clear(&_audiod_itf[itf].rx_ff[channelId]);
}
uint16_t tud_audio_n_available_support_ff(uint8_t itf, uint8_t channelId)
{
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX, );
tu_fifo_count(&_audiod_itf[itf].rx_ff[channelId]);
}
uint16_t tud_audio_n_read_support_ff(uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize)
{
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_RX, );
return tu_fifo_read_n(&_audiod_itf[itf].rx_ff[channelId], buffer, bufsize);
} }
#endif #endif
#endif #endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
uint16_t tud_audio_int_ctr_n_available(uint8_t itf) uint16_t tud_audio_int_ctr_n_available(uint8_t itf)
@ -261,9 +261,9 @@ void tud_audio_int_ctr_n_read_flush (uint8_t itf)
#endif #endif
// This function is called once something is received by USB and is responsible for decoding received stream into audio channels. // This function is called once something is received by USB and is responsible for decoding received stream into audio channels.
// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_RX_FIFO_SIZE = 0. // If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE = 0.
#if CFG_TUD_AUDIO_EPSIZE_OUT #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE
static bool audio_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t* buffer, uint16_t bufsize) static bool audio_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t* buffer, uint16_t bufsize)
{ {
@ -281,7 +281,7 @@ static bool audio_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t*
{ {
case AUDIO_DATA_FORMAT_TYPE_I_PCM: case AUDIO_DATA_FORMAT_TYPE_I_PCM:
#if CFG_TUD_AUDIO_RX_FIFO_SIZE #if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
TU_VERIFY(audio_rx_done_type_I_pcm_ff_cb(rhport, audio, buffer, bufsize)); TU_VERIFY(audio_rx_done_type_I_pcm_ff_cb(rhport, audio, buffer, bufsize));
#else #else
#error YOUR DECODING AND BUFFERING IS REQUIRED HERE! #error YOUR DECODING AND BUFFERING IS REQUIRED HERE!
@ -309,11 +309,11 @@ static bool audio_rx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t*
return true; return true;
} }
#endif //CFG_TUD_AUDIO_EPSIZE_OUT #endif //CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE
// The following functions are used in case CFG_TUD_AUDIO_RX_FIFO_SIZE != 0 // The following functions are used in case CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE != 0
#if CFG_TUD_AUDIO_RX_FIFO_SIZE #if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
#if CFG_TUD_AUDIO_RX_FIFO_COUNT > 1 #if CFG_TUD_AUDIO_N_CHANNELS_RX > 1
static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t * buffer, uint16_t bufsize) static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio, uint8_t * buffer, uint16_t bufsize)
{ {
(void) rhport; (void) rhport;
@ -365,13 +365,53 @@ static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t *a
tu_fifo_write_n(&audio->rx_ff[0], buffer, bufsize); tu_fifo_write_n(&audio->rx_ff[0], buffer, bufsize);
return true; return true;
} }
#endif // CFG_TUD_AUDIO_RX_FIFO_COUNT > 1 #endif // CFG_TUD_AUDIO_N_CHANNELS_RX > 1
#endif //CFG_TUD_AUDIO_RX_FIFO_SIZE #endif //CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// WRITE API // WRITE API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE
uint16_t tud_audio_n_write(uint8_t itf, const void * data, uint16_t len)
{
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, );
return tu_fifo_write_n(&_audiod_itf[itf].ep_in_ff, data, len);
}
void tud_audio_n_clear_ep_in_ff(uint8_t itf) // Delete all content in the EP IN FIFO
{
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, );
tu_fifo_clear(&_audiod_itf[itf].ep_in_ff);
}
#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
uint16_t tud_audio_n_flush_tx_support_ff(uint8_t itf) // Force all content in the support TX FIFOs to be written into EP SW FIFO
{
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, );
audiod_interface_t* audio = &_audiod_itf[itf];
uint16_t n_bytes_copied;
TU_VERIFY(audiod_tx_done_cb(audio->rhport, audio, &n_bytes_copied));
return n_bytes_copied;
}
uint16_t tud_audio_n_clear_tx_support_ff (uint8_t itf, uint8_t channelId);
uint16_t tud_audio_n_write_support_ff(uint8_t itf, uint8_t channelId, const void * data, uint16_t len)
{
TU_VERIFY(itf < CFG_TUD_AUDIO && _audiod_itf[itf].p_desc != NULL, channelId < CFG_TUD_AUDIO_N_CHANNELS_TX, );
return tu_fifo_write_n(&audio->tx_ff[channelId], data, len);
}
#endif
#endif
/** /**
* \brief Write data to EP in buffer * \brief Write data to EP in buffer
* *
@ -383,50 +423,28 @@ static bool audio_rx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t *a
* \param[in] len: # of array elements to copy * \param[in] len: # of array elements to copy
* \return Number of bytes actually written * \return Number of bytes actually written
*/ */
#if CFG_TUD_AUDIO_EPSIZE_IN #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE
#if !CFG_TUD_AUDIO_TX_FIFO_SIZE #if !CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
/* This function is intended for later use once EP buffers (at least for ISO EPs) are implemented as ring buffers This function is intended for later use once EP buffers (at least for ISO EPs) are implemented as ring buffers
uint16_t tud_audio_n_write_ep_in_buffer(uint8_t itf, const void * data, uint16_t len) uint16_t tud_audio_n_write_ep_in_buffer(uint8_t itf, const void * data, uint16_t len)
{ {
audiod_interface_t* audio = &_audiod_itf[itf]; audiod_interface_t* audio = &_audiod_itf[itf];
if (audio->p_desc == NULL) { if (audio->p_desc == NULL) return 0;
return 0;
}
// THIS IS A CRITICAL SECTION - audio->epin_buf_cnt MUST NOT BE MODIFIED FROM HERE - happens if audiod_tx_done_cb() is executed in between! return tu_fifo_write_n(&audio->ep_in_ff, data, len);
// FOR SINGLE THREADED OPERATION:
// AS LONG AS THIS FUNCTION IS NOT EXECUTED WITHIN AN INTERRUPT ALL IS FINE!
// Determine free space
uint16_t free = CFG_TUD_AUDIO_EPSIZE_IN - audio->epin_buf_cnt;
// Clip length if needed
if (len > free) len = free;
// Write data
memcpy((void *) &audio->epin_buf[audio->epin_buf_cnt], data, len);
audio->epin_buf_cnt += len;
// Return number of bytes written
return len;
} }
*/
#else #else
#if CFG_TUD_AUDIO_TX_FIFO_COUNT == 1 #if CFG_TUD_AUDIO_N_CHANNELS_TX == 1
uint16_t tud_audio_n_write(uint8_t itf, void const* data, uint16_t len) uint16_t tud_audio_n_write(uint8_t itf, void const* data, uint16_t len)
{ {
audiod_interface_t* audio = &_audiod_itf[itf];
if (audio->p_desc == NULL)
{ {
audiod_interface_t* audio = &_audiod_itf[itf]; return 0;
if (audio->p_desc == NULL)
{
return 0;
}
return tu_fifo_write_n(&audio->tx_ff[0], data, len);
} }
return tu_fifo_write_n(&audio->tx_ff[0], data, len);
} }
#else #else
uint16_t tud_audio_n_write(uint8_t itf, uint8_t channelId, const void * data, uint16_t len) uint16_t tud_audio_n_write(uint8_t itf, uint8_t channelId, const void * data, uint16_t len)
@ -471,11 +489,11 @@ uint32_t tud_audio_int_ctr_n_write(uint8_t itf, uint8_t const* buffer, uint32_t
// This function is called once a transmit of an audio packet was successfully completed. Here, we encode samples and place it in IN EP's buffer for next transmission. // This function is called once a transmit of an audio packet was successfully completed. Here, we encode samples and place it in IN EP's buffer for next transmission.
// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_TX_FIFO_SIZE = 0 and use tud_audio_n_write_ep_in_buffer() (NOT IMPLEMENTED SO FAR). // If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE = 0 and use tud_audio_n_write_ep_in_buffer() (NOT IMPLEMENTED SO FAR).
// n_bytes_copied - Informs caller how many bytes were loaded. In case n_bytes_copied = 0, a ZLP is scheduled to inform host no data is available for current frame. // n_bytes_copied - Informs caller how many bytes were loaded. In case n_bytes_copied = 0, a ZLP is scheduled to inform host no data is available for current frame.
#if CFG_TUD_AUDIO_EPSIZE_IN #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE
static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_t * n_bytes_copied) static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t * audio, uint16_t * n_bytes_copied)
{ {
uint8_t idxDriver, idxItf; uint8_t idxDriver, idxItf;
uint8_t const *dummy2; uint8_t const *dummy2;
@ -488,10 +506,10 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_
} }
// Call a weak callback here - a possibility for user to get informed former TX was completed and data gets now loaded into EP in buffer (in case FIFOs are used) or // Call a weak callback here - a possibility for user to get informed former TX was completed and data gets now loaded into EP in buffer (in case FIFOs are used) or
// if no FIFOs are used the user may use this call back to load its data into the EP in buffer by use of tud_audio_n_write_ep_in_buffer(). // if no FIFOs are used the user may use this call back to load its data into the EP IN buffer by use of tud_audio_n_write_ep_in_buffer().
if (tud_audio_tx_done_pre_load_cb) TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idxDriver, audio->ep_in, audio->altSetting[idxItf])); if (tud_audio_tx_done_pre_load_cb) TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idxDriver, audio->ep_in, audio->altSetting[idxItf]));
#if CFG_TUD_AUDIO_TX_FIFO_SIZE #if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
switch (CFG_TUD_AUDIO_FORMAT_TYPE_TX) switch (CFG_TUD_AUDIO_FORMAT_TYPE_TX)
{ {
case AUDIO_FORMAT_TYPE_UNDEFINED: case AUDIO_FORMAT_TYPE_UNDEFINED:
@ -526,30 +544,11 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_
} }
#endif #endif
// THIS IS A CRITICAL SECTION - audio->epin_buf_cnt MUST NOT BE MODIFIED FROM HERE - happens if tud_audio_n_write_ep_in_buffer() is executed in between! // Inform how many bytes will be copied
*n_bytes_copied = tu_fifo_count(&audio->ep_in_ff);
// THIS IS NOT SOLVED SO FAR!
// FOR SINGLE THREADED OPERATION:
// THIS FUNCTION IS NOT EXECUTED WITHIN AN INTERRUPT SO IT DOES NOT INTERRUPT tud_audio_n_write_ep_in_buffer()! AS LONG AS tud_audio_n_write_ep_in_buffer() IS NOT EXECUTED WITHIN AN INTERRUPT ALL IS FINE!
// Schedule transmit // Schedule transmit
// TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->epin_buf, audio->epin_buf_cnt)); TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_in, &audio->ep_in_ff, *n_bytes_copied));
TU_VERIFY(usbd_edpt_iso_xfer(rhport, audio->ep_in, &audio->epin_ff));
// Inform how many bytes were copied
*n_bytes_copied = audio->epin_buf_cnt;
// Declare EP in buffer empty
audio->epin_buf_cnt = 0;
// TO HERE
// Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame // Call a weak callback here - a possibility for user to get informed former TX was completed and how many bytes were loaded for the next frame
if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, *n_bytes_copied, idxDriver, audio->ep_in, audio->altSetting[idxItf])); if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, *n_bytes_copied, idxDriver, audio->ep_in, audio->altSetting[idxItf]));
@ -557,19 +556,18 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_
return true; return true;
} }
#endif //CFG_TUD_AUDIO_EPSIZE_IN #endif //CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE
#if CFG_TUD_AUDIO_TX_FIFO_SIZE #if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
#if CFG_TUD_AUDIO_TX_FIFO_COUNT > 1 || (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX != CFG_TUD_AUDIO_TX_ITEMSIZE) #if CFG_TUD_AUDIO_N_CHANNELS_TX > 1 || (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX != CFG_TUD_AUDIO_TX_ITEMSIZE)
static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio) static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio)
{ {
// We encode directly into IN EP's buffer - abort if previous transfer not complete // We encode directly into IN EP's FIFO - abort if previous transfer not complete
TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in)); TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in));
// Determine amount of samples // Determine amount of samples
uint16_t const nEndpointSampleCapacity = CFG_TUD_AUDIO_EPSIZE_IN / CFG_TUD_AUDIO_N_CHANNELS_TX / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX; uint16_t const nEndpointSampleCapacity = CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE / CFG_TUD_AUDIO_N_CHANNELS_TX / CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX;
uint16_t nSamplesPerChannelToSend = tu_fifo_count(&audio->tx_ff[0]) / CFG_TUD_AUDIO_TX_ITEMSIZE; uint16_t nSamplesPerChannelToSend = tu_fifo_count(&audio->tx_ff[0]) / CFG_TUD_AUDIO_TX_ITEMSIZE;
uint16_t nBytesToSend;
uint8_t cntChannel; uint8_t cntChannel;
for (cntChannel = 1; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_TX; cntChannel++) for (cntChannel = 1; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_TX; cntChannel++)
@ -582,58 +580,47 @@ static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t*
} }
// Check if there is enough // Check if there is enough
if (nSamplesPerChannelToSend == 0) if (nSamplesPerChannelToSend == 0) return true;
{
audio->epin_buf_cnt = 0;
return true;
}
// Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT! // Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT!
nSamplesPerChannelToSend = tu_min16(nSamplesPerChannelToSend, nEndpointSampleCapacity); nSamplesPerChannelToSend = tu_min16(nSamplesPerChannelToSend, nEndpointSampleCapacity);
nBytesToSend = nSamplesPerChannelToSend * CFG_TUD_AUDIO_N_CHANNELS_TX * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX;
// Encode // Encode
uint16_t cntSample; uint16_t cntSample;
uint8_t * pBuff = audio->epin_buf;
#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == 1
uint8_t sample;
#elif CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == 2
uint16_t sample;
#else
uint32_t sample;
#endif
// TODO: Big endianess handling
for (cntSample = 0; cntSample < nSamplesPerChannelToSend; cntSample++) for (cntSample = 0; cntSample < nSamplesPerChannelToSend; cntSample++)
{ {
for (cntChannel = 0; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_TX; cntChannel++) for (cntChannel = 0; cntChannel < CFG_TUD_AUDIO_N_CHANNELS_TX; cntChannel++)
{ {
// If 8, 16, or 32 bit values are to be copied
#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX == CFG_TUD_AUDIO_TX_ITEMSIZE
tu_fifo_read_n_into_other_fifo(&audio->tx_ff[cntChannel], &audio->ep_in_ff, 0, CFG_TUD_AUDIO_TX_ITEMSIZE);
#else
// TODO: Implement a left and right justified 24 to 32 and vice versa copy process from FIFO to FIFO
uint32_t sample = 0;
// Get sample from buffer // Get sample from buffer
tu_fifo_read_n(&audio->tx_ff[cntChannel], &sample, CFG_TUD_AUDIO_TX_ITEMSIZE); tu_fifo_read_n(&audio->tx_ff[cntChannel], &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX);
// Put it into EP's buffer - Let alignment problems be handled by memcpy tu_fifo_write_n(&audio->ep_in_ff, &sample, CFG_TUD_AUDIO_TX_ITEMSIZE);
memcpy(pBuff, &sample, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX); #endif
// Advance pointer
pBuff += CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX;
} }
} }
audio->epin_buf_cnt = nBytesToSend;
return true; return true;
} }
#else #else
static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio) static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t* audio)
{ {
// TODO GET RID OF SINGLE TX_FIFO!
// We encode directly into IN EP's buffer - abort if previous transfer not complete // We encode directly into IN EP's buffer - abort if previous transfer not complete
TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in)); TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in));
// Determine amount of samples // Determine amount of samples
uint16_t nByteCount = tu_fifo_count(&audio->tx_ff[0]); uint16_t nByteCount = tu_fifo_count(&audio->tx_ff[0]);
nByteCount = tu_min16(nByteCount, CFG_TUD_AUDIO_EPSIZE_IN); nByteCount = tu_min16(nByteCount, CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE);
// Check if there is enough // Check if there is enough
if (nByteCount == 0) if (nByteCount == 0)
@ -641,20 +628,17 @@ static bool audiod_tx_done_type_I_pcm_ff_cb(uint8_t rhport, audiod_interface_t*
return true; return true;
} }
nByteCount = tu_fifo_read_n_into_other_fifo(&audio->tx_ff[0], &audio->epin_ff, 0, nByteCount); nByteCount = tu_fifo_read_n_into_other_fifo(&audio->tx_ff[0], &audio->ep_in_ff, 0, nByteCount);
// nByteCount = tu_fifo_read_n(&audio->tx_ff[0], audio->epin_buf, nByteCount);
audio->epin_buf_cnt = nByteCount;
return true; return true;
} }
#endif // CFG_TUD_AUDIO_TX_FIFO_COUNT > 1 || (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX != CFG_TUD_AUDIO_TX_ITEMSIZE) #endif // CFG_TUD_AUDIO_N_CHANNELS_TX > 1 || (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX != CFG_TUD_AUDIO_TX_ITEMSIZE)
#endif //CFG_TUD_AUDIO_TX_FIFO_SIZE #endif //CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
// This function is called once a transmit of an feedback packet was successfully completed. Here, we get the next feedback value to be sent // This function is called once a transmit of an feedback packet was successfully completed. Here, we get the next feedback value to be sent
#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
static bool audio_fb_send(uint8_t rhport, audiod_interface_t *audio) static bool audio_fb_send(uint8_t rhport, audiod_interface_t *audio)
{ {
uint8_t fb[4]; uint8_t fb[4];
@ -738,28 +722,34 @@ void audiod_init(void)
{ {
audiod_interface_t* audio = &_audiod_itf[i]; audiod_interface_t* audio = &_audiod_itf[i];
// Initialize IN EP FIFO if required
#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE
// Initialize IN EP FIFO
tu_fifo_config(&audio->ep_in_ff, &audio->ep_in_buf, CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE, 1, true);
#endif
// Initialize TX FIFOs if required // Initialize TX FIFOs if required
#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_TX_FIFO_COUNT; cnt++) for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_TX; cnt++)
{ {
tu_fifo_config(&audio->tx_ff[cnt], &audio->tx_ff_buf[cnt], CFG_TUD_AUDIO_TX_FIFO_SIZE, 1, true); tu_fifo_config(&audio->tx_ff[cnt], &audio->tx_ff_buf[cnt], CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE, 1, true);
#if CFG_FIFO_MUTEX #if CFG_FIFO_MUTEX
tu_fifo_config_mutex(&audio->tx_ff[cnt], osal_mutex_create(&audio->tx_ff_mutex[cnt])); tu_fifo_config_mutex(&audio->tx_ff[cnt], osal_mutex_create(&audio->tx_ff_mutex[cnt]));
#endif #endif
} }
// Initialize IN EP FIFO
tu_fifo_config(&audio->epin_ff, &audio->epin_buf, CFG_TUD_AUDIO_EPSIZE_IN, 1, true);
#endif #endif
#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_RX_FIFO_COUNT; cnt++) for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_RX; cnt++)
{ {
tu_fifo_config(&audio->rx_ff[cnt], &audio->rx_ff_buf[cnt], CFG_TUD_AUDIO_RX_FIFO_SIZE, 1, true); tu_fifo_config(&audio->rx_ff[cnt], &audio->rx_ff_buf[cnt], CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE, 1, true);
#if CFG_FIFO_MUTEX #if CFG_FIFO_MUTEX
tu_fifo_config_mutex(&audio->rx_ff[cnt], osal_mutex_create(&audio->rx_ff_mutex[cnt])); tu_fifo_config_mutex(&audio->rx_ff[cnt], osal_mutex_create(&audio->rx_ff_mutex[cnt]));
#endif #endif
// Initialize OUT EP FIFO
tu_fifo_config(&audio->ep_out_ff, &audio->ep_out_buf, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE, 1, true);
} }
#endif #endif
@ -781,19 +771,19 @@ void audiod_reset(uint8_t rhport)
audiod_interface_t* audio = &_audiod_itf[i]; audiod_interface_t* audio = &_audiod_itf[i];
tu_memclr(audio, ITF_MEM_RESET_SIZE); tu_memclr(audio, ITF_MEM_RESET_SIZE);
#if CFG_TUD_AUDIO_EPSIZE_IN #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE
tu_fifo_clear(&audio->epin_ff); tu_fifo_clear(&audio->ep_in_ff);
#endif #endif
#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE && CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_TX_FIFO_COUNT; cnt++) for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_TX; cnt++)
{ {
tu_fifo_clear(&audio->tx_ff[cnt]); tu_fifo_clear(&audio->tx_ff[cnt]);
} }
#endif #endif
#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_RX_FIFO_COUNT; cnt++) for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_N_CHANNELS_RX; cnt++)
{ {
tu_fifo_clear(&audio->rx_ff[cnt]); tu_fifo_clear(&audio->rx_ff[cnt]);
} }
@ -891,7 +881,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
TU_VERIFY(audiod_get_AS_interface_index(itf, &idxDriver, &idxItf, &p_desc)); TU_VERIFY(audiod_get_AS_interface_index(itf, &idxDriver, &idxItf, &p_desc));
// Look if there is an EP to be closed - for this driver, there are only 3 possible EPs which may be closed (only AS related EPs can be closed, AC EP (if present) is always open) // Look if there is an EP to be closed - for this driver, there are only 3 possible EPs which may be closed (only AS related EPs can be closed, AC EP (if present) is always open)
#if CFG_TUD_AUDIO_EPSIZE_IN > 0 #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE > 0
if (_audiod_itf[idxDriver].ep_in_as_intf_num == itf) if (_audiod_itf[idxDriver].ep_in_as_intf_num == itf)
{ {
_audiod_itf[idxDriver].ep_in_as_intf_num = 0; _audiod_itf[idxDriver].ep_in_as_intf_num = 0;
@ -904,7 +894,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
} }
#endif #endif
#if CFG_TUD_AUDIO_EPSIZE_OUT #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE
if (_audiod_itf[idxDriver].ep_out_as_intf_num == itf) if (_audiod_itf[idxDriver].ep_out_as_intf_num == itf)
{ {
_audiod_itf[idxDriver].ep_out_as_intf_num = 0; _audiod_itf[idxDriver].ep_out_as_intf_num = 0;
@ -945,7 +935,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
// We need to set EP non busy since this is not taken care of right now in ep_close() - THIS IS A WORKAROUND! // We need to set EP non busy since this is not taken care of right now in ep_close() - THIS IS A WORKAROUND!
usbd_edpt_clear_stall(rhport, ep_addr); usbd_edpt_clear_stall(rhport, ep_addr);
#if CFG_TUD_AUDIO_EPSIZE_IN > 0 #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE > 0
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && ((tusb_desc_endpoint_t const *) p_desc)->bmAttributes.usage == 0x00) // Check if usage is data EP if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && ((tusb_desc_endpoint_t const *) p_desc)->bmAttributes.usage == 0x00) // Check if usage is data EP
{ {
// Save address // Save address
@ -961,7 +951,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
} }
#endif #endif
#if CFG_TUD_AUDIO_EPSIZE_OUT #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE
if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) // Checking usage not necessary if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) // Checking usage not necessary
{ {
@ -973,7 +963,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request)); if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
// Prepare for incoming data // Prepare for incoming data
TU_ASSERT(usbd_edpt_xfer(rhport, ep_addr, _audiod_itf[idxDriver].epout_buf, CFG_TUD_AUDIO_EPSIZE_OUT), false); TU_ASSERT(usbd_edpt_xfer(rhport, ep_addr, _audiod_itf[idxDriver].ep_out_buf, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE), false);
} }
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
@ -1242,7 +1232,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
#endif #endif
#if CFG_TUD_AUDIO_EPSIZE_IN #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE
// Data transmission of audio packet finished // Data transmission of audio packet finished
if (_audiod_itf[idxDriver].ep_in == ep_addr) if (_audiod_itf[idxDriver].ep_in == ep_addr)
@ -1264,16 +1254,16 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
} }
#endif #endif
#if CFG_TUD_AUDIO_EPSIZE_OUT #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE
// New audio packet received // New audio packet received
if (_audiod_itf[idxDriver].ep_out == ep_addr) if (_audiod_itf[idxDriver].ep_out == ep_addr)
{ {
// Save into buffer - do whatever has to be done // Save into buffer - do whatever has to be done
TU_VERIFY(audio_rx_done_cb(rhport, &_audiod_itf[idxDriver], _audiod_itf[idxDriver].epout_buf, xferred_bytes)); TU_VERIFY(audio_rx_done_cb(rhport, &_audiod_itf[idxDriver], _audiod_itf[idxDriver].ep_out_buf, xferred_bytes));
// prepare for next transmission // prepare for next transmission
TU_ASSERT(usbd_edpt_xfer(rhport, ep_addr, _audiod_itf[idxDriver].epout_buf, CFG_TUD_AUDIO_EPSIZE_OUT), false); TU_ASSERT(usbd_edpt_xfer(rhport, ep_addr, _audiod_itf[idxDriver].ep_out_buf, CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE), false);
return true; return true;
} }

View File

@ -38,9 +38,11 @@
// Class Driver Configuration // Class Driver Configuration
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// All sizes are in bytes!
// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just waste a few bytes) // Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just waste a few bytes)
#ifndef CFG_TUD_AUDIO_N_AS_INT #ifndef CFG_TUD_AUDIO_N_AS_INT
#define CFG_TUD_AUDIO_N_AS_INT 0 #error You must tell the driver the number of Standard AS Interface Descriptors you have defined in the descriptors!
#endif #endif
// Size of control buffer used to receive and send control messages via EP0 - has to be big enough to hold your biggest request structure e.g. range requests with multiple intervals defined or cluster descriptors // Size of control buffer used to receive and send control messages via EP0 - has to be big enough to hold your biggest request structure e.g. range requests with multiple intervals defined or cluster descriptors
@ -48,20 +50,6 @@
#error You must define an audio class control request buffer size! #error You must define an audio class control request buffer size!
#endif #endif
// Use of TX/RX FIFOs - If sizes are not zero, audio.c implements FIFOs for RX and TX (whatever defined).
// For RX: the input stream gets decoded into its corresponding channels, where for each channel a FIFO is setup to hold its data -> see: audio_rx_done_cb().
// For TX: the output stream is composed from CFG_TUD_AUDIO_N_CHANNELS_TX channels, where for each channel a FIFO is defined.
// Further, it implements encoding and decoding of the individual channels (parameterized by the defines below).
// If you don't use the FIFOs you need to handle encoding and decoding on your own in audio_rx_done_cb() and audio_tx_done_cb(). This, however, allows for optimizations.
#ifndef CFG_TUD_AUDIO_TX_FIFO_SIZE
#define CFG_TUD_AUDIO_TX_FIFO_SIZE 0 // Buffer size per channel
#endif
#ifndef CFG_TUD_AUDIO_RX_FIFO_SIZE
#define CFG_TUD_AUDIO_RX_FIFO_SIZE 0 // Buffer size per channel
#endif
// End point sizes - Limits: Full Speed <= 1023, High Speed <= 1024 // End point sizes - Limits: Full Speed <= 1023, High Speed <= 1024
#ifndef CFG_TUD_AUDIO_EPSIZE_IN #ifndef CFG_TUD_AUDIO_EPSIZE_IN
#define CFG_TUD_AUDIO_EPSIZE_IN 0 // TX #define CFG_TUD_AUDIO_EPSIZE_IN 0 // TX
@ -71,12 +59,80 @@
#define CFG_TUD_AUDIO_EPSIZE_OUT 0 // RX #define CFG_TUD_AUDIO_EPSIZE_OUT 0 // RX
#endif #endif
#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP // Software EP FIFO buffer sizes - must be >= EP SIZEs!
#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 // Feedback #if CFG_TUD_AUDIO_EPSIZE_IN
#ifndef CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE
#define CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_IN // TX
#endif
#endif #endif
#if CFG_TUD_AUDIO_EPSIZE_OUT
#ifndef CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE
#define CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE CFG_TUD_AUDIO_EPSIZE_OUT // RX
#endif
#endif
// General information of number of TX and/or RX channels - is used in case support FIFOs (see below) are used and can be used for descriptor definitions
#ifndef CFG_TUD_AUDIO_N_CHANNELS_TX
#define CFG_TUD_AUDIO_N_CHANNELS_TX 0
#endif
#ifndef CFG_TUD_AUDIO_N_CHANNELS_RX
#define CFG_TUD_AUDIO_N_CHANNELS_RX 0
#endif
// Use of TX/RX support FIFOs
// Support FIFOs are not mandatory for the audio driver, rather they are intended to be of use in
// - TX case: CFG_TUD_AUDIO_N_CHANNELS_TX channels need to be encoded into one USB output stream (currently PCM type I is implemented)
// - RX case: CFG_TUD_AUDIO_N_CHANNELS_RX channels need to be decoded from a single USB input stream (currently PCM type I is implemented)
//
// This encoding/decoding is done in software and thus time consuming. If you can encode/decode your stream more efficiently do not use the
// support FIFOs but write/read directly into/from the EP_X_SW_BUFFER_FIFOs using
// - tud_audio_n_write() or
// - tud_audio_n_read().
// To write/read to/from the support FIFOs use
// - tud_audio_n_write_support_ff() or
// - tud_audio_n_read_support_ff().
//
// The encoding/decoding format type done is defined below.
//
// The encoding/decoding starts when the private callback functions
// - audio_tx_done_cb()
// - audio_rx_done_cb()
// are invoked. If support FIFOs are used the corresponding encoding/decoding functions are called from there.
// Once encoding/decoding is done the result is put directly into the EP_X_SW_BUFFER_FIFOs. You can use the public callback functions
// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb()
// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb()
// if you want to get informed what happened.
//
// If you don't use the support FIFOs you may use the public callback functions
// - tud_audio_tx_done_pre_load_cb() or tud_audio_tx_done_post_load_cb()
// - tud_audio_rx_done_pre_read_cb() or tud_audio_rx_done_post_read_cb()
// to write/read from/into the EP_X_SW_BUFFER_FIFOs at the right time.
//
// If you need a different encoding which is not support so far implement it in the
// - audio_tx_done_cb()
// - audio_rx_done_cb()
// functions.
// Size of support FIFOs - if size > 0 there are as many FIFOs set up as TX/RX channels defined
#ifndef CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
#define CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE 0 // Buffer size per channel - minimum size: ceil(f_s/1000)*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX
#endif
#ifndef CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
#define CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE 0 // Buffer size per channel - minimum size: ceil(f_s/1000)*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX
#endif
// Enable/disable feedback EP (required for asynchronous RX applications)
#ifndef CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 // Feedback - 0 or 1
#endif
// Audio interrupt control EP size - disabled if 0
#ifndef CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN #ifndef CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 // Audio interrupt control #define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 // Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74)
#endif #endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
@ -85,15 +141,8 @@
#endif #endif
#endif #endif
#ifndef CFG_TUD_AUDIO_N_CHANNELS_TX // Audio data format types - look in audio.h for existing types
#define CFG_TUD_AUDIO_N_CHANNELS_TX 1 // Used in case support FIFOs are used
#endif
#ifndef CFG_TUD_AUDIO_N_CHANNELS_RX
#define CFG_TUD_AUDIO_N_CHANNELS_RX 1
#endif
// Audio data format types
#ifndef CFG_TUD_AUDIO_FORMAT_TYPE_TX #ifndef CFG_TUD_AUDIO_FORMAT_TYPE_TX
#define CFG_TUD_AUDIO_FORMAT_TYPE_TX AUDIO_FORMAT_TYPE_UNDEFINED // If this option is used, an encoding function has to be implemented in audio_device.c #define CFG_TUD_AUDIO_FORMAT_TYPE_TX AUDIO_FORMAT_TYPE_UNDEFINED // If this option is used, an encoding function has to be implemented in audio_device.c
#endif #endif
@ -110,8 +159,8 @@
#define CFG_TUD_AUDIO_FORMAT_TYPE_I_TX AUDIO_DATA_FORMAT_TYPE_I_PCM #define CFG_TUD_AUDIO_FORMAT_TYPE_I_TX AUDIO_DATA_FORMAT_TYPE_I_PCM
#endif #endif
#ifndef CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX // bSubslotSize #ifndef CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX // bSubslotSize
#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 1 #define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 1
#endif #endif
#ifndef CFG_TUD_AUDIO_TX_ITEMSIZE #ifndef CFG_TUD_AUDIO_TX_ITEMSIZE
@ -136,8 +185,8 @@
#define CFG_TUD_AUDIO_FORMAT_TYPE_I_RX AUDIO_DATA_FORMAT_TYPE_I_PCM #define CFG_TUD_AUDIO_FORMAT_TYPE_I_RX AUDIO_DATA_FORMAT_TYPE_I_PCM
#endif #endif
#ifndef CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX // bSubslotSize #ifndef CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX // bSubslotSize
#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX 1 #define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX 1
#endif #endif
#if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX == 1 #if CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX == 1
@ -170,69 +219,84 @@ extern "C" {
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
bool tud_audio_n_mounted (uint8_t itf); bool tud_audio_n_mounted (uint8_t itf);
#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE
#if CFG_TUD_AUDIO_RX_FIFO_COUNT > 1
uint16_t tud_audio_n_available (uint8_t itf, uint8_t channelId); uint16_t tud_audio_n_available (uint8_t itf);
uint16_t tud_audio_n_read (uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize); uint16_t tud_audio_n_read (uint8_t itf, void* buffer, uint16_t bufsize);
void tud_audio_n_read_flush (uint8_t itf, uint8_t channelId); void tud_audio_n_clear_ep_out_ff (uint8_t itf); // Delete all content in the EP OUT FIFO
#else
uint16_t tud_audio_n_available (uint8_t itf); #if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
uint16_t tud_audio_n_read (uint8_t itf, void* buffer, uint16_t bufsize); void tud_audio_n_clear_rx_support_ff (uint8_t itf, uint8_t channelId); // Delete all content in the support RX FIFOs
void tud_audio_n_read_flush (uint8_t itf); uint16_t tud_audio_n_available_support_ff (uint8_t itf, uint8_t channelId);
#endif uint16_t tud_audio_n_read_support_ff (uint8_t itf, uint8_t channelId, void* buffer, uint16_t bufsize);
#endif #endif
/* This function is intended for later use once EP buffers (at least for ISO EPs) are implemented as ring buffers
#if CFG_TUD_AUDIO_EPSIZE_IN && !CFG_TUD_AUDIO_TX_FIFO_SIZE
uint16_t tud_audio_n_write_ep_in_buffer(uint8_t itf, const void * data, uint16_t len)
#endif
*/
#ifndef CFG_TUD_AUDIO_TX_FIFO_COUNT
#define CFG_TUD_AUDIO_TX_FIFO_COUNT 1
#endif #endif
#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE
#if CFG_TUD_AUDIO_TX_FIFO_COUNT > 1
uint16_t tud_audio_n_write (uint8_t itf, uint8_t channelId, const void * data, uint16_t len); uint16_t tud_audio_n_write (uint8_t itf, const void * data, uint16_t len);
#else void tud_audio_n_clear_ep_in_ff (uint8_t itf); // Delete all content in the EP IN FIFO
uint16_t tud_audio_n_write (uint8_t itf, const void * data, uint16_t len);
#endif #if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
uint16_t tud_audio_n_write_flush(uint8_t itf); uint16_t tud_audio_n_flush_tx_support_ff (uint8_t itf); // Force all content in the support TX FIFOs to be written into EP SW FIFO
uint16_t tud_audio_n_clear_tx_support_ff (uint8_t itf, uint8_t channelId);
uint16_t tud_audio_n_write_support_ff (uint8_t itf, uint8_t channelId, const void * data, uint16_t len);
#endif #endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0 #endif
uint16_t tud_audio_int_ctr_n_available (uint8_t itf);
uint16_t tud_audio_int_ctr_n_read (uint8_t itf, void* buffer, uint16_t bufsize); #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
void tud_audio_int_ctr_n_read_flush (uint8_t itf); uint16_t tud_audio_int_ctr_n_available (uint8_t itf);
uint16_t tud_audio_int_ctr_n_write (uint8_t itf, uint8_t const* buffer, uint16_t bufsize); uint16_t tud_audio_int_ctr_n_read (uint8_t itf, void* buffer, uint16_t bufsize);
void tud_audio_int_ctr_n_clear (uint8_t itf); // Delete all content in the AUDIO_INT_CTR FIFO
uint16_t tud_audio_int_ctr_n_write (uint8_t itf, uint8_t const* buffer, uint16_t len);
#endif #endif
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Application API (Interface0) // Application API (Interface0)
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
static inline bool tud_audio_mounted (void); static inline bool tud_audio_mounted (void);
#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE // RX API
static inline uint16_t tud_audio_available (void);
static inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize); #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE
static inline void tud_audio_read_flush (void);
static inline uint16_t tud_audio_available (void);
static inline void tud_audio_clear_ep_out_ff (void); // Delete all content in the EP OUT FIFO
static inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize);
#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
static inline void tud_audio_clear_rx_support_ff (uint8_t channelId);
static inline uint16_t tud_audio_available_support_ff (uint8_t channelId);
static inline uint16_t tud_audio_read_support_ff (uint8_t channelId, void* buffer, uint16_t bufsize);
#endif #endif
#if CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE
#if CFG_TUD_AUDIO_TX_FIFO_COUNT > 1
static inline uint16_t tud_audio_write (uint8_t channelId, uint8_t const* buffer, uint16_t bufsize);
#else
static inline uint16_t tud_audio_write (uint8_t const* buffer, uint16_t bufsize);
#endif
#endif #endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0 // TX API
static inline uint32_t tud_audio_int_ctr_available (void);
static inline uint32_t tud_audio_int_ctr_read (void* buffer, uint32_t bufsize); #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE
static inline void tud_audio_int_ctr_read_flush (void);
static inline uint32_t tud_audio_int_ctr_write (uint8_t const* buffer, uint32_t bufsize); static inline uint16_t tud_audio_write (const void * data, uint16_t len);
static inline uint16_t tud_audio_clear_ep_in_ff (void);
#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
static inline uint16_t tud_audio_flush_tx_support_ff (void);
static inline uint16_t tud_audio_clear_tx_support_ff (uint8_t channelId);
static inline uint16_t tud_audio_write_support_ff (uint8_t channelId, const void * data, uint16_t len);
#endif
#endif
// INT CTR API
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
static inline uint16_t tud_audio_int_ctr_available (void);
static inline uint16_t tud_audio_int_ctr_read (void* buffer, uint16_t bufsize);
static inline void tud_audio_int_ctr_clear (void);
static inline uint16_t tud_audio_int_ctr_write (uint8_t const* buffer, uint16_t len);
#endif #endif
// Buffer control EP data and schedule a transmit // Buffer control EP data and schedule a transmit
@ -247,16 +311,17 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req
// Application Callback API (weak is optional) // Application Callback API (weak is optional)
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
#if CFG_TUD_AUDIO_EPSIZE_IN #if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE
TU_ATTR_WEAK bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting); TU_ATTR_WEAK bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting);
TU_ATTR_WEAK bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting); TU_ATTR_WEAK bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t itf, uint8_t ep_in, uint8_t cur_alt_setting);
#endif #endif
#if CFG_TUD_AUDIO_EPSIZE_OUT #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE
TU_ATTR_WEAK bool tud_audio_rx_done_cb(uint8_t rhport, uint8_t * buffer, uint16_t bufsize); TU_ATTR_WEAK bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint8_t itf, uint8_t ep_out, uint8_t cur_alt_setting);
TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t itf, uint8_t ep_out, uint8_t cur_alt_setting);
#endif #endif
#if CFG_TUD_AUDIO_EPSIZE_OUT > 0 && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
TU_ATTR_WEAK bool tud_audio_fb_done_cb(uint8_t rhport); TU_ATTR_WEAK bool tud_audio_fb_done_cb(uint8_t rhport);
// User code should call this function with feedback value in 16.16 format for FS and HS. // User code should call this function with feedback value in 16.16 format for FS and HS.
// Value will be corrected for FS to 10.14 format automatically. // Value will be corrected for FS to 10.14 format automatically.
@ -302,64 +367,82 @@ static inline bool tud_audio_mounted(void)
return tud_audio_n_mounted(0); return tud_audio_n_mounted(0);
} }
#if CFG_TUD_AUDIO_EPSIZE_IN // RX API
#if CFG_TUD_AUDIO_TX_FIFO_SIZE && CFG_TUD_AUDIO_TX_FIFO_COUNT > 1
static inline uint16_t tud_audio_write (uint8_t channelId, uint8_t const* buffer, uint16_t n_bytes) // Short version if only one audio function is used
{
return tud_audio_n_write(0, channelId, buffer, n_bytes);
}
#else
static inline uint16_t tud_audio_write (uint8_t const* buffer, uint16_t n_bytes) // Short version if only one audio function is used
{
return tud_audio_n_write(0, buffer, n_bytes);
}
#endif
static inline uint16_t tud_audio_write_flush (void) // Short version if only one audio function is used #if CFG_TUD_AUDIO_EP_OUT_SW_BUFFER_SIZE
{
#if CFG_TUD_AUDIO_TX_FIFO_SIZE
return tud_audio_n_write_flush(0);
#else
return 0;
#endif
}
#endif // CFG_TUD_AUDIO_EPSIZE_IN && CFG_TUD_AUDIO_TX_FIFO_SIZE
#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_RX_FIFO_SIZE static inline uint16_t tud_audio_available (void)
#if CFG_TUD_AUDIO_RX_FIFO_COUNT > 1
static inline uint16_t tud_audio_available(uint8_t channelId)
{
return tud_audio_n_available(0, channelId);
}
static inline uint16_t tud_audio_read(uint8_t channelId, void* buffer, uint16_t bufsize)
{
return tud_audio_n_read(0, channelId, buffer, bufsize);
}
static inline void tud_audio_read_flush(uint8_t channelId)
{
tud_audio_n_read_flush(0, channelId);
}
#else
static inline uint16_t tud_audio_available(void)
{ {
return tud_audio_n_available(0); return tud_audio_n_available(0);
} }
static inline uint16_t tud_audio_read(void *buffer, uint16_t bufsize) static inline uint16_t tud_audio_read (void* buffer, uint16_t bufsize)
{ {
return tud_audio_n_read(0, buffer, bufsize); return tud_audio_n_read(0, buffer, bufsize);
} }
static inline void tud_audio_read_flush(void) static inline uint16_t tud_audio_clear_ep_out_ff (void)
{ {
tud_audio_n_read_flush(0); return tud_audio_n_clear_ep_out_ff(0);
} }
#endif
#if CFG_TUD_AUDIO_RX_SUPPORT_SW_FIFO_SIZE
static inline void tud_audio_clear_rx_support_ff (uint8_t channelId)
{
tud_audio_n_clear_rx_support_ff(0, channelId);
}
static inline uint16_t tud_audio_available_support_ff (uint8_t channelId)
{
return tud_audio_n_available_support_ff(0, channelId);
}
static inline uint16_t tud_audio_read_support_ff (uint8_t channelId, void* buffer, uint16_t bufsize)
{
return tud_audio_n_read_support_ff(0, channelId, buffer, bufsize);
}
#endif #endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0 #endif
// TX API
#if CFG_TUD_AUDIO_EP_IN_SW_BUFFER_SIZE
static inline uint16_t tud_audio_write (const void * data, uint16_t len)
{
return tud_audio_n_write(0, data, len);
}
static inline uint16_t tud_audio_clear_ep_in_ff (void)
{
return tud_audio_n_clear_ep_in_ff(0);
}
#if CFG_TUD_AUDIO_TX_SUPPORT_SW_FIFO_SIZE
static inline uint16_t tud_audio_flush_tx_support_ff (void)
{
return tud_audio_n_flush_tx_support_ff(0);
}
static inline uint16_t tud_audio_clear_tx_support_ff (uint8_t channelId)
{
return tud_audio_n_clear_tx_support_ff(0, channelId);
}
static inline uint16_t tud_audio_write_support_ff (uint8_t channelId, const void * data, uint16_t len)
{
return tud_audio_n_write_support_ff(0, channelId, data, len);
}
#endif
#endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
static inline uint16_t tud_audio_int_ctr_available(void) static inline uint16_t tud_audio_int_ctr_available(void)
{ {
return tud_audio_int_ctr_n_available(0); return tud_audio_int_ctr_n_available(0);
@ -370,25 +453,25 @@ static inline uint16_t tud_audio_int_ctr_read(void* buffer, uint16_t bufsize)
return tud_audio_int_ctr_n_read(0, buffer, bufsize); return tud_audio_int_ctr_n_read(0, buffer, bufsize);
} }
static inline void tud_audio_int_ctr_read_flush(void) static inline void tud_audio_int_ctr_clear(void)
{ {
return tud_audio_int_ctr_n_read_flush(0); return tud_audio_int_ctr_n_clear(0);
} }
static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t bufsize) static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t len)
{ {
return tud_audio_int_ctr_n_write(0, buffer, bufsize); return tud_audio_int_ctr_n_write(0, buffer, len);
} }
#endif #endif
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Internal Class Driver API // Internal Class Driver API
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
void audiod_init (void); void audiod_init (void);
void audiod_reset (uint8_t rhport); void audiod_reset (uint8_t rhport);
uint16_t audiod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len); uint16_t audiod_open (uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
bool audiod_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request); bool audiod_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
bool audiod_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes); bool audiod_xfer_cb (uint8_t rhport, uint8_t edpt_addr, xfer_result_t result, uint32_t xferred_bytes);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -125,23 +125,23 @@ void dcd_disconnect(uint8_t rhport) TU_ATTR_WEAK;
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) TU_ATTR_WEAK; void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const * request) TU_ATTR_WEAK;
// Configure endpoint's registers according to descriptor // Configure endpoint's registers according to descriptor
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc); bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc);
// Close an endpoint. // Close an endpoint.
// Since it is weak, caller must TU_ASSERT this function's existence before calling it. // Since it is weak, caller must TU_ASSERT this function's existence before calling it.
void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK; void dcd_edpt_close (uint8_t rhport, uint8_t ep_addr) TU_ATTR_WEAK;
// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack // Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
// Submit an ISO transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack // Submit an ISO transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff); bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes);
// Stall endpoint // Stall endpoint
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr);
// clear stall, data toggle is also reset to DATA0 // clear stall, data toggle is also reset to DATA0
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr); void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr);
//--------------------------------------------------------------------+ //--------------------------------------------------------------------+
// Event API (implemented by stack) // Event API (implemented by stack)

View File

@ -1206,12 +1206,16 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
} }
} }
bool usbd_edpt_iso_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff) // The number of bytes has to be given explicitly to allow more flexible control of how many
// bytes should be written and second to keep the return value free to give back a boolean
// success message. If total_bytes is too big, the FIFO will copy only what is available
// into the USB buffer!
bool usbd_edpt_iso_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
{ {
uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr);
TU_LOG2(" Queue ISO EP %02X with %u bytes ... ", ep_addr, tu_fifo_count(ff)); TU_LOG2(" Queue ISO EP %02X with %u bytes ... ", ep_addr, count);
// Attempt to transfer on a busy endpoint, sound like an race condition ! // Attempt to transfer on a busy endpoint, sound like an race condition !
TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0); TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0);
@ -1220,7 +1224,7 @@ bool usbd_edpt_iso_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff)
// and usbd task can preempt and clear the busy // and usbd task can preempt and clear the busy
_usbd_dev.ep_status[epnum][dir].busy = true; _usbd_dev.ep_status[epnum][dir].busy = true;
if ( dcd_edpt_iso_xfer(rhport, ep_addr, ff) ) if (dcd_edpt_iso_xfer(rhport, ep_addr, ff, total_bytes))
{ {
TU_LOG2("OK\r\n"); TU_LOG2("OK\r\n");
return true; return true;

View File

@ -73,7 +73,7 @@ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr);
bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
// Submit a usb ISO transfer by use of a FIFO (ring buffer) - all bytes in FIFO get transmitted // Submit a usb ISO transfer by use of a FIFO (ring buffer) - all bytes in FIFO get transmitted
bool usbd_edpt_iso_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff); bool usbd_edpt_iso_xfer(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes);
// Claim an endpoint before submitting a transfer. // Claim an endpoint before submitting a transfer.
// If caller does not make any transfer, it must release endpoint for others. // If caller does not make any transfer, it must release endpoint for others.

View File

@ -670,13 +670,15 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
return true; return true;
} }
bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff) // The number of bytes has to be given explicitly to allow more flexible control of how many
// bytes should be written and second to keep the return value free to give back a boolean
// success message. If total_bytes is too big, the FIFO will copy only what is available
// into the USB buffer!
bool dcd_edpt_iso_xfer (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes)
{ {
// USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1 // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1
TU_ASSERT(ff->item_size == 1); TU_ASSERT(ff->item_size == 1);
uint16_t total_bytes = tu_fifo_count(ff);
uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr);