arduino-audio-tools
AudioUSB.h
1 #pragma once
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 
6 //--------------------------------------------------------------------+
7 // MACRO CONSTANT TYPEDEF PROTYPES
8 //--------------------------------------------------------------------+
9 
10 #ifndef AUDIO_SAMPLE_RATE
11 #define AUDIO_SAMPLE_RATE 48000
12 #endif
13 
14 //--------------------------------------------------------------------+
15 // Board Specific Configuration
16 //--------------------------------------------------------------------+
17 
18 // RHPort number used for device can be defined by board.mk, default to port 0
19 #ifndef BOARD_TUD_RHPORT
20 #define BOARD_TUD_RHPORT 0
21 #endif
22 
23 // RHPort max operational speed can defined by board.mk
24 #ifndef BOARD_TUD_MAX_SPEED
25 #define BOARD_TUD_MAX_SPEED OPT_MODE_DEFAULT_SPEED
26 #endif
27 
28 //--------------------------------------------------------------------
29 // COMMON CONFIGURATION
30 //--------------------------------------------------------------------
31 
32 // defined by compiler flags for flexibility
33 #ifndef CFG_TUSB_MCU
34 #ifdef ESP32
35 #define CFG_TUSB_MCU OPT_MCU_ESP32S2
36 #else
37 #error CFG_TUSB_MCU must be defined
38 #endif
39 
40 #endif
41 
42 #if !defined(CFG_TUSB_OS) && !defined(ESP32)
43 #define CFG_TUSB_OS OPT_OS_NONE
44 #endif
45 
46 #ifndef CFG_TUSB_DEBUG
47 #define CFG_TUSB_DEBUG 0
48 #endif
49 
50 // Enable Device stack
51 #define CFG_TUD_ENABLED 1
52 
53 // Default is max speed that hardware controller could support with on-chip PHY
54 #define CFG_TUD_MAX_SPEED BOARD_TUD_MAX_SPEED
55 
56 // CFG_TUSB_DEBUG is defined by compiler in DEBUG build
57 // #define CFG_TUSB_DEBUG 0
58 
59 /* USB DMA on some MCUs can only access a specific SRAM region with restriction
60  * on alignment. Tinyusb use follows macros to declare transferring memory so
61  * that they can be put into those specific section. e.g
62  * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
63  * - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
64  */
65 #ifndef CFG_TUSB_MEM_SECTION
66 #define CFG_TUSB_MEM_SECTION
67 #endif
68 
69 #ifndef CFG_TUSB_MEM_ALIGN
70 #define CFG_TUSB_MEM_ALIGN __attribute__((aligned(4)))
71 #endif
72 
73 //--------------------------------------------------------------------
74 // DEVICE CONFIGURATION
75 //--------------------------------------------------------------------
76 #define _TUSB_CONFIG_H_
77 
78 #ifndef CFG_TUD_ENDPOINT0_SIZE
79 #define CFG_TUD_ENDPOINT0_SIZE 64
80 #endif
81 
82 //------------- CLASS -------------//
83 #define CFG_TUD_AUDIO 1
84 #ifndef ESP32
85 #define CFG_TUD_CDC 0
86 #define CFG_TUD_MSC 0
87 #define CFG_TUD_HID 0
88 #define CFG_TUD_MIDI 0
89 #define CFG_TUD_VENDOR 0
90 #endif
91 //--------------------------------------------------------------------
92 // AUDIO CLASS DRIVER CONFIGURATION
93 //--------------------------------------------------------------------
94 
95 // Have a look into audio_device.h for all configurations
96 
97 #define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_ONE_CH_DESC_LEN
98 #define CFG_TUD_AUDIO_FUNC_1_N_AS_INT \
99  1 // Number of Standard AS Interface Descriptors (4.9.1) defined per audio
100  // function - this is required to be able to remember the current alternate
101  // settings of these interfaces - We restrict us here to have a constant
102  // number for all audio functions (which means this has to be the maximum
103  // number of AS interfaces an audio function has and a second audio function
104  // with less AS interfaces just wastes a few bytes)
105 #define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 // Size of control request buffer
106 
107 #define CFG_TUD_AUDIO_ENABLE_EP_IN 1
108 #define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX \
109  2 // Driver gets this info from the descriptors - we define it here to use it
110  // to setup the descriptors and to do calculations with it below
111 #define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX \
112  1 // Driver gets this info from the descriptors - we define it here to use it
113  // to setup the descriptors and to do calculations with it below - be aware:
114  // for different number of channels you need another descriptor!
115 #define CFG_TUD_AUDIO_EP_SZ_IN \
116  (48 + 1) * \
117  CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * \
118  CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX // 48 Samples (48 kHz) x 2
119  // Bytes/Sample x
120  // CFG_TUD_AUDIO_N_CHANNELS_TX
121  // Channels - One extra sample is
122  // needed for asynchronous transfer
123  // adjustment, see feedback EP
124 #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX \
125  CFG_TUD_AUDIO_EP_SZ_IN // Maximum EP IN size for all AS alternate settings
126  // used
127 #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ CFG_TUD_AUDIO_EP_SZ_IN + 1
128 
129 /* A combination of interfaces must have a unique product id, since PC will save
130  * device driver after the first plug. Same VID/PID with different interface e.g
131  * MSC (first), then CDC (later) will possibly cause system error on PC.
132  *
133  * Auto ProductID layout's Bitmap:
134  * [MSB] AUDIO | MIDI | HID | MSC | CDC [LSB]
135  */
136 #ifndef ESP32
137 #define _PID_MAP(itf, n) ((CFG_TUD_##itf) << (n))
138 #define USB_PID \
139  (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
140  _PID_MAP(MIDI, 3) | _PID_MAP(AUDIO, 4) | _PID_MAP(VENDOR, 5))
141 #endif
142 
143 #include "class/audio/audio_device.h"
144 #include "tusb.h"
145 
146 namespace audio_tools {
147 
148 //--------------------------------------------------------------------+
149 // Device Descriptors
150 //--------------------------------------------------------------------+
151 tusb_desc_device_t const desc_device = {
152  .bLength = sizeof(tusb_desc_device_t),
153  .bDescriptorType = TUSB_DESC_DEVICE,
154  .bcdUSB = 0x0200,
155 
156  // Use Interface Association Descriptor (IAD) for Audio
157  // As required by USB Specs IAD's subclass must be common class (2) and
158  // protocol must be IAD (1)
159  .bDeviceClass = TUSB_CLASS_MISC,
160  .bDeviceSubClass = MISC_SUBCLASS_COMMON,
161  .bDeviceProtocol = MISC_PROTOCOL_IAD,
162  .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
163 
164  .idVendor = 0xCafe,
165  .idProduct = USB_PID,
166  .bcdDevice = 0x0100,
167 
168  .iManufacturer = 0x01,
169  .iProduct = 0x02,
170  .iSerialNumber = 0x03,
171 
172  .bNumConfigurations = 0x01};
173 
174 // Invoked when received GET DEVICE DESCRIPTOR
175 // Application return pointer to descriptor
176 uint8_t const *tud_descriptor_device_cb(void) {
177  return (uint8_t const *)&desc_device;
178 }
179 
180 //--------------------------------------------------------------------+
181 // Configuration Descriptor
182 //--------------------------------------------------------------------+
183 enum { ITF_NUM_AUDIO_CONTROL = 0, ITF_NUM_AUDIO_STREAMING, ITF_NUM_TOTAL };
184 
185 #define CONFIG_TOTAL_LEN \
186  (TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_MIC_ONE_CH_DESC_LEN)
187 
188 #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || \
189  CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
190 // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
191 // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
192 #define EPNUM_AUDIO 0x03
193 
194 #elif TU_CHECK_MCU(OPT_MCU_NRF5X)
195 // nRF5x ISO can only be endpoint 8
196 #define EPNUM_AUDIO 0x08
197 
198 #else
199 #define EPNUM_AUDIO 0x01
200 #endif
201 
202 uint8_t const desc_configuration[] = {
203  // Config number, interface count, string index, total length, attribute,
204  // power in mA
205  TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
206 
207  // Interface number, string index, EP Out & EP In address, EP size
208  TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR(
209  /*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0,
210  /*_nBytesPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX,
211  /*_nBitsUsedPerSample*/ CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX * 8,
212  /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ CFG_TUD_AUDIO_EP_SZ_IN)};
213 
214 // Invoked when received GET CONFIGURATION DESCRIPTOR
215 // Application return pointer to descriptor
216 // Descriptor contents must exist long enough for transfer to complete
217 uint8_t const *tud_descriptor_configuration_cb(uint8_t index) {
218  (void)index; // for multiple configurations
219  return desc_configuration;
220 }
221 
222 //--------------------------------------------------------------------+
223 // String Descriptors
224 //--------------------------------------------------------------------+
225 
226 // array of pointer to string descriptors
227 char const *string_desc_arr[] = {
228  (const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)
229  "PaniRCorp", // 1: Manufacturer
230  "MicNode", // 2: Product
231  "123456", // 3: Serials, should use chip ID
232  "UAC2", // 4: Audio Interface
233 };
234 
235 static uint16_t _desc_str[32];
236 
237 // Invoked when received GET STRING DESCRIPTOR request
238 // Application return pointer to descriptor, whose contents must exist long
239 // enough for transfer to complete
240 uint16_t const *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
241  (void)langid;
242 
243  uint8_t chr_count;
244 
245  if (index == 0) {
246  memcpy(&_desc_str[1], string_desc_arr[0], 2);
247  chr_count = 1;
248  } else {
249  // Convert ASCII string into UTF-16
250 
251  if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])))
252  return NULL;
253 
254  const char *str = string_desc_arr[index];
255 
256  // Cap at max char
257  chr_count = (uint8_t)strlen(str);
258  if (chr_count > 31)
259  chr_count = 31;
260 
261  for (uint8_t i = 0; i < chr_count; i++) {
262  _desc_str[1 + i] = str[i];
263  }
264  }
265 
266  // first byte is length (including header), second byte is string type
267  _desc_str[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * chr_count + 2));
268 
269  return _desc_str;
270 }
271 
272 /* Blink pattern
273  * - 250 ms : device not mounted
274  * - 1000 ms : device mounted
275  * - 2500 ms : device is suspended
276  */
277 enum {
278  BLINK_NOT_MOUNTED = 250,
279  BLINK_MOUNTED = 1000,
280  BLINK_SUSPENDED = 2500,
281 };
282 
283 static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
284 static int channels = 2;
285 static uint8_t bytesPerSample;
286 static Stream *p_in = nullptr;
287 static Print *p_out = nullptr;
288 
289 // Audio controls
290 // Current states
291 bool mute[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0
292 uint16_t
293  volume[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // +1 for master channel 0
294 uint32_t sampFreq;
295 uint8_t clkValid;
296 
297 // Range states
298 audio_control_range_2_n_t(
299  1) volumeRng[CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX + 1]; // Volume range state
300 audio_control_range_4_n_t(1) sampleFreqRng; // Sample frequency range state
301 
302 // Audio test data
303 uint16_t test_buffer_audio[(CFG_TUD_AUDIO_EP_SZ_IN - 2) / 2];
304 uint16_t startVal = 0;
305 
306 void led_blinking_task(void);
307 void audio_task(void);
308 
309 /*------------- MAIN -------------*/
310 class AudioUSB {
311 public:
312  AudioUSB(Stream &in) {
313  p_in = &in;
314  p_out = &in;
315  }
316  AudioUSB(Print &out) { p_out = &out; }
317  void begin(AudioInfo cfg) {
318  this->info = cfg;
319  channels = cfg.channels;
320  // board_init();
321 
322  // init device stack on configured roothub port
323  tud_init(BOARD_TUD_RHPORT);
324 
325  // Init values
326  sampFreq = cfg.sample_rate;
327  clkValid = 1;
328 
329  sampleFreqRng.wNumSubRanges = 1;
330  sampleFreqRng.subrange[0].bMin = cfg.sample_rate;
331  sampleFreqRng.subrange[0].bMax = cfg.sample_rate;
332  sampleFreqRng.subrange[0].bRes = 0;
333  }
334 
335  void copy() {
336  tud_task(); // tinyusb device task
337  led_blinking_task();
338  audio_task();
339  }
340 
341 protected:
342  AudioInfo info;
343 };
344 
345 //--------------------------------------------------------------------+
346 // Device callbacks
347 //--------------------------------------------------------------------+
348 
349 // Invoked when device is mounted
350 void tud_mount_cb(void) { blink_interval_ms = BLINK_MOUNTED; }
351 
352 // Invoked when device is unmounted
353 void tud_umount_cb(void) { blink_interval_ms = BLINK_NOT_MOUNTED; }
354 
355 // Invoked when usb bus is suspended
356 // remote_wakeup_en : if host allow us to perform remote wakeup
357 // Within 7ms, device must draw an average of current less than 2.5 mA from
358 // bus
359 void tud_suspend_cb(bool remote_wakeup_en) {
360  (void)remote_wakeup_en;
361  blink_interval_ms = BLINK_SUSPENDED;
362 }
363 
364 // Invoked when usb bus is resumed
365 void tud_resume_cb(void) { blink_interval_ms = BLINK_MOUNTED; }
366 
367 //--------------------------------------------------------------------+
368 // AUDIO Task
369 //--------------------------------------------------------------------+
370 
371 void audio_task(void) {
372  // Yet to be filled - e.g. put meas data into TX FIFOs etc.
373  // asm("nop");
374 }
375 
376 //--------------------------------------------------------------------+
377 // Application Callback API Implementations
378 //--------------------------------------------------------------------+
379 
380 // Invoked when audio class specific set request received for an EP
381 bool tud_audio_set_req_ep_cb(uint8_t rhport,
382  tusb_control_request_t const *p_request,
383  uint8_t *pBuff) {
384  (void)rhport;
385  (void)pBuff;
386 
387  // We do not support any set range requests here, only current value
388  // requests
389  TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
390 
391  // Page 91 in UAC2 specification
392  uint8_t channelNum = TU_U16_LOW(p_request->wValue);
393  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
394  uint8_t ep = TU_U16_LOW(p_request->wIndex);
395 
396  (void)channelNum;
397  (void)ctrlSel;
398  (void)ep;
399 
400  return false; // Yet not implemented
401 }
402 
403 // Invoked when audio class specific set request received for an interface
404 bool tud_audio_set_req_itf_cb(uint8_t rhport,
405  tusb_control_request_t const *p_request,
406  uint8_t *pBuff) {
407  (void)rhport;
408  (void)pBuff;
409 
410  // We do not support any set range requests here, only current value
411  // requests
412  TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
413 
414  // Page 91 in UAC2 specification
415  uint8_t channelNum = TU_U16_LOW(p_request->wValue);
416  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
417  uint8_t itf = TU_U16_LOW(p_request->wIndex);
418 
419  (void)channelNum;
420  (void)ctrlSel;
421  (void)itf;
422 
423  return false; // Yet not implemented
424 }
425 
426 // Invoked when audio class specific set request received for an entity
427 bool tud_audio_set_req_entity_cb(uint8_t rhport,
428  tusb_control_request_t const *p_request,
429  uint8_t *pBuff) {
430  (void)rhport;
431 
432  // Page 91 in UAC2 specification
433  uint8_t channelNum = TU_U16_LOW(p_request->wValue);
434  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
435  uint8_t itf = TU_U16_LOW(p_request->wIndex);
436  uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
437 
438  (void)itf;
439 
440  // We do not support any set range requests here, only current value
441  // requests
442  TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
443 
444  // If request is for our feature unit
445  if (entityID == 2) {
446  switch (ctrlSel) {
447  case AUDIO_FU_CTRL_MUTE:
448  // Request uses format layout 1
449  TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t));
450 
451  mute[channelNum] = ((audio_control_cur_1_t *)pBuff)->bCur;
452 
453  TU_LOG2(" Set Mute: %d of channel: %u\r\n", mute[channelNum],
454  channelNum);
455  return true;
456 
457  case AUDIO_FU_CTRL_VOLUME:
458  // Request uses format layout 2
459  TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t));
460 
461  volume[channelNum] = (uint16_t)((audio_control_cur_2_t *)pBuff)->bCur;
462 
463  TU_LOG2(" Set Volume: %d dB of channel: %u\r\n", volume[channelNum],
464  channelNum);
465  return true;
466 
467  // Unknown/Unsupported control
468  default:
469  TU_BREAKPOINT();
470  return false;
471  }
472  }
473  return false; // Yet not implemented
474 }
475 
476 // Invoked when audio class specific get request received for an EP
477 bool tud_audio_get_req_ep_cb(uint8_t rhport,
478  tusb_control_request_t const *p_request) {
479  (void)rhport;
480 
481  // Page 91 in UAC2 specification
482  uint8_t channelNum = TU_U16_LOW(p_request->wValue);
483  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
484  uint8_t ep = TU_U16_LOW(p_request->wIndex);
485 
486  (void)channelNum;
487  (void)ctrlSel;
488  (void)ep;
489 
490  // return tud_control_xfer(rhport, p_request, &tmp, 1);
491 
492  return false; // Yet not implemented
493 }
494 
495 // Invoked when audio class specific get request received for an interface
496 bool tud_audio_get_req_itf_cb(uint8_t rhport,
497  tusb_control_request_t const *p_request) {
498  (void)rhport;
499 
500  // Page 91 in UAC2 specification
501  uint8_t channelNum = TU_U16_LOW(p_request->wValue);
502  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
503  uint8_t itf = TU_U16_LOW(p_request->wIndex);
504 
505  (void)channelNum;
506  (void)ctrlSel;
507  (void)itf;
508 
509  return false; // Yet not implemented
510 }
511 
512 // Invoked when audio class specific get request received for an entity
513 bool tud_audio_get_req_entity_cb(uint8_t rhport,
514  tusb_control_request_t const *p_request) {
515  (void)rhport;
516 
517  // Page 91 in UAC2 specification
518  uint8_t channelNum = TU_U16_LOW(p_request->wValue);
519  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
520  // uint8_t itf = TU_U16_LOW(p_request->wIndex); // Since
521  // we have only one audio function implemented, we do not need the itf value
522  uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
523 
524  // Input terminal (Microphone input)
525  if (entityID == 1) {
526  switch (ctrlSel) {
527  case AUDIO_TE_CTRL_CONNECTOR: {
528  // The terminal connector control only has a get request with only the
529  // CUR attribute.
530  audio_desc_channel_cluster_t ret;
531 
532  // Those are dummy values for now
533  ret.bNrChannels = channels;
534  ret.bmChannelConfig = (audio_channel_config_t)0;
535  ret.iChannelNames = 0;
536 
537  TU_LOG2(" Get terminal connector\r\n");
538 
539  return tud_audio_buffer_and_schedule_control_xfer(
540  rhport, p_request, (void *)&ret, sizeof(ret));
541  } break;
542 
543  // Unknown/Unsupported control selector
544  default:
545  TU_BREAKPOINT();
546  return false;
547  }
548  }
549 
550  // Feature unit
551  if (entityID == 2) {
552  switch (ctrlSel) {
553  case AUDIO_FU_CTRL_MUTE:
554  // Audio control mute cur parameter block consists of only one byte - we
555  // thus can send it right away There does not exist a range parameter
556  // block for mute
557  TU_LOG2(" Get Mute of channel: %u\r\n", channelNum);
558  return tud_control_xfer(rhport, p_request, &mute[channelNum], 1);
559 
560  case AUDIO_FU_CTRL_VOLUME:
561  switch (p_request->bRequest) {
562  case AUDIO_CS_REQ_CUR:
563  TU_LOG2(" Get Volume of channel: %u\r\n", channelNum);
564  return tud_control_xfer(rhport, p_request, &volume[channelNum],
565  sizeof(volume[channelNum]));
566 
567  case AUDIO_CS_REQ_RANGE:
568  TU_LOG2(" Get Volume range of channel: %u\r\n", channelNum);
569 
570  // Copy values - only for testing - better is version below
571  audio_control_range_2_n_t(1) ret;
572 
573  ret.wNumSubRanges = 1;
574  ret.subrange[0].bMin = -90; // -90 dB
575  ret.subrange[0].bMax = 90; // +90 dB
576  ret.subrange[0].bRes = 1; // 1 dB steps
577 
578  return tud_audio_buffer_and_schedule_control_xfer(
579  rhport, p_request, (void *)&ret, sizeof(ret));
580 
581  // Unknown/Unsupported control
582  default:
583  TU_BREAKPOINT();
584  return false;
585  }
586  break;
587 
588  // Unknown/Unsupported control
589  default:
590  TU_BREAKPOINT();
591  return false;
592  }
593  }
594 
595  // Clock Source unit
596  if (entityID == 4) {
597  switch (ctrlSel) {
598  case AUDIO_CS_CTRL_SAM_FREQ:
599  // channelNum is always zero in this case
600  switch (p_request->bRequest) {
601  case AUDIO_CS_REQ_CUR:
602  TU_LOG2(" Get Sample Freq.\r\n");
603  return tud_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq));
604 
605  case AUDIO_CS_REQ_RANGE:
606  TU_LOG2(" Get Sample Freq. range\r\n");
607  return tud_control_xfer(rhport, p_request, &sampleFreqRng,
608  sizeof(sampleFreqRng));
609 
610  // Unknown/Unsupported control
611  default:
612  TU_BREAKPOINT();
613  return false;
614  }
615  break;
616 
617  case AUDIO_CS_CTRL_CLK_VALID:
618  // Only cur attribute exists for this request
619  TU_LOG2(" Get Sample Freq. valid\r\n");
620  return tud_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid));
621 
622  // Unknown/Unsupported control
623  default:
624  TU_BREAKPOINT();
625  return false;
626  }
627  }
628 
629  TU_LOG2(" Unsupported entity: %d\r\n", entityID);
630  return false; // Yet not implemented
631 }
632 
633 bool tud_audio_tx_done_pre_load_cb(uint8_t rhport, uint8_t itf, uint8_t ep_in,
634  uint8_t cur_alt_setting) {
635  (void)rhport;
636  (void)itf;
637  (void)ep_in;
638  (void)cur_alt_setting;
639 
640  tud_audio_write((uint8_t *)test_buffer_audio, CFG_TUD_AUDIO_EP_SZ_IN - 2);
641 
642  return true;
643 }
644 
645 bool tud_audio_tx_done_post_load_cb(uint8_t rhport, uint16_t n_bytes_copied,
646  uint8_t itf, uint8_t ep_in,
647  uint8_t cur_alt_setting) {
648  (void)rhport;
649  (void)n_bytes_copied;
650  (void)itf;
651  (void)ep_in;
652  (void)cur_alt_setting;
653 
654  // for (size_t cnt = 0; cnt < (CFG_TUD_AUDIO_EP_SZ_IN - 2) / 2; cnt++) {
655  // test_buffer_audio[cnt] = startVal++;
656  // }
657  if (p_in != nullptr) {
658  p_in->readBytes((uint8_t *)test_buffer_audio, CFG_TUD_AUDIO_EP_SZ_IN - 2);
659  } else {
660  memset(test_buffer_audio, 0, CFG_TUD_AUDIO_EP_SZ_IN - 2);
661  }
662 
663  return true;
664 }
665 
666 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)
667 {
668  (void)rhport;
669  (void)func_id;
670  (void)ep_out;
671  (void)cur_alt_setting;
672 
673  //free-running, adjust myself to match pace
674  bytes_read = tud_audio_read(test_buffer_audio, CFG_TUD_AUDIO_EP_SZ_IN - 2); //read from USB, write to buffer
675  if (p_print!=nullptr){
676  p_print->write(usb_spk_buf, bytes_read);
677  }
678 
679  return true;
680 }
681 
682 
683 bool tud_audio_set_itf_close_EP_cb(uint8_t rhport,
684  tusb_control_request_t const *p_request) {
685  (void)rhport;
686  (void)p_request;
687  startVal = 0;
688 
689  return true;
690 }
691 
692 //--------------------------------------------------------------------+
693 // BLINKING TASK
694 //--------------------------------------------------------------------+
695 void led_blinking_task(void) {
696 #ifdef PIN_LED
697  static uint32_t start_ms = 0;
698  static bool led_state = false;
699 
700  // Blink every interval ms
701  if (millis() - start_ms < blink_interval_ms)
702  return; // not enough time
703  start_ms += blink_interval_ms;
704 
705  digitalWrite(PIN_LED, led_state);
706  led_state = 1 - led_state; // toggle
707 #endif
708 }
709 
710 } // namespace audio_tools
Definition: AudioUSB.h:310
Definition: NoArduino.h:58
Definition: NoArduino.h:125
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition: AudioConfig.h:821
uint32_t millis()
Returns the milliseconds since the start.
Definition: Time.h:12
Basic Audio information which drives e.g. I2S.
Definition: AudioTypes.h:50
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition: AudioTypes.h:53
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition: AudioTypes.h:55