Open FFBoard
Open source force feedback firmware
audio_device.c
Go to the documentation of this file.
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2020 Reinhard Panhuber, Jerzy Kasenberg
5 * Copyright (c) 2023 HiFiPhile
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 *
25 * This file is part of the TinyUSB stack.
26 */
27
28/*
29 * This driver supports at most one out EP, one in EP, one control EP, and one feedback EP and one alternative interface other than zero. Hence, only one input terminal and one output terminal are support, if you need more adjust the driver!
30 * It supports multiple TX and RX channels.
31 *
32 * In case you need more alternate interfaces, you need to define additional defines for this specific alternate interface. Just define them and set them in the set_interface function.
33 *
34 * There are three data flow structures currently implemented, where at least one SW-FIFO is used to decouple the asynchronous processes MCU vs. host
35 *
36 * 1. Input data -> SW-FIFO -> MCU USB
37 *
38 * The most easiest version, available in case the target MCU can handle the software FIFO (SW-FIFO) and if it is implemented in the device driver (if yes then dcd_edpt_xfer_fifo() is available)
39 *
40 * 2. Input data -> SW-FIFO -> Linear buffer -> MCU USB
41 *
42 * In case the target MCU can not handle a SW-FIFO, a linear buffer is used. This uses the default function dcd_edpt_xfer(). In this case more memory is required.
43 *
44 * 3. (Input data 1 | Input data 2 | ... | Input data N) -> (SW-FIFO 1 | SW-FIFO 2 | ... | SW-FIFO N) -> Linear buffer -> MCU USB
45 *
46 * This case is used if you have more channels which need to be combined into one stream. Every channel has its own SW-FIFO. All data is encoded into an Linear buffer.
47 *
48 * The same holds in the RX case.
49 *
50 * */
51
52#include "tusb_option.h"
53
54#if (CFG_TUD_ENABLED && CFG_TUD_AUDIO)
55
56//--------------------------------------------------------------------+
57// INCLUDE
58//--------------------------------------------------------------------+
59#include "device/usbd.h"
60#include "device/usbd_pvt.h"
61
62#include "audio_device.h"
63
64//--------------------------------------------------------------------+
65// MACRO CONSTANT TYPEDEF
66//--------------------------------------------------------------------+
67
68// Use ring buffer if it's available, some MCUs need extra RAM requirements
69// For DWC2 enable ring buffer will disable DMA (if available)
70#ifndef TUD_AUDIO_PREFER_RING_BUFFER
71 #if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX || \
72 defined(TUP_USBIP_DWC2)
73 #define TUD_AUDIO_PREFER_RING_BUFFER 0
74 #else
75 #define TUD_AUDIO_PREFER_RING_BUFFER 1
76 #endif
77#endif
78
79// Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer
80// is available or driver is would need to be changed dramatically
81
82// Only STM32 and dcd_transdimension use non-linear buffer for now
83// dwc2 except esp32sx (since it may use dcd_esp32sx)
84#if (defined(TUP_USBIP_DWC2) && !TU_CHECK_MCU(OPT_MCU_ESP32S2, OPT_MCU_ESP32S3)) || \
85 defined(TUP_USBIP_FSDEV) || \
86 CFG_TUSB_MCU == OPT_MCU_RX63X || \
87 CFG_TUSB_MCU == OPT_MCU_RX65X || \
88 CFG_TUSB_MCU == OPT_MCU_RX72N || \
89 CFG_TUSB_MCU == OPT_MCU_LPC18XX || \
90 CFG_TUSB_MCU == OPT_MCU_LPC43XX || \
91 CFG_TUSB_MCU == OPT_MCU_MIMXRT1XXX || \
92 CFG_TUSB_MCU == OPT_MCU_MSP432E4
93 #if TUD_AUDIO_PREFER_RING_BUFFER
94 #define USE_LINEAR_BUFFER 0
95 #else
96 #define USE_LINEAR_BUFFER 1
97 #endif
98#else
99 #define USE_LINEAR_BUFFER 1
100#endif
101
102// Declaration of buffers
103
104// Check for maximum supported numbers
105#if CFG_TUD_AUDIO > 3
106#error Maximum number of audio functions restricted to three!
107#endif
108
109// Put sw_buf in USB section only if necessary
110#if USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING
111#define IN_SW_BUF_MEM_SECTION
112#else
113#define IN_SW_BUF_MEM_SECTION CFG_TUD_MEM_SECTION
114#endif
115#if USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING
116#define OUT_SW_BUF_MEM_SECTION
117#else
118#define OUT_SW_BUF_MEM_SECTION CFG_TUD_MEM_SECTION
119#endif
120
121// EP IN software buffers and mutexes
122#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
123 #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
124 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];
125 #if CFG_FIFO_MUTEX
126 tu_static osal_mutex_def_t ep_in_ff_mutex_wr_1; // No need for read mutex as only USB driver reads from FIFO
127 #endif
128 #endif // CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
129
130 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
131 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];
132 #if CFG_FIFO_MUTEX
133 tu_static osal_mutex_def_t ep_in_ff_mutex_wr_2; // No need for read mutex as only USB driver reads from FIFO
134 #endif
135 #endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
136
137 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
138 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];
139 #if CFG_FIFO_MUTEX
140 tu_static osal_mutex_def_t ep_in_ff_mutex_wr_3; // No need for read mutex as only USB driver reads from FIFO
141 #endif
142 #endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
143#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
144
145// Linear buffer TX in case:
146// - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR
147// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into
148#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING)
149 #if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0
150 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];
151 #endif
152
153 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0
154 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];
155 #endif
156
157 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0
158 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];
159 #endif
160#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
161
162// EP OUT software buffers and mutexes
163#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
164 #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
165 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];
166 #if CFG_FIFO_MUTEX
167 tu_static osal_mutex_def_t ep_out_ff_mutex_rd_1; // No need for write mutex as only USB driver writes into FIFO
168 #endif
169 #endif // CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
170
171 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
172 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];
173 #if CFG_FIFO_MUTEX
174 tu_static osal_mutex_def_t ep_out_ff_mutex_rd_2; // No need for write mutex as only USB driver writes into FIFO
175 #endif
176 #endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
177
178 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
179 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];
180 #if CFG_FIFO_MUTEX
181 tu_static osal_mutex_def_t ep_out_ff_mutex_rd_3; // No need for write mutex as only USB driver writes into FIFO
182 #endif
183 #endif // CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
184#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
185
186// Linear buffer RX in case:
187// - target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR
188// - the software encoding is used - in this case the linear buffers serve as a target memory where logical channels are encoded into
189#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
190 #if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0
191 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];
192 #endif
193
194 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0
195 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];
196 #endif
197
198 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0
199 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];
200 #endif
201#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
202
203// Control buffers
204tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ];
205
206#if CFG_TUD_AUDIO > 1
207tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ];
208#endif
209
210#if CFG_TUD_AUDIO > 2
211tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ];
212#endif
213
214// Active alternate setting of interfaces
215tu_static uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT];
216
217#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0
218tu_static uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT];
219#endif
220
221#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0
222tu_static uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT];
223#endif
224
225// Software encoding/decoding support FIFOs
226#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
227 #if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
228 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];
229 tu_static tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO];
230 #if CFG_FIFO_MUTEX
231 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
232 #endif
233 #endif
234
235 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
236 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];
237 tu_static tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO];
238 #if CFG_FIFO_MUTEX
239 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
240 #endif
241 #endif
242
243 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
244 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];
245 tu_static tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO];
246 #if CFG_FIFO_MUTEX
247 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
248 #endif
249 #endif
250#endif
251
252#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
253 #if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
254 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];
255 tu_static tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO];
256 #if CFG_FIFO_MUTEX
257 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
258 #endif
259 #endif
260
261 #if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
262 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];
263 tu_static tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO];
264 #if CFG_FIFO_MUTEX
265 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
266 #endif
267 #endif
268
269 #if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
270 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];
271 tu_static tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO];
272 #if CFG_FIFO_MUTEX
273 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
274 #endif
275 #endif
276#endif
277
278typedef struct
279{
280 uint8_t rhport;
281 uint8_t const * p_desc; // Pointer pointing to Standard AC Interface Descriptor(4.7.1) - Audio Control descriptor defining audio function
282
283#if CFG_TUD_AUDIO_ENABLE_EP_IN
284 uint8_t ep_in; // TX audio data EP.
285 uint16_t ep_in_sz; // Current size of TX EP
286 uint8_t ep_in_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to output terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero)
287#endif
288
289#if CFG_TUD_AUDIO_ENABLE_EP_OUT
290 uint8_t ep_out; // Incoming (into uC) audio data EP.
291 uint16_t ep_out_sz; // Current size of RX EP
292 uint8_t ep_out_as_intf_num; // Corresponding Standard AS Interface Descriptor (4.9.1) belonging to input terminal to which this EP belongs - 0 is invalid (this fits to UAC2 specification since AS interfaces can not have interface number equal to zero)
293
294#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
295 uint8_t ep_fb; // Feedback EP.
296#endif
297
298#endif
299
300#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
301 uint8_t ep_int; // Audio control interrupt EP.
302#endif
303
304 bool mounted; // Device opened
305
306 uint16_t desc_length; // Length of audio function descriptor
307
308#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
309 struct {
310 CFG_TUSB_MEM_ALIGN uint32_t send_buf;
311 uint32_t value; // Feedback value for asynchronous mode (in 16.16 format).
312 uint32_t min_value; // min value according to UAC2 FMT-2.0 section 2.3.1.1.
313 uint32_t max_value; // max value according to UAC2 FMT-2.0 section 2.3.1.1.
314
315 uint8_t frame_shift; // bInterval-1 in unit of frame (FS), micro-frame (HS)
318 union {
319 uint8_t power_of_2; // pre-computed power of 2 shift
320 float float_const; // pre-computed float constant
321
322 struct {
323 uint32_t sample_freq;
324 uint32_t mclk_freq;
325 }fixed;
326
327 struct {
328 uint32_t nom_value; // In 16.16 format
329 uint32_t fifo_lvl_avg; // In 16.16 format
330 uint16_t fifo_lvl_thr; // fifo level threshold
331 uint16_t rate_const[2]; // pre-computed feedback/fifo_depth rate
332 }fifo_count;
333 }compute;
334
335 } feedback;
336#endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
337
338 // Decoding parameters - parameters are set when alternate AS interface is set by host
339 // Coding is currently only supported for EP. Software coding corresponding to AS interfaces without EPs are not supported currently.
340#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
343
344#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
348#endif
349#endif
350
351#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
353 uint16_t packet_sz_tx[3];
355 uint8_t interval_tx;
356#endif
357
358 // Encoding parameters - parameters are set when alternate AS interface is set by host
359#if CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL)
363
364#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
367#endif
368#endif
369
370 /*------------- From this point, data is not cleared by bus reset -------------*/
371
372 // Buffer for control requests
373 uint8_t * ctrl_buf;
374 uint8_t ctrl_buf_sz;
375
376 // Current active alternate settings
377 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!
378
379 // EP Transfer buffers and FIFOs
380#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
382#endif
383
384#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
386#endif
387
388 // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74)
389#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
390 CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[6];
391#endif
392
393 // Support FIFOs for software encoding and decoding
394#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
398#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
400#endif
401#endif
402
403#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
407#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
409#endif
410#endif
411
412 // Linear buffer in case target MCU is not capable of handling a ring buffer FIFO e.g. no hardware buffer is available or driver is would need to be changed dramatically OR the support FIFOs are used
413#if CFG_TUD_AUDIO_ENABLE_EP_OUT && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_DECODING)
414 uint8_t * lin_buf_out;
415#define USE_LINEAR_BUFFER_RX 1
416#endif
417
418#if CFG_TUD_AUDIO_ENABLE_EP_IN && (USE_LINEAR_BUFFER || CFG_TUD_AUDIO_ENABLE_ENCODING)
419 uint8_t * lin_buf_in;
420#define USE_LINEAR_BUFFER_TX 1
421#endif
422
424
425#ifndef USE_LINEAR_BUFFER_TX
426#define USE_LINEAR_BUFFER_TX 0
427#endif
428
429#ifndef USE_LINEAR_BUFFER_RX
430#define USE_LINEAR_BUFFER_RX 0
431#endif
432
433#define ITF_MEM_RESET_SIZE offsetof(audiod_function_t, ctrl_buf)
434
435//--------------------------------------------------------------------+
436// WEAK FUNCTION STUBS
437//--------------------------------------------------------------------+
438
439#if CFG_TUD_AUDIO_ENABLE_EP_IN
440TU_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) {
441 (void) rhport;
442 (void) func_id;
443 (void) ep_in;
444 (void) cur_alt_setting;
445 return true;
446}
447
448TU_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) {
449 (void) rhport;
450 (void) n_bytes_copied;
451 (void) func_id;
452 (void) ep_in;
453 (void) cur_alt_setting;
454 return true;
455}
456#endif
457
458#if CFG_TUD_AUDIO_ENABLE_EP_OUT
459TU_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) {
460 (void) rhport;
461 (void) n_bytes_received;
462 (void) func_id;
463 (void) ep_out;
464 (void) cur_alt_setting;
465 return true;
466}
467
468TU_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) {
469 (void) rhport;
470 (void) n_bytes_received;
471 (void) func_id;
472 (void) ep_out;
473 (void) cur_alt_setting;
474 return true;
475}
476#endif
477
478#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
479TU_ATTR_WEAK void tud_audio_fb_done_cb(uint8_t func_id) {
480 (void) func_id;
481}
482
483TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t* feedback_param) {
484 (void) func_id;
485 (void) alt_itf;
486 feedback_param->method = AUDIO_FEEDBACK_METHOD_DISABLED;
487}
488
489TU_ATTR_WEAK bool tud_audio_feedback_format_correction_cb(uint8_t func_id) {
490 (void) func_id;
491 return CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION;
492}
493#endif
494
495TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func_id, uint32_t frame_number, uint8_t interval_shift) {
496 (void) func_id;
497 (void) frame_number;
498 (void) interval_shift;
499}
500
501#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
502TU_ATTR_WEAK void tud_audio_int_done_cb(uint8_t rhport) {
503 (void) rhport;
504}
505#endif
506
507// Invoked when audio set interface request received
508TU_ATTR_WEAK bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request) {
509 (void) rhport;
510 (void) p_request;
511 return true;
512}
513
514// Invoked when audio set interface request received which closes an EP
515TU_ATTR_WEAK bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const * p_request) {
516 (void) rhport;
517 (void) p_request;
518 return true;
519}
520
521// Invoked when audio class specific set request received for an EP
522TU_ATTR_WEAK bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) {
523 (void) rhport;
524 (void) p_request;
525 (void) pBuff;
526 TU_LOG2(" No EP set request callback available!\r\n");
527 return false; // In case no callback function is present or request can not be conducted we stall it
528}
529
530// Invoked when audio class specific set request received for an interface
531TU_ATTR_WEAK bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) {
532 (void) rhport;
533 (void) p_request;
534 (void) pBuff;
535 TU_LOG2(" No interface set request callback available!\r\n");
536 return false; // In case no callback function is present or request can not be conducted we stall it
537}
538
539// Invoked when audio class specific set request received for an entity
540TU_ATTR_WEAK bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) {
541 (void) rhport;
542 (void) p_request;
543 (void) pBuff;
544 TU_LOG2(" No entity set request callback available!\r\n");
545 return false; // In case no callback function is present or request can not be conducted we stall it
546}
547
548// Invoked when audio class specific get request received for an EP
549TU_ATTR_WEAK bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request) {
550 (void) rhport;
551 (void) p_request;
552 TU_LOG2(" No EP get request callback available!\r\n");
553 return false; // Stall
554}
555
556// Invoked when audio class specific get request received for an interface
557TU_ATTR_WEAK bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request) {
558 (void) rhport;
559 (void) p_request;
560 TU_LOG2(" No interface get request callback available!\r\n");
561 return false; // Stall
562}
563
564// Invoked when audio class specific get request received for an entity
565TU_ATTR_WEAK bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request) {
566 (void) rhport;
567 (void) p_request;
568 TU_LOG2(" No entity get request callback available!\r\n");
569 return false; // Stall
570}
571
572//--------------------------------------------------------------------+
573// INTERNAL OBJECT & FUNCTION DECLARATION
574//--------------------------------------------------------------------+
575tu_static CFG_TUD_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO];
576
577#if CFG_TUD_AUDIO_ENABLE_EP_OUT
578static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received);
579#endif
580
581#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
582static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received);
583#endif
584
585#if CFG_TUD_AUDIO_ENABLE_EP_IN
586static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t* audio);
587#endif
588
589#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
590static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio);
591#endif
592
593static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request);
594static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request);
595
596static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int);
597static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio, uint8_t *idxItf, uint8_t const **pp_desc_int);
598static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id);
599static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id);
600static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id);
601static uint8_t audiod_get_audio_fct_idx(audiod_function_t * audio);
602
603#if (CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL || CFG_TUD_AUDIO_ENABLE_ENCODING)) || (CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING)
604static 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);
605
606static inline uint8_t tu_desc_subtype(void const* desc)
607{
608 return ((uint8_t const*) desc)[2];
609}
610#endif
611
612#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
614static uint16_t audiod_tx_packet_size(const uint16_t* norminal_size, uint16_t data_count, uint16_t fifo_depth, uint16_t max_size);
615#endif
616
617#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
618static bool audiod_set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq);
619static void audiod_fb_fifo_count_update(audiod_function_t* audio, uint16_t lvl_new);
620#endif
621
622bool tud_audio_n_mounted(uint8_t func_id)
623{
624 TU_VERIFY(func_id < CFG_TUD_AUDIO);
625 audiod_function_t* audio = &_audiod_fct[func_id];
626
627 return audio->mounted;
628}
629
630//--------------------------------------------------------------------+
631// READ API
632//--------------------------------------------------------------------+
633
634#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
635
636uint16_t tud_audio_n_available(uint8_t func_id)
637{
638 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
639 return tu_fifo_count(&_audiod_fct[func_id].ep_out_ff);
640}
641
642uint16_t tud_audio_n_read(uint8_t func_id, void* buffer, uint16_t bufsize)
643{
644 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
645 return tu_fifo_read_n(&_audiod_fct[func_id].ep_out_ff, buffer, bufsize);
646}
647
648bool tud_audio_n_clear_ep_out_ff(uint8_t func_id)
649{
650 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
651 return tu_fifo_clear(&_audiod_fct[func_id].ep_out_ff);
652}
653
655{
656 if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_out_ff;
657 return NULL;
658}
659
660#endif
661
662#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
663// Delete all content in the support RX FIFOs
664bool tud_audio_n_clear_rx_support_ff(uint8_t func_id, uint8_t ff_idx)
665{
666 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
667 return tu_fifo_clear(&_audiod_fct[func_id].rx_supp_ff[ff_idx]);
668}
669
670uint16_t tud_audio_n_available_support_ff(uint8_t func_id, uint8_t ff_idx)
671{
672 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
673 return tu_fifo_count(&_audiod_fct[func_id].rx_supp_ff[ff_idx]);
674}
675
676uint16_t tud_audio_n_read_support_ff(uint8_t func_id, uint8_t ff_idx, void* buffer, uint16_t bufsize)
677{
678 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_rx_supp_ff);
679 return tu_fifo_read_n(&_audiod_fct[func_id].rx_supp_ff[ff_idx], buffer, bufsize);
680}
681
682tu_fifo_t* tud_audio_n_get_rx_support_ff(uint8_t func_id, uint8_t ff_idx)
683{
684 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];
685 return NULL;
686}
687#endif
688
689// This function is called once an audio packet is received by the USB and is responsible for putting data from USB memory into EP_OUT_FIFO (or support FIFOs + decoding of received stream into audio channels).
690// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_DECODING = 0.
691
692#if CFG_TUD_AUDIO_ENABLE_EP_OUT
693
694static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received)
695{
696 uint8_t idxItf = 0;
697 uint8_t const *dummy2;
698 uint8_t idx_audio_fct = 0;
699
700 idx_audio_fct = audiod_get_audio_fct_idx(audio);
701 TU_VERIFY(audiod_get_AS_interface_index(audio->ep_out_as_intf_num, audio, &idxItf, &dummy2));
702
703 // 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)
704 TU_VERIFY(tud_audio_rx_done_pre_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf]));
705
706#if CFG_TUD_AUDIO_ENABLE_DECODING
707
708 switch (audio->format_type_rx)
709 {
711 // INDIVIDUAL DECODING PROCEDURE REQUIRED HERE!
712 TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n");
713 TU_BREAKPOINT();
714 break;
715
717
718 switch (audio->format_type_I_rx)
719 {
721 TU_VERIFY(audiod_decode_type_I_pcm(rhport, audio, n_bytes_received));
722 break;
723
724 default:
725 // DESIRED CFG_TUD_AUDIO_FORMAT_TYPE_I_RX NOT IMPLEMENTED!
726 TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_RX encoding not implemented!\r\n");
727 TU_BREAKPOINT();
728 break;
729 }
730 break;
731
732 default:
733 // Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented!
734 TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_RX not implemented!\r\n");
735 TU_BREAKPOINT();
736 break;
737 }
738
739 // Prepare for next transmission
740 TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false);
741
742#else
743
744#if USE_LINEAR_BUFFER_RX
745 // Data currently is in linear buffer, copy into EP OUT FIFO
746 TU_VERIFY(tu_fifo_write_n(&audio->ep_out_ff, audio->lin_buf_out, n_bytes_received));
747
748 // Schedule for next receive
749 TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false);
750#else
751 // Data is already placed in EP FIFO, schedule for next receive
752 TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false);
753#endif
754
755#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
757 {
759 }
760#endif
761
762#endif
763
764 // Call a weak callback here - a possibility for user to get informed decoding was completed
765 TU_VERIFY(tud_audio_rx_done_post_read_cb(rhport, n_bytes_received, idx_audio_fct, audio->ep_out, audio->alt_setting[idxItf]));
766
767 return true;
768}
769
770#endif //CFG_TUD_AUDIO_ENABLE_EP_OUT
771
772// The following functions are used in case CFG_TUD_AUDIO_ENABLE_DECODING != 0
773#if CFG_TUD_AUDIO_ENABLE_DECODING && CFG_TUD_AUDIO_ENABLE_EP_OUT
774
775// Decoding according to 2.3.1.5 Audio Streams
776
777// Helper function
778static inline void * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesPerSample, void * dst, const void * dst_end, void * src, uint8_t const n_ff_used)
779{
780 // Due to one FIFO contains 2 channels, data always aligned to (nBytesPerSample * 2)
781 uint16_t * dst16 = dst;
782 uint16_t * src16 = src;
783 const uint16_t * dst_end16 = dst_end;
784 uint32_t * dst32 = dst;
785 uint32_t * src32 = src;
786 const uint32_t * dst_end32 = dst_end;
787
788 if (nBytesPerSample == 1)
789 {
790 while(dst16 < dst_end16)
791 {
792 *dst16++ = *src16++;
793 src16 += n_ff_used - 1;
794 }
795 return src16;
796 }
797 else if (nBytesPerSample == 2)
798 {
799 while(dst32 < dst_end32)
800 {
801 *dst32++ = *src32++;
802 src32 += n_ff_used - 1;
803 }
804 return src32;
805 }
806 else if (nBytesPerSample == 3)
807 {
808 while(dst16 < dst_end16)
809 {
810 *dst16++ = *src16++;
811 *dst16++ = *src16++;
812 *dst16++ = *src16++;
813 src16 += 3 * (n_ff_used - 1);
814 }
815 return src16;
816 }
817 else // nBytesPerSample == 4
818 {
819 while(dst32 < dst_end32)
820 {
821 *dst32++ = *src32++;
822 *dst32++ = *src32++;
823 src32 += 2 * (n_ff_used - 1);
824 }
825 return src32;
826 }
827}
828
829static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t* audio, uint16_t n_bytes_received)
830{
831 (void) rhport;
832
833 // Determine amount of samples
834 uint8_t const n_ff_used = audio->n_ff_used_rx;
835 uint16_t const nBytesPerFFToRead = n_bytes_received / n_ff_used;
836 uint8_t cnt_ff;
837
838 // Decode
839 uint8_t * src;
840 uint8_t * dst_end;
841
843
844 for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++)
845 {
846 tu_fifo_get_write_info(&audio->rx_supp_ff[cnt_ff], &info);
847
848 if (info.len_lin != 0)
849 {
850 info.len_lin = tu_min16(nBytesPerFFToRead, info.len_lin);
851 src = &audio->lin_buf_out[cnt_ff*audio->n_channels_per_ff_rx * audio->n_bytes_per_sample_rx];
852 dst_end = info.ptr_lin + info.len_lin;
853 src = audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sample_rx, info.ptr_lin, dst_end, src, n_ff_used);
854
855 // Handle wrapped part of FIFO
856 info.len_wrap = tu_min16(nBytesPerFFToRead - info.len_lin, info.len_wrap);
857 if (info.len_wrap != 0)
858 {
859 dst_end = info.ptr_wrap + info.len_wrap;
860 audiod_interleaved_copy_bytes_fast_decode(audio->n_bytes_per_sample_rx, info.ptr_wrap, dst_end, src, n_ff_used);
861 }
862 tu_fifo_advance_write_pointer(&audio->rx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
863 }
864 }
865
866 // 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
867 // TU_VERIFY(cnt != n_bytes);
868
869#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
871 {
873 }
874#endif
875
876 return true;
877}
878#endif //CFG_TUD_AUDIO_ENABLE_DECODING
879
880//--------------------------------------------------------------------+
881// WRITE API
882//--------------------------------------------------------------------+
883
884#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
885
897uint16_t tud_audio_n_write(uint8_t func_id, const void * data, uint16_t len)
898{
899 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
900 return tu_fifo_write_n(&_audiod_fct[func_id].ep_in_ff, data, len);
901}
902
903bool tud_audio_n_clear_ep_in_ff(uint8_t func_id) // Delete all content in the EP IN FIFO
904{
905 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
906 return tu_fifo_clear(&_audiod_fct[func_id].ep_in_ff);
907}
908
910{
911 if(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL) return &_audiod_fct[func_id].ep_in_ff;
912 return NULL;
913}
914
915#endif
916
917#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
918
919uint16_t tud_audio_n_flush_tx_support_ff(uint8_t func_id) // Force all content in the support TX FIFOs to be written into linear buffer and schedule a transmit
920{
921 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
922 audiod_function_t* audio = &_audiod_fct[func_id];
923
924 uint16_t n_bytes_copied = tu_fifo_count(&audio->tx_supp_ff[0]);
925
926 TU_VERIFY(audiod_tx_done_cb(audio->rhport, audio));
927
928 n_bytes_copied -= tu_fifo_count(&audio->tx_supp_ff[0]);
929 n_bytes_copied = n_bytes_copied*audio->tx_supp_ff[0].item_size;
930
931 return n_bytes_copied;
932}
933
934bool tud_audio_n_clear_tx_support_ff(uint8_t func_id, uint8_t ff_idx)
935{
936 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff);
937 return tu_fifo_clear(&_audiod_fct[func_id].tx_supp_ff[ff_idx]);
938}
939
940uint16_t tud_audio_n_write_support_ff(uint8_t func_id, uint8_t ff_idx, const void * data, uint16_t len)
941{
942 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL && ff_idx < _audiod_fct[func_id].n_tx_supp_ff);
943 return tu_fifo_write_n(&_audiod_fct[func_id].tx_supp_ff[ff_idx], data, len);
944}
945
946tu_fifo_t* tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx)
947{
948 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];
949 return NULL;
950}
951
952#endif
953
954
955#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
956// If no interrupt transmit is pending bytes get written into buffer and a transmit is scheduled - once transmit completed tud_audio_int_done_cb() is called in inform user
958{
959 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
960
961 TU_VERIFY(_audiod_fct[func_id].ep_int != 0);
962
963 // We write directly into the EP's buffer - abort if previous transfer not complete
964 TU_VERIFY(usbd_edpt_claim(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int));
965
966 // Check length
967 if (tu_memcpy_s(_audiod_fct[func_id].ep_int_buf, sizeof(_audiod_fct[func_id].ep_int_buf), data, sizeof(audio_interrupt_data_t)) == 0)
968 {
969 // Schedule transmit
970 TU_ASSERT(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int, _audiod_fct[func_id].ep_int_buf, sizeof(_audiod_fct[func_id].ep_int_buf)), 0);
971 } else
972 {
973 // Release endpoint since we don't make any transfer
974 usbd_edpt_release(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int);
975 }
976
977 return true;
978}
979#endif
980
981// This function is called once a transmit of an audio packet was successfully completed. Here, we encode samples and place it in IN EP's buffer for next transmission.
982// If you prefer your own (more efficient) implementation suiting your purpose set CFG_TUD_AUDIO_ENABLE_ENCODING = 0 and use tud_audio_n_write.
983
984// n_bytes_copied - Informs caller how many bytes were loaded. In case n_bytes_copied = 0, a ZLP is scheduled to inform host no data is available for current frame.
985#if CFG_TUD_AUDIO_ENABLE_EP_IN
986static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t * audio)
987{
988 uint8_t idxItf;
989 uint8_t const *dummy2;
990
991 uint8_t idx_audio_fct = audiod_get_audio_fct_idx(audio);
992 TU_VERIFY(audiod_get_AS_interface_index(audio->ep_in_as_intf_num, audio, &idxItf, &dummy2));
993
994 // Only send something if current alternate interface is not 0 as in this case nothing is to be sent due to UAC2 specifications
995 if (audio->alt_setting[idxItf] == 0) return false;
996
997 // 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
998 // 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().
999 TU_VERIFY(tud_audio_tx_done_pre_load_cb(rhport, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf]));
1000
1001 // Send everything in ISO EP FIFO
1002 uint16_t n_bytes_tx;
1003
1004 // If support FIFOs are used, encode and schedule transmit
1005#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
1006 switch (audio->format_type_tx)
1007 {
1009 // INDIVIDUAL ENCODING PROCEDURE REQUIRED HERE!
1010 TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n");
1011 TU_BREAKPOINT();
1012 n_bytes_tx = 0;
1013 break;
1014
1016
1017 switch (audio->format_type_I_tx)
1018 {
1020
1021 n_bytes_tx = audiod_encode_type_I_pcm(rhport, audio);
1022 break;
1023
1024 default:
1025 // YOUR ENCODING IS REQUIRED HERE!
1026 TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_TX encoding not implemented!\r\n");
1027 TU_BREAKPOINT();
1028 n_bytes_tx = 0;
1029 break;
1030 }
1031 break;
1032
1033 default:
1034 // Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!
1035 TU_LOG2(" Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!\r\n");
1036 TU_BREAKPOINT();
1037 n_bytes_tx = 0;
1038 break;
1039 }
1040
1041 TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx));
1042
1043#else
1044 // No support FIFOs, if no linear buffer required schedule transmit, else put data into linear buffer and schedule
1045#if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
1046 // packet_sz_tx is based on total packet size, here we want size for each support buffer.
1047 n_bytes_tx = audiod_tx_packet_size(audio->packet_sz_tx, tu_fifo_count(&audio->ep_in_ff), audio->ep_in_ff.depth, audio->ep_in_sz);
1048#else
1049 n_bytes_tx = tu_min16(tu_fifo_count(&audio->ep_in_ff), audio->ep_in_sz); // Limit up to max packet size, more can not be done for ISO
1050#endif
1051#if USE_LINEAR_BUFFER_TX
1052 tu_fifo_read_n(&audio->ep_in_ff, audio->lin_buf_in, n_bytes_tx);
1053 TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_in, audio->lin_buf_in, n_bytes_tx));
1054#else
1055 // Send everything in ISO EP FIFO
1056 TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_in, &audio->ep_in_ff, n_bytes_tx));
1057#endif
1058
1059#endif
1060
1061 // 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
1062 TU_VERIFY(tud_audio_tx_done_post_load_cb(rhport, n_bytes_tx, idx_audio_fct, audio->ep_in, audio->alt_setting[idxItf]));
1063
1064 return true;
1065}
1066
1067#endif //CFG_TUD_AUDIO_ENABLE_EP_IN
1068
1069#if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_EP_IN
1070// Take samples from the support buffer and encode them into the IN EP software FIFO
1071// Returns number of bytes written into linear buffer
1072
1073/* 2.3.1.7.1 PCM Format
1074The PCM (Pulse Coded Modulation) format is the most commonly used audio format to represent audio
1075data streams. The audio data is not compressed and uses a signed two’s-complement fixed point format. It
1076is left-justified (the sign bit is the Msb) and data is padded with trailing zeros to fill the remaining unused
1077bits of the subslot. The binary point is located to the right of the sign bit so that all values lie within the
1078range [-1, +1)
1079 */
1080
1081/*
1082 * This function encodes channels saved within the support FIFOs into one stream by interleaving the PCM samples
1083 * in the support FIFOs according to 2.3.1.5 Audio Streams. It does not control justification (left or right) and
1084 * does not change the number of bytes per sample.
1085 * */
1086
1087// Helper function
1088static inline void * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesPerSample, void * src, const void * src_end, void * dst, uint8_t const n_ff_used)
1089{
1090 // Due to one FIFO contains 2 channels, data always aligned to (nBytesPerSample * 2)
1091 uint16_t * dst16 = dst;
1092 uint16_t * src16 = src;
1093 const uint16_t * src_end16 = src_end;
1094 uint32_t * dst32 = dst;
1095 uint32_t * src32 = src;
1096 const uint32_t * src_end32 = src_end;
1097
1098 if (nBytesPerSample == 1)
1099 {
1100 while(src16 < src_end16)
1101 {
1102 *dst16++ = *src16++;
1103 dst16 += n_ff_used - 1;
1104 }
1105 return dst16;
1106 }
1107 else if (nBytesPerSample == 2)
1108 {
1109 while(src32 < src_end32)
1110 {
1111 *dst32++ = *src32++;
1112 dst32 += n_ff_used - 1;
1113 }
1114 return dst32;
1115 }
1116 else if (nBytesPerSample == 3)
1117 {
1118 while(src16 < src_end16)
1119 {
1120 *dst16++ = *src16++;
1121 *dst16++ = *src16++;
1122 *dst16++ = *src16++;
1123 dst16 += 3 * (n_ff_used - 1);
1124 }
1125 return dst16;
1126 }
1127 else // nBytesPerSample == 4
1128 {
1129 while(src32 < src_end32)
1130 {
1131 *dst32++ = *src32++;
1132 *dst32++ = *src32++;
1133 dst32 += 2 * (n_ff_used - 1);
1134 }
1135 return dst32;
1136 }
1137}
1138
1139static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t* audio)
1140{
1141 // This function relies on the fact that the length of the support FIFOs was configured to be a multiple of the active sample size in bytes s.t. no sample is split within a wrap
1142 // This is ensured within set_interface, where the FIFOs are reconfigured according to this size
1143
1144 // We encode directly into IN EP's linear buffer - abort if previous transfer not complete
1145 TU_VERIFY(!usbd_edpt_busy(rhport, audio->ep_in));
1146
1147 // Determine amount of samples
1148 uint8_t const n_ff_used = audio->n_ff_used_tx;
1149 uint16_t nBytesPerFFToSend = tu_fifo_count(&audio->tx_supp_ff[0]);
1150 uint8_t cnt_ff;
1151
1152 for (cnt_ff = 1; cnt_ff < n_ff_used; cnt_ff++)
1153 {
1154 uint16_t const count = tu_fifo_count(&audio->tx_supp_ff[cnt_ff]);
1155 if (count < nBytesPerFFToSend)
1156 {
1157 nBytesPerFFToSend = count;
1158 }
1159 }
1160
1161#if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
1162 const uint16_t norm_packet_sz_tx[3] = {audio->packet_sz_tx[0] / n_ff_used,
1163 audio->packet_sz_tx[1] / n_ff_used,
1164 audio->packet_sz_tx[2] / n_ff_used};
1165 // packet_sz_tx is based on total packet size, here we want size for each support buffer.
1166 nBytesPerFFToSend = audiod_tx_packet_size(norm_packet_sz_tx, nBytesPerFFToSend, audio->tx_supp_ff[0].depth, audio->ep_in_sz / n_ff_used);
1167 // Check if there is enough data
1168 if (nBytesPerFFToSend == 0) return 0;
1169#else
1170 // Check if there is enough data
1171 if (nBytesPerFFToSend == 0) return 0;
1172 // Limit to maximum sample number - THIS IS A POSSIBLE ERROR SOURCE IF TOO MANY SAMPLE WOULD NEED TO BE SENT BUT CAN NOT!
1173 nBytesPerFFToSend = tu_min16(nBytesPerFFToSend, audio->ep_in_sz / n_ff_used);
1174 // Round to full number of samples (flooring)
1175 uint16_t const nSlotSize = audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx;
1176 nBytesPerFFToSend = (nBytesPerFFToSend / nSlotSize) * nSlotSize;
1177#endif
1178
1179 // Encode
1180 uint8_t * dst;
1181 uint8_t * src_end;
1182
1184
1185 for (cnt_ff = 0; cnt_ff < n_ff_used; cnt_ff++)
1186 {
1187 dst = &audio->lin_buf_in[cnt_ff*audio->n_channels_per_ff_tx*audio->n_bytes_per_sample_tx];
1188
1189 tu_fifo_get_read_info(&audio->tx_supp_ff[cnt_ff], &info);
1190
1191 if (info.len_lin != 0)
1192 {
1193 info.len_lin = tu_min16(nBytesPerFFToSend, info.len_lin); // Limit up to desired length
1194 src_end = (uint8_t *)info.ptr_lin + info.len_lin;
1195 dst = audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sample_tx, info.ptr_lin, src_end, dst, n_ff_used);
1196
1197 // Limit up to desired length
1198 info.len_wrap = tu_min16(nBytesPerFFToSend - info.len_lin, info.len_wrap);
1199
1200 // Handle wrapped part of FIFO
1201 if (info.len_wrap != 0)
1202 {
1203 src_end = (uint8_t *)info.ptr_wrap + info.len_wrap;
1204 audiod_interleaved_copy_bytes_fast_encode(audio->n_bytes_per_sample_tx, info.ptr_wrap, src_end, dst, n_ff_used);
1205 }
1206
1207 tu_fifo_advance_read_pointer(&audio->tx_supp_ff[cnt_ff], info.len_lin + info.len_wrap);
1208 }
1209 }
1210
1211 return nBytesPerFFToSend * n_ff_used;
1212}
1213#endif //CFG_TUD_AUDIO_ENABLE_ENCODING
1214
1215// This function is called once a transmit of a feedback packet was successfully completed. Here, we get the next feedback value to be sent
1216
1217#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
1218static inline bool audiod_fb_send(audiod_function_t *audio)
1219{
1220 bool apply_correction = (TUSB_SPEED_FULL == tud_speed_get()) && audio->feedback.format_correction;
1221 // Format the feedback value
1222 if (apply_correction)
1223 {
1224 uint8_t * fb = (uint8_t *) &audio->feedback.send_buf;
1225
1226 // For FS format is 10.14
1227 *(fb++) = (audio->feedback.value >> 2) & 0xFF;
1228 *(fb++) = (audio->feedback.value >> 10) & 0xFF;
1229 *(fb++) = (audio->feedback.value >> 18) & 0xFF;
1230 *fb = 0;
1231 } else
1232 {
1233 audio->feedback.send_buf = audio->feedback.value;
1234 }
1235
1236 // About feedback format on FS
1237 //
1238 // 3 variables: Format | packetSize | sendSize | Working OS:
1239 // 16.16 4 4 Linux, Windows
1240 // 16.16 4 3 Linux
1241 // 16.16 3 4 Linux
1242 // 16.16 3 3 Linux
1243 // 10.14 4 4 Linux
1244 // 10.14 4 3 Linux
1245 // 10.14 3 4 Linux, OSX
1246 // 10.14 3 3 Linux, OSX
1247 //
1248 // We send 3 bytes since sending packet larger than wMaxPacketSize is pretty ugly
1249 return usbd_edpt_xfer(audio->rhport, audio->ep_fb, (uint8_t *) &audio->feedback.send_buf, apply_correction ? 3 : 4);
1250}
1251#endif
1252
1253//--------------------------------------------------------------------+
1254// USBD Driver API
1255//--------------------------------------------------------------------+
1256void audiod_init(void)
1257{
1258 tu_memclr(_audiod_fct, sizeof(_audiod_fct));
1259
1260 for(uint8_t i=0; i<CFG_TUD_AUDIO; i++)
1261 {
1262 audiod_function_t* audio = &_audiod_fct[i];
1263
1264 // Initialize control buffers
1265 switch (i)
1266 {
1267 case 0:
1268 audio->ctrl_buf = ctrl_buf_1;
1269 audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ;
1270 break;
1271#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ > 0
1272 case 1:
1273 audio->ctrl_buf = ctrl_buf_2;
1274 audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ;
1275 break;
1276#endif
1277#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ > 0
1278 case 2:
1279 audio->ctrl_buf = ctrl_buf_3;
1280 audio->ctrl_buf_sz = CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ;
1281 break;
1282#endif
1283 }
1284
1285 // Initialize active alternate interface buffers
1286 switch (i)
1287 {
1288#if CFG_TUD_AUDIO_FUNC_1_N_AS_INT > 0
1289 case 0:
1290 audio->alt_setting = alt_setting_1;
1291 break;
1292#endif
1293#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_N_AS_INT > 0
1294 case 1:
1295 audio->alt_setting = alt_setting_2;
1296 break;
1297#endif
1298#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_N_AS_INT > 0
1299 case 2:
1300 audio->alt_setting = alt_setting_3;
1301 break;
1302#endif
1303 }
1304
1305 // Initialize IN EP FIFO if required
1306#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
1307
1308 switch (i)
1309 {
1310#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
1311 case 0:
1312 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);
1313#if CFG_FIFO_MUTEX
1315#endif
1316 break;
1317#endif
1318#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
1319 case 1:
1320 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);
1321#if CFG_FIFO_MUTEX
1323#endif
1324 break;
1325#endif
1326#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
1327 case 2:
1328 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);
1329#if CFG_FIFO_MUTEX
1331#endif
1332 break;
1333#endif
1334 }
1335#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
1336
1337 // Initialize linear buffers
1338#if USE_LINEAR_BUFFER_TX
1339 switch (i)
1340 {
1341#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX > 0
1342 case 0:
1343 audio->lin_buf_in = lin_buf_in_1;
1344 break;
1345#endif
1346#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SZ_MAX > 0
1347 case 1:
1348 audio->lin_buf_in = lin_buf_in_2;
1349 break;
1350#endif
1351#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SZ_MAX > 0
1352 case 2:
1353 audio->lin_buf_in = lin_buf_in_3;
1354 break;
1355#endif
1356 }
1357#endif // USE_LINEAR_BUFFER_TX
1358
1359 // Initialize OUT EP FIFO if required
1360#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
1361
1362 switch (i)
1363 {
1364#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
1365 case 0:
1366 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);
1367#if CFG_FIFO_MUTEX
1369#endif
1370 break;
1371#endif
1372#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
1373 case 1:
1374 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);
1375#if CFG_FIFO_MUTEX
1377#endif
1378 break;
1379#endif
1380#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
1381 case 2:
1382 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);
1383#if CFG_FIFO_MUTEX
1385#endif
1386 break;
1387#endif
1388 }
1389#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
1390
1391 // Initialize linear buffers
1392#if USE_LINEAR_BUFFER_RX
1393 switch (i)
1394 {
1395#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX > 0
1396 case 0:
1397 audio->lin_buf_out = lin_buf_out_1;
1398 break;
1399#endif
1400#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SZ_MAX > 0
1401 case 1:
1402 audio->lin_buf_out = lin_buf_out_2;
1403 break;
1404#endif
1405#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SZ_MAX > 0
1406 case 2:
1407 audio->lin_buf_out = lin_buf_out_3;
1408 break;
1409#endif
1410 }
1411#endif // USE_LINEAR_BUFFER_TX
1412
1413 // Initialize TX support FIFOs if required
1414#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
1415
1416 switch (i)
1417 {
1418#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
1419 case 0:
1420 audio->tx_supp_ff = tx_supp_ff_1;
1421 audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO;
1422 audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ;
1423 for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO; cnt++)
1424 {
1425 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);
1426#if CFG_FIFO_MUTEX
1428#endif
1429 }
1430
1431 break;
1432#endif // CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
1433
1434#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
1435 case 1:
1436 audio->tx_supp_ff = tx_supp_ff_2;
1437 audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO;
1438 audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ;
1439 for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO; cnt++)
1440 {
1441 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);
1442#if CFG_FIFO_MUTEX
1444#endif
1445 }
1446
1447 break;
1448#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
1449
1450#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
1451 case 2:
1452 audio->tx_supp_ff = tx_supp_ff_3;
1453 audio->n_tx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO;
1454 audio->tx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ;
1455 for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO; cnt++)
1456 {
1457 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);
1458#if CFG_FIFO_MUTEX
1460#endif
1461 }
1462
1463 break;
1464#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
1465 }
1466#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
1467
1468 // Set encoding parameters for Type_I formats
1469#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
1470 switch (i)
1471 {
1472#if CFG_TUD_AUDIO_FUNC_1_TX_SUPP_SW_FIFO_SZ > 0
1473 case 0:
1474 audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_TX;
1475 break;
1476#endif
1477#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_TX_SUPP_SW_FIFO_SZ > 0
1478 case 1:
1479 audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_TX;
1480 break;
1481#endif
1482#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_TX_SUPP_SW_FIFO_SZ > 0
1483 case 2:
1484 audio->n_channels_per_ff_tx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_TX;
1485 break;
1486#endif
1487 }
1488#endif // CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
1489
1490 // Initialize RX support FIFOs if required
1491#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
1492
1493 switch (i)
1494 {
1495#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
1496 case 0:
1497 audio->rx_supp_ff = rx_supp_ff_1;
1498 audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO;
1499 audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ;
1500 for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO; cnt++)
1501 {
1502 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);
1503#if CFG_FIFO_MUTEX
1505#endif
1506 }
1507
1508 break;
1509#endif // CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
1510
1511#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
1512 case 1:
1513 audio->rx_supp_ff = rx_supp_ff_2;
1514 audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO;
1515 audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ;
1516 for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO; cnt++)
1517 {
1518 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);
1519#if CFG_FIFO_MUTEX
1521#endif
1522 }
1523
1524 break;
1525#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
1526
1527#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
1528 case 2:
1529 audio->rx_supp_ff = rx_supp_ff_3;
1530 audio->n_rx_supp_ff = CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO;
1531 audio->rx_supp_ff_sz_max = CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ;
1532 for (uint8_t cnt = 0; cnt < CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO; cnt++)
1533 {
1534 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);
1535#if CFG_FIFO_MUTEX
1537#endif
1538 }
1539
1540 break;
1541#endif // CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
1542 }
1543#endif // CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
1544
1545 // Set encoding parameters for Type_I formats
1546#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
1547 switch (i)
1548 {
1549#if CFG_TUD_AUDIO_FUNC_1_RX_SUPP_SW_FIFO_SZ > 0
1550 case 0:
1551 audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_1_CHANNEL_PER_FIFO_RX;
1552 break;
1553#endif
1554#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_RX_SUPP_SW_FIFO_SZ > 0
1555 case 1:
1556 audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_2_CHANNEL_PER_FIFO_RX;
1557 break;
1558#endif
1559#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_RX_SUPP_SW_FIFO_SZ > 0
1560 case 2:
1561 audio->n_channels_per_ff_rx = CFG_TUD_AUDIO_FUNC_3_CHANNEL_PER_FIFO_RX;
1562 break;
1563#endif
1564 }
1565#endif // CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
1566 }
1567}
1568
1569bool audiod_deinit(void) {
1570 return false; // TODO not implemented yet
1571}
1572
1573void audiod_reset(uint8_t rhport)
1574{
1575 (void) rhport;
1576
1577 for(uint8_t i=0; i<CFG_TUD_AUDIO; i++)
1578 {
1579 audiod_function_t* audio = &_audiod_fct[i];
1580 tu_memclr(audio, ITF_MEM_RESET_SIZE);
1581
1582#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_ENCODING
1583 tu_fifo_clear(&audio->ep_in_ff);
1584#endif
1585
1586#if CFG_TUD_AUDIO_ENABLE_EP_OUT && !CFG_TUD_AUDIO_ENABLE_DECODING
1587 tu_fifo_clear(&audio->ep_out_ff);
1588#endif
1589
1590#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_ENCODING
1591 for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++)
1592 {
1593 tu_fifo_clear(&audio->tx_supp_ff[cnt]);
1594 }
1595#endif
1596
1597#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
1598 for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++)
1599 {
1600 tu_fifo_clear(&audio->rx_supp_ff[cnt]);
1601 }
1602#endif
1603 }
1604}
1605
1606uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
1607{
1608 (void) max_len;
1609
1610 TU_VERIFY ( TUSB_CLASS_AUDIO == itf_desc->bInterfaceClass &&
1612
1613 // Verify version is correct - this check can be omitted
1614 TU_VERIFY(itf_desc->bInterfaceProtocol == AUDIO_INT_PROTOCOL_CODE_V2);
1615
1616 // Verify interrupt control EP is enabled if demanded by descriptor
1617 TU_ASSERT(itf_desc->bNumEndpoints <= 1); // 0 or 1 EPs are allowed
1618 if (itf_desc->bNumEndpoints == 1)
1619 {
1620 TU_ASSERT(CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP);
1621 }
1622
1623 // Alternate setting MUST be zero - this check can be omitted
1624 TU_VERIFY(itf_desc->bAlternateSetting == 0);
1625
1626 // Find available audio driver interface
1627 uint8_t i;
1628 for (i = 0; i < CFG_TUD_AUDIO; i++)
1629 {
1630 if (!_audiod_fct[i].p_desc)
1631 {
1632 _audiod_fct[i].p_desc = (uint8_t const *)itf_desc; // Save pointer to AC descriptor which is by specification always the first one
1633 _audiod_fct[i].rhport = rhport;
1634
1635 // Setup descriptor lengths
1636 switch (i)
1637 {
1638 case 0:
1639 _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_1_DESC_LEN;
1640 break;
1641#if CFG_TUD_AUDIO > 1
1642 case 1:
1643 _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_2_DESC_LEN;
1644 break;
1645#endif
1646#if CFG_TUD_AUDIO > 2
1647 case 2:
1648 _audiod_fct[i].desc_length = CFG_TUD_AUDIO_FUNC_3_DESC_LEN;
1649 break;
1650#endif
1651 }
1652
1653#ifdef TUP_DCD_EDPT_ISO_ALLOC
1654 {
1655 #if CFG_TUD_AUDIO_ENABLE_EP_IN
1656 uint8_t ep_in = 0;
1657 uint16_t ep_in_size = 0;
1658 #endif
1659
1660 #if CFG_TUD_AUDIO_ENABLE_EP_OUT
1661 uint8_t ep_out = 0;
1662 uint16_t ep_out_size = 0;
1663 #endif
1664
1665 #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
1666 uint8_t ep_fb = 0;
1667 #endif
1668 uint8_t const *p_desc = _audiod_fct[i].p_desc;
1669 uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
1670 // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
1671 while (p_desc_end - p_desc > 0)
1672 {
1673 if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT)
1674 {
1675 tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
1676 if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS)
1677 {
1678 #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
1679 // Explicit feedback EP
1680 if (desc_ep->bmAttributes.usage == 1)
1681 {
1682 ep_fb = desc_ep->bEndpointAddress;
1683 }
1684 #endif
1685 // Data EP
1686 if (desc_ep->bmAttributes.usage == 0)
1687 {
1688 if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN)
1689 {
1690 #if CFG_TUD_AUDIO_ENABLE_EP_IN
1691 ep_in = desc_ep->bEndpointAddress;
1692 ep_in_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_in_size);
1693 #endif
1694 } else
1695 {
1696 #if CFG_TUD_AUDIO_ENABLE_EP_OUT
1697 ep_out = desc_ep->bEndpointAddress;
1698 ep_out_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_out_size);
1699 #endif
1700 }
1701 }
1702
1703 }
1704 }
1705
1706 p_desc = tu_desc_next(p_desc);
1707 }
1708
1709 #if CFG_TUD_AUDIO_ENABLE_EP_IN
1710 if (ep_in)
1711 {
1712 usbd_edpt_iso_alloc(rhport, ep_in, ep_in_size);
1713 }
1714 #endif
1715
1716 #if CFG_TUD_AUDIO_ENABLE_EP_OUT
1717 if (ep_out)
1718 {
1719 usbd_edpt_iso_alloc(rhport, ep_out, ep_out_size);
1720 }
1721 #endif
1722
1723 #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
1724 if (ep_fb)
1725 {
1726 usbd_edpt_iso_alloc(rhport, ep_fb, 4);
1727 }
1728 #endif
1729 }
1730#endif // TUP_DCD_EDPT_ISO_ALLOC
1731
1732#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
1733 {
1734 uint8_t const *p_desc = _audiod_fct[i].p_desc;
1735 uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
1736 // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
1737 while (p_desc_end - p_desc > 0)
1738 {
1739 if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT)
1740 {
1741 tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
1742 if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS)
1743 {
1744 if (desc_ep->bmAttributes.usage == 0)
1745 {
1746 if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN)
1747 {
1748 _audiod_fct[i].interval_tx = desc_ep->bInterval;
1749 }
1750 }
1751 }
1752 } else
1754 {
1756 {
1757 _audiod_fct[i].bclock_id_tx = p_desc[8];
1758 }
1759 }
1760 p_desc = tu_desc_next(p_desc);
1761 }
1762 }
1763#endif // CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
1764
1765#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
1766 {
1767 uint8_t const *p_desc = _audiod_fct[i].p_desc;
1768 uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
1769 // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
1770 while (p_desc_end - p_desc > 0)
1771 {
1772 // For each endpoint
1773 if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT)
1774 {
1775 tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc;
1776 uint8_t const ep_addr = desc_ep->bEndpointAddress;
1777 // If endpoint is input-direction and interrupt-type
1778 if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.xfer == TUSB_XFER_INTERRUPT)
1779 {
1780 // Store endpoint number and open endpoint
1781 _audiod_fct[i].ep_int = ep_addr;
1782 TU_ASSERT(usbd_edpt_open(_audiod_fct[i].rhport, desc_ep));
1783 }
1784 }
1785 p_desc = tu_desc_next(p_desc);
1786 }
1787 }
1788#endif
1789
1790 _audiod_fct[i].mounted = true;
1791 break;
1792 }
1793 }
1794
1795 // Verify we found a free one
1796 TU_ASSERT( i < CFG_TUD_AUDIO );
1797
1798 // This is all we need so far - the EPs are setup by a later set_interface request (as per UAC2 specification)
1799 uint16_t drv_len = _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; // - TUD_AUDIO_DESC_IAD_LEN since tinyUSB already handles the IAD descriptor
1800
1801 return drv_len;
1802}
1803
1804static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const * p_request)
1805{
1806 uint8_t const itf = tu_u16_low(p_request->wIndex);
1807
1808 // Find index of audio streaming interface
1809 uint8_t func_id, idxItf;
1810 uint8_t const *dummy;
1811
1812 TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &dummy));
1813 _audiod_fct[func_id].ctrl_buf[0] = _audiod_fct[func_id].alt_setting[idxItf];
1814 TU_VERIFY(tud_control_xfer(rhport, p_request, _audiod_fct[func_id].ctrl_buf, 1));
1815
1816 TU_LOG2(" Get itf: %u - current alt: %u\r\n", itf, _audiod_fct[func_id].alt_setting[idxItf]);
1817
1818 return true;
1819}
1820
1821static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const * p_request)
1822{
1823 (void) rhport;
1824
1825 // Here we need to do the following:
1826
1827 // 1. Find the audio driver assigned to the given interface to be set
1828 // Since one audio driver interface has to be able to cover an unknown number of interfaces (AC, AS + its alternate settings), the best memory efficient way to solve this is to always search through the descriptors.
1829 // The audio driver is mapped to an audio function by a reference pointer to the corresponding AC interface of this audio function which serves as a starting point for searching
1830
1831 // 2. Close EPs which are currently open
1832 // To do so it is not necessary to know the current active alternate interface since we already save the current EP addresses - we simply close them
1833
1834 // 3. Open new EP
1835
1836 uint8_t const itf = tu_u16_low(p_request->wIndex);
1837 uint8_t const alt = tu_u16_low(p_request->wValue);
1838
1839 TU_LOG2(" Set itf: %u - alt: %u\r\n", itf, alt);
1840
1841 // Find index of audio streaming interface and index of interface
1842 uint8_t func_id, idxItf;
1843 uint8_t const *p_desc;
1844 TU_VERIFY(audiod_get_AS_interface_index_global(itf, &func_id, &idxItf, &p_desc));
1845
1846 audiod_function_t* audio = &_audiod_fct[func_id];
1847
1848 // Look if there is an EP to be closed - for this driver, there are only 3 possible EPs which may be closed (only AS related EPs can be closed, AC EP (if present) is always open)
1849#if CFG_TUD_AUDIO_ENABLE_EP_IN
1850 if (audio->ep_in_as_intf_num == itf)
1851 {
1852 audio->ep_in_as_intf_num = 0;
1853 #ifndef TUP_DCD_EDPT_ISO_ALLOC
1854 usbd_edpt_close(rhport, audio->ep_in);
1855 #endif
1856
1857 // Clear FIFOs, since data is no longer valid
1858 #if !CFG_TUD_AUDIO_ENABLE_ENCODING
1859 tu_fifo_clear(&audio->ep_in_ff);
1860 #else
1861 for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++)
1862 {
1863 tu_fifo_clear(&audio->tx_supp_ff[cnt]);
1864 }
1865 #endif
1866
1867 // Invoke callback - can be used to stop data sampling
1868 TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
1869
1870 audio->ep_in = 0; // Necessary?
1871
1872 #if CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
1873 audio->packet_sz_tx[0] = 0;
1874 audio->packet_sz_tx[1] = 0;
1875 audio->packet_sz_tx[2] = 0;
1876 #endif
1877 }
1878#endif // CFG_TUD_AUDIO_ENABLE_EP_IN
1879
1880#if CFG_TUD_AUDIO_ENABLE_EP_OUT
1881 if (audio->ep_out_as_intf_num == itf)
1882 {
1883 audio->ep_out_as_intf_num = 0;
1884 #ifndef TUP_DCD_EDPT_ISO_ALLOC
1885 usbd_edpt_close(rhport, audio->ep_out);
1886 #endif
1887
1888 // Clear FIFOs, since data is no longer valid
1889 #if !CFG_TUD_AUDIO_ENABLE_DECODING
1890 tu_fifo_clear(&audio->ep_out_ff);
1891 #else
1892 for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++)
1893 {
1894 tu_fifo_clear(&audio->rx_supp_ff[cnt]);
1895 }
1896 #endif
1897
1898 // Invoke callback - can be used to stop data sampling
1899 TU_VERIFY(tud_audio_set_itf_close_EP_cb(rhport, p_request));
1900
1901 audio->ep_out = 0; // Necessary?
1902
1903 // Close corresponding feedback EP
1904 #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
1905 #ifndef TUP_DCD_EDPT_ISO_ALLOC
1906 usbd_edpt_close(rhport, audio->ep_fb);
1907 #endif
1908 audio->ep_fb = 0;
1909 tu_memclr(&audio->feedback, sizeof(audio->feedback));
1910 #endif
1911 }
1912#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
1913
1914 // Save current alternative interface setting
1915 audio->alt_setting[idxItf] = alt;
1916
1917 // Open new EP if necessary - EPs are only to be closed or opened for AS interfaces - Look for AS interface with correct alternate interface
1918 // Get pointer at end
1919 uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN;
1920
1921 // p_desc starts at required interface with alternate setting zero
1922 // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
1923 while (p_desc_end - p_desc > 0)
1924 {
1925 // Find correct interface
1926 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)
1927 {
1928#if (CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL || CFG_TUD_AUDIO_ENABLE_ENCODING)) || (CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING)
1929 uint8_t const * p_desc_parse_for_params = p_desc;
1930#endif
1931 // From this point forward follow the EP descriptors associated to the current alternate setting interface - Open EPs if necessary
1932 uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints;
1933 // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
1934 while (foundEPs < nEps && (p_desc_end - p_desc > 0))
1935 {
1936 if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT)
1937 {
1938 tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc;
1939#ifdef TUP_DCD_EDPT_ISO_ALLOC
1940 TU_ASSERT(usbd_edpt_iso_activate(rhport, desc_ep));
1941#else
1942 TU_ASSERT(usbd_edpt_open(rhport, desc_ep));
1943#endif
1944 uint8_t const ep_addr = desc_ep->bEndpointAddress;
1945
1946 //TODO: We need to set EP non busy since this is not taken care of right now in ep_close() - THIS IS A WORKAROUND!
1947 usbd_edpt_clear_stall(rhport, ep_addr);
1948
1949#if CFG_TUD_AUDIO_ENABLE_EP_IN
1950 if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 0x00) // Check if usage is data EP
1951 {
1952 // Save address
1953 audio->ep_in = ep_addr;
1954 audio->ep_in_as_intf_num = itf;
1955 audio->ep_in_sz = tu_edpt_packet_size(desc_ep);
1956
1957 // If software encoding is enabled, parse for the corresponding parameters - doing this here means only AS interfaces with EPs get scanned for parameters
1958 #if CFG_TUD_AUDIO_ENABLE_ENCODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
1959 audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf);
1960
1961 // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap
1962 #if CFG_TUD_AUDIO_ENABLE_ENCODING && CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
1963 const uint16_t active_fifo_depth = (uint16_t) ((audio->tx_supp_ff_sz_max / (audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx))
1964 * (audio->n_channels_per_ff_tx * audio->n_bytes_per_sample_tx));
1965 for (uint8_t cnt = 0; cnt < audio->n_tx_supp_ff; cnt++)
1966 {
1967 tu_fifo_config(&audio->tx_supp_ff[cnt], audio->tx_supp_ff[cnt].buffer, active_fifo_depth, 1, true);
1968 }
1969 audio->n_ff_used_tx = audio->n_channels_tx / audio->n_channels_per_ff_tx;
1970 TU_ASSERT( audio->n_ff_used_tx <= audio->n_tx_supp_ff );
1971 #endif
1972 #endif
1973
1974 // Schedule first transmit if alternate interface is not zero i.e. streaming is disabled - in case no sample data is available a ZLP is loaded
1975 // It is necessary to trigger this here since the refill is done with an RX FIFO empty interrupt which can only trigger if something was in there
1976 TU_VERIFY(audiod_tx_done_cb(rhport, &_audiod_fct[func_id]));
1977 }
1978#endif // CFG_TUD_AUDIO_ENABLE_EP_IN
1979
1980#if CFG_TUD_AUDIO_ENABLE_EP_OUT
1981
1982 if (tu_edpt_dir(ep_addr) == TUSB_DIR_OUT) // Checking usage not necessary
1983 {
1984 // Save address
1985 audio->ep_out = ep_addr;
1986 audio->ep_out_as_intf_num = itf;
1987 audio->ep_out_sz = tu_edpt_packet_size(desc_ep);
1988
1989 #if CFG_TUD_AUDIO_ENABLE_DECODING
1990 audiod_parse_for_AS_params(audio, p_desc_parse_for_params, p_desc_end, itf);
1991
1992 // Reconfigure size of support FIFOs - this is necessary to avoid samples to get split in case of a wrap
1993 #if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
1994 const uint16_t active_fifo_depth = (audio->rx_supp_ff_sz_max / audio->n_bytes_per_sample_rx) * audio->n_bytes_per_sample_rx;
1995 for (uint8_t cnt = 0; cnt < audio->n_rx_supp_ff; cnt++)
1996 {
1997 tu_fifo_config(&audio->rx_supp_ff[cnt], audio->rx_supp_ff[cnt].buffer, active_fifo_depth, 1, true);
1998 }
1999 audio->n_ff_used_rx = audio->n_channels_rx / audio->n_channels_per_ff_rx;
2000 TU_ASSERT( audio->n_ff_used_rx <= audio->n_rx_supp_ff );
2001 #endif
2002 #endif
2003
2004 // Prepare for incoming data
2005 #if USE_LINEAR_BUFFER_RX
2006 TU_VERIFY(usbd_edpt_xfer(rhport, audio->ep_out, audio->lin_buf_out, audio->ep_out_sz), false);
2007 #else
2008 TU_VERIFY(usbd_edpt_xfer_fifo(rhport, audio->ep_out, &audio->ep_out_ff, audio->ep_out_sz), false);
2009 #endif
2010 }
2011
2012 #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
2013 if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.usage == 1) // Check if usage is explicit data feedback
2014 {
2015 audio->ep_fb = ep_addr;
2016 audio->feedback.frame_shift = desc_ep->bInterval -1;
2017 }
2018 #endif
2019#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
2020
2021 foundEPs += 1;
2022 }
2023 p_desc = tu_desc_next(p_desc);
2024 }
2025
2026 TU_VERIFY(foundEPs == nEps);
2027
2028 // Invoke one callback for a final set interface
2029 TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
2030
2031#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
2032 // Prepare feedback computation if endpoint is available
2033 if(audio->ep_fb != 0)
2034 {
2035 audio_feedback_params_t fb_param;
2036
2037 tud_audio_feedback_params_cb(func_id, alt, &fb_param);
2038 audio->feedback.compute_method = fb_param.method;
2039
2042
2043 // Minimal/Maximum value in 16.16 format for full speed (1ms per frame) or high speed (125 us per frame)
2044 uint32_t const frame_div = (TUSB_SPEED_FULL == tud_speed_get()) ? 1000 : 8000;
2045 audio->feedback.min_value = ((fb_param.sample_freq - 1)/frame_div) << 16;
2046 audio->feedback.max_value = (fb_param.sample_freq/frame_div + 1) << 16;
2047
2048 switch(fb_param.method)
2049 {
2053 audiod_set_fb_params_freq(audio, fb_param.sample_freq, fb_param.frequency.mclk_freq);
2054 break;
2055
2057 {
2058 // Initialize the threshold level to half filled
2059 uint16_t fifo_lvl_thr;
2060#if CFG_TUD_AUDIO_ENABLE_DECODING
2061 fifo_lvl_thr = tu_fifo_depth(&audio->rx_supp_ff[0]) / 2;
2062#else
2063 fifo_lvl_thr = tu_fifo_depth(&audio->ep_out_ff) / 2;
2064#endif
2065 audio->feedback.compute.fifo_count.fifo_lvl_thr = fifo_lvl_thr;
2066 audio->feedback.compute.fifo_count.fifo_lvl_avg = ((uint32_t)fifo_lvl_thr) << 16;
2067 // Avoid 64bit division
2068 uint32_t nominal = ((fb_param.sample_freq / 100) << 16) / (frame_div / 100);
2069 audio->feedback.compute.fifo_count.nom_value = nominal;
2070 audio->feedback.compute.fifo_count.rate_const[0] = (uint16_t) ((audio->feedback.max_value - nominal) / fifo_lvl_thr);
2071 audio->feedback.compute.fifo_count.rate_const[1] = (uint16_t) ((nominal - audio->feedback.min_value) / fifo_lvl_thr);
2072 // On HS feedback is more sensitive since packet size can vary every MSOF, could cause instability
2074 audio->feedback.compute.fifo_count.rate_const[0] /= 8;
2075 audio->feedback.compute.fifo_count.rate_const[1] /= 8;
2076 }
2077 }
2078 break;
2079
2080 // nothing to do
2081 default: break;
2082 }
2083 }
2084#endif // CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
2085
2086 // We are done - abort loop
2087 break;
2088 }
2089
2090 // Moving forward
2091 p_desc = tu_desc_next(p_desc);
2092 }
2093
2094#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
2095 // Disable SOF interrupt if no driver has any enabled feedback EP
2096 bool enable_sof = false;
2097 for(uint8_t i=0; i < CFG_TUD_AUDIO; i++)
2098 {
2099 if (_audiod_fct[i].ep_fb != 0 &&
2103 {
2104 enable_sof = true;
2105 break;
2106 }
2107 }
2108 usbd_sof_enable(rhport, SOF_CONSUMER_AUDIO, enable_sof);
2109#endif
2110
2111#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
2113#endif
2114
2115 tud_control_status(rhport, p_request);
2116
2117 return true;
2118}
2119
2120// Invoked when class request DATA stage is finished.
2121// return false to stall control EP (e.g Host send non-sense DATA)
2122static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const * p_request)
2123{
2124 // Handle audio class specific set requests
2125 if(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && p_request->bmRequestType_bit.direction == TUSB_DIR_OUT)
2126 {
2127 uint8_t func_id;
2128
2129 switch (p_request->bmRequestType_bit.recipient)
2130 {
2132 {
2133 uint8_t itf = TU_U16_LOW(p_request->wIndex);
2134 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
2135
2136 if (entityID != 0)
2137 {
2138 // Check if entity is present and get corresponding driver index
2139 TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
2140
2141#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
2142 uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
2143 if (_audiod_fct[func_id].bclock_id_tx == entityID && ctrlSel == AUDIO_CS_CTRL_SAM_FREQ && p_request->bRequest == AUDIO_CS_REQ_CUR) {
2144 _audiod_fct[func_id].sample_rate_tx = tu_unaligned_read32(_audiod_fct[func_id].ctrl_buf);
2145 }
2146#endif
2147
2148 // Invoke callback
2149 return tud_audio_set_req_entity_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
2150 }
2151 else
2152 {
2153 // Find index of audio driver structure and verify interface really exists
2154 TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
2155
2156 // Invoke callback
2157 return tud_audio_set_req_itf_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
2158 }
2159 }
2160 break;
2161
2163 {
2164 uint8_t ep = TU_U16_LOW(p_request->wIndex);
2165
2166 // Check if entity is present and get corresponding driver index
2167 TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
2168
2169 // Invoke callback
2170 return tud_audio_set_req_ep_cb(rhport, p_request, _audiod_fct[func_id].ctrl_buf);
2171 }
2172 break;
2173 // Unknown/Unsupported recipient
2174 default: TU_BREAKPOINT(); return false;
2175 }
2176 }
2177 return true;
2178}
2179
2180// Handle class control request
2181// return false to stall control endpoint (e.g unsupported request)
2182static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const * p_request)
2183{
2184 (void) rhport;
2185
2186 // Handle standard requests - standard set requests usually have no data stage so we also handle set requests here
2187 if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD)
2188 {
2189 switch (p_request->bRequest)
2190 {
2192 return audiod_get_interface(rhport, p_request);
2193
2195 return audiod_set_interface(rhport, p_request);
2196
2198 return true;
2199
2200 // Unknown/Unsupported request
2201 default: TU_BREAKPOINT(); return false;
2202 }
2203 }
2204
2205 // Handle class requests
2206 if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS)
2207 {
2208 uint8_t itf = TU_U16_LOW(p_request->wIndex);
2209 uint8_t func_id;
2210
2211 // Conduct checks which depend on the recipient
2212 switch (p_request->bmRequestType_bit.recipient)
2213 {
2215 {
2216 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
2217
2218 // Verify if entity is present
2219 if (entityID != 0)
2220 {
2221 // Find index of audio driver structure and verify entity really exists
2222 TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
2223
2224 // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
2225 if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
2226 {
2227 return tud_audio_get_req_entity_cb(rhport, p_request);
2228 }
2229 }
2230 else
2231 {
2232 // Find index of audio driver structure and verify interface really exists
2233 TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
2234
2235 // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
2236 if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
2237 {
2238 return tud_audio_get_req_itf_cb(rhport, p_request);
2239 }
2240 }
2241 }
2242 break;
2243
2245 {
2246 uint8_t ep = TU_U16_LOW(p_request->wIndex);
2247
2248 // Find index of audio driver structure and verify EP really exists
2249 TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
2250
2251 // In case we got a get request invoke callback - callback needs to answer as defined in UAC2 specification page 89 - 5. Requests
2252 if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN)
2253 {
2254 return tud_audio_get_req_ep_cb(rhport, p_request);
2255 }
2256 }
2257 break;
2258
2259 // Unknown/Unsupported recipient
2260 default: TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false;
2261 }
2262
2263 // If we end here, the received request is a set request - we schedule a receive for the data stage and return true here. We handle the rest later in audiod_control_complete() once the data stage was finished
2264 TU_VERIFY(tud_control_xfer(rhport, p_request, _audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz));
2265 return true;
2266 }
2267
2268 // There went something wrong - unsupported control request type
2269 TU_BREAKPOINT();
2270 return false;
2271}
2272
2273bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
2274{
2275 if ( stage == CONTROL_STAGE_SETUP )
2276 {
2277 return audiod_control_request(rhport, request);
2278 }
2279 else if ( stage == CONTROL_STAGE_DATA )
2280 {
2281 return audiod_control_complete(rhport, request);
2282 }
2283
2284 return true;
2285}
2286
2287bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
2288{
2289 (void) result;
2290 (void) xferred_bytes;
2291
2292 // Search for interface belonging to given end point address and proceed as required
2293 for (uint8_t func_id = 0; func_id < CFG_TUD_AUDIO; func_id++)
2294 {
2295 audiod_function_t* audio = &_audiod_fct[func_id];
2296
2297#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP
2298
2299 // Data transmission of control interrupt finished
2300 if (audio->ep_int == ep_addr)
2301 {
2302 // According to USB2 specification, maximum payload of interrupt EP is 8 bytes on low speed, 64 bytes on full speed, and 1024 bytes on high speed (but only if an alternate interface other than 0 is used - see specification p. 49)
2303 // In case there is nothing to send we have to return a NAK - this is taken care of by PHY ???
2304 // In case of an erroneous transmission a retransmission is conducted - this is taken care of by PHY ???
2305
2306 // I assume here, that things above are handled by PHY
2307 // All transmission is done - what remains to do is to inform job was completed
2308
2309 tud_audio_int_done_cb(rhport);
2310 return true;
2311 }
2312
2313#endif
2314
2315#if CFG_TUD_AUDIO_ENABLE_EP_IN
2316
2317 // Data transmission of audio packet finished
2318 if (audio->ep_in == ep_addr && audio->alt_setting != 0)
2319 {
2320 // USB 2.0, section 5.6.4, third paragraph, states "An isochronous endpoint must specify its required bus access period. However, an isochronous endpoint must be prepared to handle poll rates faster than the one specified."
2321 // That paragraph goes on to say "An isochronous IN endpoint must return a zero-length packet whenever data is requested at a faster interval than the specified interval and data is not available."
2322 // This can only be solved reliably if we load a ZLP after every IN transmission since we can not say if the host requests samples earlier than we declared! Once all samples are collected we overwrite the loaded ZLP.
2323
2324 // Check if there is data to load into EPs buffer - if not load it with ZLP
2325 // Be aware - we as a device are not able to know if the host polls for data with a faster rate as we stated this in the descriptors. Therefore we always have to put something into the EPs buffer. However, once we did that, there is no way of aborting this or replacing what we put into the buffer before!
2326 // This is the only place where we can fill something into the EPs buffer!
2327
2328 // Load new data
2329 TU_VERIFY(audiod_tx_done_cb(rhport, audio));
2330
2331 // Transmission of ZLP is done by audiod_tx_done_cb()
2332 return true;
2333 }
2334#endif
2335
2336#if CFG_TUD_AUDIO_ENABLE_EP_OUT
2337
2338 // New audio packet received
2339 if (audio->ep_out == ep_addr)
2340 {
2341 TU_VERIFY(audiod_rx_done_cb(rhport, audio, (uint16_t) xferred_bytes));
2342 return true;
2343 }
2344
2345
2346#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
2347 // Transmission of feedback EP finished
2348 if (audio->ep_fb == ep_addr)
2349 {
2350 tud_audio_fb_done_cb(func_id);
2351
2352 // Schedule a transmit with the new value if EP is not busy
2353 if (usbd_edpt_claim(rhport, audio->ep_fb))
2354 {
2355 // Schedule next transmission - value is changed bytud_audio_n_fb_set() in the meantime or the old value gets sent
2356 return audiod_fb_send(audio);
2357 }
2358 }
2359#endif
2360#endif
2361 }
2362
2363 return false;
2364}
2365
2366#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
2367
2368static bool audiod_set_fb_params_freq(audiod_function_t* audio, uint32_t sample_freq, uint32_t mclk_freq)
2369{
2370 // Check if frame interval is within sane limits
2371 // The interval value n_frames was taken from the descriptors within audiod_set_interface()
2372
2373 // n_frames_min is ceil(2^10 * f_s / f_m) for full speed and ceil(2^13 * f_s / f_m) for high speed
2374 // this lower limit ensures the measures feedback value has sufficient precision
2375 uint32_t const k = (TUSB_SPEED_FULL == tud_speed_get()) ? 10 : 13;
2376 uint32_t const n_frame = (1UL << audio->feedback.frame_shift);
2377
2378 if ( (((1UL << k) * sample_freq / mclk_freq) + 1) > n_frame )
2379 {
2380 TU_LOG1(" UAC2 feedback interval too small\r\n"); TU_BREAKPOINT(); return false;
2381 }
2382
2383 // Check if parameters really allow for a power of two division
2384 if ((mclk_freq % sample_freq) == 0 && tu_is_power_of_two(mclk_freq / sample_freq))
2385 {
2387 audio->feedback.compute.power_of_2 = (uint8_t) (16 - (audio->feedback.frame_shift - 1) - tu_log2(mclk_freq / sample_freq));
2388 }
2390 {
2391 audio->feedback.compute.float_const = (float)sample_freq / (float) mclk_freq * (1UL << (16 - (audio->feedback.frame_shift - 1)));
2392 }
2393 else
2394 {
2395 audio->feedback.compute.fixed.sample_freq = sample_freq;
2396 audio->feedback.compute.fixed.mclk_freq = mclk_freq;
2397 }
2398
2399 return true;
2400}
2401
2402static void audiod_fb_fifo_count_update(audiod_function_t* audio, uint16_t lvl_new)
2403{
2404 /* Low-pass (averaging) filter */
2405 uint32_t lvl = audio->feedback.compute.fifo_count.fifo_lvl_avg;
2406 lvl = (uint32_t)(((uint64_t)lvl * 63 + ((uint32_t)lvl_new << 16)) >> 6);
2408
2409 uint32_t const ff_lvl = lvl >> 16;
2410 uint16_t const ff_thr = audio->feedback.compute.fifo_count.fifo_lvl_thr;
2411 uint16_t const *rate = audio->feedback.compute.fifo_count.rate_const;
2412
2413 uint32_t feedback;
2414
2415 if(ff_lvl < ff_thr)
2416 {
2417 feedback = audio->feedback.compute.fifo_count.nom_value + (ff_thr - ff_lvl) * rate[0];
2418 } else
2419 {
2420 feedback = audio->feedback.compute.fifo_count.nom_value - (ff_lvl - ff_thr) * rate[1];
2421 }
2422
2423 if ( feedback > audio->feedback.max_value ) feedback = audio->feedback.max_value;
2424 if ( feedback < audio->feedback.min_value ) feedback = audio->feedback.min_value;
2425 audio->feedback.value = feedback;
2426
2427 // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value
2428 if (usbd_edpt_claim(audio->rhport, audio->ep_fb))
2429 {
2430 audiod_fb_send(audio);
2431 }
2432}
2433
2434uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles)
2435{
2436 audiod_function_t* audio = &_audiod_fct[func_id];
2437 uint32_t feedback;
2438
2439 switch (audio->feedback.compute_method)
2440 {
2442 feedback = (cycles << audio->feedback.compute.power_of_2);
2443 break;
2444
2446 feedback = (uint32_t) ((float) cycles * audio->feedback.compute.float_const);
2447 break;
2448
2450 {
2451 uint64_t fb64 = (((uint64_t) cycles) * audio->feedback.compute.fixed.sample_freq) << (16 - (audio->feedback.frame_shift - 1));
2452 feedback = (uint32_t) (fb64 / audio->feedback.compute.fixed.mclk_freq);
2453 }
2454 break;
2455
2456 default: return 0;
2457 }
2458
2459 // For Windows: https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/usb-2-0-audio-drivers
2460 // The size of isochronous packets created by the device must be within the limits specified in FMT-2.0 section 2.3.1.1.
2461 // This means that the deviation of actual packet size from nominal size must not exceed +/- one audio slot
2462 // (audio slot = channel count samples).
2463 if ( feedback > audio->feedback.max_value ) feedback = audio->feedback.max_value;
2464 if ( feedback < audio->feedback.min_value ) feedback = audio->feedback.min_value;
2465
2466 tud_audio_n_fb_set(func_id, feedback);
2467
2468 return feedback;
2469}
2470
2471bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback)
2472{
2473 TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL);
2474
2475 _audiod_fct[func_id].feedback.value = feedback;
2476
2477 // Schedule a transmit with the new value if EP is not busy - this triggers repetitive scheduling of the feedback value
2478 if (usbd_edpt_claim(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_fb))
2479 {
2480 return audiod_fb_send(&_audiod_fct[func_id]);
2481 }
2482
2483 return true;
2484}
2485#endif
2486
2487TU_ATTR_FAST_FUNC void audiod_sof_isr (uint8_t rhport, uint32_t frame_count)
2488{
2489 (void) rhport;
2490 (void) frame_count;
2491
2492#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
2493 // Determine feedback value - The feedback method is described in 5.12.4.2 of the USB 2.0 spec
2494 // Boiled down, the feedback value Ff = n_samples / (micro)frame.
2495 // Since an accuracy of less than 1 Sample / second is desired, at least n_frames = ceil(2^K * f_s / f_m) frames need to be measured, where K = 10 for full speed and K = 13 for high speed, f_s is the sampling frequency e.g. 48 kHz and f_m is the cpu clock frequency e.g. 100 MHz (or any other master clock whose clock count is available and locked to f_s)
2496 // The update interval in the (4.10.2.1) Feedback Endpoint Descriptor must be less or equal to 2^(K - P), where P = min( ceil(log2(f_m / f_s)), K)
2497 // feedback = n_cycles / n_frames * f_s / f_m in 16.16 format, where n_cycles are the number of main clock cycles within fb_n_frames
2498
2499 // Iterate over audio functions and set feedback value
2500 for(uint8_t i=0; i < CFG_TUD_AUDIO; i++)
2501 {
2502 audiod_function_t* audio = &_audiod_fct[i];
2503
2504 if (audio->ep_fb != 0)
2505 {
2506 // HS shift need to be adjusted since SOF event is generated for frame only
2507 uint8_t const hs_adjust = (TUSB_SPEED_HIGH == tud_speed_get()) ? 3 : 0;
2508 uint32_t const interval = 1UL << (audio->feedback.frame_shift - hs_adjust);
2509 if ( 0 == (frame_count & (interval-1)) )
2510 {
2512 }
2513 }
2514 }
2515#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
2516}
2517
2518bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const * p_request, void* data, uint16_t len)
2519{
2520 // Handles only sending of data not receiving
2521 if (p_request->bmRequestType_bit.direction == TUSB_DIR_OUT) return false;
2522
2523 // Get corresponding driver index
2524 uint8_t func_id;
2525 uint8_t itf = TU_U16_LOW(p_request->wIndex);
2526
2527 // Conduct checks which depend on the recipient
2528 switch (p_request->bmRequestType_bit.recipient)
2529 {
2531 {
2532 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
2533
2534 // Verify if entity is present
2535 if (entityID != 0)
2536 {
2537 // Find index of audio driver structure and verify entity really exists
2538 TU_VERIFY(audiod_verify_entity_exists(itf, entityID, &func_id));
2539 }
2540 else
2541 {
2542 // Find index of audio driver structure and verify interface really exists
2543 TU_VERIFY(audiod_verify_itf_exists(itf, &func_id));
2544 }
2545 }
2546 break;
2547
2549 {
2550 uint8_t ep = TU_U16_LOW(p_request->wIndex);
2551
2552 // Find index of audio driver structure and verify EP really exists
2553 TU_VERIFY(audiod_verify_ep_exists(ep, &func_id));
2554 }
2555 break;
2556
2557 // Unknown/Unsupported recipient
2558 default: TU_LOG2(" Unsupported recipient: %d\r\n", p_request->bmRequestType_bit.recipient); TU_BREAKPOINT(); return false;
2559 }
2560
2561 // Crop length
2562 if (len > _audiod_fct[func_id].ctrl_buf_sz) len = _audiod_fct[func_id].ctrl_buf_sz;
2563
2564 // Copy into buffer
2565 TU_VERIFY(0 == tu_memcpy_s(_audiod_fct[func_id].ctrl_buf, _audiod_fct[func_id].ctrl_buf_sz, data, (size_t)len));
2566
2567#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
2568 // Find data for sampling_frequency_control
2569 if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS && p_request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE)
2570 {
2571 uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
2572 uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
2573 if (_audiod_fct[func_id].bclock_id_tx == entityID && ctrlSel == AUDIO_CS_CTRL_SAM_FREQ && p_request->bRequest == AUDIO_CS_REQ_CUR)
2574 {
2575 _audiod_fct[func_id].sample_rate_tx = tu_unaligned_read32(_audiod_fct[func_id].ctrl_buf);
2576 }
2577 }
2578#endif
2579
2580 // Schedule transmit
2581 return tud_control_xfer(rhport, p_request, (void*)_audiod_fct[func_id].ctrl_buf, len);
2582}
2583
2584// This helper function finds for a given audio function and AS interface number the index of the attached driver structure, the index of the interface in the audio function
2585// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and
2586// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero.
2587static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t * audio, uint8_t *idxItf, uint8_t const **pp_desc_int)
2588{
2589 if (audio->p_desc)
2590 {
2591 // Get pointer at end
2592 uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN;
2593
2594 // Advance past AC descriptors
2595 uint8_t const *p_desc = tu_desc_next(audio->p_desc);
2596 p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength;
2597
2598 uint8_t tmp = 0;
2599 // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
2600 while (p_desc_end - p_desc > 0)
2601 {
2602 // We assume the number of alternate settings is increasing thus we return the index of alternate setting zero!
2603 if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0)
2604 {
2605 if (((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == itf)
2606 {
2607 *idxItf = tmp;
2608 *pp_desc_int = p_desc;
2609 return true;
2610 }
2611 // Increase index, bytes read, and pointer
2612 tmp++;
2613 }
2614 p_desc = tu_desc_next(p_desc);
2615 }
2616 }
2617 return false;
2618}
2619
2620// This helper function finds for a given AS interface number the index of the attached driver structure, the index of the interface in the audio function
2621// (e.g. the std. AS interface with interface number 15 is the first AS interface for the given audio function and thus gets index zero), and
2622// finally a pointer to the std. AS interface, where the pointer always points to the first alternate setting i.e. alternate interface zero.
2623static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int)
2624{
2625 // Loop over audio driver interfaces
2626 uint8_t i;
2627 for (i = 0; i < CFG_TUD_AUDIO; i++)
2628 {
2629 if (audiod_get_AS_interface_index(itf, &_audiod_fct[i], idxItf, pp_desc_int))
2630 {
2631 *func_id = i;
2632 return true;
2633 }
2634 }
2635
2636 return false;
2637}
2638
2639// Verify an entity with the given ID exists and returns also the corresponding driver index
2640static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id)
2641{
2642 uint8_t i;
2643 for (i = 0; i < CFG_TUD_AUDIO; i++)
2644 {
2645 // Look for the correct driver by checking if the unique standard AC interface number fits
2646 if (_audiod_fct[i].p_desc && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf)
2647 {
2648 // Get pointers after class specific AC descriptors and end of AC descriptors - entities are defined in between
2649 uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc); // Points to CS AC descriptor
2650 uint8_t const *p_desc_end = ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength + p_desc;
2651 p_desc = tu_desc_next(p_desc); // Get past CS AC descriptor
2652
2653 // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
2654 while (p_desc_end - p_desc > 0)
2655 {
2656 if (p_desc[3] == entityID) // Entity IDs are always at offset 3
2657 {
2658 *func_id = i;
2659 return true;
2660 }
2661 p_desc = tu_desc_next(p_desc);
2662 }
2663 }
2664 }
2665 return false;
2666}
2667
2668static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id)
2669{
2670 uint8_t i;
2671 for (i = 0; i < CFG_TUD_AUDIO; i++)
2672 {
2673 if (_audiod_fct[i].p_desc)
2674 {
2675 // Get pointer at beginning and end
2676 uint8_t const *p_desc = _audiod_fct[i].p_desc;
2677 uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN;
2678 // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
2679 while (p_desc_end - p_desc > 0)
2680 {
2681 if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const *)_audiod_fct[i].p_desc)->bInterfaceNumber == itf)
2682 {
2683 *func_id = i;
2684 return true;
2685 }
2686 p_desc = tu_desc_next(p_desc);
2687 }
2688 }
2689 }
2690 return false;
2691}
2692
2693static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id)
2694{
2695 uint8_t i;
2696 for (i = 0; i < CFG_TUD_AUDIO; i++)
2697 {
2698 if (_audiod_fct[i].p_desc)
2699 {
2700 // Get pointer at end
2701 uint8_t const *p_desc_end = _audiod_fct[i].p_desc + _audiod_fct[i].desc_length;
2702
2703 // Advance past AC descriptors - EP we look for are streaming EPs
2704 uint8_t const *p_desc = tu_desc_next(_audiod_fct[i].p_desc);
2705 p_desc += ((audio_desc_cs_ac_interface_t const *)p_desc)->wTotalLength;
2706
2707 // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
2708 while (p_desc_end - p_desc > 0)
2709 {
2710 if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT && ((tusb_desc_endpoint_t const * )p_desc)->bEndpointAddress == ep)
2711 {
2712 *func_id = i;
2713 return true;
2714 }
2715 p_desc = tu_desc_next(p_desc);
2716 }
2717 }
2718 }
2719 return false;
2720}
2721
2722#if (CFG_TUD_AUDIO_ENABLE_EP_IN && (CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL || CFG_TUD_AUDIO_ENABLE_ENCODING)) || (CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING)
2723// p_desc points to the AS interface of alternate setting zero
2724// itf is the interface number of the corresponding interface - we check if the interface belongs to EP in or EP out to see if it is a TX or RX parameter
2725// Currently, only AS interfaces with an EP (in or out) are supposed to be parsed for!
2726static 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)
2727{
2728#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
2729 if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) return; // Abort, this interface has no EP, this driver does not support this currently
2730#endif
2731#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT
2732 if (as_itf != audio->ep_in_as_intf_num) return;
2733#endif
2734#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
2735 if (as_itf != audio->ep_out_as_intf_num) return;
2736#endif
2737
2738 p_desc = tu_desc_next(p_desc); // Exclude standard AS interface descriptor of current alternate interface descriptor
2739 // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning
2740 while (p_desc_end - p_desc > 0)
2741 {
2742 // Abort if follow up descriptor is a new standard interface descriptor - indicates the last AS descriptor was already finished
2743 if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) break;
2744
2745 // Look for a Class-Specific AS Interface Descriptor(4.9.2) to verify format type and format and also to get number of physical channels
2747 {
2748#if CFG_TUD_AUDIO_ENABLE_EP_IN
2749 if (as_itf == audio->ep_in_as_intf_num)
2750 {
2751 audio->n_channels_tx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels;
2752 audio->format_type_tx = (audio_format_type_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType);
2753
2754#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING
2755 audio->format_type_I_tx = (audio_data_format_type_I_t)(((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats);
2756#endif
2757 }
2758#endif
2759
2760#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
2761 if (as_itf == audio->ep_out_as_intf_num)
2762 {
2763 audio->n_channels_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bNrChannels;
2764 audio->format_type_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bFormatType;
2765#if CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
2766 audio->format_type_I_rx = ((audio_desc_cs_as_interface_t const * )p_desc)->bmFormats;
2767#endif
2768 }
2769#endif
2770 }
2771
2772 // Look for a Type I Format Type Descriptor(2.3.1.6 - Audio Formats)
2773#if CFG_TUD_AUDIO_ENABLE_TYPE_I_ENCODING || CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL || CFG_TUD_AUDIO_ENABLE_TYPE_I_DECODING
2775 {
2776#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
2777 if (as_itf != audio->ep_in_as_intf_num && as_itf != audio->ep_out_as_intf_num) break; // Abort loop, this interface has no EP, this driver does not support this currently
2778#endif
2779#if CFG_TUD_AUDIO_ENABLE_EP_IN && !CFG_TUD_AUDIO_ENABLE_EP_OUT
2780 if (as_itf != audio->ep_in_as_intf_num) break;
2781#endif
2782#if !CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_ENABLE_EP_OUT
2783 if (as_itf != audio->ep_out_as_intf_num) break;
2784#endif
2785
2786#if CFG_TUD_AUDIO_ENABLE_EP_IN
2787 if (as_itf == audio->ep_in_as_intf_num)
2788 {
2789 audio->n_bytes_per_sample_tx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize;
2790 }
2791#endif
2792
2793#if CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_DECODING
2794 if (as_itf == audio->ep_out_as_intf_num)
2795 {
2796 audio->n_bytes_per_sample_rx = ((audio_desc_type_I_format_t const * )p_desc)->bSubslotSize;
2797 }
2798#endif
2799 }
2800#endif
2801
2802 // Other format types are not supported yet
2803
2804 p_desc = tu_desc_next(p_desc);
2805 }
2806}
2807#endif
2808
2809#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
2810
2812{
2813 TU_VERIFY(audio->format_type_tx == AUDIO_FORMAT_TYPE_I);
2814 TU_VERIFY(audio->n_channels_tx);
2815 TU_VERIFY(audio->n_bytes_per_sample_tx);
2816 TU_VERIFY(audio->interval_tx);
2817 TU_VERIFY(audio->sample_rate_tx);
2818
2819 const uint8_t interval = (tud_speed_get() == TUSB_SPEED_FULL) ? audio->interval_tx : 1 << (audio->interval_tx - 1);
2820
2821 const uint16_t sample_normimal = (uint16_t)(audio->sample_rate_tx * interval / ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000));
2822 const uint16_t sample_reminder = (uint16_t)(audio->sample_rate_tx * interval % ((tud_speed_get() == TUSB_SPEED_FULL) ? 1000 : 8000));
2823
2824 const uint16_t packet_sz_tx_min = (uint16_t)((sample_normimal - 1) * audio->n_channels_tx * audio->n_bytes_per_sample_tx);
2825 const uint16_t packet_sz_tx_norm = (uint16_t)(sample_normimal * audio->n_channels_tx * audio->n_bytes_per_sample_tx);
2826 const uint16_t packet_sz_tx_max = (uint16_t)((sample_normimal + 1) * audio->n_channels_tx * audio->n_bytes_per_sample_tx);
2827
2828 // Endpoint size must larger than packet size
2829 TU_ASSERT(packet_sz_tx_max <= audio->ep_in_sz);
2830
2831 // Frmt20.pdf 2.3.1.1 USB Packets
2832 if (sample_reminder)
2833 {
2834 // All virtual frame packets must either contain INT(nav) audio slots (small VFP) or INT(nav)+1 (large VFP) audio slots
2835 audio->packet_sz_tx[0] = packet_sz_tx_norm;
2836 audio->packet_sz_tx[1] = packet_sz_tx_norm;
2837 audio->packet_sz_tx[2] = packet_sz_tx_max;
2838 } else
2839 {
2840 // In the case where nav = INT(nav), ni may vary between INT(nav)-1 (small VFP), INT(nav)
2841 // (medium VFP) and INT(nav)+1 (large VFP).
2842 audio->packet_sz_tx[0] = packet_sz_tx_min;
2843 audio->packet_sz_tx[1] = packet_sz_tx_norm;
2844 audio->packet_sz_tx[2] = packet_sz_tx_max;
2845 }
2846
2847 return true;
2848}
2849
2850static uint16_t audiod_tx_packet_size(const uint16_t* norminal_size, uint16_t data_count, uint16_t fifo_depth, uint16_t max_depth)
2851{
2852 // Flow control need a FIFO size of at least 4*Navg
2853 if(norminal_size[1] && norminal_size[1] <= fifo_depth * 4)
2854 {
2855 // Use blackout to prioritize normal size packet
2856 static int ctrl_blackout = 0;
2857 uint16_t packet_size;
2858 uint16_t slot_size = norminal_size[2] - norminal_size[1];
2859 if (data_count < norminal_size[0])
2860 {
2861 // If you get here frequently, then your I2S clock deviation is too big !
2862 packet_size = 0;
2863 } else
2864 if (data_count < fifo_depth / 2 - slot_size && !ctrl_blackout)
2865 {
2866 packet_size = norminal_size[0];
2867 ctrl_blackout = 10;
2868 } else
2869 if (data_count > fifo_depth / 2 + slot_size && !ctrl_blackout)
2870 {
2871 packet_size = norminal_size[2];
2872 if(norminal_size[0] == norminal_size[1])
2873 {
2874 // nav > INT(nav), eg. 44.1k, 88.2k
2875 ctrl_blackout = 0;
2876 } else
2877 {
2878 // nav = INT(nav), eg. 48k, 96k
2879 ctrl_blackout = 10;
2880 }
2881 } else
2882 {
2883 packet_size = norminal_size[1];
2884 if (ctrl_blackout)
2885 {
2886 ctrl_blackout--;
2887 }
2888 }
2889 // Normally this cap is not necessary
2890 return tu_min16(packet_size, max_depth);
2891 } else
2892 {
2893 return tu_min16(data_count, max_depth);
2894 }
2895}
2896
2897#endif
2898
2899// No security checks here - internal function only which should always succeed
2901{
2902 for (uint8_t cnt=0; cnt < CFG_TUD_AUDIO; cnt++)
2903 {
2904 if (&_audiod_fct[cnt] == audio) return cnt;
2905 }
2906 return 0;
2907}
2908
2909#endif //CFG_TUD_ENABLED && CFG_TUD_AUDIO
static uint8_t tu_desc_subtype(void const *desc)
Definition: audio_device.c:606
tu_static osal_mutex_def_t ep_in_ff_mutex_wr_2
Definition: audio_device.c:133
static bool audiod_get_AS_interface_index_global(uint8_t itf, uint8_t *func_id, uint8_t *idxItf, uint8_t const **pp_desc_int)
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]
Definition: audio_device.c:236
tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_3[CFG_TUD_AUDIO_FUNC_3_CTRL_BUF_SZ]
Definition: audio_device.c:211
tu_static osal_mutex_def_t rx_supp_ff_mutex_rd_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]
Definition: audio_device.c:273
static uint8_t audiod_get_audio_fct_idx(audiod_function_t *audio)
static bool audiod_control_request(uint8_t rhport, tusb_control_request_t const *p_request)
static bool audiod_control_complete(uint8_t rhport, tusb_control_request_t const *p_request)
static bool audiod_tx_done_cb(uint8_t rhport, audiod_function_t *audio)
Definition: audio_device.c:986
static uint16_t audiod_encode_type_I_pcm(uint8_t rhport, audiod_function_t *audio)
tu_static tu_fifo_t tx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]
Definition: audio_device.c:245
static bool audiod_rx_done_cb(uint8_t rhport, audiod_function_t *audio, uint16_t n_bytes_received)
Definition: audio_device.c:694
static void audiod_fb_fifo_count_update(audiod_function_t *audio, uint16_t lvl_new)
tu_static uint8_t alt_setting_3[CFG_TUD_AUDIO_FUNC_3_N_AS_INT]
Definition: audio_device.c:222
tu_static osal_mutex_def_t ep_in_ff_mutex_wr_3
Definition: audio_device.c:140
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]
Definition: audio_device.c:228
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]
Definition: audio_device.c:150
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]
Definition: audio_device.c:262
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]
Definition: audio_device.c:131
tu_static osal_mutex_def_t tx_supp_ff_mutex_wr_3[CFG_TUD_AUDIO_FUNC_3_N_TX_SUPP_SW_FIFO]
Definition: audio_device.c:247
static bool audiod_verify_itf_exists(uint8_t itf, uint8_t *func_id)
static bool audiod_calc_tx_packet_sz(audiod_function_t *audio)
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]
Definition: audio_device.c:179
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]
Definition: audio_device.c:165
tu_static tu_fifo_t rx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]
Definition: audio_device.c:263
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]
Definition: audio_device.c:270
static bool audiod_verify_ep_exists(uint8_t ep, uint8_t *func_id)
static bool audiod_fb_send(audiod_function_t *audio)
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]
Definition: audio_device.c:138
static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *p_request)
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]
Definition: audio_device.c:244
tu_static tu_fifo_t rx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]
Definition: audio_device.c:255
tu_static osal_mutex_def_t ep_in_ff_mutex_wr_1
Definition: audio_device.c:126
tu_static uint8_t alt_setting_1[CFG_TUD_AUDIO_FUNC_1_N_AS_INT]
Definition: audio_device.c:215
tu_static tu_fifo_t tx_supp_ff_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]
Definition: audio_device.c:237
tu_static osal_mutex_def_t rx_supp_ff_mutex_rd_1[CFG_TUD_AUDIO_FUNC_1_N_RX_SUPP_SW_FIFO]
Definition: audio_device.c:257
tu_static CFG_TUD_MEM_SECTION audiod_function_t _audiod_fct[CFG_TUD_AUDIO]
Definition: audio_device.c:575
tu_static osal_mutex_def_t ep_out_ff_mutex_rd_1
Definition: audio_device.c:167
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]
Definition: audio_device.c:154
static bool audiod_get_interface(uint8_t rhport, tusb_control_request_t const *p_request)
static bool audiod_get_AS_interface_index(uint8_t itf, audiod_function_t *audio, uint8_t *idxItf, uint8_t const **pp_desc_int)
tu_static tu_fifo_t tx_supp_ff_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]
Definition: audio_device.c:229
tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_2[CFG_TUD_AUDIO_FUNC_2_CTRL_BUF_SZ]
Definition: audio_device.c:207
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]
Definition: audio_device.c:158
tu_static tu_fifo_t rx_supp_ff_3[CFG_TUD_AUDIO_FUNC_3_N_RX_SUPP_SW_FIFO]
Definition: audio_device.c:271
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]
Definition: audio_device.c:254
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]
Definition: audio_device.c:172
tu_static uint8_t alt_setting_2[CFG_TUD_AUDIO_FUNC_2_N_AS_INT]
Definition: audio_device.c:218
static uint16_t audiod_tx_packet_size(const uint16_t *norminal_size, uint16_t data_count, uint16_t fifo_depth, uint16_t max_size)
static void * audiod_interleaved_copy_bytes_fast_encode(uint16_t const nBytesPerSample, void *src, const void *src_end, void *dst, uint8_t const n_ff_used)
static void * audiod_interleaved_copy_bytes_fast_decode(uint16_t const nBytesPerSample, void *dst, const void *dst_end, void *src, uint8_t const n_ff_used)
Definition: audio_device.c:778
tu_static osal_mutex_def_t tx_supp_ff_mutex_wr_1[CFG_TUD_AUDIO_FUNC_1_N_TX_SUPP_SW_FIFO]
Definition: audio_device.c:231
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]
Definition: audio_device.c:124
static bool audiod_verify_entity_exists(uint8_t itf, uint8_t entityID, uint8_t *func_id)
tu_static CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf_1[CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ]
Definition: audio_device.c:204
tu_static osal_mutex_def_t tx_supp_ff_mutex_wr_2[CFG_TUD_AUDIO_FUNC_2_N_TX_SUPP_SW_FIFO]
Definition: audio_device.c:239
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]
Definition: audio_device.c:191
tu_static osal_mutex_def_t rx_supp_ff_mutex_rd_2[CFG_TUD_AUDIO_FUNC_2_N_RX_SUPP_SW_FIFO]
Definition: audio_device.c:265
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)
tu_static osal_mutex_def_t ep_out_ff_mutex_rd_3
Definition: audio_device.c:181
static bool audiod_decode_type_I_pcm(uint8_t rhport, audiod_function_t *audio, uint16_t n_bytes_received)
Definition: audio_device.c:829
static bool audiod_set_fb_params_freq(audiod_function_t *audio, uint32_t sample_freq, uint32_t mclk_freq)
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]
Definition: audio_device.c:199
tu_static osal_mutex_def_t ep_out_ff_mutex_rd_2
Definition: audio_device.c:174
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]
Definition: audio_device.c:195
static struct @612 data
static usb_descriptor_buffers_t desc
Definition: dcd_pio_usb.c:46
uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
TU_ATTR_FAST_FUNC void audiod_sof_isr(uint8_t rhport, uint32_t frame_count)
TU_ATTR_WEAK void tud_audio_int_done_cb(uint8_t rhport)
Definition: audio_device.c:502
bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_request_t const *p_request, void *data, uint16_t len)
bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
bool tud_audio_int_n_write(uint8_t func_id, const audio_interrupt_data_t *data)
Definition: audio_device.c:957
TU_ATTR_WEAK bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request)
Definition: audio_device.c:557
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)
Definition: audio_device.c:468
bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
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)
Definition: audio_device.c:440
void audiod_init(void)
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)
Definition: audio_device.c:448
TU_ATTR_WEAK void tud_audio_fb_done_cb(uint8_t func_id)
Definition: audio_device.c:479
TU_ATTR_WEAK bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request)
Definition: audio_device.c:549
bool audiod_deinit(void)
tu_fifo_t * tud_audio_n_get_ep_out_ff(uint8_t func_id)
Definition: audio_device.c:654
uint16_t tud_audio_n_available_support_ff(uint8_t func_id, uint8_t ff_idx)
Definition: audio_device.c:670
uint16_t tud_audio_n_read(uint8_t func_id, void *buffer, uint16_t bufsize)
Definition: audio_device.c:642
bool tud_audio_n_fb_set(uint8_t func_id, uint32_t feedback)
tu_fifo_t * tud_audio_n_get_rx_support_ff(uint8_t func_id, uint8_t ff_idx)
Definition: audio_device.c:682
tu_fifo_t * tud_audio_n_get_ep_in_ff(uint8_t func_id)
Definition: audio_device.c:909
bool tud_audio_n_clear_ep_in_ff(uint8_t func_id)
Definition: audio_device.c:903
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)
Definition: audio_device.c:495
uint16_t tud_audio_n_write(uint8_t func_id, const void *data, uint16_t len)
Write data to EP in buffer.
Definition: audio_device.c:897
void audiod_reset(uint8_t rhport)
uint16_t tud_audio_n_write_support_ff(uint8_t func_id, uint8_t ff_idx, const void *data, uint16_t len)
Definition: audio_device.c:940
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)
Definition: audio_device.c:459
TU_ATTR_WEAK void tud_audio_feedback_params_cb(uint8_t func_id, uint8_t alt_itf, audio_feedback_params_t *feedback_param)
Definition: audio_device.c:483
uint32_t tud_audio_feedback_update(uint8_t func_id, uint32_t cycles)
tu_fifo_t * tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx)
Definition: audio_device.c:946
TU_ATTR_WEAK bool tud_audio_feedback_format_correction_cb(uint8_t func_id)
Definition: audio_device.c:489
TU_ATTR_WEAK bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request)
Definition: audio_device.c:565
TU_ATTR_WEAK bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff)
Definition: audio_device.c:522
bool tud_audio_n_clear_tx_support_ff(uint8_t func_id, uint8_t ff_idx)
Definition: audio_device.c:934
bool tud_audio_n_clear_ep_out_ff(uint8_t func_id)
Definition: audio_device.c:648
bool tud_audio_n_clear_rx_support_ff(uint8_t func_id, uint8_t ff_idx)
Definition: audio_device.c:664
uint16_t tud_audio_n_flush_tx_support_ff(uint8_t func_id)
Definition: audio_device.c:919
uint16_t tud_audio_n_available(uint8_t func_id)
Definition: audio_device.c:636
TU_ATTR_WEAK bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request)
Definition: audio_device.c:508
TU_ATTR_WEAK bool tud_audio_set_itf_close_EP_cb(uint8_t rhport, tusb_control_request_t const *p_request)
Definition: audio_device.c:515
uint16_t tud_audio_n_read_support_ff(uint8_t func_id, uint8_t ff_idx, void *buffer, uint16_t bufsize)
Definition: audio_device.c:676
bool tud_audio_n_mounted(uint8_t func_id)
Definition: audio_device.c:622
TU_ATTR_WEAK bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff)
Definition: audio_device.c:540
TU_ATTR_WEAK bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff)
Definition: audio_device.c:531
@ AUDIO_FEEDBACK_METHOD_FIFO_COUNT
Definition: audio_device.h:525
@ AUDIO_FEEDBACK_METHOD_FREQUENCY_FIXED
Definition: audio_device.h:522
@ AUDIO_FEEDBACK_METHOD_DISABLED
Definition: audio_device.h:521
@ AUDIO_FEEDBACK_METHOD_FREQUENCY_POWER_OF_2
Definition: audio_device.h:524
@ AUDIO_FEEDBACK_METHOD_FREQUENCY_FLOAT
Definition: audio_device.h:523
audio_data_format_type_I_t
Definition: audio.h:486
audio_format_type_t
Rest is yet to be implemented.
Definition: audio.h:473
@ AUDIO_CS_AS_INTERFACE_FORMAT_TYPE
Definition: audio.h:116
@ AUDIO_CS_AS_INTERFACE_AS_GENERAL
Definition: audio.h:115
@ AUDIO_CS_AC_INTERFACE_OUTPUT_TERMINAL
Definition: audio.h:98
@ AUDIO_DATA_FORMAT_TYPE_I_PCM
Definition: audio.h:487
@ AUDIO_CS_CTRL_SAM_FREQ
Definition: audio.h:162
@ AUDIO_SUBCLASS_CONTROL
Audio Control.
Definition: audio.h:61
@ AUDIO_CS_REQ_CUR
Definition: audio.h:151
@ AUDIO_TERM_TYPE_USB_STREAMING
Definition: audio.h:438
@ AUDIO_INT_PROTOCOL_CODE_V2
Version 2.0.
Definition: audio.h:70
@ AUDIO_FORMAT_TYPE_UNDEFINED
Definition: audio.h:474
@ AUDIO_FORMAT_TYPE_I
Definition: audio.h:475
uint8_t const * buffer
Definition: midi_device.h:100
uint32_t bufsize
Definition: midi_device.h:95
StaticSemaphore_t osal_mutex_def_t
Definition: osal_freertos.h:46
static TU_ATTR_ALWAYS_INLINE osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef)
AUDIO Channel Cluster Descriptor (4.1)
Definition: audio.h:647
uint16_t wValue
Definition: audio.h:934
struct TU_ATTR_PACKED::@16::TU_ATTR_PACKED bmRequestType_bit
uint8_t bInterval
Definition: tusb_types.h:372
uint8_t bmAttributes
See: audio_clock_source_attribute_t.
Definition: audio.h:672
uint16_t wIndex
Definition: audio.h:943
uint8_t bInterfaceClass
Class code (assigned by the USB-IF).
Definition: tusb_types.h:349
uint8_t bEndpointAddress
Definition: video.h:306
uint8_t bInterfaceSubClass
Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bInterfaceCla...
Definition: tusb_types.h:350
uint8_t bRequest
Request type audio_cs_req_t.
Definition: audio.h:831
uint8_t bNumEndpoints
Number of endpoints used by this interface (excluding endpoint zero). If this value is zero,...
Definition: tusb_types.h:348
uint8_t bInterfaceProtocol
Protocol code (assigned by the USB). These codes are qualified by the value of the bInterfaceClass ...
Definition: tusb_types.h:351
uint8_t bAlternateSetting
Value used to select this alternate setting for the interface identified in the prior field.
Definition: tusb_types.h:347
struct audio_feedback_params_t::@1::@3 frequency
uint8_t n_channels_per_ff_rx
Definition: audio_device.c:399
struct audiod_function_t::@4 feedback
uint8_t * ctrl_buf
Definition: audio_device.c:373
tu_fifo_t * rx_supp_ff
Definition: audio_device.c:395
tu_fifo_t ep_out_ff
Definition: audio_device.c:381
uint16_t tx_supp_ff_sz_max
Definition: audio_device.c:406
audio_format_type_t format_type_tx
Definition: audio_device.c:360
uint8_t n_bytes_per_sample_tx
Definition: audio_device.c:362
uint16_t desc_length
Definition: audio_device.c:306
uint8_t const * p_desc
Definition: audio_device.c:281
audio_data_format_type_I_t format_type_I_rx
Definition: audio_device.c:345
tu_fifo_t ep_in_ff
Definition: audio_device.c:385
CFG_TUSB_MEM_ALIGN uint32_t send_buf
Definition: audio_device.c:310
uint8_t * lin_buf_out
Definition: audio_device.c:414
uint16_t rx_supp_ff_sz_max
Definition: audio_device.c:397
struct audiod_function_t::@4::@6::@8 fifo_count
uint32_t sample_freq
Definition: audio_device.c:323
uint16_t rate_const[2]
Definition: audio_device.c:331
uint16_t packet_sz_tx[3]
Definition: audio_device.c:353
audio_format_type_t format_type_rx
Definition: audio_device.c:341
uint8_t n_bytes_per_sample_rx
Definition: audio_device.c:346
uint8_t ep_in_as_intf_num
Definition: audio_device.c:286
uint16_t fifo_lvl_thr
Definition: audio_device.c:330
struct audiod_function_t::@4::@6::@7 fixed
uint8_t * alt_setting
Definition: audio_device.c:377
tu_fifo_t * tx_supp_ff
Definition: audio_device.c:404
uint8_t n_channels_per_ff_tx
Definition: audio_device.c:408
uint32_t fifo_lvl_avg
Definition: audio_device.c:329
union audiod_function_t::@4::@6 compute
uint32_t sample_rate_tx
Definition: audio_device.c:352
uint8_t * lin_buf_in
Definition: audio_device.c:419
uint8_t ep_out_as_intf_num
Definition: audio_device.c:292
audio_data_format_type_I_t format_type_I_tx
Definition: audio_device.c:365
uint8_t compute_method
Definition: audio_device.c:316
uint16_t depth
Definition: tusb_fifo.h:108
uint8_t * buffer
Definition: tusb_fifo.h:107
static TU_ATTR_ALWAYS_INLINE uint8_t tu_u16_low(uint16_t ui16)
Definition: tusb_common.h:146
static TU_ATTR_ALWAYS_INLINE uint16_t tu_min16(uint16_t x, uint16_t y)
Definition: tusb_common.h:155
static bool tu_is_power_of_two(uint32_t value)
Definition: tusb_common.h:195
static TU_ATTR_ALWAYS_INLINE uint32_t tu_unaligned_read32(const void *mem)
Definition: tusb_common.h:207
static TU_ATTR_ALWAYS_INLINE uint16_t tu_unaligned_read16(const void *mem)
Definition: tusb_common.h:219
static TU_ATTR_ALWAYS_INLINE int tu_memcpy_s(void *dest, size_t destsz, const void *src, size_t count)
Definition: tusb_common.h:114
static uint8_t tu_log2(uint32_t value)
Definition: tusb_common.h:183
uint16_t tu_fifo_count(tu_fifo_t *f)
Get number of items in FIFO.
Definition: tusb_fifo.c:590
void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info)
Get linear write info.
Definition: tusb_fifo.c:1057
bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_size, bool overwritable)
Definition: tusb_fifo.c:70
uint16_t tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n)
This function will write n elements into the array index specified by the write pointer and increment...
Definition: tusb_fifo.c:861
void tu_fifo_advance_write_pointer(tu_fifo_t *f, uint16_t n)
Advance write pointer - intended to be used in combination with DMA. It is possible to fill the FIFO ...
Definition: tusb_fifo.c:948
uint16_t tu_fifo_read_n(tu_fifo_t *f, void *buffer, uint16_t n)
This function will read n elements from the array index specified by the read pointer and increment t...
Definition: tusb_fifo.c:730
void tu_fifo_advance_read_pointer(tu_fifo_t *f, uint16_t n)
Advance read pointer - intended to be used in combination with DMA. It is possible to read from the F...
Definition: tusb_fifo.c:969
void tu_fifo_get_read_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info)
Get read info.
Definition: tusb_fifo.c:989
bool tu_fifo_clear(tu_fifo_t *f)
Clear the fifo read and write pointers.
Definition: tusb_fifo.c:896
static TU_ATTR_ALWAYS_INLINE uint16_t tu_fifo_depth(tu_fifo_t *f)
Definition: tusb_fifo.h:180
static TU_ATTR_ALWAYS_INLINE void tu_fifo_config_mutex(tu_fifo_t *f, osal_mutex_t wr_mutex, osal_mutex_t rd_mutex)
Definition: tusb_fifo.h:149
@ TUSB_DIR_IN
Definition: tusb_types.h:67
@ TUSB_DIR_OUT
Definition: tusb_types.h:66
@ TUSB_REQ_CLEAR_FEATURE
Definition: tusb_types.h:123
@ TUSB_REQ_SET_INTERFACE
Definition: tusb_types.h:133
@ TUSB_REQ_GET_INTERFACE
Definition: tusb_types.h:132
@ TUSB_SPEED_FULL
Definition: tusb_types.h:50
@ TUSB_SPEED_HIGH
Definition: tusb_types.h:52
@ TUSB_CLASS_AUDIO
Definition: tusb_types.h:160
xfer_result_t
Definition: tusb_types.h:236
@ TUSB_REQ_RCPT_ENDPOINT
Definition: tusb_types.h:153
@ TUSB_REQ_RCPT_INTERFACE
Definition: tusb_types.h:152
static TU_ATTR_ALWAYS_INLINE uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const *desc_ep)
Definition: tusb_types.h:515
@ TUSB_XFER_ISOCHRONOUS
Definition: tusb_types.h:60
@ TUSB_XFER_INTERRUPT
Definition: tusb_types.h:62
TU_ATTR_PACKED_END TU_ATTR_BIT_FIELD_ORDER_END static TU_ATTR_ALWAYS_INLINE tusb_dir_t tu_edpt_dir(uint8_t addr)
Definition: tusb_types.h:502
@ CONTROL_STAGE_DATA
Definition: tusb_types.h:269
@ CONTROL_STAGE_SETUP
Definition: tusb_types.h:268
static TU_ATTR_ALWAYS_INLINE uint8_t tu_desc_type(void const *desc)
Definition: tusb_types.h:537
@ TUSB_REQ_TYPE_STANDARD
Definition: tusb_types.h:144
@ TUSB_REQ_TYPE_CLASS
Definition: tusb_types.h:145
static TU_ATTR_ALWAYS_INLINE uint8_t const * tu_desc_next(void const *desc)
Definition: tusb_types.h:531
@ TUSB_DESC_CS_INTERFACE
Definition: tusb_types.h:114
@ TUSB_DESC_ENDPOINT
Definition: tusb_types.h:97
@ TUSB_DESC_INTERFACE
Definition: tusb_types.h:96
void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
Definition: usbd.c:1398
void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr)
Definition: usbd.c:1424
tusb_speed_t tud_speed_get(void)
Definition: usbd.c:407
bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
Definition: usbd.c:1309
bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
Definition: usbd.c:1277
bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr)
Definition: usbd.c:1286
bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr)
Definition: usbd.c:1376
bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr)
Definition: usbd.c:1299
bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes)
Definition: usbd.c:1348
void usbd_sof_enable(uint8_t rhport, sof_consumer_t consumer, bool en)
Definition: usbd.c:1445
bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
Definition: usbd.c:1474
bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size)
Definition: usbd.c:1462
bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const *request, void *buffer, uint16_t len)
Definition: usbd_control.c:111
bool tud_control_status(uint8_t rhport, tusb_control_request_t const *request)
Definition: usbd_control.c:81
CFG_TUH_MEM_ALIGN tusb_control_request_t request
Definition: usbh.c:259
volatile uint8_t stage
Definition: usbh.c:265