Преглед изворни кода

Commit before sharing.

Setup a test example - UNTESTED!
Missing: Start transmitting audio data in set_interface.
Reinhard Panhuber пре 5 година
родитељ
комит
c14f68e2c1

+ 12 - 0
examples/device/audio_test/Makefile

@@ -0,0 +1,12 @@
+include ../../../tools/top.mk
+include ../../make.mk
+
+INC += \
+  src \
+  $(TOP)/hw \
+
+# Example source
+EXAMPLE_SOURCE += $(wildcard src/*.c)
+SRC_C += $(addprefix $(CURRENT_PATH)/, $(EXAMPLE_SOURCE))
+
+include ../../rules.mk

+ 367 - 0
examples/device/audio_test/src/main.c

@@ -0,0 +1,367 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020 Reinhard Panhuber
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bsp/board.h"
+#include "tusb.h"
+
+//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTYPES
+//--------------------------------------------------------------------+
+
+/* Blink pattern
+ * - 250 ms  : device not mounted
+ * - 1000 ms : device mounted
+ * - 2500 ms : device is suspended
+ */
+enum  {
+  BLINK_NOT_MOUNTED = 250,
+  BLINK_MOUNTED = 1000,
+  BLINK_SUSPENDED = 2500,
+};
+
+static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED;
+
+// Audio controls
+// Current states
+bool mute[CFG_TUD_AUDIO_N_CHANNELS_TX + 1]; 						// +1 for master channel 0
+uint16_t volume[CFG_TUD_AUDIO_N_CHANNELS_TX + 1]; 					// +1 for master channel 0
+uint32_t sampFreq;
+uint8_t clkValid;
+
+// Range states
+audio_control_range_2_n_t(1) volumeRng[CFG_TUD_AUDIO_N_CHANNELS_TX+1]; 			// Volume range state
+audio_control_range_4_n_t(1) sampleFreqRng; 						// Sample frequency range state
+
+void led_blinking_task(void);
+void audio_task(void);
+
+/*------------- MAIN -------------*/
+int main(void)
+{
+  board_init();
+
+  tusb_init();
+
+  // Init values
+  sampFreq = 44100;
+  clkValid = 1;
+
+  sampleFreqRng.wNumSubRanges = 1;
+  sampleFreqRng.subrange[0].bMin = 44100;
+  sampleFreqRng.subrange[0].bMax = 44100;
+  sampleFreqRng.subrange[0].bRes = 0;
+
+  while (1)
+  {
+    tud_task(); // tinyusb device task
+    led_blinking_task();
+    audio_task();
+  }
+
+
+  return 0;
+}
+
+//--------------------------------------------------------------------+
+// Device callbacks
+//--------------------------------------------------------------------+
+
+// Invoked when device is mounted
+void tud_mount_cb(void)
+{
+  blink_interval_ms = BLINK_MOUNTED;
+}
+
+// Invoked when device is unmounted
+void tud_umount_cb(void)
+{
+  blink_interval_ms = BLINK_NOT_MOUNTED;
+}
+
+// Invoked when usb bus is suspended
+// remote_wakeup_en : if host allow us  to perform remote wakeup
+// Within 7ms, device must draw an average of current less than 2.5 mA from bus
+void tud_suspend_cb(bool remote_wakeup_en)
+{
+  (void) remote_wakeup_en;
+  blink_interval_ms = BLINK_SUSPENDED;
+}
+
+// Invoked when usb bus is resumed
+void tud_resume_cb(void)
+{
+  blink_interval_ms = BLINK_MOUNTED;
+}
+
+//--------------------------------------------------------------------+
+// AUDIO Task
+//--------------------------------------------------------------------+
+
+void audio_task(void)
+{
+  // Yet to be filled - e.g. put meas data into TX FIFOs etc.
+  asm("nop");
+}
+
+//--------------------------------------------------------------------+
+// Application Callback API Implementations
+//--------------------------------------------------------------------+
+
+// Invoked when audio class specific set request received for an EP
+bool tud_audio_set_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
+{
+  (void) rhport;
+
+  // We do not support any set range requests here, only current value requests
+  TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
+
+  // Page 91 in UAC2 specification
+  uint8_t channelNum = TU_U16_LOW(p_request->wValue);
+  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
+  uint8_t ep = TU_U16_LOW(p_request->wIndex);
+
+  return false; 	// Yet not implemented
+}
+
+// Invoked when audio class specific set request received for an interface
+bool tud_audio_set_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
+{
+  (void) rhport;
+
+  // We do not support any set range requests here, only current value requests
+  TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
+
+  // Page 91 in UAC2 specification
+  uint8_t channelNum = TU_U16_LOW(p_request->wValue);
+  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
+  uint8_t itf = TU_U16_LOW(p_request->wIndex);
+
+  return false; 	// Yet not implemented
+}
+
+// Invoked when audio class specific set request received for an entity
+bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff)
+{
+  (void) rhport;
+
+  // Page 91 in UAC2 specification
+  uint8_t channelNum = TU_U16_LOW(p_request->wValue);
+  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
+  uint8_t itf = TU_U16_LOW(p_request->wIndex);
+  uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
+
+  // We do not support any set range requests here, only current value requests
+  TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR);
+
+  // If request is for our feature unit
+  if (entityID == 2)
+  {
+    switch (ctrlSel)
+    {
+      case AUDIO_FU_CTRL_MUTE:
+	// Request uses format layout 1
+	TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t));
+
+	mute[channelNum] = ((audio_control_cur_1_t *)pBuff)->bCur;
+
+	TU_LOG2("    Set Mute: %d of channel: %u\r\n", mute[channelNum], channelNum);
+
+	return true;
+
+      case AUDIO_FU_CTRL_VOLUME:
+	// Request uses format layout 2
+	TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t));
+
+	volume[channelNum] = ((audio_control_cur_2_t *)pBuff)->bCur;
+
+	TU_LOG2("    Set Volume: %d dB of channel: %u\r\n", volume[channelNum], channelNum);
+
+	return true;
+
+	// Unknown/Unsupported control
+      default: TU_BREAKPOINT(); return false;
+    }
+  }
+  return false; 	// Yet not implemented
+}
+
+// Invoked when audio class specific get request received for an EP
+bool tud_audio_get_req_ep_cb(uint8_t rhport, tusb_control_request_t const * p_request)
+{
+  (void) rhport;
+
+  // Page 91 in UAC2 specification
+  uint8_t channelNum = TU_U16_LOW(p_request->wValue);
+  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
+  uint8_t ep = TU_U16_LOW(p_request->wIndex);
+
+  //	return tud_control_xfer(rhport, p_request, &tmp, 1);
+
+  return false; 	// Yet not implemented
+}
+
+// Invoked when audio class specific get request received for an interface
+bool tud_audio_get_req_itf_cb(uint8_t rhport, tusb_control_request_t const * p_request)
+{
+  (void) rhport;
+
+  // Page 91 in UAC2 specification
+  uint8_t channelNum = TU_U16_LOW(p_request->wValue);
+  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
+  uint8_t itf = TU_U16_LOW(p_request->wIndex);
+
+  return false; 	// Yet not implemented
+}
+
+// Invoked when audio class specific get request received for an entity
+bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request)
+{
+  (void) rhport;
+
+  // Page 91 in UAC2 specification
+  uint8_t channelNum = TU_U16_LOW(p_request->wValue);
+  uint8_t ctrlSel = TU_U16_HIGH(p_request->wValue);
+  // uint8_t itf = TU_U16_LOW(p_request->wIndex); 			// Since we have only one audio function implemented, we do not need the itf value
+  uint8_t entityID = TU_U16_HIGH(p_request->wIndex);
+
+  // Input terminal (Microphone input)
+  if (entityID == 1)
+  {
+    switch (ctrlSel)
+    {
+      case AUDIO_TE_CTRL_CONNECTOR:;
+      // The terminal connector control only has a get request with only the CUR attribute.
+
+      audio_desc_channel_cluster_t ret;
+
+      // Those are dummy values for now
+      ret.bNrChannels = 1;
+      ret.bmChannelConfig = 0;
+      ret.iChannelNames = 0;
+
+      TU_LOG2("    Get terminal connector\r\n");
+
+      return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*)&ret, sizeof(ret));
+
+      // Unknown/Unsupported control selector
+      default: TU_BREAKPOINT(); return false;
+    }
+  }
+
+  // Feature unit
+  if (entityID == 2)
+  {
+    switch (ctrlSel)
+    {
+      case AUDIO_FU_CTRL_MUTE:
+	// Audio control mute cur parameter block consists of only one byte - we thus can send it right away
+	// There does not exist a range parameter block for mute
+	TU_LOG2("    Get Mute of channel: %u\r\n", channelNum);
+	return tud_control_xfer(rhport, p_request, &mute[channelNum], 1);
+
+      case AUDIO_FU_CTRL_VOLUME:
+
+	switch (p_request->bRequest)
+	{
+	  case AUDIO_CS_REQ_CUR:
+	    TU_LOG2("    Get Volume of channel: %u\r\n", channelNum);
+	    return tud_control_xfer(rhport, p_request, &volume[channelNum], sizeof(volume[channelNum]));
+	  case AUDIO_CS_REQ_RANGE:
+	    TU_LOG2("    Get Volume range of channel: %u\r\n", channelNum);
+
+	    // Copy values - only for testing - better is version below
+	    audio_control_range_2_n_t(1) ret;
+
+	    ret.wNumSubRanges = 1;
+	    ret.subrange[0].bMin = -90; 	// -90 dB
+	    ret.subrange[0].bMax = 90;		// +90 dB
+	    ret.subrange[0].bRes = 1; 		// 1 dB steps
+
+	    return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, (void*)&ret, sizeof(ret));
+
+	    // Unknown/Unsupported control
+	  default: TU_BREAKPOINT(); return false;
+	}
+
+	// Unknown/Unsupported control
+	  default: TU_BREAKPOINT(); return false;
+    }
+  }
+
+  // Clock Source unit
+  if (entityID == 4)
+  {
+    switch (ctrlSel)
+    {
+      case AUDIO_CS_CTRL_SAM_FREQ:
+
+	// channelNum is always zero in this case
+
+	switch (p_request->bRequest)
+	{
+	  case AUDIO_CS_REQ_CUR:
+	    TU_LOG2("    Get Sample Freq.\r\n");
+	    return tud_control_xfer(rhport, p_request, &sampFreq, sizeof(sampFreq));
+	  case AUDIO_CS_REQ_RANGE:
+	    TU_LOG2("    Get Sample Freq. range\r\n");
+	    return tud_control_xfer(rhport, p_request, &sampleFreqRng, sizeof(sampleFreqRng));
+
+	    // Unknown/Unsupported control
+	  default: TU_BREAKPOINT(); return false;
+	}
+
+	  case AUDIO_CS_CTRL_CLK_VALID:
+	    // Only cur attribute exists for this request
+	    TU_LOG2("    Get Sample Freq. valid\r\n");
+	    return tud_control_xfer(rhport, p_request, &clkValid, sizeof(clkValid));
+
+	    // Unknown/Unsupported control
+	  default: TU_BREAKPOINT(); return false;
+    }
+  }
+
+  TU_LOG2("  Unsupported entity: %d\r\n", entityID);
+  return false; 	// Yet not implemented
+}
+
+//--------------------------------------------------------------------+
+// BLINKING TASK
+//--------------------------------------------------------------------+
+void led_blinking_task(void)
+{
+  static uint32_t start_ms = 0;
+  static bool led_state = false;
+
+  // Blink every interval ms
+  if ( board_millis() - start_ms < blink_interval_ms) return; // not enough time
+  start_ms += blink_interval_ms;
+
+  board_led_write(led_state);
+  led_state = 1 - led_state; // toggle
+}

+ 112 - 0
examples/device/audio_test/src/tusb_config.h

@@ -0,0 +1,112 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#ifndef _TUSB_CONFIG_H_
+#define _TUSB_CONFIG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//--------------------------------------------------------------------
+// COMMON CONFIGURATION
+//--------------------------------------------------------------------
+
+// defined by compiler flags for flexibility
+#ifndef CFG_TUSB_MCU
+#error CFG_TUSB_MCU must be defined
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX
+#define CFG_TUSB_RHPORT0_MODE       (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED)
+#else
+#define CFG_TUSB_RHPORT0_MODE       OPT_MODE_DEVICE
+#endif
+
+#define CFG_TUSB_OS                 OPT_OS_NONE
+
+// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
+// #define CFG_TUSB_DEBUG           0
+
+/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
+ * Tinyusb use follows macros to declare transferring memory so that they can be put
+ * into those specific section.
+ * e.g
+ * - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
+ * - CFG_TUSB_MEM_ALIGN   : __attribute__ ((aligned(4)))
+ */
+#ifndef CFG_TUSB_MEM_SECTION
+#define CFG_TUSB_MEM_SECTION
+#endif
+
+#ifndef CFG_TUSB_MEM_ALIGN
+#define CFG_TUSB_MEM_ALIGN          __attribute__ ((aligned(4)))
+#endif
+
+//--------------------------------------------------------------------
+// DEVICE CONFIGURATION
+//--------------------------------------------------------------------
+
+#ifndef CFG_TUD_ENDPOINT0_SIZE
+#define CFG_TUD_ENDPOINT0_SIZE    64
+#endif
+
+//------------- CLASS -------------//
+#define CFG_TUD_CDC               0
+#define CFG_TUD_MSC               0
+#define CFG_TUD_HID               0
+#define CFG_TUD_MIDI              0
+#define CFG_TUD_AUDIO             1
+#define CFG_TUD_VENDOR            0
+
+//--------------------------------------------------------------------
+// AUDIO CLASS DRIVER CONFIGURATION
+//--------------------------------------------------------------------
+
+// Audio format type
+#define CFG_TUD_AUDIO_USE_TX_FIFO 				1
+#define CFG_TUD_AUDIO_FORMAT_TYPE_TX 				AUDIO_FORMAT_TYPE_I
+#define CFG_TUD_AUDIO_FORMAT_TYPE_RX 				AUDIO_FORMAT_TYPE_UNDEFINED
+
+// Audio format type I specifications
+#define CFG_TUD_AUDIO_FORMAT_TYPE_I_TX 				AUDIO_DATA_FORMAT_TYPE_I_PCM
+#define CFG_TUD_AUDIO_N_CHANNELS_TX 				1
+#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX			3
+
+// EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense)
+#define CFG_TUD_AUDIO_EPSIZE_IN    				45*CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX*CFG_TUD_AUDIO_N_CHANNELS_TX 	// 45 Samples (44.1 kHz) x 3 Bytes/Sample x 1 Channels
+#define CFG_TUD_AUDIO_TX_FIFO_SIZE 				45*4 									// 45 Samples (44.1 kHz) x 4 Bytes/Sample (1 word)
+
+// Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes)
+#define CFG_TUD_AUDIO_N_AS_INT 			   		1
+
+// Size of control request buffer
+#define CFG_TUD_AUDIO_CTRL_BUF_SIZE 				64
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TUSB_CONFIG_H_ */

+ 167 - 0
examples/device/audio_test/src/usb_descriptors.c

@@ -0,0 +1,167 @@
+/* 
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include "tusb.h"
+
+/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
+ * Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
+ *
+ * Auto ProductID layout's Bitmap:
+ *   [MSB]     AUDIO | MIDI | HID | MSC | CDC          [LSB]
+ */
+#define _PID_MAP(itf, n)  ( (CFG_TUD_##itf) << (n) )
+#define USB_PID           (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
+    _PID_MAP(MIDI, 3) | _PID_MAP(AUDIO, 4) | _PID_MAP(VENDOR, 5) )
+
+//--------------------------------------------------------------------+
+// Device Descriptors
+//--------------------------------------------------------------------+
+tusb_desc_device_t const desc_device =
+{
+    .bLength            = sizeof(tusb_desc_device_t),
+    .bDescriptorType    = TUSB_DESC_DEVICE,
+    .bcdUSB             = 0x0200,
+
+    // Use Interface Association Descriptor (IAD) for CDC
+    // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1)
+    .bDeviceClass       = TUSB_CLASS_MISC,
+    .bDeviceSubClass    = MISC_SUBCLASS_COMMON,
+    .bDeviceProtocol    = MISC_PROTOCOL_IAD,
+    .bMaxPacketSize0    = CFG_TUD_ENDPOINT0_SIZE,
+
+    .idVendor           = 0xCafe,
+    .idProduct          = USB_PID,
+    .bcdDevice          = 0x0100,
+
+    .iManufacturer      = 0x01,
+    .iProduct           = 0x02,
+    .iSerialNumber      = 0x03,
+
+    .bNumConfigurations = 0x01
+};
+
+// Invoked when received GET DEVICE DESCRIPTOR
+// Application return pointer to descriptor
+uint8_t const * tud_descriptor_device_cb(void)
+{
+  return (uint8_t const *) &desc_device;
+}
+
+//--------------------------------------------------------------------+
+// Configuration Descriptor
+//--------------------------------------------------------------------+
+enum
+{
+  ITF_NUM_AUDIO_CONTROL = 0,
+  ITF_NUM_AUDIO_STREAMING,
+  ITF_NUM_TOTAL
+};
+
+#define CONFIG_TOTAL_LEN    	(TUD_CONFIG_DESC_LEN + CFG_TUD_AUDIO * TUD_AUDIO_MIC_DESC_LEN)
+
+#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
+// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
+// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
+#define EPNUM_AUDIO   0x03
+#else
+#define EPNUM_AUDIO   0x01
+#endif
+
+// These variables are required by the audio driver in audio_device.c
+
+// List of audio descriptor lengths which is required by audio driver - you need as many entries as CFG_TUD_AUDIO - unfortunately this is not possible to determine otherwise
+const uint16_t tud_audio_desc_lengths[] = {TUD_AUDIO_MIC_DESC_LEN};
+
+// TAKE CARE - THE NUMBER OF AUDIO STREAMING INTERFACES PER AUDIO FUNCTION MUST NOT EXCEED CFG_TUD_AUDIO_N_AS_INT - IF IT DOES INCREASE CFG_TUD_AUDIO_N_AS_INT IN tusb_config.h!
+
+uint8_t const desc_configuration[] =
+{
+    // Interface count, string index, total length, attribute, power in mA
+    TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
+
+    // Interface number, string index, EP Out & EP In address, EP size
+    TUD_AUDIO_MIC_DESCRIPTOR(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_stridx*/ 0, /*_nBytesPerSample*/ 3, /*_nBitsUsedPerSample*/ 24, /*_epin*/ 0x80 | EPNUM_AUDIO, /*_epsize*/ 45*3)
+};
+
+// Invoked when received GET CONFIGURATION DESCRIPTOR
+// Application return pointer to descriptor
+// Descriptor contents must exist long enough for transfer to complete
+uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
+{
+  (void) index; // for multiple configurations
+  return desc_configuration;
+}
+
+//--------------------------------------------------------------------+
+// String Descriptors
+//--------------------------------------------------------------------+
+
+// array of pointer to string descriptors
+char const* string_desc_arr [] =
+{
+    (const char[]) { 0x09, 0x04 }, 	// 0: is supported language is English (0x0409)
+    "PaniRCorp",                   	// 1: Manufacturer
+    "MicNode",              		// 2: Product
+    "123456",                      	// 3: Serials, should use chip ID
+    "UAC2",                 	 	// 4: Audio Interface
+};
+
+static uint16_t _desc_str[32];
+
+// Invoked when received GET STRING DESCRIPTOR request
+// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
+uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
+{
+  (void) langid;
+
+  uint8_t chr_count;
+
+  if ( index == 0)
+  {
+    memcpy(&_desc_str[1], string_desc_arr[0], 2);
+    chr_count = 1;
+  }else
+  {
+    // Convert ASCII string into UTF-16
+
+    if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
+
+    const char* str = string_desc_arr[index];
+
+    // Cap at max char
+    chr_count = strlen(str);
+    if ( chr_count > 31 ) chr_count = 31;
+
+    for(uint8_t i=0; i<chr_count; i++)
+    {
+      _desc_str[1+i] = str[i];
+    }
+  }
+
+  // first byte is length (including header), second byte is string type
+  _desc_str[0] = (TUSB_DESC_STRING << 8 ) | (2*chr_count + 2);
+
+  return _desc_str;
+}

Разлика између датотеке није приказан због своје велике величине
+ 762 - 761
src/class/audio/audio.h


+ 25 - 65
src/class/audio/audio_device.c

@@ -384,7 +384,8 @@ static bool audio_tx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_t
   {
     case AUDIO_FORMAT_TYPE_UNDEFINED:
       // INDIVIDUAL ENCODING PROCEDURE REQUIRED HERE!
-      asm("nop");
+      TU_LOG2("  Desired CFG_TUD_AUDIO_FORMAT encoding not implemented!\r\n");
+      TU_BREAKPOINT();
       break;
 
     case AUDIO_FORMAT_TYPE_I:
@@ -402,19 +403,21 @@ static bool audio_tx_done_cb(uint8_t rhport, audiod_interface_t* audio, uint16_t
 
 	default:
 	  // YOUR ENCODING AND SENDING IS REQUIRED HERE!
-	  asm("nop");
+	  TU_LOG2("  Desired CFG_TUD_AUDIO_FORMAT_TYPE_I_TX encoding not implemented!\r\n");
+	  TU_BREAKPOINT();
 	  break;
       }
       break;
 
 	default:
 	  // Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!
-	  asm("nop");
+	  TU_LOG2("  Desired CFG_TUD_AUDIO_FORMAT_TYPE_TX not implemented!\r\n");
+	  TU_BREAKPOINT();
 	  break;
   }
 
   // Call a weak callback here - a possibility for user to get informed TX was completed
-  TU_VERIFY(tud_audio_tx_done_cb(rhport, n_bytes_copied));
+  if (tud_audio_tx_done_cb) TU_VERIFY(tud_audio_tx_done_cb(rhport, n_bytes_copied));
   return true;
 }
 
@@ -497,7 +500,7 @@ static uint16_t audio_fb_done_cb(uint8_t rhport, audiod_interface_t* audio)
   // Here we need to return the feedback value
 #error RETURN YOUR FEEDBACK VALUE HERE!
 
-  TU_VERIFY(tud_audio_fb_done_cb(rhport));
+  if (tud_audio_fb_done_cb) TU_VERIFY(tud_audio_fb_done_cb(rhport));
   return 0;
 }
 
@@ -522,57 +525,12 @@ static bool audio_int_ctr_done_cb(uint8_t rhport, audiod_interface_t* audio, uin
 
   *n_bytes_copied = cnt;
 
-  TU_VERIFY(tud_audio_int_ctr_done_cb(rhport, n_bytes_copied));
+  if (tud_audio_int_ctr_done_cb) TU_VERIFY(tud_audio_int_ctr_done_cb(rhport, n_bytes_copied));
 
   return true;
 }
 #endif
 
-// Callback functions
-// Currently the return value has to effect so far. The return value finally is discarded in tud_task(void) in usbd.c - we just incorporate that for later use
-
-#if CFG_TUD_AUDIO_EPSIZE_IN
-TU_ATTR_WEAK bool tud_audio_tx_done_cb(uint8_t rhport, uint16_t * n_bytes_copied)
-{
-  (void) rhport;
-  (void) n_bytes_copied;
-
-  /* NOTE: This function should not be modified, when the callback is needed,
-           the tud_audio_tx_done_cb could be implemented in the user file
-   */
-
-  return true;
-}
-#endif
-
-#if CFG_TUD_AUDIO_EPSIZE_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
-TU_ATTR_WEAK bool tud_audio_fb_done_cb(uint8_t rhport)
-{
-  (void) rhport;
-
-  /* NOTE: This function should not be modified, when the callback is needed,
-           the tud_audio_fb_done_cb could be implemented in the user file
-   */
-
-  return true;
-}
-#endif
-
-#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN
-TU_ATTR_WEAK bool tud_audio_int_ctr_done_cb(uint8_t rhport, uint16_t * n_bytes_copied)
-{
-  (void) rhport;
-  (void) n_bytes_copied;
-
-  /* NOTE: This function should not be modified, when the callback is needed,
-	           the tud_audio_int_ctr_done_cb could be implemented in the user file
-   */
-
-  return true;
-}
-
-#endif
-
 //--------------------------------------------------------------------+
 // USBD Driver API
 //--------------------------------------------------------------------+
@@ -755,6 +713,8 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
   }
 #endif
 
+  // Save current alternative interface setting
+  _audiod_itf[idxDriver].altSetting[idxItf] = alt;
 
   // Open new EP if necessary - EPs are only to be closed or opened for AS interfaces - Look for AS interface with correct alternate interface
   // Get pointer at end
@@ -778,8 +738,16 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
 #if CFG_TUD_AUDIO_EPSIZE_IN > 0
 	  if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && ((tusb_desc_endpoint_t const *) p_desc)->bmAttributes.usage == 0x00) 	// Check if usage is data EP
 	  {
+	    // Save address
 	    _audiod_itf[idxDriver].ep_in = ep_addr;
 	    _audiod_itf[idxDriver].ep_in_as_intf_num = itf;
+
+	    // HERE WE WOULD NEED TO SCHEDULE OUR FIRST TRANSMIT, HOWEVER, WE ALSO WOULD FIRST NEED TO ENABLE SAMPLING AT ALL - HOW TO HANDLE THIS?
+	    // Invoke callback - fill something in the FIFO here for now
+	    if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
+
+	    uint16_t n_bytes_copied;
+	    TU_VERIFY(audio_tx_done_cb(rhport, &_audiod_itf[idxDriver], &n_bytes_copied));
 	  }
 #endif
 
@@ -791,6 +759,9 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
 	    _audiod_itf[idxDriver].ep_out = ep_addr;
 	    _audiod_itf[idxDriver].ep_out_as_intf_num = itf;
 
+	    // Invoke callback
+	    if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
+
 	    // Prepare for incoming data
 	    TU_ASSERT(usbd_edpt_xfer(rhport, ep_addr, _audiod_itf[idxDriver].epout_buf, CFG_TUD_AUDIO_EPSIZE_OUT), false);
 	  }
@@ -799,6 +770,9 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
 	  if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && ((tusb_desc_endpoint_t const *) p_desc)->bmAttributes.usage == 0x10) 	// Check if usage is implicit data feedback
 	  {
 	    _audiod_itf[idxDriver].ep_fb = ep_addr;
+
+	    // Invoke callback
+	    if (tud_audio_set_itf_cb) TU_VERIFY(tud_audio_set_itf_cb(rhport, p_request));
 	  }
 #endif
 
@@ -818,20 +792,6 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
     p_desc = tu_desc_next(p_desc);
   }
 
-//  // Check for nothing found - we can rely on this since EP descriptors are never the last descriptors, there are always also class specific EP descriptors following!
-//  TU_VERIFY(p_desc < p_desc_end);
-
-  // Save current alternative interface setting
-  _audiod_itf[idxDriver].altSetting[idxItf] = alt;
-
-  // Invoke callback
-  if (tud_audio_set_itf_cb)
-  {
-    if (!tud_audio_set_itf_cb(rhport, p_request)) return false;
-  }
-
-  // Start sending or receiving?
-
   tud_control_status(rhport, p_request);
 
   return true;

+ 5 - 4
src/class/audio/audio_device.h

@@ -1,7 +1,8 @@
 /* 
  * The MIT License (MIT)
  *
- * Copyright (c) 2020 Ha Thach (tinyusb.org) and Reinhard Panhuber
+ * Copyright (c) 2020 Ha Thach (tinyusb.org)
+ * Copyright (c) 2020 Reinhard Panhuber
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -217,15 +218,15 @@ bool tud_audio_buffer_and_schedule_control_xfer(uint8_t rhport, tusb_control_req
 //--------------------------------------------------------------------+
 
 #if CFG_TUD_AUDIO_EPSIZE_IN
-bool tud_audio_tx_done_cb(uint8_t rhport, uint16_t * n_bytes_copied);
+TU_ATTR_WEAK bool tud_audio_tx_done_cb(uint8_t rhport, uint16_t * n_bytes_copied);
 #endif
 
 #if CFG_TUD_AUDIO_EPSIZE_OUT
-bool tud_audio_rx_done_cb(uint8_t rhport, uint8_t * buffer, uint16_t bufsize);
+TU_ATTR_WEAK bool tud_audio_rx_done_cb(uint8_t rhport, uint8_t * buffer, uint16_t bufsize);
 #endif
 
 #if CFG_TUD_AUDIO_EPSIZE_OUT > 0 && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP
-bool tud_audio_fb_done_cb(uint8_t rhport);
+TU_ATTR_WEAK bool tud_audio_fb_done_cb(uint8_t rhport);
 #endif
 
 #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN

+ 1 - 0
src/portable/st/synopsys/dcd_synopsys.c

@@ -4,6 +4,7 @@
  * Copyright (c) 2018 Scott Shawcroft, 2019 William D. Jones for Adafruit Industries
  * Copyright (c) 2019 Ha Thach (tinyusb.org)
  * Copyright (c) 2020 Jan Duempelmann
+ * Copyright (c) 2020 Reinhard Panhuber
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal

Неке датотеке нису приказане због велике количине промена