#include "tusb_option.h"
#if (TUSB_OPT_DEVICE_ENABLED && CFG_TUD_AUDIO)
#include "device/usbd.h"
#include "device/usbd_pvt.h"
#include "audio_device.h"
#ifndef TUD_AUDIO_PREFER_RING_BUFFER
#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
#define TUD_AUDIO_PREFER_RING_BUFFER 0
#else
#define TUD_AUDIO_PREFER_RING_BUFFER 1
#endif
#endif
#if defined (STM32F105x8) || defined (STM32F105xB) || defined (STM32F105xC) || \
defined (STM32F107xB) || defined (STM32F107xC)
#define STM32F1_SYNOPSYS
#endif
#if defined (STM32L475xx) || defined (STM32L476xx) || \
defined (STM32L485xx) || defined (STM32L486xx) || defined (STM32L496xx) || \
defined (STM32L4R5xx) || defined (STM32L4R7xx) || defined (STM32L4R9xx) || \
defined (STM32L4S5xx) || defined (STM32L4S7xx) || defined (STM32L4S9xx)
#define STM32L4_SYNOPSYS
#endif
#if (CFG_TUSB_MCU == OPT_MCU_STM32F1 && defined(STM32F1_SYNOPSYS)) || \
CFG_TUSB_MCU == OPT_MCU_STM32F2 || \
CFG_TUSB_MCU == OPT_MCU_STM32F4 || \
CFG_TUSB_MCU == OPT_MCU_STM32F7 || \
CFG_TUSB_MCU == OPT_MCU_STM32H7 || \
(CFG_TUSB_MCU == OPT_MCU_STM32L4 && defined(STM32L4_SYNOPSYS)) || \
CFG_TUSB_MCU == OPT_MCU_RX63X || \
CFG_TUSB_MCU == OPT_MCU_RX65X || \
CFG_TUSB_MCU == OPT_MCU_RX72N || \
CFG_TUSB_MCU == OPT_MCU_GD32VF103 || \
CFG_TUSB_MCU == OPT_MCU_LPC18XX || \
CFG_TUSB_MCU == OPT_MCU_LPC43XX || \
CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
CFG_TUSB_MCU == OPT_MCU_MSP432E4
#if TUD_AUDIO_PREFER_RING_BUFFER
#define USE_LINEAR_BUFFER 0
#else
#define USE_LINEAR_BUFFER 1
#endif
#else
#define USE_LINEAR_BUFFER 1
#endif
#if CFG_TUD_AUDIO > 3
#error Maximum number of audio functions restricted to three!
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ];
#if CFG_FIFO_MUTEX
osal_mutex_def_t ep_in_ff_mutex_wr_1; #endif
#endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ];
#if CFG_FIFO_MUTEX
osal_mutex_def_t ep_in_ff_mutex_wr_2; #endif
#endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ];
#if CFG_FIFO_MUTEX
osal_mutex_def_t ep_in_ff_mutex_wr_3; #endif
#endif #endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING)
#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX];
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX];
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX];
#endif
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ];
#if CFG_FIFO_MUTEX
osal_mutex_def_t ep_out_ff_mutex_rd_1; #endif
#endif #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ];
#if CFG_FIFO_MUTEX
osal_mutex_def_t ep_out_ff_mutex_rd_2; #endif
#endif #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ];
#if CFG_FIFO_MUTEX
osal_mutex_def_t ep_out_ff_mutex_rd_3; #endif
#endif #endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX];
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX];
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX];
#endif
#endif
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ];
#if CFG_TUD_AUDIO > 1
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ];
#endif
#if CFG_TUD_AUDIO > 2
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ];
#endif
uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT];
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0
uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT];
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0
uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ];
tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; #endif
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ];
tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; #endif
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t tx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ];
tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; #endif
#endif
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ];
tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; #endif
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ];
tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; #endif
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t rx_supp_ff_buf_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO][CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ];
tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO];
#if CFG_FIFO_MUTEX
osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; #endif
#endif
#endif
typedef struct
{
uint8_t rhport;
uint8_t const * p_desc;
#if CFG_TUD_AUDIO_ENABLE_EP_IN
uint8_t ep_in; uint16_t ep_in_sz; uint8_t ep_in_as_intf_num; #endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
uint8_t ep_out; uint16_t ep_out_sz; uint8_t ep_out_as_intf_num;
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
uint8_t ep_fb; #endif
#endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
uint8_t ep_int_ctr; #endif
uint16_t desc_length;
uint8_t * ctrl_buf;
uint8_t ctrl_buf_sz;
uint8_t * alt_setting;
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
#if !CFG_TUD_AUDIO_ENABLE_DECODING
tu_fifo_t ep_out_ff;
#endif
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
uint32_t fb_val; #endif
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
tu_fifo_t ep_in_ff;
#endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE];
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
audio_format_type_t format_type_rx;
uint8_t n_channels_rx;
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
audio_data_format_type_I_t format_type_I_rx;
uint8_t n_bytes_per_sampe_rx;
uint8_t n_channels_per_ff_rx;
uint8_t n_ff_used_rx;
#endif
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
audio_format_type_t format_type_tx;
uint8_t n_channels_tx;
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
audio_data_format_type_I_t format_type_I_tx;
uint8_t n_bytes_per_sampe_tx;
uint8_t n_channels_per_ff_tx;
uint8_t n_ff_used_tx;
#endif
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
tu_fifo_t * rx_supp_ff;
uint8_t n_rx_supp_ff;
uint16_t rx_supp_ff_sz_max;
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
tu_fifo_t * tx_supp_ff;
uint8_t n_tx_supp_ff;
uint16_t tx_supp_ff_sz_max;
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
uint8_t * lin_buf_out;
#define USE_LINEAR_BUFFER_RX 1
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING)
uint8_t * lin_buf_in;
#define USE_LINEAR_BUFFER_TX 1
#endif
} audiod_function_t;
#ifndef USE_LINEAR_BUFFER_TX
#define USE_LINEAR_BUFFER_TX 0
#endif
#ifndef USE_LINEAR_BUFFER_RX
#define USE_LINEAR_BUFFER_RX 0
#endif
#define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ctrl_buf)
CFG_TUSB_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO];
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received);
#endif
#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received);
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN
static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t* audio);
#endif
#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio);
#endif
static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request);
static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request);
static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int);
static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio, uint8_t *idxItf, uint8_t const **pp_desc_int);
static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id);
static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id);
static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id);
static uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio);
#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING
static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const as_itf);
static inline uint8_t tu_desc_subtype(void const* desc)
{
return ((uint8_t const*) desc)[2];
}
#endif
bool tud_audio_n_mounted(uint8_t func_id)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO);
audiod_function_t* audio = &_audiod_fct[func_id];
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
if (audio->ep_out == 0) return false;
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN
if (audio->ep_in == 0) return false;
#endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
if (audio->ep_int_ctr == 0) return false;
#endif
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
if (audio->ep_fb == 0) return false;
#endif
return true;
}
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
uint16_t tud_audio_n_available(uint8_t func_id)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
return tu_fifo_count(&_audiod_fct[func_id].ep_out_ff);
}
uint16_t tud_audio_n_read(uint8_t func_id, void* buffer, uint16_t bufsize)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
return tu_fifo_read_n(&_audiod_fct[func_id].ep_out_ff, buffer, bufsize);
}
bool tud_audio_n_clear_ep_out_ff(uint8_t func_id)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
return tu_fifo_clear(&_audiod_fct[func_id].ep_out_ff);
}
tu_fifo_t* tud_audio_n_get_ep_out_ff(uint8_t func_id)
{
if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_out_ff;
return NULL;
}
#endif
#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
bool tud_audio_n_clear_rx_support_ff(uint8_t func_id, uint8_t ff_idx)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
return tu_fifo_clear(&_audiod_fct[func_id].rx_supp_ff[ff_idx]);
}
uint16_t tud_audio_n_available_support_ff(uint8_t func_id, uint8_t ff_idx)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
return tu_fifo_count(&_audiod_fct[func_id].rx_supp_ff[ff_idx]);
}
uint16_t tud_audio_n_read_support_ff(uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
return tu_fifo_read_n(&_audiod_fct[func_id].rx_supp_ff[ff_idx], buffer, bufsize);
}
tu_fifo_t* tud_audio_n_get_rx_support_ff(uint8_t func_id, uint8_t ff_idx)
{
if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff) return &_audiod_fct[func_id].rx_supp_ff[ff_idx];
return NULL;
}
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received)
{
uint8_t idxItf;
uint8_t const *dummy2;
uint8_t idx_audio_fct = 0;
if (tud_audio_rx_done_pre_read_cb || tud_audio_rx_done_post_read_cb)
{
idx_audio_fct = audiod_get_audio_fct_idx(audio);
TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio, &idxItf, &dummy2));
}
if (tud_audio_rx_done_pre_read_cb) TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf]));
#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
switch (audio->format_type_rx)
{
case AUDIO_FORMAT_TYPE_UNDEFINED:
TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n");
TU_BREAKPOINT();
break;
case AUDIO_FORMAT_TYPE_I:
switch (audio->format_type_I_tx)
{
case AUDIO_DATA_FORMAT_TYPE_I_PCM:
TU_VERIFY(audiod_decode_type_I_pcm(rhport, audio, n_bytes_received));
break;
default:
TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_RX encoding not implemented!\r\n");
TU_BREAKPOINT();
break;
}
break;
default:
TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented!\r\n");
TU_BREAKPOINT();
break;
}
TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false);
#else
#if USE_LINEAR_BUFFER_RX
TU_VERIFY(tu_fifo_write_n(&audio->ep_out_ff, audio->lin_buf_out, n_bytes_received));
TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false);
#else
TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false);
#endif
#endif
if (tud_audio_rx_done_post_read_cb) TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf]));
return true;
}
#endif
#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
static inline uint8_t * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesToCopy, void * dst, uint8_t * dst_end, uint8_t * src, uint8_t const n_ff_used)
{
typedef struct{
uint16_t val;
} __attribute((__packed__)) unaligned_uint16_t;
typedef struct{
uint32_t val;
} __attribute((__packed__)) unaligned_uint32_t;
switch (nBytesToCopy)
{
case 1:
while((uint8_t *)dst < dst_end)
{
*(uint8_t *)dst++ = *src;
src += n_ff_used;
}
break;
case 2:
while((uint8_t *)dst < dst_end)
{
*(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src;
dst += 2;
src += 2 * n_ff_used;
}
break;
case 3:
while((uint8_t *)dst < dst_end)
{
*(uint8_t *)dst++ = *src++;
*(uint8_t *)dst++ = *src++;
*(uint8_t *)dst++ = *src++;
src += 3 * (n_ff_used - 1);
}
break;
case 4:
while((uint8_t *)dst < dst_end)
{
*(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src;
dst += 4;
src += 4 * n_ff_used;
}
break;
}
return src;
}
static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received)
{
(void) rhport;
uint8_t const n_ff_used = audio->n_ff_used_rx;
uint16_t const nBytesPerFFToRead = n_bytes_received / n_ff_used;
uint8_t cnt_ff;
uint8_t * src;
uint8_t * dst_end;
tu_fifo_buffer_info_t info;
for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++)
{
tu_fifo_get_write_info(&audio->rx_supp_ff[cnt_ff], &info);
if (info.len_lin != 0)
{
info.len_lin = tu_min16(nBytesPerFFToRead, info.len_lin);
src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sampe_rx];
dst_end = info.ptr_lin + info.len_lin;
src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_lin, dst_end, src, n_ff_used);
info.len_wrap = tu_min16(nBytesPerFFToRead - info.len_lin, info.len_wrap);
if (info.len_wrap != 0)
{
dst_end = info.ptr_wrap + info.len_wrap;
audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sampe_rx, info.ptr_wrap, dst_end, src, n_ff_used);
}
tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
}
}
return true;
}
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
uint16_t tud_audio_n_write(uint8_t func_id, const void * data, uint16_t len)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
return tu_fifo_write_n(&_audiod_fct[func_id].ep_in_ff, data, len);
}
bool tud_audio_n_clear_ep_in_ff(uint8_t func_id) {
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
return tu_fifo_clear(&_audiod_fct[func_id].ep_in_ff);
}
tu_fifo_t* tud_audio_n_get_ep_in_ff(uint8_t func_id)
{
if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_in_ff;
return NULL;
}
#endif
#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
uint16_t tud_audio_n_flush_tx_support_ff(uint8_t func_id) {
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
audiod_function_t* audio = &_audiod_fct[func_id];
uint16_t n_bytes_copied = tu_fifo_count(&audio->tx_supp_ff[0]);
TU_VERIFY(audiod_tx_done_cb(audio->rhport, audio));
n_bytes_copied -= tu_fifo_count(&audio->tx_supp_ff[0]);
n_bytes_copied = n_bytes_copied*audio->tx_supp_ff[0].item_size;
return n_bytes_copied;
}
bool tud_audio_n_clear_tx_support_ff(uint8_t func_id, uint8_t ff_idx)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff);
return tu_fifo_clear(&_audiod_fct[func_id].tx_supp_ff[ff_idx]);
}
uint16_t tud_audio_n_write_support_ff(uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff);
return tu_fifo_write_n(&_audiod_fct[func_id].tx_supp_ff[ff_idx], data, len);
}
tu_fifo_t* tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx)
{
if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff) return &_audiod_fct[func_id].tx_supp_ff[ff_idx];
return NULL;
}
#endif
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
uint16_t tud_audio_int_ctr_n_write(uint8_t func_id, uint8_t const* buffer, uint16_t len)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
TU_VERIFY(!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr));
TU_VERIFY(len <= CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE);
memcpy(_audiod_fct[func_id].ep_int_ctr_buf, buffer, len);
TU_VERIFY(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr, _audiod_fct[func_id].ep_int_ctr_buf, len));
return true;
}
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN
static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio)
{
uint8_t idxItf;
uint8_t const *dummy2;
uint8_t idx_audio_fct = audiod_get_audio_fct_idx(audio);
TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, audio, &idxItf, &dummy2));
if (audio->alt_setting[idxItf] == 0) return false;
if (tud_audio_tx_done_pre_load_cb) TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf]));
uint16_t n_bytes_tx;
#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
switch (audio->format_type_tx)
{
case AUDIO_FORMAT_TYPE_UNDEFINED:
TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n");
TU_BREAKPOINT();
n_bytes_tx = 0;
break;
case AUDIO_FORMAT_TYPE_I:
switch (audio->format_type_I_tx)
{
case AUDIO_DATA_FORMAT_TYPE_I_PCM:
n_bytes_tx = audiod_encode_type_I_pcm(rhport, audio);
break;
default:
TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_TX encoding not implemented!\r\n");
TU_BREAKPOINT();
n_bytes_tx = 0;
break;
}
break;
default:
TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!\r\n");
TU_BREAKPOINT();
n_bytes_tx = 0;
break;
}
TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx));
#else
n_bytes_tx = tu_min16(tu_fifo_count(&audio->ep_in_ff), audio->ep_in_sz);
#if USE_LINEAR_BUFFER_TX
tu_fifo_read_n(&audio->ep_in_ff, audio->lin_buf_in, n_bytes_tx);
TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx));
#else
TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx));
#endif
#endif
if (tud_audio_tx_done_post_load_cb) TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf]));
return true;
}
#endif
#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
static inline uint8_t * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesToCopy, uint8_t * src, uint8_t * src_end, uint8_t * dst, uint8_t const n_ff_used)
{
typedef struct{
uint16_t val;
} __attribute((__packed__)) unaligned_uint16_t;
typedef struct{
uint32_t val;
} __attribute((__packed__)) unaligned_uint32_t;
switch (nBytesToCopy)
{
case 1:
while(src < src_end)
{
*dst = *src++;
dst += n_ff_used;
}
break;
case 2:
while(src < src_end)
{
*(unaligned_uint16_t*)dst = *(unaligned_uint16_t*)src;
src += 2;
dst += 2 * n_ff_used;
}
break;
case 3:
while(src < src_end)
{
*dst++ = *src++;
*dst++ = *src++;
*dst++ = *src++;
dst += 3 * (n_ff_used - 1);
}
break;
case 4:
while(src < src_end)
{
*(unaligned_uint32_t*)dst = *(unaligned_uint32_t*)src;
src += 4;
dst += 4 * n_ff_used;
}
break;
}
return dst;
}
static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio)
{
TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in));
uint8_t const n_ff_used = audio->n_ff_used_tx;
uint16_t const nBytesToCopy = audio->n_channels_per_ff_tx * audio->n_bytes_per_sampe_tx;
uint16_t const capPerFF = audio->ep_in_sz / n_ff_used; uint16_t nBytesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]);
uint8_t cnt_ff;
for (cnt_ff = 1; cnt_ff < n_ff_used; cnt_ff++)
{
uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cnt_ff]);
if (count < nBytesPerFFToSend)
{
nBytesPerFFToSend = count;
}
}
if (nBytesPerFFToSend == 0) return 0;
nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, capPerFF);
nBytesPerFFToSend = (nBytesPerFFToSend / nBytesToCopy) * nBytesToCopy;
uint8_t * dst;
uint8_t * src_end;
tu_fifo_buffer_info_t info;
for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++)
{
dst = &audio->lin_buf_in[cnt_ff*audio->n_channels_per_ff_tx*audio->n_bytes_per_sampe_tx];
tu_fifo_get_read_info(&audio->tx_supp_ff[cnt_ff], &info);
if (info.len_lin != 0)
{
info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin); src_end = (uint8_t *)info.ptr_lin + info.len_lin;
dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_lin, src_end, dst, n_ff_used);
info.len_wrap = tu_min16(nBytesPerFFToSend - info.len_lin, info.len_wrap);
if (info.len_wrap != 0)
{
src_end = (uint8_t *)info.ptr_wrap + info.len_wrap;
audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sampe_tx, info.ptr_wrap, src_end, dst, n_ff_used);
}
tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
}
}
return nBytesPerFFToSend * n_ff_used;
}
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
static inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio)
{
return usbd_edpt_xfer(rhport, audio->ep_fb, (uint8_t *) &audio->fb_val, 4);
}
#endif
void audiod_init(void)
{
tu_memclr(_audiod_fct, sizeof(_audiod_fct));
for(uint8_t i=0; i<CFG_TUD_AUDIO; i++)
{
audiod_function_t* audio = &_audiod_fct[i];
switch (i)
{
case 0:
audio->ctrl_buf = ctrl_buf_1;
audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ;
break;
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ > 0
case 1:
audio->ctrl_buf = ctrl_buf_2;
audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ;
break;
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ > 0
case 2:
audio->ctrl_buf = ctrl_buf_3;
audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ;
break;
#endif
}
switch (i)
{
#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0
case 0:
audio->alt_setting = alt_setting_1;
break;
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0
case 1:
audio->alt_setting = alt_setting_2;
break;
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0
case 2:
audio->alt_setting = alt_setting_3;
break;
#endif
}
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
switch (i)
{
#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
case 0:
tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, 1, true);
#if CFG_FIFO_MUTEX
tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_1), NULL);
#endif
break;
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
case 1:
tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, 1, true);
#if CFG_FIFO_MUTEX
tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_2), NULL);
#endif
break;
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
case 2:
tu_fifo_config(&audio->ep_in_ff, audio_ep_in_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, 1, true);
#if CFG_FIFO_MUTEX
tu_fifo_config_mutex(&audio->ep_in_ff, osal_mutex_create(&ep_in_ff_mutex_wr_3), NULL);
#endif
break;
#endif
}
#endif
#if USE_LINEAR_BUFFER_TX
switch (i)
{
#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0
case 0:
audio->lin_buf_in = lin_buf_in_1;
break;
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0
case 1:
audio->lin_buf_in = lin_buf_in_2;
break;
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0
case 2:
audio->lin_buf_in = lin_buf_in_3;
break;
#endif
}
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
switch (i)
{
#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
case 0:
tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, 1, true);
#if CFG_FIFO_MUTEX
tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_1));
#endif
break;
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
case 1:
tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, 1, true);
#if CFG_FIFO_MUTEX
tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_2));
#endif
break;
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
case 2:
tu_fifo_config(&audio->ep_out_ff, audio_ep_out_sw_buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, 1, true);
#if CFG_FIFO_MUTEX
tu_fifo_config_mutex(&audio->ep_out_ff, NULL, osal_mutex_create(&ep_out_ff_mutex_rd_3));
#endif
break;
#endif
}
#endif
#if USE_LINEAR_BUFFER_RX
switch (i)
{
#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0
case 0:
audio->lin_buf_out = lin_buf_out_1;
break;
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0
case 1:
audio->lin_buf_out = lin_buf_out_2;
break;
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0
case 2:
audio->lin_buf_out = lin_buf_out_3;
break;
#endif
}
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
switch (i)
{
#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
case 0:
audio->tx_supp_ff = tx_supp_ff_1;
audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO;
audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ;
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++)
{
tu_fifo_config(&tx_supp_ff_1[cnt], tx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ, 1, true);
#if CFG_FIFO_MUTEX
tu_fifo_config_mutex(&tx_supp_ff_1[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_1[cnt]), NULL);
#endif
}
break;
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
case 1:
audio->tx_supp_ff = tx_supp_ff_2;
audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO;
audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ;
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; cnt++)
{
tu_fifo_config(&tx_supp_ff_2[cnt], tx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ, 1, true);
#if CFG_FIFO_MUTEX
tu_fifo_config_mutex(&tx_supp_ff_2[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_2[cnt]), NULL);
#endif
}
break;
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
case 2:
audio->tx_supp_ff = tx_supp_ff_3;
audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO;
audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ;
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; cnt++)
{
tu_fifo_config(&tx_supp_ff_3[cnt], tx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ, 1, true);
#if CFG_FIFO_MUTEX
tu_fifo_config_mutex(&tx_supp_ff_3[cnt], osal_mutex_create(&tx_supp_ff_mutex_wr_3[cnt]), NULL);
#endif
}
break;
#endif }
#endif
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
switch (i)
{
#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
case 0:
audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX;
break;
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
case 1:
audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX;
break;
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
case 2:
audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX;
break;
#endif
}
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
switch (i)
{
#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
case 0:
audio->rx_supp_ff = rx_supp_ff_1;
audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO;
audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ;
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; cnt++)
{
tu_fifo_config(&rx_supp_ff_1[cnt], rx_supp_ff_buf_1[cnt], CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ, 1, true);
#if CFG_FIFO_MUTEX
tu_fifo_config_mutex(&rx_supp_ff_1[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_1[cnt]), NULL);
#endif
}
break;
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
case 1:
audio->rx_supp_ff = rx_supp_ff_2;
audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO;
audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ;
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; cnt++)
{
tu_fifo_config(&rx_supp_ff_2[cnt], rx_supp_ff_buf_2[cnt], CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ, 1, true);
#if CFG_FIFO_MUTEX
tu_fifo_config_mutex(&rx_supp_ff_2[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_2[cnt]), NULL);
#endif
}
break;
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
case 2:
audio->rx_supp_ff = rx_supp_ff_3;
audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO;
audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ;
for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; cnt++)
{
tu_fifo_config(&rx_supp_ff_3[cnt], rx_supp_ff_buf_3[cnt], CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ, 1, true);
#if CFG_FIFO_MUTEX
tu_fifo_config_mutex(&rx_supp_ff_3[cnt], osal_mutex_create(&rx_supp_ff_mutex_rd_3[cnt]), NULL);
#endif
}
break;
#endif }
#endif
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
switch (i)
{
#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
case 0:
audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX;
break;
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
case 1:
audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX;
break;
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
case 2:
audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX;
break;
#endif
}
#endif }
}
void audiod_reset(uint8_t rhport)
{
(void) rhport;
for(uint8_t i=0; i<CFG_TUD_AUDIO; i++)
{
audiod_function_t* audio = &_audiod_fct[i];
tu_memclr(audio, ITF_MEM_RESET_SIZE);
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
tu_fifo_clear(&audio->ep_in_ff);
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
tu_fifo_clear(&audio->ep_out_ff);
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++)
{
tu_fifo_clear(&audio->tx_supp_ff[cnt]);
}
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++)
{
tu_fifo_clear(&audio->rx_supp_ff[cnt]);
}
#endif
}
}
uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
{
(void) max_len;
TU_VERIFY ( TUSB_CLASS_AUDIO == itf_desc->bInterfaceClass &&
AUDIO_SUBCLASS_CONTROL == itf_desc->bInterfaceSubClass);
TU_VERIFY(itf_desc->bInterfaceProtocol == AUDIO_INT_PROTOCOL_CODE_V2);
if (itf_desc->bNumEndpoints == 1) {
TU_VERIFY(CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0);
}
TU_VERIFY(itf_desc->bAlternateSetting == 0);
uint8_t i;
for (i = 0; i < CFG_TUD_AUDIO; i++)
{
if (!_audiod_fct[i].p_desc)
{
_audiod_fct[i].p_desc = (uint8_t const *)itf_desc; _audiod_fct[i].rhport = rhport;
switch (i)
{
case 0:
_audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_1_DESC_LEN;
break;
#if CFG_TUD_AUDIO > 1
case 1:
_audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_2_DESC_LEN;
break;
#endif
#if CFG_TUD_AUDIO > 2
case 2:
_audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_3_DESC_LEN;
break;
#endif
}
break;
}
}
TU_ASSERT( i < CFG_TUD_AUDIO );
uint16_t drv_len = _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
return drv_len;
}
static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request)
{
uint8_t const itf = tu_u16_low(p_request->wIndex);
uint8_t func_id, idxItf;
uint8_t const *dummy;
TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &dummy));
TU_VERIFY(tud_control_xfer(rhport, p_request, &_audiod_fct[func_id].alt_setting[idxItf], 1));
TU_LOG2(" Get itf: %u - current alt: %u\r\n", itf, _audiod_fct[func_id].alt_setting[idxItf]);
return true;
}
static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request)
{
(void) rhport;
uint8_t const itf = tu_u16_low(p_request->wIndex);
uint8_t const alt = tu_u16_low(p_request->wValue);
TU_LOG2(" Set itf: %u - alt: %u\r\n", itf, alt);
uint8_t func_id, idxItf;
uint8_t const *p_desc;
TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &p_desc));
audiod_function_t* audio = &_audiod_fct[func_id];
#if CFG_TUD_AUDIO_ENABLE_EP_IN
if (audio->ep_in_as_intf_num == itf)
{
audio->ep_in_as_intf_num = 0;
usbd_edpt_close(rhport, audio->ep_in);
#if !CFG_TUD_AUDIO_ENABLE_ENCODING
tu_fifo_clear(&audio->ep_in_ff);
#else
for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++)
{
tu_fifo_clear(&audio->tx_supp_ff[cnt]);
}
#endif
if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
audio->ep_in = 0;
}
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
if (audio->ep_out_as_intf_num == itf)
{
audio->ep_out_as_intf_num = 0;
usbd_edpt_close(rhport, audio->ep_out);
#if !CFG_TUD_AUDIO_ENABLE_DECODING
tu_fifo_clear(&audio->ep_out_ff);
#else
for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++)
{
tu_fifo_clear(&audio->rx_supp_ff[cnt]);
}
#endif
if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
audio->ep_out = 0;
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
usbd_edpt_close(rhport, audio->ep_fb);
audio->ep_fb = 0; #endif
}
#endif
audio->alt_setting[idxItf] = alt;
uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN;
while (p_desc < p_desc_end)
{
if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == alt)
{
#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING
uint8_t const * p_desc_parse_for_params = p_desc;
#endif
uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints;
while (foundEPs < nEps && p_desc < p_desc_end)
{
if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT)
{
tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc;
TU_ASSERT(usbd_edpt_open(rhport, desc_ep));
uint8_t const ep_addr = desc_ep->bEndpointAddress;
usbd_edpt_clear_stall(rhport, ep_addr);
#if CFG_TUD_AUDIO_ENABLE_EP_IN
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 0x00) {
audio->ep_in = ep_addr;
audio->ep_in_as_intf_num = itf;
audio->ep_in_sz = tu_edpt_packet_size(desc_ep);
#if CFG_TUD_AUDIO_ENABLE_ENCODING
audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf);
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
const uint16_t active_fifo_depth = (audio->tx_supp_ff_sz_max / audio->n_bytes_per_sampe_tx) * audio->n_bytes_per_sampe_tx;
for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++)
{
tu_fifo_config(&audio->tx_supp_ff[cnt], audio->tx_supp_ff[cnt].buffer, active_fifo_depth, 1, true);
}
audio->n_ff_used_tx = audio->n_channels_tx / audio->n_channels_per_ff_tx;
TU_ASSERT( audio->n_ff_used_tx <= audio->n_tx_supp_ff );
#endif
#endif
if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_fct[func_id]));
}
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) {
audio->ep_out = ep_addr;
audio->ep_out_as_intf_num = itf;
audio->ep_out_sz = tu_edpt_packet_size(desc_ep);
#if CFG_TUD_AUDIO_ENABLE_DECODING
audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf);
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sampe_rx) * audio->n_bytes_per_sampe_rx;
for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++)
{
tu_fifo_config(&audio->rx_supp_ff[cnt], audio->rx_supp_ff[cnt].buffer, active_fifo_depth, 1, true);
}
audio->n_ff_used_rx = audio->n_channels_rx / audio->n_channels_per_ff_rx;
TU_ASSERT( audio->n_ff_used_rx <= audio->n_rx_supp_ff );
#endif
#endif
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
if ( !(desc_ep->bmAttributes.sync == 0x01 && audio->ep_fb == 0) )
{
if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
}
#else
if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
#endif
#if USE_LINEAR_BUFFER_RX
TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false);
#else
TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false);
#endif
}
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 1) {
audio->ep_fb = ep_addr;
if (audio->ep_out != 0)
{
if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
}
}
#endif
#endif
foundEPs += 1;
}
p_desc = tu_desc_next(p_desc);
}
TU_VERIFY(foundEPs == nEps);
break;
}
p_desc = tu_desc_next(p_desc);
}
tud_control_status(rhport, p_request);
return true;
}
static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const * p_request)
{
if(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && p_request->bmRequestType_bit.direction == TUSB_DIR_OUT)
{
uint8_t func_id;
switch (p_request->bmRequestType_bit.recipient)
{
case TUSB_REQ_RCPT_INTERFACE:
{
uint8_t itf = TU_U16_LOW(p_request->wIndex);
uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
if (entityID != 0)
{
if (tud_audio_set_req_entity_cb)
{
TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
}
else
{
TU_LOG2(" No entity set request callback available!\r\n");
return false; }
}
else
{
if (tud_audio_set_req_itf_cb)
{
TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
}
else
{
TU_LOG2(" No interface set request callback available!\r\n");
return false; }
}
}
break;
case TUSB_REQ_RCPT_ENDPOINT:
{
uint8_t ep = TU_U16_LOW(p_request->wIndex);
if (tud_audio_set_req_ep_cb)
{
TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
}
else
{
TU_LOG2(" No EP set request callback available!\r\n");
return false; }
}
break;
default: TU_BREAKPOINT(); return false;
}
}
return true;
}
static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const * p_request)
{
(void) rhport;
if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD)
{
switch (p_request->bRequest)
{
case TUSB_REQ_GET_INTERFACE:
return audiod_get_interface(rhport, p_request);
case TUSB_REQ_SET_INTERFACE:
return audiod_set_interface(rhport, p_request);
default: TU_BREAKPOINT(); return false;
}
}
if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS)
{
uint8_t itf = TU_U16_LOW(p_request->wIndex);
uint8_t func_id;
switch (p_request->bmRequestType_bit.recipient)
{
case TUSB_REQ_RCPT_INTERFACE:
{
uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
if (entityID != 0)
{
TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
{
if (tud_audio_get_req_entity_cb)
{
return tud_audio_get_req_entity_cb(rhport, p_request);
}
else
{
TU_LOG2(" No entity get request callback available!\r\n");
return false; }
}
}
else
{
TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
{
if (tud_audio_get_req_itf_cb)
{
return tud_audio_get_req_itf_cb(rhport, p_request);
}
else
{
TU_LOG2(" No interface get request callback available!\r\n");
return false; }
}
}
}
break;
case TUSB_REQ_RCPT_ENDPOINT:
{
uint8_t ep = TU_U16_LOW(p_request->wIndex);
TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
{
if (tud_audio_get_req_ep_cb)
{
return tud_audio_get_req_ep_cb(rhport, p_request);
}
else
{
TU_LOG2(" No EP get request callback available!\r\n");
return false; }
}
}
break;
default: TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false;
}
TU_VERIFY(tud_control_xfer(rhport, p_request, _audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz));
return true;
}
TU_BREAKPOINT();
return false;
}
bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
{
if ( stage == CONTROL_STAGE_SETUP )
{
return audiod_control_request(rhport, request);
}
else if ( stage == CONTROL_STAGE_DATA )
{
return audiod_control_complete(rhport, request);
}
return true;
}
bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
{
(void) result;
(void) xferred_bytes;
uint8_t func_id;
for (func_id = 0; func_id < CFG_TUD_AUDIO; func_id++)
{
#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
if (_audiod_fct[func_id].ep_int_ctr == ep_addr)
{
if (tud_audio_int_ctr_done_cb) TU_VERIFY(tud_audio_int_ctr_done_cb(rhport, (uint16_t) xferred_bytes));
}
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN
if (_audiod_fct[func_id].ep_in == ep_addr && _audiod_fct[func_id].alt_setting != 0)
{
TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_fct[func_id]));
return true;
}
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
if (_audiod_fct[func_id].ep_out == ep_addr)
{
TU_VERIFY(audiod_rx_done_cb(rhport, &_audiod_fct[func_id], (uint16_t) xferred_bytes));
return true;
}
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
if (_audiod_fct[func_id].ep_fb == ep_addr)
{
if (tud_audio_fb_done_cb) TU_VERIFY(tud_audio_fb_done_cb(rhport));
if (!usbd_edpt_busy(rhport, _audiod_fct[func_id].ep_fb))
{
return audiod_fb_send(rhport, &_audiod_fct[func_id]);
}
}
#endif
#endif
}
return false;
}
bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len)
{
if (p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) return false;
uint8_t func_id;
uint8_t itf = TU_U16_LOW(p_request->wIndex);
switch (p_request->bmRequestType_bit.recipient)
{
case TUSB_REQ_RCPT_INTERFACE:
{
uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
if (entityID != 0)
{
TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
}
else
{
TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
}
}
break;
case TUSB_REQ_RCPT_ENDPOINT:
{
uint8_t ep = TU_U16_LOW(p_request->wIndex);
TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
}
break;
default: TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false;
}
if (len > _audiod_fct[func_id].ctrl_buf_sz) len = _audiod_fct[func_id].ctrl_buf_sz;
memcpy((void *)_audiod_fct[func_id].ctrl_buf, data, (size_t)len);
return tud_control_xfer(rhport, p_request, (void*)_audiod_fct[func_id].ctrl_buf, len);
}
static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio, uint8_t *idxItf, uint8_t const **pp_desc_int)
{
if (audio->p_desc)
{
uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN;
uint8_t const *p_desc = tu_desc_next(audio->p_desc);
p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength;
uint8_t tmp = 0;
while (p_desc < p_desc_end)
{
if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0)
{
if (((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf)
{
*idxItf = tmp;
*pp_desc_int = p_desc;
return true;
}
tmp++;
}
p_desc = tu_desc_next(p_desc);
}
}
return false;
}
static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int)
{
uint8_t i;
for (i = 0; i < CFG_TUD_AUDIO; i++)
{
if (audiod_get_AS_interface_index(itf, &_audiod_fct[i], idxItf, pp_desc_int))
{
*func_id = i;
return true;
}
}
return false;
}
static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id)
{
uint8_t i;
for (i = 0; i < CFG_TUD_AUDIO; i++)
{
if (_audiod_fct[i].p_desc && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf)
{
uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc); uint8_t const *p_desc_end = ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength + p_desc;
p_desc = tu_desc_next(p_desc);
while (p_desc < p_desc_end)
{
if (p_desc[3] == entityID) {
*func_id = i;
return true;
}
p_desc = tu_desc_next(p_desc);
}
}
}
return false;
}
static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id)
{
uint8_t i;
for (i = 0; i < CFG_TUD_AUDIO; i++)
{
if (_audiod_fct[i].p_desc)
{
uint8_t const *p_desc = _audiod_fct[i].p_desc;
uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
while (p_desc < p_desc_end)
{
if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf)
{
*func_id = i;
return true;
}
p_desc = tu_desc_next(p_desc);
}
}
}
return false;
}
static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id)
{
uint8_t i;
for (i = 0; i < CFG_TUD_AUDIO; i++)
{
if (_audiod_fct[i].p_desc)
{
uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length;
uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc);
p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength;
while (p_desc < p_desc_end)
{
if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT && ((tusb_desc_endpoint_t const * )p_desc)->bEndpointAddress == ep)
{
*func_id = i;
return true;
}
p_desc = tu_desc_next(p_desc);
}
}
}
return false;
}
#if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_ENABLE_DECODING
static void audiod_parse_for_AS_params(audiod_function_t* audio, uint8_t const * p_desc, uint8_t const * p_desc_end, uint8_t const as_itf)
{
p_desc = tu_desc_next(p_desc);
while (p_desc < p_desc_end)
{
if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) break;
if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_AS_GENERAL)
{
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) break; #endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT
if (as_itf != audio->ep_in_as_intf_num) break;
#endif
#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
if (as_itf != audio->ep_out_as_intf_num) break;
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN
if (as_itf == audio->ep_in_as_intf_num)
{
audio->n_channels_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels;
audio->format_type_tx = (audio_format_type_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType);
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
audio->format_type_I_tx = (audio_data_format_type_I_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats);
#endif
}
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
if (as_itf == audio->ep_out_as_intf_num)
{
audio->n_channels_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels;
audio->format_type_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType;
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
audio->format_type_I_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats;
#endif
}
#endif
}
#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && tu_desc_subtype(p_desc) == AUDIO_CS_AS_INTERFACE_FORMAT_TYPE && ((audio_desc_type_I_format_t const * )p_desc)->bFormatType == AUDIO_FORMAT_TYPE_I)
{
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) break; #endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT
if (as_itf != audio->ep_in_as_intf_num) break;
#endif
#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
if (as_itf != audio->ep_out_as_intf_num) break;
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN
if (as_itf == audio->ep_in_as_intf_num)
{
audio->n_bytes_per_sampe_tx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize;
}
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
if (as_itf == audio->ep_out_as_intf_num)
{
audio->n_bytes_per_sampe_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize;
}
#endif
}
#endif
p_desc = tu_desc_next(p_desc);
}
}
#endif
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback)
{
TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION
if ( TUSB_SPEED_FULL == tud_speed_get() )
{
uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].fb_val;
*(fb++) = (feedback >> 2) & 0xFF;
*(fb++) = (feedback >> 10) & 0xFF;
*(fb++) = (feedback >> 18) & 0xFF;
*fb = 0;
}else
#else
{
_audiod_fct[func_id].fb_val = feedback;
}
#endif
if (!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb))
{
return audiod_fb_send(_audiod_fct[func_id].rhport, &_audiod_fct[func_id]);
}
return true;
}
#endif
uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio)
{
for (uint8_t cnt=0; cnt < CFG_TUD_AUDIO; cnt++)
{
if (&_audiod_fct[cnt] == audio) return cnt;
}
return 0;
}
#endif