|
|
|
|
@@ -2,6 +2,7 @@
|
|
|
|
|
* The MIT License (MIT)
|
|
|
|
|
*
|
|
|
|
|
* Copyright (c) 2020 Reinhard Panhuber, Jerzy Kasenberg
|
|
|
|
|
* Copyright (c) 2023 HiFiPhile
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
|
@@ -65,8 +66,10 @@
|
|
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
|
|
|
|
|
|
// Use ring buffer if it's available, some MCUs need extra RAM requirements
|
|
|
|
|
// For DWC2 enable ring buffer will disable DMA (if available)
|
|
|
|
|
#ifndef TUD_AUDIO_PREFER_RING_BUFFER
|
|
|
|
|
#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX
|
|
|
|
|
#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX || \
|
|
|
|
|
defined(TUP_USBIP_DWC2)
|
|
|
|
|
#define TUD_AUDIO_PREFER_RING_BUFFER 0
|
|
|
|
|
#else
|
|
|
|
|
#define TUD_AUDIO_PREFER_RING_BUFFER 1
|
|
|
|
|
@@ -118,23 +121,23 @@
|
|
|
|
|
// EP IN software buffers and mutexes
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
|
|
|
|
|
#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
|
|
|
|
|
IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ];
|
|
|
|
|
tu_static IN_SW_BUF_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; // No need for read mutex as only USB driver reads from FIFO
|
|
|
|
|
tu_static osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO
|
|
|
|
|
#endif
|
|
|
|
|
#endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
|
|
|
|
|
IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ];
|
|
|
|
|
tu_static IN_SW_BUF_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; // No need for read mutex as only USB driver reads from FIFO
|
|
|
|
|
tu_static osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO
|
|
|
|
|
#endif
|
|
|
|
|
#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
|
|
|
|
|
IN_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_in_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ];
|
|
|
|
|
tu_static IN_SW_BUF_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; // No need for read mutex as only USB driver reads from FIFO
|
|
|
|
|
tu_static osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO
|
|
|
|
|
#endif
|
|
|
|
|
#endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
|
|
|
|
|
#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
|
|
|
|
|
@@ -144,38 +147,38 @@
|
|
|
|
|
// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into
|
|
|
|
|
#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_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_1[CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX];
|
|
|
|
|
tu_static CFG_TUD_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_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_2[CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX];
|
|
|
|
|
tu_static CFG_TUD_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_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX];
|
|
|
|
|
tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_in_3[CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX];
|
|
|
|
|
#endif
|
|
|
|
|
#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
|
|
|
|
|
|
|
|
|
|
// EP OUT software buffers and mutexes
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
|
|
|
|
|
#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
|
|
|
|
|
OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ];
|
|
|
|
|
tu_static OUT_SW_BUF_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; // No need for write mutex as only USB driver writes into FIFO
|
|
|
|
|
tu_static osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO
|
|
|
|
|
#endif
|
|
|
|
|
#endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
|
|
|
|
|
OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ];
|
|
|
|
|
tu_static OUT_SW_BUF_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; // No need for write mutex as only USB driver writes into FIFO
|
|
|
|
|
tu_static osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO
|
|
|
|
|
#endif
|
|
|
|
|
#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
|
|
|
|
|
OUT_SW_BUF_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t audio_ep_out_sw_buf_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ];
|
|
|
|
|
tu_static OUT_SW_BUF_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; // No need for write mutex as only USB driver writes into FIFO
|
|
|
|
|
tu_static osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO
|
|
|
|
|
#endif
|
|
|
|
|
#endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
|
|
|
|
|
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
|
|
|
|
|
@@ -185,89 +188,89 @@
|
|
|
|
|
// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into
|
|
|
|
|
#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_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_1[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX];
|
|
|
|
|
tu_static CFG_TUD_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_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_2[CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX];
|
|
|
|
|
tu_static CFG_TUD_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_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX];
|
|
|
|
|
tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t lin_buf_out_3[CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX];
|
|
|
|
|
#endif
|
|
|
|
|
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
|
|
|
|
|
|
|
|
|
|
// Control buffers
|
|
|
|
|
CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ];
|
|
|
|
|
tu_static CFG_TUD_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_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ];
|
|
|
|
|
tu_static CFG_TUD_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_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ];
|
|
|
|
|
tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ];
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Active alternate setting of interfaces
|
|
|
|
|
uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT];
|
|
|
|
|
tu_static 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];
|
|
|
|
|
tu_static 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];
|
|
|
|
|
tu_static uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Software encoding/decoding support FIFOs
|
|
|
|
|
#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_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];
|
|
|
|
|
tu_static 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_static 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]; // No need for read mutex as only USB driver reads from FIFO
|
|
|
|
|
tu_static osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
|
|
|
|
|
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];
|
|
|
|
|
tu_static 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_static 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]; // No need for read mutex as only USB driver reads from FIFO
|
|
|
|
|
tu_static osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from FIFO
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
|
|
|
|
|
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];
|
|
|
|
|
tu_static 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_static 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]; // No need for read mutex as only USB driver reads from FIFO
|
|
|
|
|
tu_static osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]; // No need for read mutex as only USB driver reads from 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_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];
|
|
|
|
|
tu_static 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_static 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]; // No need for write mutex as only USB driver writes into FIFO
|
|
|
|
|
tu_static osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
|
|
|
|
|
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];
|
|
|
|
|
tu_static 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_static 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]; // No need for write mutex as only USB driver writes into FIFO
|
|
|
|
|
tu_static osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
|
|
|
|
|
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];
|
|
|
|
|
tu_static 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_static 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]; // No need for write mutex as only USB driver writes into FIFO
|
|
|
|
|
tu_static osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]; // No need for write mutex as only USB driver writes into FIFO
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
@@ -300,19 +303,18 @@ typedef struct
|
|
|
|
|
|
|
|
|
|
bool mounted; // Device opened
|
|
|
|
|
|
|
|
|
|
/*------------- From this point, data is not cleared by bus reset -------------*/
|
|
|
|
|
|
|
|
|
|
uint16_t desc_length; // Length of audio function descriptor
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
|
|
|
|
|
struct {
|
|
|
|
|
CFG_TUSB_MEM_ALIGN uint32_t value; // Feedback value for asynchronous mode (in 16.16 format).
|
|
|
|
|
CFG_TUSB_MEM_ALIGN uint32_t send_buf;
|
|
|
|
|
uint32_t value; // Feedback value for asynchronous mode (in 16.16 format).
|
|
|
|
|
uint32_t min_value; // min value according to UAC2 FMT-2.0 section 2.3.1.1.
|
|
|
|
|
uint32_t max_value; // max value according to UAC2 FMT-2.0 section 2.3.1.1.
|
|
|
|
|
|
|
|
|
|
uint8_t frame_shift; // bInterval-1 in unit of frame (FS), micro-frame (HS)
|
|
|
|
|
uint8_t compute_method;
|
|
|
|
|
|
|
|
|
|
bool format_correction;
|
|
|
|
|
union {
|
|
|
|
|
uint8_t power_of_2; // pre-computed power of 2 shift
|
|
|
|
|
float float_const; // pre-computed float constant
|
|
|
|
|
@@ -322,12 +324,12 @@ typedef struct
|
|
|
|
|
uint32_t mclk_freq;
|
|
|
|
|
}fixed;
|
|
|
|
|
|
|
|
|
|
#if 0 // implement later
|
|
|
|
|
struct {
|
|
|
|
|
uint32_t nominal_value;
|
|
|
|
|
uint32_t threshold_bytes;
|
|
|
|
|
uint32_t nom_value; // In 16.16 format
|
|
|
|
|
uint32_t fifo_lvl_avg; // In 16.16 format
|
|
|
|
|
uint16_t fifo_lvl_thr; // fifo level threshold
|
|
|
|
|
uint16_t rate_const[2]; // pre-computed feedback/fifo_depth rate
|
|
|
|
|
}fifo_count;
|
|
|
|
|
#endif
|
|
|
|
|
}compute;
|
|
|
|
|
|
|
|
|
|
} feedback;
|
|
|
|
|
@@ -365,6 +367,8 @@ typedef struct
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*------------- From this point, data is not cleared by bus reset -------------*/
|
|
|
|
|
|
|
|
|
|
// Buffer for control requests
|
|
|
|
|
uint8_t * ctrl_buf;
|
|
|
|
|
uint8_t ctrl_buf_sz;
|
|
|
|
|
@@ -373,14 +377,10 @@ typedef struct
|
|
|
|
|
uint8_t * alt_setting; // 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!
|
|
|
|
|
|
|
|
|
|
// EP Transfer buffers and FIFOs
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
|
|
|
|
|
#if !CFG_TUD_AUDIO_ENABLE_DECODING
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
|
|
|
|
|
tu_fifo_t ep_out_ff;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
|
|
|
|
|
tu_fifo_t ep_in_ff;
|
|
|
|
|
#endif
|
|
|
|
|
@@ -390,7 +390,6 @@ typedef struct
|
|
|
|
|
CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[6];
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Support FIFOs for software encoding and decoding
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
|
|
|
|
|
tu_fifo_t * rx_supp_ff;
|
|
|
|
|
@@ -433,10 +432,147 @@ typedef struct
|
|
|
|
|
|
|
|
|
|
#define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ctrl_buf)
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
|
// WEAK FUNCTION STUBS
|
|
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_EP_IN
|
|
|
|
|
TU_ATTR_WEAK bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting) {
|
|
|
|
|
(void) rhport;
|
|
|
|
|
(void) func_id;
|
|
|
|
|
(void) ep_in;
|
|
|
|
|
(void) cur_alt_setting;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TU_ATTR_WEAK bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied, uint8_t func_id, uint8_t ep_in, uint8_t cur_alt_setting) {
|
|
|
|
|
(void) rhport;
|
|
|
|
|
(void) n_bytes_copied;
|
|
|
|
|
(void) func_id;
|
|
|
|
|
(void) ep_in;
|
|
|
|
|
(void) cur_alt_setting;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_EP_OUT
|
|
|
|
|
TU_ATTR_WEAK bool tud_audio_rx_done_pre_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting) {
|
|
|
|
|
(void) rhport;
|
|
|
|
|
(void) n_bytes_received;
|
|
|
|
|
(void) func_id;
|
|
|
|
|
(void) ep_out;
|
|
|
|
|
(void) cur_alt_setting;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TU_ATTR_WEAK bool tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, uint8_t func_id, uint8_t ep_out, uint8_t cur_alt_setting) {
|
|
|
|
|
(void) rhport;
|
|
|
|
|
(void) n_bytes_received;
|
|
|
|
|
(void) func_id;
|
|
|
|
|
(void) ep_out;
|
|
|
|
|
(void) cur_alt_setting;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
|
|
|
|
|
TU_ATTR_WEAK void tud_audio_fb_done_cb(uint8_t func_id) {
|
|
|
|
|
(void) func_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param) {
|
|
|
|
|
(void) func_id;
|
|
|
|
|
(void) alt_itf;
|
|
|
|
|
feedback_param->method = AUDIO_FEEDBACK_METHOD_DISABLED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TU_ATTR_WEAK bool tud_audio_feedback_format_correction_cb(uint8_t func_id) {
|
|
|
|
|
(void) func_id;
|
|
|
|
|
return CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift) {
|
|
|
|
|
(void) func_id;
|
|
|
|
|
(void) frame_number;
|
|
|
|
|
(void) interval_shift;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
|
|
|
|
|
TU_ATTR_WEAK void tud_audio_int_done_cb(uint8_t rhport) {
|
|
|
|
|
(void) rhport;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Invoked when audio set interface request received
|
|
|
|
|
TU_ATTR_WEAK bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request) {
|
|
|
|
|
(void) rhport;
|
|
|
|
|
(void) p_request;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Invoked when audio set interface request received which closes an EP
|
|
|
|
|
TU_ATTR_WEAK bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request) {
|
|
|
|
|
(void) rhport;
|
|
|
|
|
(void) p_request;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Invoked when audio class specific set request received for an EP
|
|
|
|
|
TU_ATTR_WEAK bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) {
|
|
|
|
|
(void) rhport;
|
|
|
|
|
(void) p_request;
|
|
|
|
|
(void) pBuff;
|
|
|
|
|
TU_LOG2(" No EP set request callback available!\r\n");
|
|
|
|
|
return false; // In case no callback function is present or request can not be conducted we stall it
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Invoked when audio class specific set request received for an interface
|
|
|
|
|
TU_ATTR_WEAK bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) {
|
|
|
|
|
(void) rhport;
|
|
|
|
|
(void) p_request;
|
|
|
|
|
(void) pBuff;
|
|
|
|
|
TU_LOG2(" No interface set request callback available!\r\n");
|
|
|
|
|
return false; // In case no callback function is present or request can not be conducted we stall it
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Invoked when audio class specific set request received for an entity
|
|
|
|
|
TU_ATTR_WEAK bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) {
|
|
|
|
|
(void) rhport;
|
|
|
|
|
(void) p_request;
|
|
|
|
|
(void) pBuff;
|
|
|
|
|
TU_LOG2(" No entity set request callback available!\r\n");
|
|
|
|
|
return false; // In case no callback function is present or request can not be conducted we stall it
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Invoked when audio class specific get request received for an EP
|
|
|
|
|
TU_ATTR_WEAK bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request) {
|
|
|
|
|
(void) rhport;
|
|
|
|
|
(void) p_request;
|
|
|
|
|
TU_LOG2(" No EP get request callback available!\r\n");
|
|
|
|
|
return false; // Stall
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Invoked when audio class specific get request received for an interface
|
|
|
|
|
TU_ATTR_WEAK bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request) {
|
|
|
|
|
(void) rhport;
|
|
|
|
|
(void) p_request;
|
|
|
|
|
TU_LOG2(" No interface get request callback available!\r\n");
|
|
|
|
|
return false; // Stall
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Invoked when audio class specific get request received for an entity
|
|
|
|
|
TU_ATTR_WEAK bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request) {
|
|
|
|
|
(void) rhport;
|
|
|
|
|
(void) p_request;
|
|
|
|
|
TU_LOG2(" No entity get request callback available!\r\n");
|
|
|
|
|
return false; // Stall
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
|
// INTERNAL OBJECT & FUNCTION DECLARATION
|
|
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
|
CFG_TUD_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO];
|
|
|
|
|
tu_static CFG_TUD_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);
|
|
|
|
|
@@ -479,7 +615,8 @@ static uint16_t audiod_tx_packet_size(const uint16_t* norminal_size, uint16_t da
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
|
|
|
|
|
static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq);
|
|
|
|
|
static bool audiod_set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq);
|
|
|
|
|
static void audiod_fb_fifo_count_update(audiod_function_t* audio, uint16_t lvl_new);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
bool tud_audio_n_mounted(uint8_t func_id)
|
|
|
|
|
@@ -560,19 +697,13 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t
|
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
|
|
// Call a weak callback here - a possibility for user to get informed an audio packet was received and data gets now loaded into EP FIFO (or decoded into support RX software FIFO)
|
|
|
|
|
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]));
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_DECODING
|
|
|
|
|
|
|
|
|
|
switch (audio->format_type_rx)
|
|
|
|
|
{
|
|
|
|
|
@@ -621,13 +752,17 @@ static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t
|
|
|
|
|
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(audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FIFO_COUNT)
|
|
|
|
|
{
|
|
|
|
|
audiod_fb_fifo_count_update(audio, tu_fifo_count(&audio->ep_out_ff));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Call a weak callback here - a possibility for user to get informed decoding was completed
|
|
|
|
|
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]));
|
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
@@ -731,6 +866,13 @@ static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, u
|
|
|
|
|
// Number of bytes should be a multiple of CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX * CFG_TUD_AUDIO_N_CHANNELS_RX but checking makes no sense - no way to correct it
|
|
|
|
|
// TU_VERIFY(cnt != n_bytes);
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
|
|
|
|
|
if(audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FIFO_COUNT)
|
|
|
|
|
{
|
|
|
|
|
audiod_fb_fifo_count_update(audio, tu_fifo_count(&audio->rx_supp_ff[0]));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
#endif //CFG_TUD_AUDIO_ENABLE_DECODING
|
|
|
|
|
@@ -854,7 +996,7 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio)
|
|
|
|
|
|
|
|
|
|
// 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 (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]));
|
|
|
|
|
TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf]));
|
|
|
|
|
|
|
|
|
|
// Send everything in ISO EP FIFO
|
|
|
|
|
uint16_t n_bytes_tx;
|
|
|
|
|
@@ -917,7 +1059,7 @@ static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// 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_tx, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf]));
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
@@ -1073,9 +1215,38 @@ static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audi
|
|
|
|
|
// This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent
|
|
|
|
|
|
|
|
|
|
#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)
|
|
|
|
|
static inline bool audiod_fb_send(audiod_function_t *audio)
|
|
|
|
|
{
|
|
|
|
|
return usbd_edpt_xfer(rhport, audio->ep_fb, (uint8_t *) &audio->feedback.value, 4);
|
|
|
|
|
bool apply_correction = (TUSB_SPEED_FULL == tud_speed_get()) && audio->feedback.format_correction;
|
|
|
|
|
// Format the feedback value
|
|
|
|
|
if (apply_correction)
|
|
|
|
|
{
|
|
|
|
|
uint8_t * fb = (uint8_t *) &audio->feedback.send_buf;
|
|
|
|
|
|
|
|
|
|
// For FS format is 10.14
|
|
|
|
|
*(fb++) = (audio->feedback.value >> 2) & 0xFF;
|
|
|
|
|
*(fb++) = (audio->feedback.value >> 10) & 0xFF;
|
|
|
|
|
*(fb++) = (audio->feedback.value >> 18) & 0xFF;
|
|
|
|
|
*fb = 0;
|
|
|
|
|
} else
|
|
|
|
|
{
|
|
|
|
|
audio->feedback.send_buf = audio->feedback.value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// About feedback format on FS
|
|
|
|
|
//
|
|
|
|
|
// 3 variables: Format | packetSize | sendSize | Working OS:
|
|
|
|
|
// 16.16 4 4 Linux, Windows
|
|
|
|
|
// 16.16 4 3 Linux
|
|
|
|
|
// 16.16 3 4 Linux
|
|
|
|
|
// 16.16 3 3 Linux
|
|
|
|
|
// 10.14 4 4 Linux
|
|
|
|
|
// 10.14 4 3 Linux
|
|
|
|
|
// 10.14 3 4 Linux, OSX
|
|
|
|
|
// 10.14 3 3 Linux, OSX
|
|
|
|
|
//
|
|
|
|
|
// We send 3 bytes since sending packet larger than wMaxPacketSize is pretty ugly
|
|
|
|
|
return usbd_edpt_xfer(audio->rhport, audio->ep_fb, (uint8_t *) &audio->feedback.send_buf, apply_correction ? 3 : 4);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
@@ -1693,7 +1864,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Invoke callback - can be used to stop data sampling
|
|
|
|
|
if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
|
|
|
|
|
TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
|
|
|
|
|
|
|
|
|
|
audio->ep_in = 0; // Necessary?
|
|
|
|
|
|
|
|
|
|
@@ -1724,7 +1895,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Invoke callback - can be used to stop data sampling
|
|
|
|
|
if (tud_audio_set_itf_close_EP_cb) TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
|
|
|
|
|
TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
|
|
|
|
|
|
|
|
|
|
audio->ep_out = 0; // Necessary?
|
|
|
|
|
|
|
|
|
|
@@ -1842,9 +2013,6 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
|
|
|
|
|
{
|
|
|
|
|
audio->ep_fb = ep_addr;
|
|
|
|
|
audio->feedback.frame_shift = desc_ep->bInterval -1;
|
|
|
|
|
|
|
|
|
|
// Enable SOF interrupt if callback is implemented
|
|
|
|
|
if (tud_audio_feedback_interval_isr) usbd_sof_enable(rhport, SOF_CONSUMER_AUDIO, true);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
|
|
|
|
|
@@ -1857,20 +2025,23 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
|
|
|
|
|
TU_VERIFY(foundEPs == nEps);
|
|
|
|
|
|
|
|
|
|
// Invoke one callback for a final set interface
|
|
|
|
|
if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
|
|
|
|
|
TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
|
|
|
|
|
// Prepare feedback computation if callback is available
|
|
|
|
|
if (tud_audio_feedback_params_cb)
|
|
|
|
|
// Prepare feedback computation if endpoint is available
|
|
|
|
|
if(audio->ep_fb != 0)
|
|
|
|
|
{
|
|
|
|
|
audio_feedback_params_t fb_param;
|
|
|
|
|
|
|
|
|
|
tud_audio_feedback_params_cb(func_id, alt, &fb_param);
|
|
|
|
|
audio->feedback.compute_method = fb_param.method;
|
|
|
|
|
|
|
|
|
|
if(TUSB_SPEED_FULL == tud_speed_get())
|
|
|
|
|
audio->feedback.format_correction = tud_audio_feedback_format_correction_cb(func_id);
|
|
|
|
|
|
|
|
|
|
// Minimal/Maximum value in 16.16 format for full speed (1ms per frame) or high speed (125 us per frame)
|
|
|
|
|
uint32_t const frame_div = (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000;
|
|
|
|
|
audio->feedback.min_value = (fb_param.sample_freq/frame_div - 1) << 16;
|
|
|
|
|
audio->feedback.min_value = ((fb_param.sample_freq - 1)/frame_div) << 16;
|
|
|
|
|
audio->feedback.max_value = (fb_param.sample_freq/frame_div + 1) << 16;
|
|
|
|
|
|
|
|
|
|
switch(fb_param.method)
|
|
|
|
|
@@ -1878,20 +2049,32 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
|
|
|
|
|
case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED:
|
|
|
|
|
case AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT:
|
|
|
|
|
case AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2:
|
|
|
|
|
set_fb_params_freq(audio, fb_param.sample_freq, fb_param.frequency.mclk_freq);
|
|
|
|
|
audiod_set_fb_params_freq(audio, fb_param.sample_freq, fb_param.frequency.mclk_freq);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
#if 0 // implement later
|
|
|
|
|
case AUDIO_FEEDBACK_METHOD_FIFO_COUNT:
|
|
|
|
|
{
|
|
|
|
|
uint64_t fb64 = ((uint64_t) fb_param.sample_freq) << 16;
|
|
|
|
|
audio->feedback.compute.fifo_count.nominal_value = (uint32_t) (fb64 / frame_div);
|
|
|
|
|
audio->feedback.compute.fifo_count.threshold_bytes = fb_param.fifo_count.threshold_bytes;
|
|
|
|
|
|
|
|
|
|
tud_audio_fb_set(audio->feedback.compute.fifo_count.nominal_value);
|
|
|
|
|
// Initialize the threshold level to half filled
|
|
|
|
|
uint16_t fifo_lvl_thr;
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_DECODING
|
|
|
|
|
fifo_lvl_thr = tu_fifo_depth(&audio->rx_supp_ff[0]) / 2;
|
|
|
|
|
#else
|
|
|
|
|
fifo_lvl_thr = tu_fifo_depth(&audio->ep_out_ff) / 2;
|
|
|
|
|
#endif
|
|
|
|
|
audio->feedback.compute.fifo_count.fifo_lvl_thr = fifo_lvl_thr;
|
|
|
|
|
audio->feedback.compute.fifo_count.fifo_lvl_avg = ((uint32_t)fifo_lvl_thr) << 16;
|
|
|
|
|
// Avoid 64bit division
|
|
|
|
|
uint32_t nominal = ((fb_param.sample_freq / 100) << 16) / (frame_div / 100);
|
|
|
|
|
audio->feedback.compute.fifo_count.nom_value = nominal;
|
|
|
|
|
audio->feedback.compute.fifo_count.rate_const[0] = (audio->feedback.max_value - nominal) / fifo_lvl_thr;
|
|
|
|
|
audio->feedback.compute.fifo_count.rate_const[1] = (nominal - audio->feedback.min_value) / fifo_lvl_thr;
|
|
|
|
|
// On HS feedback is more sensitive since packet size can vary every MSOF, could cause instability
|
|
|
|
|
if(tud_speed_get() == TUSB_SPEED_HIGH) {
|
|
|
|
|
audio->feedback.compute.fifo_count.rate_const[0] /= 8;
|
|
|
|
|
audio->feedback.compute.fifo_count.rate_const[1] /= 8;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// nothing to do
|
|
|
|
|
default: break;
|
|
|
|
|
@@ -1909,16 +2092,19 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
|
|
|
|
|
// Disable SOF interrupt if no driver has any enabled feedback EP
|
|
|
|
|
bool disable = true;
|
|
|
|
|
bool enable_sof = false;
|
|
|
|
|
for(uint8_t i=0; i < CFG_TUD_AUDIO; i++)
|
|
|
|
|
{
|
|
|
|
|
if (_audiod_fct[i].ep_fb != 0)
|
|
|
|
|
if (_audiod_fct[i].ep_fb != 0 &&
|
|
|
|
|
(_audiod_fct[i].feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED ||
|
|
|
|
|
_audiod_fct[i].feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT ||
|
|
|
|
|
_audiod_fct[i].feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2 ))
|
|
|
|
|
{
|
|
|
|
|
disable = false;
|
|
|
|
|
enable_sof = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (disable) usbd_sof_enable(rhport, SOF_CONSUMER_AUDIO, false);
|
|
|
|
|
usbd_sof_enable(rhport, SOF_CONSUMER_AUDIO, enable_sof);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
|
|
|
|
|
@@ -1948,35 +2134,19 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const
|
|
|
|
|
|
|
|
|
|
if (entityID != 0)
|
|
|
|
|
{
|
|
|
|
|
if (tud_audio_set_req_entity_cb)
|
|
|
|
|
{
|
|
|
|
|
// Check if entity is present and get corresponding driver index
|
|
|
|
|
TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
|
|
|
|
|
// Check if entity is present and get corresponding driver index
|
|
|
|
|
TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
|
|
|
|
|
|
|
|
|
|
// Invoke callback
|
|
|
|
|
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; // In case no callback function is present or request can not be conducted we stall it
|
|
|
|
|
}
|
|
|
|
|
// Invoke callback
|
|
|
|
|
return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (tud_audio_set_req_itf_cb)
|
|
|
|
|
{
|
|
|
|
|
// Find index of audio driver structure and verify interface really exists
|
|
|
|
|
TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
|
|
|
|
|
// Find index of audio driver structure and verify interface really exists
|
|
|
|
|
TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
|
|
|
|
|
|
|
|
|
|
// Invoke callback
|
|
|
|
|
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; // In case no callback function is present or request can not be conducted we stall it
|
|
|
|
|
}
|
|
|
|
|
// Invoke callback
|
|
|
|
|
return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
@@ -1985,19 +2155,11 @@ static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const
|
|
|
|
|
{
|
|
|
|
|
uint8_t ep = TU_U16_LOW(p_request->wIndex);
|
|
|
|
|
|
|
|
|
|
if (tud_audio_set_req_ep_cb)
|
|
|
|
|
{
|
|
|
|
|
// Check if entity is present and get corresponding driver index
|
|
|
|
|
TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
|
|
|
|
|
// Check if entity is present and get corresponding driver index
|
|
|
|
|
TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
|
|
|
|
|
|
|
|
|
|
// Invoke callback
|
|
|
|
|
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; // In case no callback function is present or request can not be conducted we stall it
|
|
|
|
|
}
|
|
|
|
|
// Invoke callback
|
|
|
|
|
return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
// Unknown/Unsupported recipient
|
|
|
|
|
@@ -2054,15 +2216,7 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const
|
|
|
|
|
// In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
|
|
|
|
|
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; // Stall
|
|
|
|
|
}
|
|
|
|
|
return tud_audio_get_req_entity_cb(rhport, p_request);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
@@ -2073,15 +2227,7 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const
|
|
|
|
|
// In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
|
|
|
|
|
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; // Stall
|
|
|
|
|
}
|
|
|
|
|
return tud_audio_get_req_itf_cb(rhport, p_request);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -2097,15 +2243,7 @@ static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const
|
|
|
|
|
// In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
|
|
|
|
|
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; // Stall
|
|
|
|
|
}
|
|
|
|
|
return tud_audio_get_req_ep_cb(rhport, p_request);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
@@ -2160,7 +2298,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
|
|
|
|
|
// I assume here, that things above are handled by PHY
|
|
|
|
|
// All transmission is done - what remains to do is to inform job was completed
|
|
|
|
|
|
|
|
|
|
if (tud_audio_int_done_cb) tud_audio_int_done_cb(rhport);
|
|
|
|
|
tud_audio_int_done_cb(rhport);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2201,13 +2339,13 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
|
|
|
|
|
// Transmission of feedback EP finished
|
|
|
|
|
if (audio->ep_fb == ep_addr)
|
|
|
|
|
{
|
|
|
|
|
if (tud_audio_fb_done_cb) tud_audio_fb_done_cb(func_id);
|
|
|
|
|
tud_audio_fb_done_cb(func_id);
|
|
|
|
|
|
|
|
|
|
// Schedule a transmit with the new value if EP is not busy
|
|
|
|
|
if (!usbd_edpt_busy(rhport, audio->ep_fb))
|
|
|
|
|
if (usbd_edpt_claim(rhport, audio->ep_fb))
|
|
|
|
|
{
|
|
|
|
|
// Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent
|
|
|
|
|
return audiod_fb_send(rhport, audio);
|
|
|
|
|
return audiod_fb_send(audio);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
@@ -2219,7 +2357,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3
|
|
|
|
|
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
|
|
|
|
|
|
|
|
|
|
static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq)
|
|
|
|
|
static bool audiod_set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq)
|
|
|
|
|
{
|
|
|
|
|
// Check if frame interval is within sane limits
|
|
|
|
|
// The interval value n_frames was taken from the descriptors within audiod_set_interface()
|
|
|
|
|
@@ -2238,11 +2376,11 @@ static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, u
|
|
|
|
|
if ((mclk_freq % sample_freq) == 0 && tu_is_power_of_two(mclk_freq / sample_freq))
|
|
|
|
|
{
|
|
|
|
|
audio->feedback.compute_method = AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2;
|
|
|
|
|
audio->feedback.compute.power_of_2 = 16 - audio->feedback.frame_shift - tu_log2(mclk_freq / sample_freq);
|
|
|
|
|
audio->feedback.compute.power_of_2 = 16 - (audio->feedback.frame_shift - 1) - tu_log2(mclk_freq / sample_freq);
|
|
|
|
|
}
|
|
|
|
|
else if ( audio->feedback.compute_method == AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT)
|
|
|
|
|
{
|
|
|
|
|
audio->feedback.compute.float_const = (float)sample_freq / mclk_freq * (1UL << (16 - audio->feedback.frame_shift));
|
|
|
|
|
audio->feedback.compute.float_const = (float)sample_freq / mclk_freq * (1UL << (16 - (audio->feedback.frame_shift - 1)));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
@@ -2253,6 +2391,38 @@ static bool set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, u
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void audiod_fb_fifo_count_update(audiod_function_t* audio, uint16_t lvl_new)
|
|
|
|
|
{
|
|
|
|
|
/* Low-pass (averaging) filter */
|
|
|
|
|
uint32_t lvl = audio->feedback.compute.fifo_count.fifo_lvl_avg;
|
|
|
|
|
lvl = (uint32_t)(((uint64_t)lvl * 63 + ((uint32_t)lvl_new << 16)) >> 6);
|
|
|
|
|
audio->feedback.compute.fifo_count.fifo_lvl_avg = lvl;
|
|
|
|
|
|
|
|
|
|
uint32_t const ff_lvl = lvl >> 16;
|
|
|
|
|
uint16_t const ff_thr = audio->feedback.compute.fifo_count.fifo_lvl_thr;
|
|
|
|
|
uint16_t const *rate = audio->feedback.compute.fifo_count.rate_const;
|
|
|
|
|
|
|
|
|
|
uint32_t feedback;
|
|
|
|
|
|
|
|
|
|
if(ff_lvl < ff_thr)
|
|
|
|
|
{
|
|
|
|
|
feedback = audio->feedback.compute.fifo_count.nom_value + (ff_thr - ff_lvl) * rate[0];
|
|
|
|
|
} else
|
|
|
|
|
{
|
|
|
|
|
feedback = audio->feedback.compute.fifo_count.nom_value - (ff_lvl - ff_thr) * rate[1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( feedback > audio->feedback.max_value ) feedback = audio->feedback.max_value;
|
|
|
|
|
if ( feedback < audio->feedback.min_value ) feedback = audio->feedback.min_value;
|
|
|
|
|
audio->feedback.value = feedback;
|
|
|
|
|
|
|
|
|
|
// Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value
|
|
|
|
|
if (usbd_edpt_claim(audio->rhport, audio->ep_fb))
|
|
|
|
|
{
|
|
|
|
|
audiod_fb_send(audio);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles)
|
|
|
|
|
{
|
|
|
|
|
audiod_function_t* audio = &_audiod_fct[func_id];
|
|
|
|
|
@@ -2270,7 +2440,7 @@ uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles)
|
|
|
|
|
|
|
|
|
|
case AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED:
|
|
|
|
|
{
|
|
|
|
|
uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - audio->feedback.frame_shift);
|
|
|
|
|
uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - (audio->feedback.frame_shift - 1));
|
|
|
|
|
feedback = (uint32_t) (fb64 / audio->feedback.compute.fixed.mclk_freq);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
@@ -2289,6 +2459,21 @@ uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles)
|
|
|
|
|
|
|
|
|
|
return feedback;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
_audiod_fct[func_id].feedback.value = feedback;
|
|
|
|
|
|
|
|
|
|
// Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value
|
|
|
|
|
if (usbd_edpt_claim(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb))
|
|
|
|
|
{
|
|
|
|
|
return audiod_fb_send(&_audiod_fct[func_id]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
TU_ATTR_FAST_FUNC void audiod_sof_isr (uint8_t rhport, uint32_t frame_count)
|
|
|
|
|
@@ -2315,7 +2500,7 @@ TU_ATTR_FAST_FUNC void audiod_sof_isr (uint8_t rhport, uint32_t frame_count)
|
|
|
|
|
uint32_t const interval = 1UL << (audio->feedback.frame_shift - hs_adjust);
|
|
|
|
|
if ( 0 == (frame_count & (interval-1)) )
|
|
|
|
|
{
|
|
|
|
|
if(tud_audio_feedback_interval_isr) tud_audio_feedback_interval_isr(i, frame_count, audio->feedback.frame_shift);
|
|
|
|
|
tud_audio_feedback_interval_isr(i, frame_count, audio->feedback.frame_shift);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -2703,44 +2888,8 @@ static uint16_t audiod_tx_packet_size(const uint16_t* norminal_size, uint16_t da
|
|
|
|
|
|
|
|
|
|
#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);
|
|
|
|
|
|
|
|
|
|
// Format the feedback value
|
|
|
|
|
#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION
|
|
|
|
|
if ( TUSB_SPEED_FULL == tud_speed_get() )
|
|
|
|
|
{
|
|
|
|
|
uint8_t * fb = (uint8_t *) &_audiod_fct[func_id].feedback.value;
|
|
|
|
|
|
|
|
|
|
// For FS format is 10.14
|
|
|
|
|
*(fb++) = (feedback >> 2) & 0xFF;
|
|
|
|
|
*(fb++) = (feedback >> 10) & 0xFF;
|
|
|
|
|
*(fb++) = (feedback >> 18) & 0xFF;
|
|
|
|
|
// 4th byte is needed to work correctly with MS Windows
|
|
|
|
|
*fb = 0;
|
|
|
|
|
}else
|
|
|
|
|
#else
|
|
|
|
|
{
|
|
|
|
|
// Send value as-is, caller will choose the appropriate format
|
|
|
|
|
_audiod_fct[func_id].feedback.value = feedback;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
// No security checks here - internal function only which should always succeed
|
|
|
|
|
uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio)
|
|
|
|
|
static uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio)
|
|
|
|
|
{
|
|
|
|
|
for (uint8_t cnt=0; cnt < CFG_TUD_AUDIO; cnt++)
|
|
|
|
|
{
|
|
|
|
|
|