From f931983469bf375eec9503b99e021b9b633bf23f Mon Sep 17 00:00:00 2001 From: Mark K Cowan Date: Sun, 23 Oct 2022 02:55:28 +0300 Subject: [PATCH 01/20] UAC2 supports interrupt-endpoint for providing control-change notifications to the host --- src/class/audio/audio_device.c | 58 ++++++++++++++++++++++++++++++++-- src/class/audio/audio_device.h | 46 ++++++++++++++++++++++++--- 2 files changed, 96 insertions(+), 8 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index a65d605b7..05339f9ce 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -341,7 +341,7 @@ typedef struct // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74) #if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE]; + CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE]; #endif // Decoding parameters - parameters are set when alternate AS interface is set by host @@ -464,7 +464,7 @@ bool tud_audio_n_mounted(uint8_t func_id) if (audio->ep_in == 0) return false; #endif -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP if (audio->ep_int_ctr == 0) return false; #endif @@ -813,11 +813,13 @@ tu_fifo_t* tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx) #endif -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP // If no interrupt transmit is pending bytes get written into buffer and a transmit is scheduled - once transmit completed tud_audio_int_ctr_done_cb() is called in inform user uint16_t tud_audio_int_ctr_n_write(uint8_t func_id, uint8_t const* buffer, uint16_t len) { + TU_VERIFY(_audiod_fct[func_id].ep_int_ctr != 0); + TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); // We write directly into the EP's buffer - abort if previous transfer not complete @@ -1079,6 +1081,52 @@ static inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio) } #endif +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP +static bool set_int_ctr_number(audiod_function_t *audio) +{ + + uint8_t const *p_desc = audio->p_desc; + // Get pointer at end + uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; + + + // p_desc starts at required interface with alternate setting zero + while (p_desc < p_desc_end) + { + // Find correct interface + if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == 0 && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0) + { + + uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints; + while (foundEPs < nEps && p_desc < p_desc_end) + { + // found :n endpoint + if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) + { + tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc; + + uint8_t const ep_addr = desc_ep->bEndpointAddress; + + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.xfer == 0x03) // Check if usage is interrupt EP + { + audio->ep_int_ctr = ep_addr; + TU_ASSERT(usbd_edpt_open(audio->rhport, desc_ep)); + } + + foundEPs += 1; + } + p_desc = tu_desc_next(p_desc); + } + break; + } + p_desc = tu_desc_next(p_desc); + } + + return true; + +} +#endif + //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ @@ -1484,6 +1532,10 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin // This is all we need so far - the EPs are setup by a later set_interface request (as per UAC2 specification) 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 +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP + TU_ASSERT(set_int_ctr_number(&_audiod_fct[i])); +#endif + return drv_len; } diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 0ef100fa4..0c394d235 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -191,9 +191,19 @@ #define CFG_TUD_AUDIO_ENABLE_FEEDBACK_FORMAT_CORRECTION 0 // 0 or 1 #endif +// Enable/disable interrupt EP (required for notifying host of control changes) +#ifndef CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP +#define CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP 0 // Feedback - 0 or 1 +#endif + // Audio interrupt control EP size - disabled if 0 #ifndef CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN -#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 // Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74) +// Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74) +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP +#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 6 +#else +#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 +#endif #endif #ifndef CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE @@ -388,7 +398,7 @@ uint16_t tud_audio_n_write_support_ff (uint8_t func_id, uint8_t ff_i tu_fifo_t* tud_audio_n_get_tx_support_ff (uint8_t func_id, uint8_t ff_idx); #endif -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP uint16_t tud_audio_int_ctr_n_write (uint8_t func_id, uint8_t const* buffer, uint16_t len); #endif @@ -431,7 +441,7 @@ static inline tu_fifo_t* tud_audio_get_tx_support_ff (uint8_t ff_idx); // INT CTR API -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP static inline uint16_t tud_audio_int_ctr_write (uint8_t const* buffer, uint16_t len); #endif @@ -531,7 +541,33 @@ TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP +// UAC2 §9.6 +// Structure of "interrupt data message" +typedef struct TU_ATTR_PACKED +{ + uint8_t bInfo; + uint8_t bAttribute; + union TU_ATTR_PACKED + { + uint16_t wValue; + struct TU_ATTR_PACKED + { + uint8_t wValue_cn_or_mcn; + uint8_t wValue_cs; + }; + }; + union TU_ATTR_PACKED + { + uint16_t wIndex; + struct TU_ATTR_PACKED + { + uint8_t wIndex_ep_or_int; + uint8_t wIndex_entity_id; + }; + }; +} audio_status_update_t; + TU_ATTR_WEAK bool tud_audio_int_ctr_done_cb(uint8_t rhport, uint16_t n_bytes_copied); #endif @@ -663,7 +699,7 @@ static inline tu_fifo_t* tud_audio_get_tx_support_ff(uint8_t ff_idx) #endif -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t len) { return tud_audio_int_ctr_n_write(0, buffer, len); From 025d3477e81e07ddc2db78193e8957cdb1050516 Mon Sep 17 00:00:00 2001 From: Mark K Cowan Date: Mon, 24 Oct 2022 20:41:09 +0300 Subject: [PATCH 02/20] fixed spec reference --- src/class/audio/audio_device.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 0c394d235..92a1e6585 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -542,8 +542,7 @@ TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -// UAC2 §9.6 -// Structure of "interrupt data message" +// UAC2 §6.1 "interrupt data message" typedef struct TU_ATTR_PACKED { uint8_t bInfo; From 15ed45e1a33210c5e949801a77aabd544fa170ed Mon Sep 17 00:00:00 2001 From: Mark K Cowan Date: Wed, 26 Oct 2022 21:40:30 +0300 Subject: [PATCH 03/20] clean up descriptor search for interrupt endpoint --- src/class/audio/audio_device.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 05339f9ce..efa06cf70 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -1090,40 +1090,36 @@ static bool set_int_ctr_number(audiod_function_t *audio) uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; - // p_desc starts at required interface with alternate setting zero - while (p_desc < p_desc_end) + bool found = false; + while (!found && p_desc < p_desc_end) { - // Find correct interface - if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && ((tusb_desc_interface_t const * )p_desc)->bInterfaceNumber == 0 && ((tusb_desc_interface_t const * )p_desc)->bAlternateSetting == 0) + // For each interface/alternate + if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) { - uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints; - while (foundEPs < nEps && p_desc < p_desc_end) + while (!found && foundEPs < nEps && p_desc < p_desc_end) { - // found :n endpoint + // For each endpoint if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) { tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc; - uint8_t const ep_addr = desc_ep->bEndpointAddress; - + // If endpoint is input-direction and interrupt-type if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.xfer == 0x03) // Check if usage is interrupt EP { + // Store endpoint number and open endpoint audio->ep_int_ctr = ep_addr; TU_ASSERT(usbd_edpt_open(audio->rhport, desc_ep)); + found = true; } - foundEPs += 1; } p_desc = tu_desc_next(p_desc); } - break; } p_desc = tu_desc_next(p_desc); } - - return true; - + return found; } #endif From 9673d20901dd5419c82ccc14dd2fd300ca0fa8c4 Mon Sep 17 00:00:00 2001 From: Mark K Cowan Date: Wed, 26 Oct 2022 21:43:27 +0300 Subject: [PATCH 04/20] PanRe refactor applied: s{_int_ctr_}{_int_}g; s{_INT_CTR_}{_INT_}g; --- src/class/audio/audio_device.c | 38 +++++++++++++++++----------------- src/class/audio/audio_device.h | 20 +++++++++--------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index efa06cf70..4681e1ddb 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -283,8 +283,8 @@ typedef struct #endif -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - uint8_t ep_int_ctr; // Audio control interrupt EP. +#if CFG_TUD_AUDIO_INT_EPSIZE_IN + uint8_t ep_int; // Audio control interrupt EP. #endif /*------------- From this point, data is not cleared by bus reset -------------*/ @@ -340,8 +340,8 @@ typedef struct #endif // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74) -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN - CFG_TUSB_MEM_ALIGN uint8_t ep_int_ctr_buf[CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE]; +#if CFG_TUD_AUDIO_INT_EPSIZE_IN + CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[CFG_TUD_AUDIO_INT_EP_IN_SW_BUFFER_SIZE]; #endif // Decoding parameters - parameters are set when alternate AS interface is set by host @@ -465,7 +465,7 @@ bool tud_audio_n_mounted(uint8_t func_id) #endif #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP - if (audio->ep_int_ctr == 0) return false; + if (audio->ep_int == 0) return false; #endif #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP @@ -815,23 +815,23 @@ tu_fifo_t* tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx) #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -// If no interrupt transmit is pending bytes get written into buffer and a transmit is scheduled - once transmit completed tud_audio_int_ctr_done_cb() is called in inform user -uint16_t tud_audio_int_ctr_n_write(uint8_t func_id, uint8_t const* buffer, uint16_t len) +// 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 +uint16_t tud_audio_int_n_write(uint8_t func_id, uint8_t const* buffer, uint16_t len) { - TU_VERIFY(_audiod_fct[func_id].ep_int_ctr != 0); + TU_VERIFY(_audiod_fct[func_id].ep_int != 0); TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); // We write directly into the EP's buffer - abort if previous transfer not complete - TU_VERIFY(!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr)); + TU_VERIFY(!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int)); // Check length - TU_VERIFY(len <= CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE); + TU_VERIFY(len <= CFG_TUD_AUDIO_INT_EP_IN_SW_BUFFER_SIZE); - memcpy(_audiod_fct[func_id].ep_int_ctr_buf, buffer, len); + memcpy(_audiod_fct[func_id].ep_int_buf, buffer, len); // Schedule transmit - TU_VERIFY(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int_ctr, _audiod_fct[func_id].ep_int_ctr_buf, len)); + TU_VERIFY(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int, _audiod_fct[func_id].ep_int_buf, len)); return true; } @@ -1082,7 +1082,7 @@ static inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio) #endif #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -static bool set_int_ctr_number(audiod_function_t *audio) +static bool set_int_number(audiod_function_t *audio) { uint8_t const *p_desc = audio->p_desc; @@ -1108,7 +1108,7 @@ static bool set_int_ctr_number(audiod_function_t *audio) if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.xfer == 0x03) // Check if usage is interrupt EP { // Store endpoint number and open endpoint - audio->ep_int_ctr = ep_addr; + audio->ep_int = ep_addr; TU_ASSERT(usbd_edpt_open(audio->rhport, desc_ep)); found = true; } @@ -1485,7 +1485,7 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin // Verify interrupt control EP is enabled if demanded by descriptor - this should be best some static check however - this check can be omitted if (itf_desc->bNumEndpoints == 1) // 0 or 1 EPs are allowed { - TU_VERIFY(CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN > 0); + TU_VERIFY(CFG_TUD_AUDIO_INT_EPSIZE_IN > 0); } // Alternate setting MUST be zero - this check can be omitted @@ -1529,7 +1529,7 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin 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 #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP - TU_ASSERT(set_int_ctr_number(&_audiod_fct[i])); + TU_ASSERT(set_int_number(&_audiod_fct[i])); #endif return drv_len; @@ -2030,10 +2030,10 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 { audiod_function_t* audio = &_audiod_fct[func_id]; -#if CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +#if CFG_TUD_AUDIO_INT_EPSIZE_IN // Data transmission of control interrupt finished - if (audio->ep_int_ctr == ep_addr) + if (audio->ep_int == ep_addr) { // 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) // In case there is nothing to send we have to return a NAK - this is taken care of by PHY ??? @@ -2042,7 +2042,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 // I assume here, that things above are handled by PHY // All transmission is done - what remains to do is to inform job was completed - if (tud_audio_int_ctr_done_cb) TU_VERIFY(tud_audio_int_ctr_done_cb(rhport, (uint16_t) xferred_bytes)); + if (tud_audio_int_done_cb) TU_VERIFY(tud_audio_int_done_cb(rhport, (uint16_t) xferred_bytes)); } #endif diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 92a1e6585..2e39e6049 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -197,17 +197,17 @@ #endif // Audio interrupt control EP size - disabled if 0 -#ifndef CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN +#ifndef CFG_TUD_AUDIO_INT_EPSIZE_IN // Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74) #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 6 +#define CFG_TUD_AUDIO_INT_EPSIZE_IN 6 #else -#define CFG_TUD_AUDIO_INT_CTR_EPSIZE_IN 0 +#define CFG_TUD_AUDIO_INT_EPSIZE_IN 0 #endif #endif -#ifndef CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE -#define CFG_TUD_AUDIO_INT_CTR_EP_IN_SW_BUFFER_SIZE 6 // Buffer size of audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74) +#ifndef CFG_TUD_AUDIO_INT_EP_IN_SW_BUFFER_SIZE +#define CFG_TUD_AUDIO_INT_EP_IN_SW_BUFFER_SIZE 6 // Buffer size of audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74) #endif // Use software encoding/decoding @@ -399,7 +399,7 @@ tu_fifo_t* tud_audio_n_get_tx_support_ff (uint8_t func_id, uint8_t ff_i #endif #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -uint16_t tud_audio_int_ctr_n_write (uint8_t func_id, uint8_t const* buffer, uint16_t len); +uint16_t tud_audio_int_n_write (uint8_t func_id, uint8_t const* buffer, uint16_t len); #endif //--------------------------------------------------------------------+ @@ -442,7 +442,7 @@ static inline tu_fifo_t* tud_audio_get_tx_support_ff (uint8_t ff_idx); // INT CTR API #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -static inline uint16_t tud_audio_int_ctr_write (uint8_t const* buffer, uint16_t len); +static inline uint16_t tud_audio_int_write (uint8_t const* buffer, uint16_t len); #endif // Buffer control EP data and schedule a transmit @@ -567,7 +567,7 @@ typedef struct TU_ATTR_PACKED }; } audio_status_update_t; -TU_ATTR_WEAK bool tud_audio_int_ctr_done_cb(uint8_t rhport, uint16_t n_bytes_copied); +TU_ATTR_WEAK bool tud_audio_int_done_cb(uint8_t rhport, uint16_t n_bytes_copied); #endif // Invoked when audio set interface request received @@ -699,9 +699,9 @@ static inline tu_fifo_t* tud_audio_get_tx_support_ff(uint8_t ff_idx) #endif #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -static inline uint16_t tud_audio_int_ctr_write(uint8_t const* buffer, uint16_t len) +static inline uint16_t tud_audio_int_write(uint8_t const* buffer, uint16_t len) { - return tud_audio_int_ctr_n_write(0, buffer, len); + return tud_audio_int_n_write(0, buffer, len); } #endif From 0531027b57e9401d49afa13e70f5a6a9763a3b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20V=C3=A1zquez=20Blanco?= Date: Mon, 22 Jan 2024 23:19:43 +0100 Subject: [PATCH 05/20] usbd: log outbound xfer bytes in debug --- src/device/usbd.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/device/usbd.c b/src/device/usbd.c index 5c94ebcc5..28eb9aa6e 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1232,6 +1232,11 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t // TU_VERIFY(tud_ready()); TU_LOG_USBD(" Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes); +#if CFG_TUD_LOG_LEVEL >= 3 + if(tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { + TU_LOG_MEM(CFG_TUD_LOG_LEVEL, buffer, total_bytes, 2); + } +#endif // Attempt to transfer on a busy endpoint, sound like an race condition ! TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0); From eed37476612b6c2074cc3cdabbdef88c59822114 Mon Sep 17 00:00:00 2001 From: Camila Date: Mon, 11 Mar 2024 13:11:07 +0100 Subject: [PATCH 06/20] Changes required for SDK 3.2.0: - Define EP_ALLOCREQ - Define EP_FREEREQ - Define EP_ALLOCBUFFER - Define EP_FREEBUFFER Those were previously defined in spresense-exported-sdk, but now have been removed. --- src/portable/sony/cxd56/dcd_cxd56.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/portable/sony/cxd56/dcd_cxd56.c b/src/portable/sony/cxd56/dcd_cxd56.c index 6677891a5..9a939bc6c 100644 --- a/src/portable/sony/cxd56/dcd_cxd56.c +++ b/src/portable/sony/cxd56/dcd_cxd56.c @@ -39,6 +39,25 @@ #define CXD56_SETUP_QUEUE_DEPTH (4) #define CXD56_MAX_DATA_OUT_SIZE (64) +/* Allocate/free I/O requests. + * Should not be called from interrupt processing! + */ + +#define EP_ALLOCREQ(ep) (ep)->ops->allocreq(ep) +#define EP_FREEREQ(ep,req) (ep)->ops->freereq(ep,req) + +/* Allocate/free an I/O buffer. + * Should not be called from interrupt processing! + */ + +#ifdef CONFIG_USBDEV_DMA +# define EP_ALLOCBUFFER(ep,nb) (ep)->ops->allocbuffer(ep,nb) +# define EP_FREEBUFFER(ep,buf) (ep)->ops->freebuffer(ep,buf) +#else +# define EP_ALLOCBUFFER(ep,nb) kmm_malloc(nb) +# define EP_FREEBUFFER(ep,buf) kmm_free(buf) +#endif + OSAL_QUEUE_DEF(usbd_int_set, _setup_queue_def, CXD56_SETUP_QUEUE_DEPTH, struct usb_ctrlreq_s); struct usbdcd_driver_s From 307cce92c4f630ab988e6eb1e77685bc1e82d85a Mon Sep 17 00:00:00 2001 From: Camila Date: Tue, 26 Mar 2024 18:40:22 +0100 Subject: [PATCH 07/20] Improved SDK 3.2.0 compatibility - Used usbdev_allocreq for compatibility with SDK 3.2.0 - Wrapped previous code in #ifdef for legacy compatibility --- src/portable/sony/cxd56/dcd_cxd56.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/src/portable/sony/cxd56/dcd_cxd56.c b/src/portable/sony/cxd56/dcd_cxd56.c index 9a939bc6c..83cd0718c 100644 --- a/src/portable/sony/cxd56/dcd_cxd56.c +++ b/src/portable/sony/cxd56/dcd_cxd56.c @@ -39,25 +39,6 @@ #define CXD56_SETUP_QUEUE_DEPTH (4) #define CXD56_MAX_DATA_OUT_SIZE (64) -/* Allocate/free I/O requests. - * Should not be called from interrupt processing! - */ - -#define EP_ALLOCREQ(ep) (ep)->ops->allocreq(ep) -#define EP_FREEREQ(ep,req) (ep)->ops->freereq(ep,req) - -/* Allocate/free an I/O buffer. - * Should not be called from interrupt processing! - */ - -#ifdef CONFIG_USBDEV_DMA -# define EP_ALLOCBUFFER(ep,nb) (ep)->ops->allocbuffer(ep,nb) -# define EP_FREEBUFFER(ep,buf) (ep)->ops->freebuffer(ep,buf) -#else -# define EP_ALLOCBUFFER(ep,nb) kmm_malloc(nb) -# define EP_FREEBUFFER(ep,buf) kmm_free(buf) -#endif - OSAL_QUEUE_DEF(usbd_int_set, _setup_queue_def, CXD56_SETUP_QUEUE_DEPTH, struct usb_ctrlreq_s); struct usbdcd_driver_s @@ -121,6 +102,7 @@ static int _dcd_bind(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_ usbdev = dev; usbdcd_driver.ep[0] = dev->ep0; + #ifdef EP_ALLOCREQ usbdcd_driver.req[0] = EP_ALLOCREQ(usbdcd_driver.ep[0]); if (usbdcd_driver.req[0] != NULL) { @@ -132,6 +114,9 @@ static int _dcd_bind(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_ usbdcd_driver.req[0] = NULL; } } + #else + usbdcd_driver.req[0] = usbdev_allocreq(usbdcd_driver.ep[0],64); + #endif usbdcd_driver.req[0]->callback = usbdcd_ep0incomplete; @@ -314,12 +299,18 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc) } usbdcd_driver.req[epnum] = NULL; + + #ifdef EP_ALLOCREQ usbdcd_driver.req[epnum] = EP_ALLOCREQ(usbdcd_driver.ep[epnum]); if (usbdcd_driver.req[epnum] != NULL) { usbdcd_driver.req[epnum]->len = ep_mps; } else + #else + usbdcd_driver.req[epnum] = usbdev_allocreq(usbdcd_driver.ep[epnum], ep_mps); + if(usbdcd_driver.req[epnum] == NULL) + #endif { return false; } From 05f9cab1916195ceb55d73efa56d226b2451f5d1 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Mon, 1 Apr 2024 19:48:45 +0200 Subject: [PATCH 08/20] UAC2: refactor interrupt endpoint support. --- src/class/audio/audio.h | 25 ++++++++ src/class/audio/audio_device.c | 114 ++++++++++++++------------------- src/class/audio/audio_device.h | 51 ++------------- src/device/usbd.h | 11 +++- 4 files changed, 88 insertions(+), 113 deletions(-) diff --git a/src/class/audio/audio.h b/src/class/audio/audio.h index 70d431282..d6f3e22e2 100644 --- a/src/class/audio/audio.h +++ b/src/class/audio/audio.h @@ -924,6 +924,31 @@ typedef struct TU_ATTR_PACKED { } subrange[numSubRanges]; \ } +// 6.1 Interrupt Data Message Format +typedef struct TU_ATTR_PACKED +{ + uint8_t bInfo; + uint8_t bAttribute; + union + { + uint16_t wValue; + struct + { + uint8_t wValue_cn_or_mcn; + uint8_t wValue_cs; + }; + }; + union + { + uint16_t wIndex; + struct + { + uint8_t wIndex_ep_or_int; + uint8_t wIndex_entity_id; + }; + }; +} audio_interrupt_data_t; + /** @} */ #ifdef __cplusplus diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index f4e7de0c8..93e995c56 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -301,8 +301,8 @@ typedef struct #endif -#if CFG_TUD_AUDIO_INT_EPSIZE_IN - uint8_t ep_int; // Audio control interrupt EP. +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP + uint8_t ep_int; // Audio control interrupt EP. #endif /*------------- From this point, data is not cleared by bus reset -------------*/ @@ -358,8 +358,8 @@ typedef struct #endif // Audio control interrupt buffer - no FIFO - 6 Bytes according to UAC 2 specification (p. 74) -#if CFG_TUD_AUDIO_INT_EPSIZE_IN - CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[CFG_TUD_AUDIO_INT_EP_IN_SW_BUFFER_SIZE]; +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP + CFG_TUSB_MEM_ALIGN uint8_t ep_int_buf[6]; #endif // Decoding parameters - parameters are set when alternate AS interface is set by host @@ -826,26 +826,29 @@ tu_fifo_t* tud_audio_n_get_tx_support_ff(uint8_t func_id, uint8_t ff_idx) #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP - // 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 -uint16_t tud_audio_int_n_write(uint8_t func_id, uint8_t const* buffer, uint16_t len) +bool tud_audio_int_n_write(uint8_t func_id, const audio_interrupt_data_t * data) { - TU_VERIFY(_audiod_fct[func_id].ep_int != 0); - TU_VERIFY(func_id < CFG_TUD_AUDIO && _audiod_fct[func_id].p_desc != NULL); + TU_VERIFY(_audiod_fct[func_id].ep_int != 0); + // We write directly into the EP's buffer - abort if previous transfer not complete - TU_VERIFY(!usbd_edpt_busy(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int)); + TU_VERIFY(usbd_edpt_claim(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int)); // Check length - TU_VERIFY(tu_memcpy_s(_audiod_fct[func_id].ep_int_buf, CFG_TUD_AUDIO_INT_EP_IN_SW_BUFFER_SIZE, buffer, len)==0); - - // Schedule transmit - TU_VERIFY(usbd_edpt_xfer(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int, _audiod_fct[func_id].ep_int_buf, len)); + 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) + { + // Schedule transmit + 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); + } else + { + // Release endpoint since we don't make any transfer + usbd_edpt_release(_audiod_fct[func_id].rhport, _audiod_fct[func_id].ep_int); + } return true; } - #endif // 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. @@ -1091,48 +1094,6 @@ static inline bool audiod_fb_send(uint8_t rhport, audiod_function_t *audio) } #endif -#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -static bool set_int_number(audiod_function_t *audio) -{ - - uint8_t const *p_desc = audio->p_desc; - // Get pointer at end - uint8_t const *p_desc_end = audio->p_desc + audio->desc_length - TUD_AUDIO_DESC_IAD_LEN; - - - bool found = false; - while (!found && p_desc < p_desc_end) - { - // For each interface/alternate - if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) - { - uint8_t foundEPs = 0, nEps = ((tusb_desc_interface_t const * )p_desc)->bNumEndpoints; - while (!found && foundEPs < nEps && p_desc < p_desc_end) - { - // For each endpoint - if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) - { - tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc; - uint8_t const ep_addr = desc_ep->bEndpointAddress; - // If endpoint is input-direction and interrupt-type - if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.xfer == 0x03) // Check if usage is interrupt EP - { - // Store endpoint number and open endpoint - audio->ep_int = ep_addr; - TU_ASSERT(usbd_edpt_open(audio->rhport, desc_ep)); - found = true; - } - foundEPs += 1; - } - p_desc = tu_desc_next(p_desc); - } - } - p_desc = tu_desc_next(p_desc); - } - return found; -} -#endif - //--------------------------------------------------------------------+ // USBD Driver API //--------------------------------------------------------------------+ @@ -1492,10 +1453,11 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin // Verify version is correct - this check can be omitted TU_VERIFY(itf_desc->bInterfaceProtocol == AUDIO_INT_PROTOCOL_CODE_V2); - // Verify interrupt control EP is enabled if demanded by descriptor - this should be best some static check however - this check can be omitted - if (itf_desc->bNumEndpoints == 1) // 0 or 1 EPs are allowed + // Verify interrupt control EP is enabled if demanded by descriptor + TU_ASSERT(itf_desc->bNumEndpoints <= 1); // 0 or 1 EPs are allowed + if (itf_desc->bNumEndpoints == 1) { - TU_VERIFY(CFG_TUD_AUDIO_INT_EPSIZE_IN > 0); + TU_ASSERT(CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP); } // Alternate setting MUST be zero - this check can be omitted @@ -1639,6 +1601,31 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin } #endif // CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP + { + uint8_t const *p_desc = _audiod_fct[i].p_desc; + uint8_t const *p_desc_end = p_desc + _audiod_fct[i].desc_length - TUD_AUDIO_DESC_IAD_LEN; + // Condition modified from p_desc < p_desc_end to prevent gcc>=12 strict-overflow warning + while (p_desc_end - p_desc > 0) + { + // For each endpoint + if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) + { + tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const *) p_desc; + uint8_t const ep_addr = desc_ep->bEndpointAddress; + // If endpoint is input-direction and interrupt-type + if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN && desc_ep->bmAttributes.xfer == TUSB_XFER_INTERRUPT) + { + // Store endpoint number and open endpoint + _audiod_fct[i].ep_int = ep_addr; + TU_ASSERT(usbd_edpt_open(_audiod_fct[i].rhport, desc_ep)); + } + } + p_desc = tu_desc_next(p_desc); + } + } +#endif + break; } } @@ -1649,10 +1636,6 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin // This is all we need so far - the EPs are setup by a later set_interface request (as per UAC2 specification) 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 -#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP - TU_ASSERT(set_int_number(&_audiod_fct[i])); -#endif - return drv_len; } @@ -2169,7 +2152,7 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 { audiod_function_t* audio = &_audiod_fct[func_id]; -#if CFG_TUD_AUDIO_INT_EPSIZE_IN +#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP // Data transmission of control interrupt finished if (audio->ep_int == ep_addr) @@ -2181,7 +2164,8 @@ bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint3 // I assume here, that things above are handled by PHY // All transmission is done - what remains to do is to inform job was completed - if (tud_audio_int_done_cb) TU_VERIFY(tud_audio_int_done_cb(rhport, (uint16_t) xferred_bytes)); + if (tud_audio_int_done_cb) tud_audio_int_done_cb(rhport); + return true; } #endif diff --git a/src/class/audio/audio_device.h b/src/class/audio/audio_device.h index 70bbd7ff6..040a760d6 100644 --- a/src/class/audio/audio_device.h +++ b/src/class/audio/audio_device.h @@ -198,21 +198,7 @@ // Enable/disable interrupt EP (required for notifying host of control changes) #ifndef CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -#define CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP 0 // Feedback - 0 or 1 -#endif - -// Audio interrupt control EP size - disabled if 0 -#ifndef CFG_TUD_AUDIO_INT_EPSIZE_IN -// Audio interrupt control - if required - 6 Bytes according to UAC 2 specification (p. 74) -#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -#define CFG_TUD_AUDIO_INT_EPSIZE_IN 6 -#else -#define CFG_TUD_AUDIO_INT_EPSIZE_IN 0 -#endif -#endif - -#ifndef CFG_TUD_AUDIO_INT_EP_IN_SW_BUFFER_SIZE -#define CFG_TUD_AUDIO_INT_EP_IN_SW_BUFFER_SIZE 6 // Buffer size of audio control interrupt EP - 6 Bytes according to UAC 2 specification (p. 74) +#define CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP 0 // Feedback - 0 or 1 #endif // Use software encoding/decoding @@ -404,7 +390,7 @@ tu_fifo_t* tud_audio_n_get_tx_support_ff (uint8_t func_id, uint8_t ff_i #endif #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -uint16_t tud_audio_int_n_write (uint8_t func_id, uint8_t const* buffer, uint16_t len); +bool tud_audio_int_n_write (uint8_t func_id, const audio_interrupt_data_t * data); #endif @@ -448,7 +434,7 @@ static inline tu_fifo_t* tud_audio_get_tx_support_ff (uint8_t ff_idx); // INT CTR API #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -static inline uint16_t tud_audio_int_write (uint8_t const* buffer, uint16_t len); +static inline bool tud_audio_int_write (const audio_interrupt_data_t * data); #endif // Buffer control EP data and schedule a transmit @@ -548,32 +534,7 @@ TU_ATTR_WEAK TU_ATTR_FAST_FUNC void tud_audio_feedback_interval_isr(uint8_t func #endif // CFG_TUD_AUDIO_ENABLE_EP_OUT && CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -// UAC2 §6.1 "interrupt data message" -typedef struct TU_ATTR_PACKED -{ - uint8_t bInfo; - uint8_t bAttribute; - union TU_ATTR_PACKED - { - uint16_t wValue; - struct TU_ATTR_PACKED - { - uint8_t wValue_cn_or_mcn; - uint8_t wValue_cs; - }; - }; - union TU_ATTR_PACKED - { - uint16_t wIndex; - struct TU_ATTR_PACKED - { - uint8_t wIndex_ep_or_int; - uint8_t wIndex_entity_id; - }; - }; -} audio_status_update_t; - -TU_ATTR_WEAK bool tud_audio_int_done_cb(uint8_t rhport, uint16_t n_bytes_copied); +TU_ATTR_WEAK void tud_audio_int_done_cb(uint8_t rhport); #endif // Invoked when audio set interface request received @@ -705,9 +666,9 @@ static inline tu_fifo_t* tud_audio_get_tx_support_ff(uint8_t ff_idx) #endif #if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP -static inline uint16_t tud_audio_int_write(uint8_t const* buffer, uint16_t len) +static inline bool tud_audio_int_write(const audio_interrupt_data_t * data) { - return tud_audio_int_n_write(0, buffer, len); + return tud_audio_int_n_write(0, data); } #endif diff --git a/src/device/usbd.h b/src/device/usbd.h index cf500143a..2e3987b99 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -393,6 +393,11 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb // For more channels, add definitions here +/* Standard AC Interrupt Endpoint Descriptor(4.8.2.1) */ +#define TUD_AUDIO_DESC_STD_AC_INT_EP_LEN 7 +#define TUD_AUDIO_DESC_STD_AC_INT_EP(_ep, _interval) \ + TUD_AUDIO_DESC_STD_AC_INT_EP_LEN, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_INTERRUPT, U16_TO_U8S_LE(6), _interval + /* Standard AS Interface Descriptor(4.9.1) */ #define TUD_AUDIO_DESC_STD_AS_INT_LEN 9 #define TUD_AUDIO_DESC_STD_AS_INT(_itfnum, _altset, _nEPs, _stridx) \ @@ -468,7 +473,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) @@ -517,7 +522,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) @@ -565,7 +570,7 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\ /* Standard AS Isochronous Feedback Endpoint Descriptor(4.10.2.1) */\ From 7ca988018ee057a66ab7d5635069fbc695182d2d Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Mon, 1 Apr 2024 19:50:52 +0200 Subject: [PATCH 09/20] UAC2: fix mounted condition. --- src/class/audio/audio_device.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c index 93e995c56..9a361419b 100644 --- a/src/class/audio/audio_device.c +++ b/src/class/audio/audio_device.c @@ -305,6 +305,8 @@ typedef struct uint8_t ep_int; // Audio control interrupt EP. #endif + bool mounted; // Device opened + /*------------- From this point, data is not cleared by bus reset -------------*/ uint16_t desc_length; // Length of audio function descriptor @@ -486,23 +488,7 @@ bool tud_audio_n_mounted(uint8_t func_id) TU_VERIFY(func_id < CFG_TUD_AUDIO); audiod_function_t* audio = &_audiod_fct[func_id]; -#if CFG_TUD_AUDIO_ENABLE_EP_OUT - if (audio->ep_out == 0) return false; -#endif - -#if CFG_TUD_AUDIO_ENABLE_EP_IN - if (audio->ep_in == 0) return false; -#endif - -#if CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP - if (audio->ep_int == 0) return false; -#endif - -#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP - if (audio->ep_fb == 0) return false; -#endif - - return true; + return audio->mounted; } //--------------------------------------------------------------------+ @@ -1626,6 +1612,7 @@ uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin } #endif + _audiod_fct[i].mounted = true; break; } } From 6cf27986b67996290c12f102d62c1a38e66e08d6 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Mon, 1 Apr 2024 19:55:51 +0200 Subject: [PATCH 10/20] UAC2: add interrupt volume control to uac2_headset example. --- examples/device/uac2_headset/src/main.c | 41 +++++++++++++++++++ .../device/uac2_headset/src/tusb_config.h | 3 ++ .../device/uac2_headset/src/usb_descriptors.c | 7 +++- .../device/uac2_headset/src/usb_descriptors.h | 15 ++++--- 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/examples/device/uac2_headset/src/main.c b/examples/device/uac2_headset/src/main.c index 0ab72b2f3..35b7ac94b 100644 --- a/examples/device/uac2_headset/src/main.c +++ b/examples/device/uac2_headset/src/main.c @@ -96,6 +96,7 @@ uint8_t current_resolution; void led_blinking_task(void); void audio_task(void); +void audio_control_task(void); /*------------- MAIN -------------*/ int main(void) @@ -115,6 +116,7 @@ int main(void) { tud_task(); // TinyUSB device task audio_task(); + audio_control_task(); led_blinking_task(); } } @@ -428,6 +430,45 @@ void audio_task(void) } } +void audio_control_task(void) +{ + // Press on-board button to control volume + // Open host volume control, volume should switch between 10% and 100% + + // Poll every 50ms + const uint32_t interval_ms = 50; + static uint32_t start_ms = 0; + static uint32_t btn_prev = 0; + + if ( board_millis() - start_ms < interval_ms) return; // not enough time + start_ms += interval_ms; + + uint32_t btn = board_button_read(); + + if (!btn_prev && btn) + { + // Adjust volume between 0dB (100%) and -30dB (10%) + for (int i = 0; i < CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX + 1; i++) + { + volume[i] = volume[i] == 0 ? -VOLUME_CTRL_30_DB : 0; + } + + // 6.1 Interrupt Data Message + const audio_interrupt_data_t data = { + .bInfo = 0, // Class-specific interrupt, originated from an interface + .bAttribute = AUDIO_CS_REQ_CUR, // Caused by current settings + .wValue_cn_or_mcn = 0, // CH0: master volume + .wValue_cs = AUDIO_FU_CTRL_VOLUME, // Volume change + .wIndex_ep_or_int = 0, // From the interface itself + .wIndex_entity_id = UAC2_ENTITY_SPK_FEATURE_UNIT, // From feature unit + }; + + tud_audio_int_write(&data); + } + + btn_prev = btn; +} + //--------------------------------------------------------------------+ // BLINKING TASK //--------------------------------------------------------------------+ diff --git a/examples/device/uac2_headset/src/tusb_config.h b/examples/device/uac2_headset/src/tusb_config.h index b770483dc..4b08fa676 100644 --- a/examples/device/uac2_headset/src/tusb_config.h +++ b/examples/device/uac2_headset/src/tusb_config.h @@ -105,6 +105,9 @@ extern "C" { // AUDIO CLASS DRIVER CONFIGURATION //-------------------------------------------------------------------- +// Allow volume controlled by on-baord button +#define CFG_TUD_AUDIO_ENABLE_INTERRUPT_EP 1 + #define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_HEADSET_STEREO_DESC_LEN // How many formats are used, need to adjust USB descriptor if changed diff --git a/examples/device/uac2_headset/src/usb_descriptors.c b/examples/device/uac2_headset/src/usb_descriptors.c index 6d1e6a23f..ff4dc2acc 100644 --- a/examples/device/uac2_headset/src/usb_descriptors.c +++ b/examples/device/uac2_headset/src/usb_descriptors.c @@ -82,27 +82,32 @@ uint8_t const * tud_descriptor_device_cb(void) // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ... #define EPNUM_AUDIO_IN 0x03 #define EPNUM_AUDIO_OUT 0x03 + #define EPNUM_AUDIO_INT 0x01 #elif CFG_TUSB_MCU == OPT_MCU_NRF5X // ISO endpoints for NRF5x are fixed to 0x08 (0x88) #define EPNUM_AUDIO_IN 0x08 #define EPNUM_AUDIO_OUT 0x08 + #define EPNUM_AUDIO_INT 0x01 #elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X // SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_AUDIO_IN 0x01 #define EPNUM_AUDIO_OUT 0x02 + #define EPNUM_AUDIO_INT 0x03 #elif CFG_TUSB_MCU == OPT_MCU_FT90X || CFG_TUSB_MCU == OPT_MCU_FT93X // FT9XX doesn't support a same endpoint number with different direction IN and OUT // e.g EP1 OUT & EP1 IN cannot exist together #define EPNUM_AUDIO_IN 0x01 #define EPNUM_AUDIO_OUT 0x02 + #define EPNUM_AUDIO_INT 0x03 #else #define EPNUM_AUDIO_IN 0x01 #define EPNUM_AUDIO_OUT 0x01 + #define EPNUM_AUDIO_INT 0x02 #endif uint8_t const desc_configuration[] = @@ -111,7 +116,7 @@ uint8_t const desc_configuration[] = TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100), // Interface number, string index, EP Out & EP In address, EP size - TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(2, EPNUM_AUDIO_OUT, EPNUM_AUDIO_IN | 0x80) + TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(2, EPNUM_AUDIO_OUT, EPNUM_AUDIO_IN | 0x80, EPNUM_AUDIO_INT | 0x80) }; // Invoked when received GET CONFIGURATION DESCRIPTOR diff --git a/examples/device/uac2_headset/src/usb_descriptors.h b/examples/device/uac2_headset/src/usb_descriptors.h index d7e170162..da0da83e8 100644 --- a/examples/device/uac2_headset/src/usb_descriptors.h +++ b/examples/device/uac2_headset/src/usb_descriptors.h @@ -55,6 +55,7 @@ enum + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ + TUD_AUDIO_DESC_INPUT_TERM_LEN\ + TUD_AUDIO_DESC_OUTPUT_TERM_LEN\ + + TUD_AUDIO_DESC_STD_AC_INT_EP_LEN\ /* Interface 1, Alternate 0 */\ + TUD_AUDIO_DESC_STD_AS_INT_LEN\ /* Interface 1, Alternate 1 */\ @@ -84,11 +85,11 @@ enum + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN\ + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) -#define TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(_stridx, _epout, _epin) \ +#define TUD_AUDIO_HEADSET_STEREO_DESCRIPTOR(_stridx, _epout, _epin, _epint) \ /* Standard Interface Association Descriptor (IAD) */\ TUD_AUDIO_DESC_IAD(/*_firstitf*/ ITF_NUM_AUDIO_CONTROL, /*_nitfs*/ ITF_NUM_TOTAL, /*_stridx*/ 0x00),\ /* Standard AC Interface Descriptor(4.7.1) */\ - TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_nEPs*/ 0x00, /*_stridx*/ _stridx),\ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ ITF_NUM_AUDIO_CONTROL, /*_nEPs*/ 0x01, /*_stridx*/ _stridx),\ /* Class-Specific AC Interface Header Descriptor(4.7.2) */\ TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_HEADSET, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+TUD_AUDIO_DESC_OUTPUT_TERM_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS),\ /* Clock Source Descriptor(4.7.2.1) */\ @@ -103,6 +104,8 @@ enum TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00),\ /* Output Terminal Descriptor(4.7.2.5) */\ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ UAC2_ENTITY_MIC_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_srcid*/ UAC2_ENTITY_MIC_INPUT_TERMINAL, /*_clkid*/ UAC2_ENTITY_CLOCK, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00),\ + /* Standard AC Interrupt Endpoint Descriptor(4.8.2.1) */\ + TUD_AUDIO_DESC_STD_AC_INT_EP(/*_ep*/ _epint, /*_interval*/ 0x01), \ /* Standard AS Interface Descriptor(4.9.1) */\ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */\ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)(ITF_NUM_AUDIO_STREAMING_SPK), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x05),\ @@ -114,7 +117,7 @@ enum /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ADAPTIVE | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001),\ /* Interface 1, Alternate 2 - alternate interface for data streaming */\ @@ -124,7 +127,7 @@ enum /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_RX),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ADAPTIVE | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ADAPTIVE | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_RX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX), /*_interval*/ 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_MILLISEC, /*_lockdelay*/ 0x0001),\ /* Standard AS Interface Descriptor(4.9.1) */\ @@ -138,7 +141,7 @@ enum /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_TX),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000),\ /* Interface 2, Alternate 2 - alternate interface for data streaming */\ @@ -148,7 +151,7 @@ enum /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */\ TUD_AUDIO_DESC_TYPE_I_FORMAT(CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_TX),\ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */\ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS | TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ TUD_AUDIO_EP_SIZE(CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE, CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX, CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX), /*_interval*/ 0x01),\ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */\ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) From 8936096846f3b4e0f6d2193b5f8be74a94d003f9 Mon Sep 17 00:00:00 2001 From: Ha Thach Date: Tue, 2 Apr 2024 19:56:39 +0700 Subject: [PATCH 11/20] max3421 limit max nak --- src/portable/analog/max3421/hcd_max3421.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index 61a7e2703..9e363506c 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -454,7 +454,7 @@ bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { TU_VERIFY(cfg_id == TUH_CFGID_MAX3421); tuh_configure_param_t const* cfg = (tuh_configure_param_t const*) cfg_param; - _max_nak = cfg->max3421.max_nak; + _max_nak = tu_max8(cfg->max3421.max_nak, EP_STATE_ATTEMPT_MAX-EP_STATE_ATTEMPT_1); return true; } From 9fb1fb90447fbbfdc3ca33c39cbd75bb807a7907 Mon Sep 17 00:00:00 2001 From: Ha Thach Date: Tue, 2 Apr 2024 20:39:06 +0700 Subject: [PATCH 12/20] correct max nak --- src/portable/analog/max3421/hcd_max3421.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index 9e363506c..fa6d45d3e 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -454,7 +454,7 @@ bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { TU_VERIFY(cfg_id == TUH_CFGID_MAX3421); tuh_configure_param_t const* cfg = (tuh_configure_param_t const*) cfg_param; - _max_nak = tu_max8(cfg->max3421.max_nak, EP_STATE_ATTEMPT_MAX-EP_STATE_ATTEMPT_1); + _max_nak = tu_min8(cfg->max3421.max_nak, EP_STATE_ATTEMPT_MAX-EP_STATE_ATTEMPT_1); return true; } From f8dc3b97beae611c0a68ab50b960dd1922a66f5d Mon Sep 17 00:00:00 2001 From: Ha Thach Date: Tue, 2 Apr 2024 22:47:50 +0700 Subject: [PATCH 13/20] check cfg_param pointer --- src/portable/analog/max3421/hcd_max3421.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index fa6d45d3e..242c65501 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -451,7 +451,7 @@ static max3421_ep_t * find_next_pending_ep(max3421_ep_t * cur_ep) { // optional hcd configuration, called by tuh_configure() bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { (void) rhport; - TU_VERIFY(cfg_id == TUH_CFGID_MAX3421); + TU_VERIFY(cfg_id == TUH_CFGID_MAX3421 && cfg_param != NULL); tuh_configure_param_t const* cfg = (tuh_configure_param_t const*) cfg_param; _max_nak = tu_min8(cfg->max3421.max_nak, EP_STATE_ATTEMPT_MAX-EP_STATE_ATTEMPT_1); From 252e630433ff62f9b3ee010f576b5e42e6d7d1e2 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 3 Apr 2024 13:05:53 +0700 Subject: [PATCH 14/20] try catch labeler rest api --- .github/workflows/labeler.yml | 38 ++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 4733c6f06..947b08ca2 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -28,29 +28,31 @@ jobs: issueOrPrNumber = context.payload.pull_request.number; } - // Check for Adafruit membership - const adafruitResponse = await github.rest.orgs.checkMembershipForUser({ - org: 'adafruit', - username: username - }); - - if (adafruitResponse.status === 204) { - console.log('Adafruit Member'); - label = 'Prio Urgent'; - } else { - // Check if the user is a contributor - const collaboratorResponse = await github.rest.repos.checkCollaborator({ - owner: context.repo.owner, - repo: context.repo.repo, + try { + // Check for Adafruit membership + const adafruitResponse = await github.rest.orgs.checkMembershipForUser({ + org: 'adafruit', username: username }); - if (collaboratorResponse.status === 204) { - console.log('Contributor'); - label = 'Prio Higher'; + if (adafruitResponse.status === 204) { + console.log('Adafruit Member'); + label = 'Prio Urgent'; } else { - console.log('Not a contributor or Adafruit member'); + // If not a Adafruit member, check if the user is a contributor + const collaboratorResponse = await github.rest.repos.checkCollaborator({ + owner: context.repo.owner, + repo: context.repo.repo, + username: username + }); + + if (collaboratorResponse.status === 204) { + console.log('Contributor'); + label = 'Prio Higher'; + } } + } catch (error) { + console.log(`Error processing user ${username}: ${error.message}`); } if (label !== '') { From 11722cc53393dff71a97b45e63309cb98c463b4b Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 3 Apr 2024 23:08:15 +0700 Subject: [PATCH 15/20] add note for sdk v2 and v3, also add check if allocreq failed --- src/portable/sony/cxd56/dcd_cxd56.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/portable/sony/cxd56/dcd_cxd56.c b/src/portable/sony/cxd56/dcd_cxd56.c index 83cd0718c..41814370e 100644 --- a/src/portable/sony/cxd56/dcd_cxd56.c +++ b/src/portable/sony/cxd56/dcd_cxd56.c @@ -103,19 +103,23 @@ static int _dcd_bind(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_ usbdcd_driver.ep[0] = dev->ep0; #ifdef EP_ALLOCREQ + // SDK v2 usbdcd_driver.req[0] = EP_ALLOCREQ(usbdcd_driver.ep[0]); - if (usbdcd_driver.req[0] != NULL) - { + if (usbdcd_driver.req[0] != NULL) { usbdcd_driver.req[0]->len = 64; usbdcd_driver.req[0]->buf = EP_ALLOCBUFFER(usbdcd_driver.ep[0], 64); - if (!usbdcd_driver.req[0]->buf) - { + if (!usbdcd_driver.req[0]->buf) { EP_FREEREQ(usbdcd_driver.ep[0], usbdcd_driver.req[0]); usbdcd_driver.req[0] = NULL; + return ENOMEM; } } #else - usbdcd_driver.req[0] = usbdev_allocreq(usbdcd_driver.ep[0],64); + // SDK v3 + usbdcd_driver.req[0] = usbdev_allocreq(usbdcd_driver.ep[0], 64); + if (usbdcd_driver.req[0] == NULL) { + return ENOMEM; + } #endif usbdcd_driver.req[0]->callback = usbdcd_ep0incomplete; @@ -301,17 +305,17 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc) usbdcd_driver.req[epnum] = NULL; #ifdef EP_ALLOCREQ + // sdk v2 usbdcd_driver.req[epnum] = EP_ALLOCREQ(usbdcd_driver.ep[epnum]); - if (usbdcd_driver.req[epnum] != NULL) - { + if (usbdcd_driver.req[epnum] != NULL) { usbdcd_driver.req[epnum]->len = ep_mps; } - else #else + // sdk v3 usbdcd_driver.req[epnum] = usbdev_allocreq(usbdcd_driver.ep[epnum], ep_mps); - if(usbdcd_driver.req[epnum] == NULL) #endif - { + + if(usbdcd_driver.req[epnum] == NULL) { return false; } From 7910cc298187327e05c43770b58eac528a4fecfa Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 4 Apr 2024 10:55:14 +0700 Subject: [PATCH 16/20] fix build with rp2040 + max3421 - forward MAX3421_HOST=1 from makefile to cmake - add feather_rp2040_max3421 board to run with ci for rp2040 + max3421 --- examples/build_system/make/make.mk | 1 + .../boards/feather_rp2040_max3421/board.cmake | 4 ++++ src/portable/analog/max3421/hcd_max3421.c | 13 ++++++------- 3 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 hw/bsp/rp2040/boards/feather_rp2040_max3421/board.cmake diff --git a/examples/build_system/make/make.mk b/examples/build_system/make/make.mk index e1113aa52..772befca4 100644 --- a/examples/build_system/make/make.mk +++ b/examples/build_system/make/make.mk @@ -113,6 +113,7 @@ CFLAGS += -DBOARD_$(BOARD_UPPER) ifeq (${MAX3421_HOST},1) SRC_C += src/portable/analog/max3421/hcd_max3421.c CFLAGS += -DCFG_TUH_MAX3421=1 + CMAKE_DEFSYM += -DMAX3421_HOST=1 endif # Log level is mapped to TUSB DEBUG option diff --git a/hw/bsp/rp2040/boards/feather_rp2040_max3421/board.cmake b/hw/bsp/rp2040/boards/feather_rp2040_max3421/board.cmake new file mode 100644 index 000000000..b8e5890f3 --- /dev/null +++ b/hw/bsp/rp2040/boards/feather_rp2040_max3421/board.cmake @@ -0,0 +1,4 @@ +set(PICO_BOARD adafruit_feather_rp2040) + +# Enable MAX3421E USB Host +set(MAX3421_HOST 1) diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index 242c65501..76c1a150b 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -676,19 +676,18 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf max3421_ep_t* ep = find_opened_ep(daddr, ep_num, ep_dir); TU_VERIFY(ep); - // control transfer can switch direction - ep->hxfr_bm.is_out = ep_dir ? 0u : 1u; + if (ep_num == 0) { + // control transfer can switch direction + ep->hxfr_bm.is_out = ep_dir ? 0 : 1; + ep->hxfr_bm.is_setup = 0; + ep->data_toggle = 1; + } ep->buf = buffer; ep->total_len = buflen; ep->xferred_len = 0; ep->state = EP_STATE_ATTEMPT_1; - if (ep_num == 0) { - ep->hxfr_bm.is_setup = 0; - ep->data_toggle = 1; - } - // carry out transfer if not busy if (!atomic_flag_test_and_set(&_hcd_data.busy)) { xact_generic(rhport, ep, true, false); From 93fb3b00debc613f631cb6ec848bfcb9231a325c Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 4 Apr 2024 12:51:07 +0700 Subject: [PATCH 17/20] fix build with gcc 11 --- src/portable/analog/max3421/hcd_max3421.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c index 76c1a150b..059f674cd 100644 --- a/src/portable/analog/max3421/hcd_max3421.c +++ b/src/portable/analog/max3421/hcd_max3421.c @@ -654,7 +654,7 @@ static void xact_generic(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool // status if (ep->buf == NULL || ep->total_len == 0) { - uint8_t const hxfr = HXFR_HS | (ep->hxfr_bm.is_out ? HXFR_OUT_NIN : 0); + uint8_t const hxfr = (uint8_t) (HXFR_HS | (ep->hxfr & HXFR_OUT_NIN)); peraddr_write(rhport, ep->daddr, in_isr); hxfr_write(rhport, hxfr, in_isr); return; From f603c4a330f55158da7782671158fedabb62c29c Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 4 Apr 2024 13:01:16 +0700 Subject: [PATCH 18/20] skip cdc_msc_hid_freertos example for rp2040 --- examples/host/cdc_msc_hid_freertos/skip.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 examples/host/cdc_msc_hid_freertos/skip.txt diff --git a/examples/host/cdc_msc_hid_freertos/skip.txt b/examples/host/cdc_msc_hid_freertos/skip.txt new file mode 100644 index 000000000..2ba4438fd --- /dev/null +++ b/examples/host/cdc_msc_hid_freertos/skip.txt @@ -0,0 +1 @@ +mcu:RP2040 From ebe692350047b7b2a5b46de7894352934c4200aa Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 4 Apr 2024 14:10:48 +0700 Subject: [PATCH 19/20] update build script to allow skip.txt and only.txt both exist --- hw/bsp/family_support.cmake | 45 ++++++++++++++----------------------- tools/build_utils.py | 21 ++++++++--------- 2 files changed, 28 insertions(+), 38 deletions(-) diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake index d84077ed8..4ccd6e4f2 100644 --- a/hw/bsp/family_support.cmake +++ b/hw/bsp/family_support.cmake @@ -79,17 +79,27 @@ set(WARNING_FLAGS_IAR "") function(family_filter RESULT DIR) get_filename_component(DIR ${DIR} ABSOLUTE BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) - if (EXISTS "${DIR}/only.txt") - file(READ "${DIR}/only.txt" ONLYS) - # Replace newlines with semicolon so that it is treated as a list by CMake - string(REPLACE "\n" ";" ONLYS_LINES ${ONLYS}) + if (EXISTS "${DIR}/skip.txt") + file(STRINGS "${DIR}/skip.txt" SKIPS_LINES) + foreach(MCU IN LISTS FAMILY_MCUS) + # For each line in only.txt + foreach(_line ${SKIPS_LINES}) + # If mcu:xxx exists for this mcu then skip + if (${_line} STREQUAL "mcu:${MCU}" OR ${_line} STREQUAL "board:${BOARD}" OR ${_line} STREQUAL "family:${FAMILY}") + set(${RESULT} 0 PARENT_SCOPE) + return() + endif() + endforeach() + endforeach() + endif () - # For each mcu + if (EXISTS "${DIR}/only.txt") + file(STRINGS "${DIR}/only.txt" ONLYS_LINES) foreach(MCU IN LISTS FAMILY_MCUS) # For each line in only.txt foreach(_line ${ONLYS_LINES}) # If mcu:xxx exists for this mcu or board:xxx then include - if (${_line} STREQUAL "mcu:${MCU}" OR ${_line} STREQUAL "board:${BOARD}") + if (${_line} STREQUAL "mcu:${MCU}" OR ${_line} STREQUAL "board:${BOARD}" OR ${_line} STREQUAL "family:${FAMILY}") set(${RESULT} 1 PARENT_SCOPE) return() endif() @@ -98,29 +108,8 @@ function(family_filter RESULT DIR) # Didn't find it in only file so don't build set(${RESULT} 0 PARENT_SCOPE) - - elseif (EXISTS "${DIR}/skip.txt") - file(READ "${DIR}/skip.txt" SKIPS) - # Replace newlines with semicolon so that it is treated as a list by CMake - string(REPLACE "\n" ";" SKIPS_LINES ${SKIPS}) - - # For each mcu - foreach(MCU IN LISTS FAMILY_MCUS) - # For each line in only.txt - foreach(_line ${SKIPS_LINES}) - # If mcu:xxx exists for this mcu then skip - if (${_line} STREQUAL "mcu:${MCU}") - set(${RESULT} 0 PARENT_SCOPE) - return() - endif() - endforeach() - endforeach() - - # Didn't find in skip file so build - set(${RESULT} 1 PARENT_SCOPE) else() - - # Didn't find skip or only file so build + # only.txt not exist so build set(${RESULT} 1 PARENT_SCOPE) endif() endfunction() diff --git a/tools/build_utils.py b/tools/build_utils.py index 5d735bc17..b66b64b97 100644 --- a/tools/build_utils.py +++ b/tools/build_utils.py @@ -64,18 +64,19 @@ def skip_example(example, board): skip_file = ex_dir / "skip.txt" only_file = ex_dir / "only.txt" - if skip_file.exists() and only_file.exists(): - raise RuntimeError("Only have a skip or only file. Not both.") - elif skip_file.exists(): + if skip_file.exists(): skips = skip_file.read_text().split() - return ("mcu:" + mcu in skips or - "board:" + board in skips or - "family:" + family in skips) - elif only_file.exists(): + if ("mcu:" + mcu in skips or + "board:" + board in skips or + "family:" + family in skips): + return True + + if only_file.exists(): onlys = only_file.read_text().split() - return not ("mcu:" + mcu in onlys or - "board:" + board in onlys or - "family:" + family in onlys) + if not ("mcu:" + mcu in onlys or + "board:" + board in onlys or + "family:" + family in onlys): + return True return False From 802ad885ab041ecf855c1c08d97dfc45359fd1b0 Mon Sep 17 00:00:00 2001 From: Ha Thach Date: Thu, 4 Apr 2024 17:15:38 +0700 Subject: [PATCH 20/20] minor update --- src/device/usbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/device/usbd.c b/src/device/usbd.c index 28eb9aa6e..72fde1b97 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1233,7 +1233,7 @@ bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t TU_LOG_USBD(" Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes); #if CFG_TUD_LOG_LEVEL >= 3 - if(tu_edpt_dir(ep_addr) == TUSB_DIR_IN) { + if(dir == TUSB_DIR_IN) { TU_LOG_MEM(CFG_TUD_LOG_LEVEL, buffer, total_bytes, 2); } #endif