From 297290c16da3a0f897197492e94717acc17c0c70 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Thu, 1 Feb 2024 13:11:56 +0100 Subject: [PATCH 01/11] Allow vendor class to be used without FIFO. --- src/class/vendor/vendor_device.c | 73 ++++++++++++++++++++++++++++---- src/class/vendor/vendor_device.h | 34 ++++++++++++--- 2 files changed, 91 insertions(+), 16 deletions(-) diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index a68cb21565..12b3e237cc 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -43,14 +43,26 @@ typedef struct uint8_t ep_out; /*------------- From this point, data is not cleared by bus reset -------------*/ +#if CFG_TUD_VENDOR_USE_RX_FIFO tu_fifo_t rx_ff; +#endif +#if CFG_TUD_VENDOR_USE_TX_FIFO tu_fifo_t tx_ff; +#endif +#if CFG_TUD_VENDOR_USE_RX_FIFO uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE]; +#endif +#if CFG_TUD_VENDOR_USE_TX_FIFO uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE]; +#endif +#if CFG_TUD_VENDOR_USE_RX_FIFO OSAL_MUTEX_DEF(rx_ff_mutex); +#endif +#if CFG_TUD_VENDOR_USE_TX_FIFO OSAL_MUTEX_DEF(tx_ff_mutex); +#endif // Endpoint Transfer buffer CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_VENDOR_EPSIZE]; @@ -59,7 +71,7 @@ typedef struct CFG_TUD_MEM_SECTION tu_static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR]; -#define ITF_MEM_RESET_SIZE offsetof(vendord_interface_t, rx_ff) +#define ITF_MEM_RESET_SIZE offsetof(vendord_interface_t, ep_out) + sizeof(((vendord_interface_t *)0)->ep_out) bool tud_vendor_n_mounted (uint8_t itf) @@ -67,6 +79,7 @@ bool tud_vendor_n_mounted (uint8_t itf) return _vendord_itf[itf].ep_in && _vendord_itf[itf].ep_out; } +#if CFG_TUD_VENDOR_USE_RX_FIFO uint32_t tud_vendor_n_available (uint8_t itf) { return tu_fifo_count(&_vendord_itf[itf].rx_ff); @@ -76,10 +89,12 @@ bool tud_vendor_n_peek(uint8_t itf, uint8_t* u8) { return tu_fifo_peek(&_vendord_itf[itf].rx_ff, u8); } +#endif //--------------------------------------------------------------------+ // Read API //--------------------------------------------------------------------+ +#if CFG_TUD_VENDOR_USE_RX_FIFO static void _prep_out_transaction (vendord_interface_t* p_itf) { uint8_t const rhport = 0; @@ -114,12 +129,14 @@ void tud_vendor_n_read_flush (uint8_t itf) tu_fifo_clear(&p_itf->rx_ff); _prep_out_transaction(p_itf); } +#endif //--------------------------------------------------------------------+ // Write API //--------------------------------------------------------------------+ uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize) { +#if CFG_TUD_VENDOR_USE_TX_FIFO vendord_interface_t* p_itf = &_vendord_itf[itf]; uint16_t ret = tu_fifo_write_n(&p_itf->tx_ff, buffer, (uint16_t) bufsize); @@ -128,8 +145,23 @@ uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize) tud_vendor_n_write_flush(itf); } return ret; +#else + uint8_t const rhport = 0; + vendord_interface_t* p_itf = &_vendord_itf[itf]; + + // claim endpoint + TU_VERIFY(usbd_edpt_claim(rhport, p_itf->ep_in)); + + // prepare data + TU_VERIFY(0 == tu_memcpy_s(p_itf->epin_buf, CFG_TUD_VENDOR_EPSIZE, buffer, (uint16_t) bufsize)); + + TU_ASSERT(usbd_edpt_xfer(rhport, p_itf->ep_in, p_itf->epin_buf, (uint16_t) bufsize)); + + return bufsize; +#endif } +#if CFG_TUD_VENDOR_USE_TX_FIFO uint32_t tud_vendor_n_write_flush (uint8_t itf) { vendord_interface_t* p_itf = &_vendord_itf[itf]; @@ -165,6 +197,7 @@ uint32_t tud_vendor_n_write_available (uint8_t itf) { return tu_fifo_remaining(&_vendord_itf[itf].tx_ff); } +#endif //--------------------------------------------------------------------+ // USBD Driver API @@ -175,14 +208,18 @@ void vendord_init(void) for(uint8_t i=0; irx_ff, p_itf->rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, 1, false); - tu_fifo_config(&p_itf->tx_ff, p_itf->tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, 1, false); - tu_fifo_config_mutex(&p_itf->rx_ff, NULL, osal_mutex_create(&p_itf->rx_ff_mutex)); +#endif +#if CFG_TUD_VENDOR_USE_TX_FIFO + tu_fifo_config(&p_itf->tx_ff, p_itf->tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, 1, false); tu_fifo_config_mutex(&p_itf->tx_ff, osal_mutex_create(&p_itf->tx_ff_mutex), NULL); +#endif } } @@ -195,8 +232,12 @@ void vendord_reset(uint8_t rhport) vendord_interface_t* p_itf = &_vendord_itf[i]; tu_memclr(p_itf, ITF_MEM_RESET_SIZE); +#if CFG_TUD_VENDOR_USE_RX_FIFO tu_fifo_clear(&p_itf->rx_ff); +#endif +#if CFG_TUD_VENDOR_USE_TX_FIFO tu_fifo_clear(&p_itf->tx_ff); +#endif } } @@ -234,12 +275,19 @@ uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, ui p_desc += desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t); // Prepare for incoming data - if ( p_vendor->ep_out ) +#if CFG_TUD_VENDOR_USE_RX_FIFO + _prep_out_transaction(p_vendor); +#else + if ( !usbd_edpt_xfer(rhport, p_vendor->ep_out, p_vendor->epout_buf, CFG_TUD_VENDOR_EPSIZE) ) { - _prep_out_transaction(p_vendor); + TU_LOG_FAILED(); + TU_BREAKPOINT(); } +#endif - if ( p_vendor->ep_in ) tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf)); +#if CFG_TUD_VENDOR_USE_TX_FIFO + tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf)); +#endif } return (uint16_t) ((uintptr_t) p_desc - (uintptr_t) desc_itf); @@ -262,19 +310,26 @@ bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint if ( ep_addr == p_itf->ep_out ) { +#if CFG_TUD_VENDOR_USE_RX_FIFO // Receive new data tu_fifo_write_n(&p_itf->rx_ff, p_itf->epout_buf, (uint16_t) xferred_bytes); +#endif // Invoked callback if any - if (tud_vendor_rx_cb) tud_vendor_rx_cb(itf); - + if (tud_vendor_rx_cb) tud_vendor_rx_cb(itf, p_itf->epout_buf, (uint16_t) xferred_bytes); +#if CFG_TUD_VENDOR_USE_RX_FIFO _prep_out_transaction(p_itf); +#else + TU_ASSERT(usbd_edpt_xfer(rhport, p_itf->ep_out, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE)); +#endif } else if ( ep_addr == p_itf->ep_in ) { if (tud_vendor_tx_cb) tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes); +#if CFG_TUD_VENDOR_USE_TX_FIFO // Send complete, try to send more if possible tud_vendor_n_write_flush(itf); +#endif } return true; diff --git a/src/class/vendor/vendor_device.h b/src/class/vendor/vendor_device.h index d239406b46..aabce53574 100644 --- a/src/class/vendor/vendor_device.h +++ b/src/class/vendor/vendor_device.h @@ -33,6 +33,14 @@ #define CFG_TUD_VENDOR_EPSIZE 64 #endif +#ifndef CFG_TUD_VENDOR_USE_RX_FIFO +#define CFG_TUD_VENDOR_USE_RX_FIFO 1 +#endif + +#ifndef CFG_TUD_VENDOR_USE_TX_FIFO +#define CFG_TUD_VENDOR_USE_TX_FIFO 1 +#endif + #ifdef __cplusplus extern "C" { #endif @@ -42,42 +50,50 @@ //--------------------------------------------------------------------+ bool tud_vendor_n_mounted (uint8_t itf); +#if CFG_TUD_VENDOR_USE_RX_FIFO uint32_t tud_vendor_n_available (uint8_t itf); uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize); bool tud_vendor_n_peek (uint8_t itf, uint8_t* ui8); void tud_vendor_n_read_flush (uint8_t itf); +#endif uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize); +#if CFG_TUD_VENDOR_USE_TX_FIFO uint32_t tud_vendor_n_write_flush (uint8_t itf); uint32_t tud_vendor_n_write_available (uint8_t itf); - +#endif static inline uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str); +#if CFG_TUD_VENDOR_USE_TX_FIFO // backward compatible #define tud_vendor_n_flush(itf) tud_vendor_n_write_flush(itf) +#endif //--------------------------------------------------------------------+ // Application API (Single Port) //--------------------------------------------------------------------+ static inline bool tud_vendor_mounted (void); +#if CFG_TUD_VENDOR_USE_RX_FIFO static inline uint32_t tud_vendor_available (void); static inline uint32_t tud_vendor_read (void* buffer, uint32_t bufsize); static inline bool tud_vendor_peek (uint8_t* ui8); static inline void tud_vendor_read_flush (void); +#endif static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize); static inline uint32_t tud_vendor_write_str (char const* str); +#if CFG_TUD_VENDOR_USE_TX_FIFO static inline uint32_t tud_vendor_write_available (void); static inline uint32_t tud_vendor_write_flush (void); // backward compatible #define tud_vendor_flush() tud_vendor_write_flush() - +#endif //--------------------------------------------------------------------+ // Application Callback API (weak is optional) //--------------------------------------------------------------------+ // Invoked when received new data -TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t itf); +TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t itf, uint8_t const* buffer, uint16_t bufsize); // Invoked when last rx transfer finished TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes); @@ -95,6 +111,7 @@ static inline bool tud_vendor_mounted (void) return tud_vendor_n_mounted(0); } +#if CFG_TUD_VENDOR_USE_RX_FIFO static inline uint32_t tud_vendor_available (void) { return tud_vendor_n_available(0); @@ -114,26 +131,29 @@ static inline void tud_vendor_read_flush(void) { tud_vendor_n_read_flush(0); } +#endif static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize) { return tud_vendor_n_write(0, buffer, bufsize); } -static inline uint32_t tud_vendor_write_flush (void) +static inline uint32_t tud_vendor_write_str (char const* str) { - return tud_vendor_n_write_flush(0); + return tud_vendor_n_write_str(0, str); } -static inline uint32_t tud_vendor_write_str (char const* str) +#if CFG_TUD_VENDOR_USE_TX_FIFO +static inline uint32_t tud_vendor_write_flush (void) { - return tud_vendor_n_write_str(0, str); + return tud_vendor_n_write_flush(0); } static inline uint32_t tud_vendor_write_available (void) { return tud_vendor_n_write_available(0); } +#endif //--------------------------------------------------------------------+ // Internal Class Driver API From 5c8b3d97f04443f386270eba6171af9a333855c6 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Sun, 3 Mar 2024 20:11:20 +0100 Subject: [PATCH 02/11] Use FIFO size as condition. --- src/class/vendor/vendor_device.c | 40 ++++++++++++++++---------------- src/class/vendor/vendor_device.h | 24 ++++++++++--------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index 12b3e237cc..fe746eda02 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -43,24 +43,24 @@ typedef struct uint8_t ep_out; /*------------- From this point, data is not cleared by bus reset -------------*/ -#if CFG_TUD_VENDOR_USE_RX_FIFO +#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 tu_fifo_t rx_ff; #endif -#if CFG_TUD_VENDOR_USE_TX_FIFO +#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 tu_fifo_t tx_ff; #endif -#if CFG_TUD_VENDOR_USE_RX_FIFO +#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE]; #endif -#if CFG_TUD_VENDOR_USE_TX_FIFO +#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE]; #endif -#if CFG_TUD_VENDOR_USE_RX_FIFO +#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 OSAL_MUTEX_DEF(rx_ff_mutex); #endif -#if CFG_TUD_VENDOR_USE_TX_FIFO +#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 OSAL_MUTEX_DEF(tx_ff_mutex); #endif @@ -79,7 +79,7 @@ bool tud_vendor_n_mounted (uint8_t itf) return _vendord_itf[itf].ep_in && _vendord_itf[itf].ep_out; } -#if CFG_TUD_VENDOR_USE_RX_FIFO +#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 uint32_t tud_vendor_n_available (uint8_t itf) { return tu_fifo_count(&_vendord_itf[itf].rx_ff); @@ -94,7 +94,7 @@ bool tud_vendor_n_peek(uint8_t itf, uint8_t* u8) //--------------------------------------------------------------------+ // Read API //--------------------------------------------------------------------+ -#if CFG_TUD_VENDOR_USE_RX_FIFO +#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 static void _prep_out_transaction (vendord_interface_t* p_itf) { uint8_t const rhport = 0; @@ -136,7 +136,7 @@ void tud_vendor_n_read_flush (uint8_t itf) //--------------------------------------------------------------------+ uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize) { -#if CFG_TUD_VENDOR_USE_TX_FIFO +#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 vendord_interface_t* p_itf = &_vendord_itf[itf]; uint16_t ret = tu_fifo_write_n(&p_itf->tx_ff, buffer, (uint16_t) bufsize); @@ -161,7 +161,7 @@ uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize) #endif } -#if CFG_TUD_VENDOR_USE_TX_FIFO +#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 uint32_t tud_vendor_n_write_flush (uint8_t itf) { vendord_interface_t* p_itf = &_vendord_itf[itf]; @@ -208,15 +208,15 @@ void vendord_init(void) for(uint8_t i=0; i 0 || CFG_TUD_VENDOR_TX_BUFSIZE > 0 vendord_interface_t* p_itf = &_vendord_itf[i]; #endif // config fifo -#if CFG_TUD_VENDOR_USE_RX_FIFO +#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 tu_fifo_config(&p_itf->rx_ff, p_itf->rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, 1, false); tu_fifo_config_mutex(&p_itf->rx_ff, NULL, osal_mutex_create(&p_itf->rx_ff_mutex)); #endif -#if CFG_TUD_VENDOR_USE_TX_FIFO +#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 tu_fifo_config(&p_itf->tx_ff, p_itf->tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, 1, false); tu_fifo_config_mutex(&p_itf->tx_ff, osal_mutex_create(&p_itf->tx_ff_mutex), NULL); #endif @@ -232,10 +232,10 @@ void vendord_reset(uint8_t rhport) vendord_interface_t* p_itf = &_vendord_itf[i]; tu_memclr(p_itf, ITF_MEM_RESET_SIZE); -#if CFG_TUD_VENDOR_USE_RX_FIFO +#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 tu_fifo_clear(&p_itf->rx_ff); #endif -#if CFG_TUD_VENDOR_USE_TX_FIFO +#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 tu_fifo_clear(&p_itf->tx_ff); #endif } @@ -275,7 +275,7 @@ uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, ui p_desc += desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t); // Prepare for incoming data -#if CFG_TUD_VENDOR_USE_RX_FIFO +#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 _prep_out_transaction(p_vendor); #else if ( !usbd_edpt_xfer(rhport, p_vendor->ep_out, p_vendor->epout_buf, CFG_TUD_VENDOR_EPSIZE) ) @@ -285,7 +285,7 @@ uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, ui } #endif -#if CFG_TUD_VENDOR_USE_TX_FIFO +#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf)); #endif } @@ -310,14 +310,14 @@ bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint if ( ep_addr == p_itf->ep_out ) { -#if CFG_TUD_VENDOR_USE_RX_FIFO +#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 // Receive new data tu_fifo_write_n(&p_itf->rx_ff, p_itf->epout_buf, (uint16_t) xferred_bytes); #endif // Invoked callback if any if (tud_vendor_rx_cb) tud_vendor_rx_cb(itf, p_itf->epout_buf, (uint16_t) xferred_bytes); -#if CFG_TUD_VENDOR_USE_RX_FIFO +#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 _prep_out_transaction(p_itf); #else TU_ASSERT(usbd_edpt_xfer(rhport, p_itf->ep_out, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE)); @@ -326,7 +326,7 @@ bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint else if ( ep_addr == p_itf->ep_in ) { if (tud_vendor_tx_cb) tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes); -#if CFG_TUD_VENDOR_USE_TX_FIFO +#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 // Send complete, try to send more if possible tud_vendor_n_write_flush(itf); #endif diff --git a/src/class/vendor/vendor_device.h b/src/class/vendor/vendor_device.h index aabce53574..1e973b1531 100644 --- a/src/class/vendor/vendor_device.h +++ b/src/class/vendor/vendor_device.h @@ -33,12 +33,14 @@ #define CFG_TUD_VENDOR_EPSIZE 64 #endif -#ifndef CFG_TUD_VENDOR_USE_RX_FIFO -#define CFG_TUD_VENDOR_USE_RX_FIFO 1 +/* RX FIFO can be disabled by setting this value to 0, related API will also be disabled */ +#ifndef CFG_TUD_VENDOR_RX_BUFSIZE +#define CFG_TUD_VENDOR_RX_BUFSIZE 64 #endif -#ifndef CFG_TUD_VENDOR_USE_TX_FIFO -#define CFG_TUD_VENDOR_USE_TX_FIFO 1 +/* TX FIFO can be disabled by setting this value to 0, related API will also be disabled */ +#ifndef CFG_TUD_VENDOR_TX_BUFSIZE +#define CFG_TUD_VENDOR_TX_BUFSIZE 64 #endif #ifdef __cplusplus @@ -50,7 +52,7 @@ //--------------------------------------------------------------------+ bool tud_vendor_n_mounted (uint8_t itf); -#if CFG_TUD_VENDOR_USE_RX_FIFO +#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 uint32_t tud_vendor_n_available (uint8_t itf); uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize); bool tud_vendor_n_peek (uint8_t itf, uint8_t* ui8); @@ -58,13 +60,13 @@ void tud_vendor_n_read_flush (uint8_t itf); #endif uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize); -#if CFG_TUD_VENDOR_USE_TX_FIFO +#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 uint32_t tud_vendor_n_write_flush (uint8_t itf); uint32_t tud_vendor_n_write_available (uint8_t itf); #endif static inline uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str); -#if CFG_TUD_VENDOR_USE_TX_FIFO +#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 // backward compatible #define tud_vendor_n_flush(itf) tud_vendor_n_write_flush(itf) #endif @@ -73,7 +75,7 @@ static inline uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str); // Application API (Single Port) //--------------------------------------------------------------------+ static inline bool tud_vendor_mounted (void); -#if CFG_TUD_VENDOR_USE_RX_FIFO +#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 static inline uint32_t tud_vendor_available (void); static inline uint32_t tud_vendor_read (void* buffer, uint32_t bufsize); static inline bool tud_vendor_peek (uint8_t* ui8); @@ -81,7 +83,7 @@ static inline void tud_vendor_read_flush (void); #endif static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize); static inline uint32_t tud_vendor_write_str (char const* str); -#if CFG_TUD_VENDOR_USE_TX_FIFO +#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 static inline uint32_t tud_vendor_write_available (void); static inline uint32_t tud_vendor_write_flush (void); @@ -111,7 +113,7 @@ static inline bool tud_vendor_mounted (void) return tud_vendor_n_mounted(0); } -#if CFG_TUD_VENDOR_USE_RX_FIFO +#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 static inline uint32_t tud_vendor_available (void) { return tud_vendor_n_available(0); @@ -143,7 +145,7 @@ static inline uint32_t tud_vendor_write_str (char const* str) return tud_vendor_n_write_str(0, str); } -#if CFG_TUD_VENDOR_USE_TX_FIFO +#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 static inline uint32_t tud_vendor_write_flush (void) { return tud_vendor_n_write_flush(0); From 867f17acea98fda04fa0bf8e871f61e57044f030 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 10 Sep 2024 10:44:22 +0700 Subject: [PATCH 03/11] change vendor device to use edpt stream API --- src/class/vendor/vendor_device.c | 302 +++++++++++++------------------ src/common/tusb_private.h | 6 +- src/device/usbd_pvt.h | 1 + src/tusb.c | 2 +- 4 files changed, 130 insertions(+), 181 deletions(-) diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index 06c663f1b2..d235302352 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -45,108 +45,93 @@ typedef struct uint8_t ep_out; /*------------- From this point, data is not cleared by bus reset -------------*/ -#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 - tu_fifo_t rx_ff; -#endif -#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 - tu_fifo_t tx_ff; -#endif + // Endpoint Transfer buffer + CFG_TUD_MEM_ALIGN uint8_t epout_buf[CFG_TUD_VENDOR_EPSIZE]; + CFG_TUD_MEM_ALIGN uint8_t epin_buf[CFG_TUD_VENDOR_EPSIZE]; -#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 - uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE]; -#endif #if CFG_TUD_VENDOR_TX_BUFSIZE > 0 - uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE]; + struct { + tu_edpt_stream_t stream; + uint8_t ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE]; + }tx; #endif #if CFG_TUD_VENDOR_RX_BUFSIZE > 0 - OSAL_MUTEX_DEF(rx_ff_mutex); -#endif -#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 - OSAL_MUTEX_DEF(tx_ff_mutex); + struct { + tu_edpt_stream_t stream; + uint8_t ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE]; + } rx; #endif - // Endpoint Transfer buffer - CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_VENDOR_EPSIZE]; - CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_VENDOR_EPSIZE]; } vendord_interface_t; -CFG_TUD_MEM_SECTION tu_static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR]; +CFG_TUD_MEM_SECTION static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR]; #define ITF_MEM_RESET_SIZE offsetof(vendord_interface_t, ep_out) + sizeof(((vendord_interface_t *)0)->ep_out) - -bool tud_vendor_n_mounted (uint8_t itf) -{ +bool tud_vendor_n_mounted (uint8_t itf) { return _vendord_itf[itf].ep_in && _vendord_itf[itf].ep_out; } -#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 -uint32_t tud_vendor_n_available (uint8_t itf) -{ - return tu_fifo_count(&_vendord_itf[itf].rx_ff); -} - -bool tud_vendor_n_peek(uint8_t itf, uint8_t* u8) -{ - return tu_fifo_peek(&_vendord_itf[itf].rx_ff, u8); -} -#endif - //--------------------------------------------------------------------+ // Read API //--------------------------------------------------------------------+ #if CFG_TUD_VENDOR_RX_BUFSIZE > 0 -static void _prep_out_transaction (vendord_interface_t* p_itf) -{ - uint8_t const rhport = 0; - - // claim endpoint - TU_VERIFY(usbd_edpt_claim(rhport, p_itf->ep_out), ); +// static void _prep_out_transaction (vendord_interface_t* p_itf) +// { +// uint8_t const rhport = 0; +// +// // claim endpoint +// TU_VERIFY(usbd_edpt_claim(rhport, p_itf->ep_out), ); +// +// // Prepare for incoming data but only allow what we can store in the ring buffer. +// uint16_t max_read = tu_fifo_remaining(&p_itf->rx_ff); +// if ( max_read >= CFG_TUD_VENDOR_EPSIZE ) +// { +// usbd_edpt_xfer(rhport, p_itf->ep_out, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE); +// } +// else +// { +// // Release endpoint since we don't make any transfer +// usbd_edpt_release(rhport, p_itf->ep_out); +// } +// } + +uint32_t tud_vendor_n_available (uint8_t itf) { + TU_VERIFY(itf < CFG_TUD_VENDOR, 0); + vendord_interface_t* p_itf = &_vendord_itf[itf]; + return tu_edpt_stream_read_available(&p_itf->rx.stream); +} - // Prepare for incoming data but only allow what we can store in the ring buffer. - uint16_t max_read = tu_fifo_remaining(&p_itf->rx_ff); - if ( max_read >= CFG_TUD_VENDOR_EPSIZE ) - { - usbd_edpt_xfer(rhport, p_itf->ep_out, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE); - } - else - { - // Release endpoint since we don't make any transfer - usbd_edpt_release(rhport, p_itf->ep_out); - } +bool tud_vendor_n_peek(uint8_t itf, uint8_t* u8) { + TU_VERIFY(itf < CFG_TUD_VENDOR, 0); + vendord_interface_t* p_itf = &_vendord_itf[itf]; + return tu_edpt_stream_peek(&p_itf->rx.stream, u8); } -uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize) -{ +uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize) { + TU_VERIFY(itf < CFG_TUD_VENDOR, 0); vendord_interface_t* p_itf = &_vendord_itf[itf]; - uint32_t num_read = tu_fifo_read_n(&p_itf->rx_ff, buffer, (uint16_t) bufsize); - _prep_out_transaction(p_itf); - return num_read; + return tu_edpt_stream_read(&p_itf->rx.stream, buffer, bufsize); } -void tud_vendor_n_read_flush (uint8_t itf) -{ +void tud_vendor_n_read_flush (uint8_t itf) { + TU_VERIFY(itf < CFG_TUD_VENDOR, ); vendord_interface_t* p_itf = &_vendord_itf[itf]; - tu_fifo_clear(&p_itf->rx_ff); - _prep_out_transaction(p_itf); + + tu_edpt_stream_clear(&p_itf->rx.stream); + tu_edpt_stream_read_xfer(&p_itf->rx.stream); } #endif //--------------------------------------------------------------------+ // Write API //--------------------------------------------------------------------+ -uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize) -{ +uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize) { #if CFG_TUD_VENDOR_TX_BUFSIZE > 0 + TU_VERIFY(itf < CFG_TUD_VENDOR, 0); vendord_interface_t* p_itf = &_vendord_itf[itf]; - uint16_t ret = tu_fifo_write_n(&p_itf->tx_ff, buffer, (uint16_t) bufsize); - - // flush if queue more than packet size - if (tu_fifo_count(&p_itf->tx_ff) >= CFG_TUD_VENDOR_EPSIZE) { - tud_vendor_n_write_flush(itf); - } - return ret; + return tu_edpt_stream_write(&p_itf->tx.stream, buffer, (uint16_t) bufsize); #else uint8_t const rhport = 0; vendord_interface_t* p_itf = &_vendord_itf[itf]; @@ -164,40 +149,16 @@ uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize) } #if CFG_TUD_VENDOR_TX_BUFSIZE > 0 -uint32_t tud_vendor_n_write_flush (uint8_t itf) -{ +uint32_t tud_vendor_n_write_flush (uint8_t itf) { + TU_VERIFY(itf < CFG_TUD_VENDOR, 0); vendord_interface_t* p_itf = &_vendord_itf[itf]; - - // Skip if usb is not ready yet - TU_VERIFY( tud_ready(), 0 ); - - // No data to send - if ( !tu_fifo_count(&p_itf->tx_ff) ) return 0; - - uint8_t const rhport = 0; - - // Claim the endpoint - TU_VERIFY( usbd_edpt_claim(rhport, p_itf->ep_in), 0 ); - - // Pull data from FIFO - uint16_t const count = tu_fifo_read_n(&p_itf->tx_ff, p_itf->epin_buf, sizeof(p_itf->epin_buf)); - - if ( count ) - { - TU_ASSERT( usbd_edpt_xfer(rhport, p_itf->ep_in, p_itf->epin_buf, count), 0 ); - return count; - }else - { - // Release endpoint since we don't make any transfer - // Note: data is dropped if terminal is not connected - usbd_edpt_release(rhport, p_itf->ep_in); - return 0; - } + return tu_edpt_stream_write_xfer(&p_itf->tx.stream); } -uint32_t tud_vendor_n_write_available (uint8_t itf) -{ - return tu_fifo_remaining(&_vendord_itf[itf].tx_ff); +uint32_t tud_vendor_n_write_available (uint8_t itf) { + TU_VERIFY(itf < CFG_TUD_VENDOR, 0); + vendord_interface_t* p_itf = &_vendord_itf[itf]; + return tu_edpt_stream_write_available(&p_itf->tx.stream); } #endif @@ -208,27 +169,19 @@ void vendord_init(void) { tu_memclr(_vendord_itf, sizeof(_vendord_itf)); for(uint8_t i=0; i 0 || CFG_TUD_VENDOR_TX_BUFSIZE > 0 vendord_interface_t* p_itf = &_vendord_itf[i]; -#endif + // config fifo #if CFG_TUD_VENDOR_RX_BUFSIZE > 0 - tu_fifo_config(&p_itf->rx_ff, p_itf->rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, 1, false); - - #if OSAL_MUTEX_REQUIRED - osal_mutex_t mutex_rd = osal_mutex_create(&p_itf->rx_ff_mutex); - TU_ASSERT(mutex_rd,); - tu_fifo_config_mutex(&p_itf->rx_ff, NULL, mutex_rd); - #endif + tu_edpt_stream_init(&p_itf->rx.stream, false, false, false, + p_itf->rx.ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, + p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE); #endif -#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 - tu_fifo_config(&p_itf->tx_ff, p_itf->tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, 1, false); - #if OSAL_MUTEX_REQUIRED - osal_mutex_t mutex_wr = osal_mutex_create(&p_itf->tx_ff_mutex); - TU_ASSERT(mutex_wr,); - tu_fifo_config_mutex(&p_itf->tx_ff, mutex_wr, NULL); - #endif +#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 + tu_edpt_stream_init(&p_itf->tx.stream, false, true, false, + p_itf->tx.ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, + p_itf->epin_buf, CFG_TUD_VENDOR_EPSIZE); #endif } } @@ -261,37 +214,31 @@ bool vendord_deinit(void) { return true; } -void vendord_reset(uint8_t rhport) -{ +void vendord_reset(uint8_t rhport) { (void) rhport; - for(uint8_t i=0; i 0 - tu_fifo_clear(&p_itf->rx_ff); + tu_edpt_stream_clear(&p_itf->rx.stream); #endif #if CFG_TUD_VENDOR_TX_BUFSIZE > 0 - tu_fifo_clear(&p_itf->tx_ff); + tu_edpt_stream_clear(&p_itf->tx.stream); #endif } } -uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) -{ +uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len) { TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == desc_itf->bInterfaceClass, 0); - - uint8_t const * p_desc = tu_desc_next(desc_itf); - uint8_t const * desc_end = p_desc + max_len; + const uint8_t* p_desc = tu_desc_next(desc_itf); + const uint8_t* desc_end = p_desc + max_len; // Find available interface vendord_interface_t* p_vendor = NULL; - for(uint8_t i=0; iitf_num = desc_itf->bInterfaceNumber; - if (desc_itf->bNumEndpoints) - { + uint8_t found_ep = 0; + while (found_ep < desc_itf->bNumEndpoints) { // skip non-endpoint descriptors - while ( (TUSB_DESC_ENDPOINT != tu_desc_type(p_desc)) && (p_desc < desc_end) ) - { + while ( (TUSB_DESC_ENDPOINT != tu_desc_type(p_desc)) && (p_desc < desc_end) ) { p_desc = tu_desc_next(p_desc); } + if (p_desc >= desc_end) { + break; + } - // Open endpoint pair with usbd helper - TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_BULK, &p_vendor->ep_out, &p_vendor->ep_in), 0); - - p_desc += desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t); - - // Prepare for incoming data -#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 - _prep_out_transaction(p_vendor); -#else - if ( !usbd_edpt_xfer(rhport, p_vendor->ep_out, p_vendor->epout_buf, CFG_TUD_VENDOR_EPSIZE) ) - { - TU_LOG_FAILED(); - TU_BREAKPOINT(); + const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc; + TU_ASSERT(usbd_edpt_open(rhport, desc_ep)); + found_ep++; + + if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { + p_vendor->ep_in = desc_ep->bEndpointAddress; + + #if CFG_TUD_VENDOR_TX_BUFSIZE > 0 + tu_edpt_stream_open(&p_vendor->tx.stream, rhport, desc_ep); + tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf)); + #endif + } else { + p_vendor->ep_out = desc_ep->bEndpointAddress; + + #if CFG_TUD_VENDOR_RX_BUFSIZE > 0 + tu_edpt_stream_open(&p_vendor->rx.stream, rhport, desc_ep); + TU_ASSERT(tu_edpt_stream_read_xfer(&p_vendor->rx.stream) > 0, 0); // prepare for incoming data + #else + if ( !usbd_edpt_xfer(rhport, p_vendor->ep_out, p_vendor->epout_buf, CFG_TUD_VENDOR_EPSIZE) ) { + TU_LOG_FAILED(); + TU_BREAKPOINT(); + } + #endif } -#endif -#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 - tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf)); -#endif + p_desc = tu_desc_next(p_desc); } return (uint16_t) ((uintptr_t) p_desc - (uintptr_t) desc_itf); } -bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) -{ +bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { + (void) rhport; (void) result; uint8_t itf = 0; vendord_interface_t* p_itf = _vendord_itf; - for ( ; ; itf++, p_itf++) - { + for ( ; ; itf++, p_itf++) { if (itf >= TU_ARRAY_SIZE(_vendord_itf)) return false; - if ( ( ep_addr == p_itf->ep_out ) || ( ep_addr == p_itf->ep_in ) ) break; } - if ( ep_addr == p_itf->ep_out ) - { + if ( ep_addr == p_itf->ep_out ) { #if CFG_TUD_VENDOR_RX_BUFSIZE > 0 - // Receive new data - tu_fifo_write_n(&p_itf->rx_ff, p_itf->epout_buf, (uint16_t) xferred_bytes); + // Receive new data, put it into stream's fifo + tu_edpt_stream_read_xfer_complete(&p_itf->rx.stream, xferred_bytes); #endif // Invoked callback if any - if (tud_vendor_rx_cb) tud_vendor_rx_cb(itf, p_itf->epout_buf, (uint16_t) xferred_bytes); + if (tud_vendor_rx_cb) { + tud_vendor_rx_cb(itf, p_itf->epout_buf, (uint16_t) xferred_bytes); + } + #if CFG_TUD_VENDOR_RX_BUFSIZE > 0 - _prep_out_transaction(p_itf); + tu_edpt_stream_read_xfer(&p_itf->rx.stream); #else TU_ASSERT(usbd_edpt_xfer(rhport, p_itf->ep_out, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE)); #endif - } - else if ( ep_addr == p_itf->ep_in ) - { - if (tud_vendor_tx_cb) tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes); + } else if ( ep_addr == p_itf->ep_in ) { + if (tud_vendor_tx_cb) { + tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes); + } #if CFG_TUD_VENDOR_TX_BUFSIZE > 0 // Send complete, try to send more if possible - if ( 0 == tud_vendor_n_write_flush(itf) ) - { - // If there is no data left, a ZLP should be sent if - // xferred_bytes is multiple of EP Packet size and not zero - if ( !tu_fifo_count(&p_itf->tx_ff) && xferred_bytes && (0 == (xferred_bytes & (BULK_PACKET_SIZE-1))) ) - { - if ( usbd_edpt_claim(rhport, p_itf->ep_in) ) - { - usbd_edpt_xfer(rhport, p_itf->ep_in, NULL, 0); - } - } + if ( 0 == tu_edpt_stream_write_xfer(&p_itf->tx.stream) ) { + // If there is no data left, a ZLP should be sent if xferred_bytes is multiple of EP Packet size and not zero + tu_edpt_stream_write_zlp_if_needed(&p_itf->tx.stream, xferred_bytes); } #endif } diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h index 373a502564..5a1eb683b6 100644 --- a/src/common/tusb_private.h +++ b/src/common/tusb_private.h @@ -42,10 +42,10 @@ typedef struct TU_ATTR_PACKED }tu_edpt_state_t; typedef struct { - bool is_host; // host or device most + bool is_host; // host or device union { - uint8_t daddr; - uint8_t rhport; + uint8_t daddr; // host mode + uint8_t rhport; // device mode uint8_t hwid; }; uint8_t ep_addr; diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h index 335d46cd89..90f37db3ed 100644 --- a/src/device/usbd_pvt.h +++ b/src/device/usbd_pvt.h @@ -28,6 +28,7 @@ #include "osal/osal.h" #include "common/tusb_fifo.h" +#include "common/tusb_private.h" #ifdef __cplusplus extern "C" { diff --git a/src/tusb.c b/src/tusb.c index 860e8ac350..7b840e3a25 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -315,7 +315,7 @@ uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) { uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const* buffer, uint32_t bufsize) { TU_VERIFY(bufsize); // TODO support ZLP - uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize); + const uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize); // flush if fifo has more than packet size or // in rare case: fifo depth is configured too small (which never reach packet size) From c0030810dda8d9cca9cd041f246180ff03dc6624 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 10 Sep 2024 16:15:51 +0700 Subject: [PATCH 04/11] update edpt_stream to support non-buffered (no fifo) mode --- src/common/tusb_private.h | 14 +++--- src/tusb.c | 102 ++++++++++++++++++++++++-------------- 2 files changed, 72 insertions(+), 44 deletions(-) diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h index 5a1eb683b6..ef0d5315e9 100644 --- a/src/common/tusb_private.h +++ b/src/common/tusb_private.h @@ -129,11 +129,9 @@ uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s); // Start an zero-length packet if needed bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes); -// Get the number of bytes available for writing -TU_ATTR_ALWAYS_INLINE static inline -uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) { - return (uint32_t) tu_fifo_remaining(&s->ff); -} +// Get the number of bytes available for writing to FIFO +// Note: if no fifo, return endpoint size if not busy, 0 otherwise +uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s); //--------------------------------------------------------------------+ // Stream Read @@ -148,13 +146,15 @@ uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s); // Must be called in the transfer complete callback TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_read_xfer_complete(tu_edpt_stream_t* s, uint32_t xferred_bytes) { - tu_fifo_write_n(&s->ff, s->ep_buf, (uint16_t) xferred_bytes); + if (tu_fifo_depth(&s->ff)) { + tu_fifo_write_n(&s->ff, s->ep_buf, (uint16_t) xferred_bytes); + } } // Same as tu_edpt_stream_read_xfer_complete but skip the first n bytes TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_read_xfer_complete_offset(tu_edpt_stream_t* s, uint32_t xferred_bytes, uint32_t skip_offset) { - if (skip_offset < xferred_bytes) { + if (tu_fifo_depth(&s->ff) && (skip_offset < xferred_bytes)) { tu_fifo_write_n(&s->ff, s->ep_buf + skip_offset, (uint16_t) (xferred_bytes - skip_offset)); } } diff --git a/src/tusb.c b/src/tusb.c index 7b840e3a25..44fd2dc140 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -239,8 +239,7 @@ bool tu_edpt_stream_deinit(tu_edpt_stream_t* s) { return true; } -TU_ATTR_ALWAYS_INLINE static inline -bool stream_claim(tu_edpt_stream_t* s) { +TU_ATTR_ALWAYS_INLINE static inline bool stream_claim(tu_edpt_stream_t* s) { if (s->is_host) { #if CFG_TUH_ENABLED return usbh_edpt_claim(s->daddr, s->ep_addr); @@ -253,8 +252,7 @@ bool stream_claim(tu_edpt_stream_t* s) { return false; } -TU_ATTR_ALWAYS_INLINE static inline -bool stream_xfer(tu_edpt_stream_t* s, uint16_t count) { +TU_ATTR_ALWAYS_INLINE static inline bool stream_xfer(tu_edpt_stream_t* s, uint16_t count) { if (s->is_host) { #if CFG_TUH_ENABLED return usbh_edpt_xfer(s->daddr, s->ep_addr, count ? s->ep_buf : NULL, count); @@ -267,8 +265,7 @@ bool stream_xfer(tu_edpt_stream_t* s, uint16_t count) { return false; } -TU_ATTR_ALWAYS_INLINE static inline -bool stream_release(tu_edpt_stream_t* s) { +TU_ATTR_ALWAYS_INLINE static inline bool stream_release(tu_edpt_stream_t* s) { if (s->is_host) { #if CFG_TUH_ENABLED return usbh_edpt_release(s->daddr, s->ep_addr); @@ -296,7 +293,6 @@ uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) { // skip if no data TU_VERIFY(tu_fifo_count(&s->ff), 0); - // Claim the endpoint TU_VERIFY(stream_claim(s), 0); // Pull data from FIFO -> EP buf @@ -315,46 +311,78 @@ uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) { uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const* buffer, uint32_t bufsize) { TU_VERIFY(bufsize); // TODO support ZLP - const uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize); - // flush if fifo has more than packet size or - // in rare case: fifo depth is configured too small (which never reach packet size) - if ((tu_fifo_count(&s->ff) >= s->ep_packetsize) || (tu_fifo_depth(&s->ff) < s->ep_packetsize)) { - tu_edpt_stream_write_xfer(s); + if (0 == tu_fifo_depth(&s->ff)) { + // no fifo for buffered + TU_VERIFY(stream_claim(s), 0); + const uint32_t xact_len = tu_min32(bufsize, s->ep_bufsize); + memcpy(s->ep_buf, buffer, xact_len); + TU_ASSERT(stream_xfer(s, xact_len), 0); + return xact_len; + } else { + const uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize); + + // flush if fifo has more than packet size or + // in rare case: fifo depth is configured too small (which never reach packet size) + if ((tu_fifo_count(&s->ff) >= s->ep_packetsize) || (tu_fifo_depth(&s->ff) < s->ep_packetsize)) { + tu_edpt_stream_write_xfer(s); + } + return ret; } +} - return ret; +uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) { + if (tu_fifo_depth(&s->ff)) { + return (uint32_t) tu_fifo_remaining(&s->ff); + } else { + bool is_busy = true; + if (s->is_host) { + #if CFG_TUH_ENABLED + is_busy = usbh_edpt_busy(s->daddr, s->ep_addr); + #endif + } else { + #if CFG_TUD_ENABLED + is_busy = usbd_edpt_busy(s->rhport, s->ep_addr); + #endif + } + return is_busy ? 0 : s->ep_bufsize; + } } //--------------------------------------------------------------------+ // Stream Read //--------------------------------------------------------------------+ uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) { - uint16_t available = tu_fifo_remaining(&s->ff); - - // Prepare for incoming data but only allow what we can store in the ring buffer. - // TODO Actually we can still carry out the transfer, keeping count of received bytes - // and slowly move it to the FIFO when read(). - // This pre-check reduces endpoint claiming - TU_VERIFY(available >= s->ep_packetsize); - - // claim endpoint - TU_VERIFY(stream_claim(s), 0); - - // get available again since fifo can be changed before endpoint is claimed - available = tu_fifo_remaining(&s->ff); - - if (available >= s->ep_packetsize) { - // multiple of packet size limit by ep bufsize - uint16_t count = (uint16_t) (available & ~(s->ep_packetsize - 1)); - count = tu_min16(count, s->ep_bufsize); - - TU_ASSERT(stream_xfer(s, count), 0); - return count; + if (0 == tu_fifo_depth(&s->ff)) { + // no fifo for buffered + TU_VERIFY(stream_claim(s), 0); + TU_ASSERT(stream_xfer(s, s->ep_bufsize), 0); + return s->ep_bufsize; } else { - // Release endpoint since we don't make any transfer - stream_release(s); - return 0; + uint16_t available = tu_fifo_remaining(&s->ff); + + // Prepare for incoming data but only allow what we can store in the ring buffer. + // TODO Actually we can still carry out the transfer, keeping count of received bytes + // and slowly move it to the FIFO when read(). + // This pre-check reduces endpoint claiming + TU_VERIFY(available >= s->ep_packetsize); + + TU_VERIFY(stream_claim(s), 0); + + // get available again since fifo can be changed before endpoint is claimed + available = tu_fifo_remaining(&s->ff); + + if (available >= s->ep_packetsize) { + // multiple of packet size limit by ep bufsize + uint16_t count = (uint16_t) (available & ~(s->ep_packetsize - 1)); + count = tu_min16(count, s->ep_bufsize); + TU_ASSERT(stream_xfer(s, count), 0); + return count; + } else { + // Release endpoint since we don't make any transfer + stream_release(s); + return 0; + } } } From cc816dc9c04762f14468a0b7b1826768e731f53f Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 10 Sep 2024 17:41:20 +0700 Subject: [PATCH 05/11] change edpt stream api to take hwid from API to reduce memory footprint --- src/class/cdc/cdc_host.c | 22 +++++++------- src/common/tusb_private.h | 25 +++++++--------- src/tusb.c | 62 +++++++++++++++++++-------------------- 3 files changed, 52 insertions(+), 57 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 133a10f6ec..8717970e60 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -341,14 +341,14 @@ uint32_t tuh_cdc_write(uint8_t idx, void const* buffer, uint32_t bufsize) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tu_edpt_stream_write(&p_cdc->stream.tx, buffer, bufsize); + return tu_edpt_stream_write(p_cdc->daddr, &p_cdc->stream.tx, buffer, bufsize); } uint32_t tuh_cdc_write_flush(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tu_edpt_stream_write_xfer(&p_cdc->stream.tx); + return tu_edpt_stream_write_xfer(p_cdc->daddr, &p_cdc->stream.tx); } bool tuh_cdc_write_clear(uint8_t idx) { @@ -362,7 +362,7 @@ uint32_t tuh_cdc_write_available(uint8_t idx) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tu_edpt_stream_write_available(&p_cdc->stream.tx); + return tu_edpt_stream_write_available(p_cdc->daddr, &p_cdc->stream.tx); } //--------------------------------------------------------------------+ @@ -373,7 +373,7 @@ uint32_t tuh_cdc_read (uint8_t idx, void* buffer, uint32_t bufsize) { cdch_interface_t* p_cdc = get_itf(idx); TU_VERIFY(p_cdc); - return tu_edpt_stream_read(&p_cdc->stream.rx, buffer, bufsize); + return tu_edpt_stream_read(p_cdc->daddr, &p_cdc->stream.rx, buffer, bufsize); } uint32_t tuh_cdc_read_available(uint8_t idx) { @@ -395,7 +395,7 @@ bool tuh_cdc_read_clear (uint8_t idx) { TU_VERIFY(p_cdc); bool ret = tu_edpt_stream_clear(&p_cdc->stream.rx); - tu_edpt_stream_read_xfer(&p_cdc->stream.rx); + tu_edpt_stream_read_xfer(p_cdc->daddr, &p_cdc->stream.rx); return ret; } @@ -677,10 +677,10 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t // invoke tx complete callback to possibly refill tx fifo if (tuh_cdc_tx_complete_cb) tuh_cdc_tx_complete_cb(idx); - if ( 0 == tu_edpt_stream_write_xfer(&p_cdc->stream.tx) ) { + if ( 0 == tu_edpt_stream_write_xfer(daddr, &p_cdc->stream.tx) ) { // If there is no data left, a ZLP should be sent if: // - xferred_bytes is multiple of EP Packet size and not zero - tu_edpt_stream_write_zlp_if_needed(&p_cdc->stream.tx, xferred_bytes); + tu_edpt_stream_write_zlp_if_needed(daddr, &p_cdc->stream.tx, xferred_bytes); } } else if ( ep_addr == p_cdc->stream.rx.ep_addr ) { #if CFG_TUH_CDC_FTDI @@ -698,7 +698,7 @@ bool cdch_xfer_cb(uint8_t daddr, uint8_t ep_addr, xfer_result_t event, uint32_t if (tuh_cdc_rx_cb) tuh_cdc_rx_cb(idx); // prepare for next transfer if needed - tu_edpt_stream_read_xfer(&p_cdc->stream.rx); + tu_edpt_stream_read_xfer(daddr, &p_cdc->stream.rx); }else if ( ep_addr == p_cdc->ep_notif ) { // TODO handle notification endpoint }else { @@ -719,9 +719,9 @@ static bool open_ep_stream_pair(cdch_interface_t* p_cdc, tusb_desc_endpoint_t co TU_ASSERT(tuh_edpt_open(p_cdc->daddr, desc_ep)); if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { - tu_edpt_stream_open(&p_cdc->stream.rx, p_cdc->daddr, desc_ep); + tu_edpt_stream_open(&p_cdc->stream.rx, desc_ep); } else { - tu_edpt_stream_open(&p_cdc->stream.tx, p_cdc->daddr, desc_ep); + tu_edpt_stream_open(&p_cdc->stream.tx, desc_ep); } desc_ep = (tusb_desc_endpoint_t const*) tu_desc_next(desc_ep); @@ -763,7 +763,7 @@ static void set_config_complete(cdch_interface_t * p_cdc, uint8_t idx, uint8_t i if (tuh_cdc_mount_cb) tuh_cdc_mount_cb(idx); // Prepare for incoming data - tu_edpt_stream_read_xfer(&p_cdc->stream.rx); + tu_edpt_stream_read_xfer(p_cdc->daddr, &p_cdc->stream.rx); // notify usbh that driver enumeration is complete usbh_driver_set_config_complete(p_cdc->daddr, itf_num); diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h index ef0d5315e9..71a395c79e 100644 --- a/src/common/tusb_private.h +++ b/src/common/tusb_private.h @@ -42,14 +42,11 @@ typedef struct TU_ATTR_PACKED }tu_edpt_state_t; typedef struct { - bool is_host; // host or device - union { - uint8_t daddr; // host mode - uint8_t rhport; // device mode - uint8_t hwid; + struct { + uint8_t is_host : 1; // host or device + uint8_t is_highspeed: 1; // is highspeed }; uint8_t ep_addr; - uint8_t ep_speed; uint16_t ep_packetsize; uint16_t ep_bufsize; @@ -97,16 +94,14 @@ bool tu_edpt_stream_deinit(tu_edpt_stream_t* s); // Open an stream for an endpoint // hwid is either device address (host mode) or rhport (device mode) TU_ATTR_ALWAYS_INLINE static inline -void tu_edpt_stream_open(tu_edpt_stream_t* s, uint8_t hwid, tusb_desc_endpoint_t const *desc_ep) { +void tu_edpt_stream_open(tu_edpt_stream_t* s, tusb_desc_endpoint_t const *desc_ep) { tu_fifo_clear(&s->ff); - s->hwid = hwid; s->ep_addr = desc_ep->bEndpointAddress; s->ep_packetsize = tu_edpt_packet_size(desc_ep); } TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_close(tu_edpt_stream_t* s) { - s->hwid = 0; s->ep_addr = 0; } @@ -121,27 +116,27 @@ bool tu_edpt_stream_clear(tu_edpt_stream_t* s) { //--------------------------------------------------------------------+ // Write to stream -uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize); +uint32_t tu_edpt_stream_write(uint8_t hwid, tu_edpt_stream_t* s, void const *buffer, uint32_t bufsize); // Start an usb transfer if endpoint is not busy -uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s); +uint32_t tu_edpt_stream_write_xfer(uint8_t hwid, tu_edpt_stream_t* s); // Start an zero-length packet if needed -bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes); +bool tu_edpt_stream_write_zlp_if_needed(uint8_t hwid, tu_edpt_stream_t* s, uint32_t last_xferred_bytes); // Get the number of bytes available for writing to FIFO // Note: if no fifo, return endpoint size if not busy, 0 otherwise -uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s); +uint32_t tu_edpt_stream_write_available(uint8_t hwid, tu_edpt_stream_t* s); //--------------------------------------------------------------------+ // Stream Read //--------------------------------------------------------------------+ // Read from stream -uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize); +uint32_t tu_edpt_stream_read(uint8_t hwid, tu_edpt_stream_t* s, void* buffer, uint32_t bufsize); // Start an usb transfer if endpoint is not busy -uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s); +uint32_t tu_edpt_stream_read_xfer(uint8_t hwid, tu_edpt_stream_t* s); // Must be called in the transfer complete callback TU_ATTR_ALWAYS_INLINE static inline diff --git a/src/tusb.c b/src/tusb.c index 44fd2dc140..69c1f97750 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -239,40 +239,40 @@ bool tu_edpt_stream_deinit(tu_edpt_stream_t* s) { return true; } -TU_ATTR_ALWAYS_INLINE static inline bool stream_claim(tu_edpt_stream_t* s) { +TU_ATTR_ALWAYS_INLINE static inline bool stream_claim(uint8_t hwid, tu_edpt_stream_t* s) { if (s->is_host) { #if CFG_TUH_ENABLED - return usbh_edpt_claim(s->daddr, s->ep_addr); + return usbh_edpt_claim(hwid, s->ep_addr); #endif } else { #if CFG_TUD_ENABLED - return usbd_edpt_claim(s->rhport, s->ep_addr); + return usbd_edpt_claim(hwid, s->ep_addr); #endif } return false; } -TU_ATTR_ALWAYS_INLINE static inline bool stream_xfer(tu_edpt_stream_t* s, uint16_t count) { +TU_ATTR_ALWAYS_INLINE static inline bool stream_xfer(uint8_t hwid, tu_edpt_stream_t* s, uint16_t count) { if (s->is_host) { #if CFG_TUH_ENABLED - return usbh_edpt_xfer(s->daddr, s->ep_addr, count ? s->ep_buf : NULL, count); + return usbh_edpt_xfer(hwid, s->ep_addr, count ? s->ep_buf : NULL, count); #endif } else { #if CFG_TUD_ENABLED - return usbd_edpt_xfer(s->rhport, s->ep_addr, count ? s->ep_buf : NULL, count); + return usbd_edpt_xfer(hwid, s->ep_addr, count ? s->ep_buf : NULL, count); #endif } return false; } -TU_ATTR_ALWAYS_INLINE static inline bool stream_release(tu_edpt_stream_t* s) { +TU_ATTR_ALWAYS_INLINE static inline bool stream_release(uint8_t hwid, tu_edpt_stream_t* s) { if (s->is_host) { #if CFG_TUH_ENABLED - return usbh_edpt_release(s->daddr, s->ep_addr); + return usbh_edpt_release(hwid, s->ep_addr); #endif } else { #if CFG_TUD_ENABLED - return usbd_edpt_release(s->rhport, s->ep_addr); + return usbd_edpt_release(hwid, s->ep_addr); #endif } return false; @@ -281,43 +281,43 @@ TU_ATTR_ALWAYS_INLINE static inline bool stream_release(tu_edpt_stream_t* s) { //--------------------------------------------------------------------+ // Stream Write //--------------------------------------------------------------------+ -bool tu_edpt_stream_write_zlp_if_needed(tu_edpt_stream_t* s, uint32_t last_xferred_bytes) { +bool tu_edpt_stream_write_zlp_if_needed(uint8_t hwid, tu_edpt_stream_t* s, uint32_t last_xferred_bytes) { // ZLP condition: no pending data, last transferred bytes is multiple of packet size TU_VERIFY(!tu_fifo_count(&s->ff) && last_xferred_bytes && (0 == (last_xferred_bytes & (s->ep_packetsize - 1)))); - TU_VERIFY(stream_claim(s)); - TU_ASSERT(stream_xfer(s, 0)); + TU_VERIFY(stream_claim(hwid, s)); + TU_ASSERT(stream_xfer(hwid, s, 0)); return true; } -uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t* s) { +uint32_t tu_edpt_stream_write_xfer(uint8_t hwid, tu_edpt_stream_t* s) { // skip if no data TU_VERIFY(tu_fifo_count(&s->ff), 0); - TU_VERIFY(stream_claim(s), 0); + TU_VERIFY(stream_claim(hwid, s), 0); // Pull data from FIFO -> EP buf uint16_t const count = tu_fifo_read_n(&s->ff, s->ep_buf, s->ep_bufsize); if (count) { - TU_ASSERT(stream_xfer(s, count), 0); + TU_ASSERT(stream_xfer(hwid, s, count), 0); return count; } else { // Release endpoint since we don't make any transfer // Note: data is dropped if terminal is not connected - stream_release(s); + stream_release(hwid, s); return 0; } } -uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const* buffer, uint32_t bufsize) { +uint32_t tu_edpt_stream_write(uint8_t hwid, tu_edpt_stream_t* s, void const* buffer, uint32_t bufsize) { TU_VERIFY(bufsize); // TODO support ZLP if (0 == tu_fifo_depth(&s->ff)) { // no fifo for buffered - TU_VERIFY(stream_claim(s), 0); + TU_VERIFY(stream_claim(hwid, s), 0); const uint32_t xact_len = tu_min32(bufsize, s->ep_bufsize); memcpy(s->ep_buf, buffer, xact_len); - TU_ASSERT(stream_xfer(s, xact_len), 0); + TU_ASSERT(stream_xfer(hwid, s, xact_len), 0); return xact_len; } else { const uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize); @@ -325,24 +325,24 @@ uint32_t tu_edpt_stream_write(tu_edpt_stream_t* s, void const* buffer, uint32_t // flush if fifo has more than packet size or // in rare case: fifo depth is configured too small (which never reach packet size) if ((tu_fifo_count(&s->ff) >= s->ep_packetsize) || (tu_fifo_depth(&s->ff) < s->ep_packetsize)) { - tu_edpt_stream_write_xfer(s); + tu_edpt_stream_write_xfer(hwid, s); } return ret; } } -uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) { +uint32_t tu_edpt_stream_write_available(uint8_t hwid, tu_edpt_stream_t* s) { if (tu_fifo_depth(&s->ff)) { return (uint32_t) tu_fifo_remaining(&s->ff); } else { bool is_busy = true; if (s->is_host) { #if CFG_TUH_ENABLED - is_busy = usbh_edpt_busy(s->daddr, s->ep_addr); + is_busy = usbh_edpt_busy(hwid, s->ep_addr); #endif } else { #if CFG_TUD_ENABLED - is_busy = usbd_edpt_busy(s->rhport, s->ep_addr); + is_busy = usbd_edpt_busy(hwid, s->ep_addr); #endif } return is_busy ? 0 : s->ep_bufsize; @@ -352,11 +352,11 @@ uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t* s) { //--------------------------------------------------------------------+ // Stream Read //--------------------------------------------------------------------+ -uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) { +uint32_t tu_edpt_stream_read_xfer(uint8_t hwid, tu_edpt_stream_t* s) { if (0 == tu_fifo_depth(&s->ff)) { // no fifo for buffered - TU_VERIFY(stream_claim(s), 0); - TU_ASSERT(stream_xfer(s, s->ep_bufsize), 0); + TU_VERIFY(stream_claim(hwid, s), 0); + TU_ASSERT(stream_xfer(hwid, s, s->ep_bufsize), 0); return s->ep_bufsize; } else { uint16_t available = tu_fifo_remaining(&s->ff); @@ -367,7 +367,7 @@ uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) { // This pre-check reduces endpoint claiming TU_VERIFY(available >= s->ep_packetsize); - TU_VERIFY(stream_claim(s), 0); + TU_VERIFY(stream_claim(hwid, s), 0); // get available again since fifo can be changed before endpoint is claimed available = tu_fifo_remaining(&s->ff); @@ -376,19 +376,19 @@ uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t* s) { // multiple of packet size limit by ep bufsize uint16_t count = (uint16_t) (available & ~(s->ep_packetsize - 1)); count = tu_min16(count, s->ep_bufsize); - TU_ASSERT(stream_xfer(s, count), 0); + TU_ASSERT(stream_xfer(hwid, s, count), 0); return count; } else { // Release endpoint since we don't make any transfer - stream_release(s); + stream_release(hwid, s); return 0; } } } -uint32_t tu_edpt_stream_read(tu_edpt_stream_t* s, void* buffer, uint32_t bufsize) { +uint32_t tu_edpt_stream_read(uint8_t hwid, tu_edpt_stream_t* s, void* buffer, uint32_t bufsize) { uint32_t num_read = tu_fifo_read_n(&s->ff, buffer, (uint16_t) bufsize); - tu_edpt_stream_read_xfer(s); + tu_edpt_stream_read_xfer(hwid, s); return num_read; } From bbeae09259707ba6b79db55dda2fd89b9e99f14f Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 10 Sep 2024 17:45:03 +0700 Subject: [PATCH 06/11] update vendor device to use edpt stream which also support non-buffereed (no fifo) mode --- src/class/vendor/vendor_device.c | 170 +++++++++++-------------------- src/class/vendor/vendor_device.h | 117 ++++++++------------- 2 files changed, 101 insertions(+), 186 deletions(-) diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index d235302352..5d33d2e60e 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -38,8 +38,7 @@ //--------------------------------------------------------------------+ #define BULK_PACKET_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) -typedef struct -{ +typedef struct { uint8_t itf_num; uint8_t ep_in; uint8_t ep_out; @@ -49,19 +48,19 @@ typedef struct CFG_TUD_MEM_ALIGN uint8_t epout_buf[CFG_TUD_VENDOR_EPSIZE]; CFG_TUD_MEM_ALIGN uint8_t epin_buf[CFG_TUD_VENDOR_EPSIZE]; -#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 struct { tu_edpt_stream_t stream; + #if CFG_TUD_VENDOR_TX_BUFSIZE > 0 uint8_t ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE]; + #endif }tx; -#endif -#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 struct { tu_edpt_stream_t stream; + #if CFG_TUD_VENDOR_RX_BUFSIZE > 0 uint8_t ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE]; + #endif } rx; -#endif } vendord_interface_t; @@ -69,6 +68,10 @@ CFG_TUD_MEM_SECTION static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR]; #define ITF_MEM_RESET_SIZE offsetof(vendord_interface_t, ep_out) + sizeof(((vendord_interface_t *)0)->ep_out) +//-------------------------------------------------------------------- +// Application API +//-------------------------------------------------------------------- + bool tud_vendor_n_mounted (uint8_t itf) { return _vendord_itf[itf].ep_in && _vendord_itf[itf].ep_out; } @@ -76,91 +79,63 @@ bool tud_vendor_n_mounted (uint8_t itf) { //--------------------------------------------------------------------+ // Read API //--------------------------------------------------------------------+ -#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 -// static void _prep_out_transaction (vendord_interface_t* p_itf) -// { -// uint8_t const rhport = 0; -// -// // claim endpoint -// TU_VERIFY(usbd_edpt_claim(rhport, p_itf->ep_out), ); -// -// // Prepare for incoming data but only allow what we can store in the ring buffer. -// uint16_t max_read = tu_fifo_remaining(&p_itf->rx_ff); -// if ( max_read >= CFG_TUD_VENDOR_EPSIZE ) -// { -// usbd_edpt_xfer(rhport, p_itf->ep_out, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE); -// } -// else -// { -// // Release endpoint since we don't make any transfer -// usbd_edpt_release(rhport, p_itf->ep_out); -// } -// } - uint32_t tud_vendor_n_available (uint8_t itf) { TU_VERIFY(itf < CFG_TUD_VENDOR, 0); vendord_interface_t* p_itf = &_vendord_itf[itf]; + return tu_edpt_stream_read_available(&p_itf->rx.stream); } bool tud_vendor_n_peek(uint8_t itf, uint8_t* u8) { TU_VERIFY(itf < CFG_TUD_VENDOR, 0); vendord_interface_t* p_itf = &_vendord_itf[itf]; + return tu_edpt_stream_peek(&p_itf->rx.stream, u8); } uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize) { TU_VERIFY(itf < CFG_TUD_VENDOR, 0); vendord_interface_t* p_itf = &_vendord_itf[itf]; - return tu_edpt_stream_read(&p_itf->rx.stream, buffer, bufsize); + uint8_t const rhport = 0; + + return tu_edpt_stream_read(rhport, &p_itf->rx.stream, buffer, bufsize); } void tud_vendor_n_read_flush (uint8_t itf) { TU_VERIFY(itf < CFG_TUD_VENDOR, ); vendord_interface_t* p_itf = &_vendord_itf[itf]; + uint8_t const rhport = 0; tu_edpt_stream_clear(&p_itf->rx.stream); - tu_edpt_stream_read_xfer(&p_itf->rx.stream); + tu_edpt_stream_read_xfer(rhport, &p_itf->rx.stream); } -#endif //--------------------------------------------------------------------+ // Write API //--------------------------------------------------------------------+ uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize) { -#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 TU_VERIFY(itf < CFG_TUD_VENDOR, 0); vendord_interface_t* p_itf = &_vendord_itf[itf]; - return tu_edpt_stream_write(&p_itf->tx.stream, buffer, (uint16_t) bufsize); -#else uint8_t const rhport = 0; - vendord_interface_t* p_itf = &_vendord_itf[itf]; - // claim endpoint - TU_VERIFY(usbd_edpt_claim(rhport, p_itf->ep_in)); - - // prepare data - TU_VERIFY(0 == tu_memcpy_s(p_itf->epin_buf, CFG_TUD_VENDOR_EPSIZE, buffer, (uint16_t) bufsize)); - - TU_ASSERT(usbd_edpt_xfer(rhport, p_itf->ep_in, p_itf->epin_buf, (uint16_t) bufsize)); - - return bufsize; -#endif + return tu_edpt_stream_write(rhport, &p_itf->tx.stream, buffer, (uint16_t) bufsize); } -#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 uint32_t tud_vendor_n_write_flush (uint8_t itf) { TU_VERIFY(itf < CFG_TUD_VENDOR, 0); vendord_interface_t* p_itf = &_vendord_itf[itf]; - return tu_edpt_stream_write_xfer(&p_itf->tx.stream); + uint8_t const rhport = 0; + + return tu_edpt_stream_write_xfer(rhport, &p_itf->tx.stream); } uint32_t tud_vendor_n_write_available (uint8_t itf) { TU_VERIFY(itf < CFG_TUD_VENDOR, 0); vendord_interface_t* p_itf = &_vendord_itf[itf]; - return tu_edpt_stream_write_available(&p_itf->tx.stream); + uint8_t const rhport = 0; + + return tu_edpt_stream_write_available(rhport, &p_itf->tx.stream); } -#endif //--------------------------------------------------------------------+ // USBD Driver API @@ -171,46 +146,36 @@ void vendord_init(void) { for(uint8_t i=0; i 0 + uint8_t* rx_ff_buf = + #if CFG_TUD_VENDOR_RX_BUFSIZE > 0 + p_itf->rx.ff_buf; + #else + NULL; + #endif + tu_edpt_stream_init(&p_itf->rx.stream, false, false, false, - p_itf->rx.ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, + rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE); -#endif -#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 + uint8_t* tx_ff_buf = + #if CFG_TUD_VENDOR_TX_BUFSIZE > 0 + p_itf->tx.ff_buf; + #else + NULL; + #endif + tu_edpt_stream_init(&p_itf->tx.stream, false, true, false, - p_itf->tx.ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, + tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, p_itf->epin_buf, CFG_TUD_VENDOR_EPSIZE); -#endif } } bool vendord_deinit(void) { -#if OSAL_MUTEX_REQUIRED - #if CFG_TUD_VENDOR_RX_BUFSIZE > 0 for(uint8_t i=0; irx_ff.mutex_rd; - - if (mutex_rd) { - osal_mutex_delete(mutex_rd); - tu_fifo_config_mutex(&p_itf->rx_ff, NULL, NULL); - } + tu_edpt_stream_deinit(&p_itf->rx.stream); + tu_edpt_stream_deinit(&p_itf->tx.stream); } - #endif - #if CFG_TUD_VENDOR_TX_BUFSIZE > 0 - for(uint8_t i=0; itx_ff.mutex_wr; - - if (mutex_wr) { - osal_mutex_delete(mutex_wr); - tu_fifo_config_mutex(&p_itf->tx_ff, NULL, NULL); - } - } - #endif -#endif return true; } @@ -219,14 +184,9 @@ void vendord_reset(uint8_t rhport) { for(uint8_t i=0; i 0 tu_edpt_stream_clear(&p_itf->rx.stream); -#endif -#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 tu_edpt_stream_clear(&p_itf->tx.stream); -#endif } } @@ -262,23 +222,12 @@ uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, ui if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) { p_vendor->ep_in = desc_ep->bEndpointAddress; - - #if CFG_TUD_VENDOR_TX_BUFSIZE > 0 - tu_edpt_stream_open(&p_vendor->tx.stream, rhport, desc_ep); + tu_edpt_stream_open(&p_vendor->tx.stream, desc_ep); tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf)); - #endif } else { p_vendor->ep_out = desc_ep->bEndpointAddress; - - #if CFG_TUD_VENDOR_RX_BUFSIZE > 0 - tu_edpt_stream_open(&p_vendor->rx.stream, rhport, desc_ep); - TU_ASSERT(tu_edpt_stream_read_xfer(&p_vendor->rx.stream) > 0, 0); // prepare for incoming data - #else - if ( !usbd_edpt_xfer(rhport, p_vendor->ep_out, p_vendor->epout_buf, CFG_TUD_VENDOR_EPSIZE) ) { - TU_LOG_FAILED(); - TU_BREAKPOINT(); - } - #endif + tu_edpt_stream_open(&p_vendor->rx.stream, desc_ep); + TU_ASSERT(tu_edpt_stream_read_xfer(rhport, &p_vendor->rx.stream) > 0, 0); // prepare for incoming data } p_desc = tu_desc_next(p_desc); @@ -288,44 +237,39 @@ uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, ui } bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { - (void) rhport; (void) result; uint8_t itf = 0; vendord_interface_t* p_itf = _vendord_itf; for ( ; ; itf++, p_itf++) { - if (itf >= TU_ARRAY_SIZE(_vendord_itf)) return false; - if ( ( ep_addr == p_itf->ep_out ) || ( ep_addr == p_itf->ep_in ) ) break; + if (itf >= CFG_TUD_VENDOR) return false; + if ((ep_addr == p_itf->rx.stream.ep_addr) || (ep_addr == p_itf->tx.stream.ep_addr)) break; } - if ( ep_addr == p_itf->ep_out ) { -#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 - // Receive new data, put it into stream's fifo + if ( ep_addr == p_itf->rx.stream.ep_addr ) { + // Received new data: put into stream's fifo tu_edpt_stream_read_xfer_complete(&p_itf->rx.stream, xferred_bytes); -#endif // Invoked callback if any if (tud_vendor_rx_cb) { tud_vendor_rx_cb(itf, p_itf->epout_buf, (uint16_t) xferred_bytes); } -#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 - tu_edpt_stream_read_xfer(&p_itf->rx.stream); -#else - TU_ASSERT(usbd_edpt_xfer(rhport, p_itf->ep_out, p_itf->epout_buf, CFG_TUD_VENDOR_EPSIZE)); -#endif - } else if ( ep_addr == p_itf->ep_in ) { + tu_edpt_stream_read_xfer(rhport, &p_itf->rx.stream); + } else if ( ep_addr == p_itf->tx.stream.ep_addr ) { + // Send complete if (tud_vendor_tx_cb) { tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes); } -#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 - // Send complete, try to send more if possible - if ( 0 == tu_edpt_stream_write_xfer(&p_itf->tx.stream) ) { + + #if CFG_TUD_VENDOR_TX_BUFSIZE > 0 + // try to send more if possible + if ( 0 == tu_edpt_stream_write_xfer(rhport, &p_itf->tx.stream) ) { // If there is no data left, a ZLP should be sent if xferred_bytes is multiple of EP Packet size and not zero - tu_edpt_stream_write_zlp_if_needed(&p_itf->tx.stream, xferred_bytes); + tu_edpt_stream_write_zlp_if_needed(rhport, &p_itf->tx.stream, xferred_bytes); } -#endif + #endif } return true; diff --git a/src/class/vendor/vendor_device.h b/src/class/vendor/vendor_device.h index 4a0cc31519..149ae2d564 100644 --- a/src/class/vendor/vendor_device.h +++ b/src/class/vendor/vendor_device.h @@ -33,12 +33,12 @@ #define CFG_TUD_VENDOR_EPSIZE 64 #endif -/* RX FIFO can be disabled by setting this value to 0, related API will also be disabled */ +// RX FIFO can be disabled by setting this value to 0 #ifndef CFG_TUD_VENDOR_RX_BUFSIZE #define CFG_TUD_VENDOR_RX_BUFSIZE 64 #endif -/* TX FIFO can be disabled by setting this value to 0, related API will also be disabled */ +// TX FIFO can be disabled by setting this value to 0 #ifndef CFG_TUD_VENDOR_TX_BUFSIZE #define CFG_TUD_VENDOR_TX_BUFSIZE 64 #endif @@ -48,115 +48,86 @@ #endif //--------------------------------------------------------------------+ -// Application API (Multiple Interfaces) +// Application API (Multiple Interfaces) i.e CFG_TUD_VENDOR > 1 //--------------------------------------------------------------------+ bool tud_vendor_n_mounted (uint8_t itf); - -#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 uint32_t tud_vendor_n_available (uint8_t itf); uint32_t tud_vendor_n_read (uint8_t itf, void* buffer, uint32_t bufsize); bool tud_vendor_n_peek (uint8_t itf, uint8_t* ui8); void tud_vendor_n_read_flush (uint8_t itf); -#endif uint32_t tud_vendor_n_write (uint8_t itf, void const* buffer, uint32_t bufsize); -#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 uint32_t tud_vendor_n_write_flush (uint8_t itf); uint32_t tud_vendor_n_write_available (uint8_t itf); -#endif -static inline uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str); -#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 -// backward compatible -#define tud_vendor_n_flush(itf) tud_vendor_n_write_flush(itf) -#endif - -//--------------------------------------------------------------------+ -// Application API (Single Port) -//--------------------------------------------------------------------+ -static inline bool tud_vendor_mounted (void); -#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 -static inline uint32_t tud_vendor_available (void); -static inline uint32_t tud_vendor_read (void* buffer, uint32_t bufsize); -static inline bool tud_vendor_peek (uint8_t* ui8); -static inline void tud_vendor_read_flush (void); -#endif -static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize); -static inline uint32_t tud_vendor_write_str (char const* str); -#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 -static inline uint32_t tud_vendor_write_available (void); -static inline uint32_t tud_vendor_write_flush (void); +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str); // backward compatible -#define tud_vendor_flush() tud_vendor_write_flush() -#endif -//--------------------------------------------------------------------+ -// Application Callback API (weak is optional) -//--------------------------------------------------------------------+ - -// Invoked when received new data -TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t itf, uint8_t const* buffer, uint16_t bufsize); -// Invoked when last rx transfer finished -TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes); +#define tud_vendor_n_flush(itf) tud_vendor_n_write_flush(itf) //--------------------------------------------------------------------+ -// Inline Functions +// Application API (Single Port) i.e CFG_TUD_VENDOR = 1 //--------------------------------------------------------------------+ -static inline uint32_t tud_vendor_n_write_str (uint8_t itf, char const* str) -{ - return tud_vendor_n_write(itf, str, strlen(str)); +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_n_write_str(uint8_t itf, char const* str) { + return tud_vendor_n_write(itf, str, strlen(str)); } -static inline bool tud_vendor_mounted (void) -{ - return tud_vendor_n_mounted(0); +TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_mounted(void) { + return tud_vendor_n_mounted(0); } -#if CFG_TUD_VENDOR_RX_BUFSIZE > 0 -static inline uint32_t tud_vendor_available (void) -{ - return tud_vendor_n_available(0); +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_available(void) { + return tud_vendor_n_available(0); } -static inline uint32_t tud_vendor_read (void* buffer, uint32_t bufsize) -{ - return tud_vendor_n_read(0, buffer, bufsize); +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_read(void* buffer, uint32_t bufsize) { + return tud_vendor_n_read(0, buffer, bufsize); } -static inline bool tud_vendor_peek (uint8_t* ui8) -{ - return tud_vendor_n_peek(0, ui8); +TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_peek(uint8_t* ui8) { + return tud_vendor_n_peek(0, ui8); } -static inline void tud_vendor_read_flush(void) -{ - tud_vendor_n_read_flush(0); +TU_ATTR_ALWAYS_INLINE static inline void tud_vendor_read_flush(void) { + tud_vendor_n_read_flush(0); } -#endif -static inline uint32_t tud_vendor_write (void const* buffer, uint32_t bufsize) -{ - return tud_vendor_n_write(0, buffer, bufsize); +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write(void const* buffer, uint32_t bufsize) { + return tud_vendor_n_write(0, buffer, bufsize); } -static inline uint32_t tud_vendor_write_str (char const* str) -{ - return tud_vendor_n_write_str(0, str); +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_str(char const* str) { + return tud_vendor_n_write_str(0, str); } -#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 -static inline uint32_t tud_vendor_write_flush (void) -{ - return tud_vendor_n_write_flush(0); +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_flush(void) { + return tud_vendor_n_write_flush(0); } -static inline uint32_t tud_vendor_write_available (void) -{ - return tud_vendor_n_write_available(0); +#if CFG_TUD_VENDOR_TX_BUFSIZE > 0 +TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_available(void) { + return tud_vendor_n_write_available(0); } #endif +// backward compatible +#define tud_vendor_flush() tud_vendor_write_flush() + +//--------------------------------------------------------------------+ +// Application Callback API (weak is optional) +//--------------------------------------------------------------------+ + +// Invoked when received new data +TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t itf, uint8_t const* buffer, uint16_t bufsize); +// Invoked when last rx transfer finished +TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t itf, uint32_t sent_bytes); + +//--------------------------------------------------------------------+ +// Inline Functions +//--------------------------------------------------------------------+ + + //--------------------------------------------------------------------+ // Internal Class Driver API //--------------------------------------------------------------------+ From 7373a0239645b48bbd1c11e9542699924e1f3a0d Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 10 Sep 2024 18:13:38 +0700 Subject: [PATCH 07/11] minor clean up --- examples/device/webusb_serial/src/main.c | 124 +++++++----------- .../device/webusb_serial/src/tusb_config.h | 2 +- src/common/tusb_private.h | 14 +- 3 files changed, 51 insertions(+), 89 deletions(-) diff --git a/examples/device/webusb_serial/src/main.c b/examples/device/webusb_serial/src/main.c index 800d435b8a..bcc33f657e 100644 --- a/examples/device/webusb_serial/src/main.c +++ b/examples/device/webusb_serial/src/main.c @@ -73,8 +73,7 @@ static uint32_t blink_interval_ms = BLINK_NOT_MOUNTED; #define URL "example.tinyusb.org/webusb-serial/index.html" -const tusb_desc_webusb_url_t desc_url = -{ +const tusb_desc_webusb_url_t desc_url = { .bLength = 3 + sizeof(URL) - 1, .bDescriptorType = 3, // WEBUSB URL type .bScheme = 1, // 0: http, 1: https @@ -86,11 +85,9 @@ static bool web_serial_connected = false; //------------- prototypes -------------// void led_blinking_task(void); void cdc_task(void); -void webserial_task(void); /*------------- MAIN -------------*/ -int main(void) -{ +int main(void) { board_init(); // init device stack on configured roothub port @@ -100,33 +97,28 @@ int main(void) board_init_after_tusb(); } - while (1) - { + while (1) { tud_task(); // tinyusb device task cdc_task(); - webserial_task(); led_blinking_task(); } } // send characters to both CDC and WebUSB -void echo_all(uint8_t buf[], uint32_t count) -{ +void echo_all(const uint8_t buf[], uint32_t count) { // echo to web serial - if ( web_serial_connected ) - { + if (web_serial_connected) { tud_vendor_write(buf, count); tud_vendor_write_flush(); } // echo to cdc - if ( tud_cdc_connected() ) - { - for(uint32_t i=0; ibmRequestType_bit.type) - { + switch (request->bmRequestType_bit.type) { case TUSB_REQ_TYPE_VENDOR: - switch (request->bRequest) - { + switch (request->bRequest) { case VENDOR_REQUEST_WEBUSB: // match vendor request in BOS descriptor // Get landing page url - return tud_control_xfer(rhport, request, (void*)(uintptr_t) &desc_url, desc_url.bLength); + return tud_control_xfer(rhport, request, (void*)(uintptr_t)&desc_url, desc_url.bLength); case VENDOR_REQUEST_MICROSOFT: - if ( request->wIndex == 7 ) - { + if (request->wIndex == 7) { // Get Microsoft OS 2.0 compatible descriptor uint16_t total_len; - memcpy(&total_len, desc_ms_os_20+8, 2); + memcpy(&total_len, desc_ms_os_20 + 8, 2); - return tud_control_xfer(rhport, request, (void*)(uintptr_t) desc_ms_os_20, total_len); - }else - { + return tud_control_xfer(rhport, request, (void*)(uintptr_t)desc_ms_os_20, total_len); + } else { return false; } default: break; } - break; + break; case TUSB_REQ_TYPE_CLASS: - if (request->bRequest == 0x22) - { + if (request->bRequest == 0x22) { // Webserial simulate the CDC_REQUEST_SET_CONTROL_LINE_STATE (0x22) to connect and disconnect. web_serial_connected = (request->wValue != 0); // Always lit LED if connected - if ( web_serial_connected ) - { + if (web_serial_connected) { board_led_write(true); blink_interval_ms = BLINK_ALWAYS_ON; tud_vendor_write_str("\r\nWebUSB interface connected\r\n"); tud_vendor_write_flush(); - }else - { + } else { blink_interval_ms = BLINK_MOUNTED; } // response with status OK return tud_control_status(rhport, request); } - break; + break; default: break; } @@ -233,32 +213,24 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ return false; } -void webserial_task(void) -{ - if ( web_serial_connected ) - { - if ( tud_vendor_available() ) - { - uint8_t buf[64]; - uint32_t count = tud_vendor_read(buf, sizeof(buf)); +void tud_vendor_rx_cb(uint8_t itf, uint8_t const* buffer, uint16_t bufsize) { + (void) itf; - // echo back to both web serial and cdc - echo_all(buf, count); - } - } -} + echo_all(buffer, bufsize); + // if using RX buffered is enabled, we need to flush the buffer to make room for new data + #if CFG_TUD_VENDOR_RX_BUFSIZE > 0 + tud_vendor_read_flush(); + #endif +} //--------------------------------------------------------------------+ // USB CDC //--------------------------------------------------------------------+ -void cdc_task(void) -{ - if ( tud_cdc_connected() ) - { +void cdc_task(void) { + if (tud_cdc_connected()) { // connected and there are data available - if ( tud_cdc_available() ) - { + if (tud_cdc_available()) { uint8_t buf[64]; uint32_t count = tud_cdc_read(buf, sizeof(buf)); @@ -270,34 +242,30 @@ void cdc_task(void) } // Invoked when cdc when line state changed e.g connected/disconnected -void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) -{ - (void) itf; +void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) { + (void)itf; // connected - if ( dtr && rts ) - { + if (dtr && rts) { // print initial message when connected tud_cdc_write_str("\r\nTinyUSB WebUSB device example\r\n"); } } // Invoked when CDC interface received data from host -void tud_cdc_rx_cb(uint8_t itf) -{ - (void) itf; +void tud_cdc_rx_cb(uint8_t itf) { + (void)itf; } //--------------------------------------------------------------------+ // BLINKING TASK //--------------------------------------------------------------------+ -void led_blinking_task(void) -{ +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 + if (board_millis() - start_ms < blink_interval_ms) return; // not enough time start_ms += blink_interval_ms; board_led_write(led_state); diff --git a/examples/device/webusb_serial/src/tusb_config.h b/examples/device/webusb_serial/src/tusb_config.h index fde732b9ec..b86ad37525 100644 --- a/examples/device/webusb_serial/src/tusb_config.h +++ b/examples/device/webusb_serial/src/tusb_config.h @@ -102,7 +102,7 @@ #define CFG_TUD_CDC_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) // Vendor FIFO size of TX and RX -// If not configured vendor endpoints will not be buffered +// If zero: vendor endpoints will not be buffered #define CFG_TUD_VENDOR_RX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) #define CFG_TUD_VENDOR_TX_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h index 71a395c79e..ce42d7ef68 100644 --- a/src/common/tusb_private.h +++ b/src/common/tusb_private.h @@ -34,29 +34,24 @@ extern "C" { #endif -typedef struct TU_ATTR_PACKED -{ +typedef struct TU_ATTR_PACKED { volatile uint8_t busy : 1; volatile uint8_t stalled : 1; volatile uint8_t claimed : 1; }tu_edpt_state_t; typedef struct { - struct { - uint8_t is_host : 1; // host or device - uint8_t is_highspeed: 1; // is highspeed - }; + uint8_t is_host; // 1: host, 0: device uint8_t ep_addr; uint16_t ep_packetsize; uint16_t ep_bufsize; - // TODO xfer_fifo can skip this buffer - uint8_t* ep_buf; + uint8_t* ep_buf; // TODO xfer_fifo can skip this buffer tu_fifo_t ff; - // mutex: read if ep rx, write if e tx + // mutex: read if rx, otherwise write OSAL_MUTEX_DEF(ff_mutexdef); }tu_edpt_stream_t; @@ -92,7 +87,6 @@ bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool ove bool tu_edpt_stream_deinit(tu_edpt_stream_t* s); // Open an stream for an endpoint -// hwid is either device address (host mode) or rhport (device mode) TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_open(tu_edpt_stream_t* s, tusb_desc_endpoint_t const *desc_ep) { tu_fifo_clear(&s->ff); From 3ab63fbc65ce1d6333594fec23f1e2239588ea31 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 10 Sep 2024 18:27:22 +0700 Subject: [PATCH 08/11] remove vendor ep_addr, use stream api instead --- .idea/cmake.xml | 12 ++++++------ src/class/vendor/vendor_device.c | 20 ++++++++------------ src/common/tusb_private.h | 1 - 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/.idea/cmake.xml b/.idea/cmake.xml index e8b46d468d..fec01a08e5 100644 --- a/.idea/cmake.xml +++ b/.idea/cmake.xml @@ -2,8 +2,8 @@ - - + + @@ -35,7 +35,7 @@ - + @@ -66,7 +66,7 @@ - + @@ -140,8 +140,8 @@ - - + + diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c index 5d33d2e60e..15829991a6 100644 --- a/src/class/vendor/vendor_device.c +++ b/src/class/vendor/vendor_device.c @@ -36,12 +36,8 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -#define BULK_PACKET_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64) - typedef struct { uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; /*------------- From this point, data is not cleared by bus reset -------------*/ // Endpoint Transfer buffer @@ -66,20 +62,22 @@ typedef struct { CFG_TUD_MEM_SECTION static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR]; -#define ITF_MEM_RESET_SIZE offsetof(vendord_interface_t, ep_out) + sizeof(((vendord_interface_t *)0)->ep_out) +#define ITF_MEM_RESET_SIZE (offsetof(vendord_interface_t, itf_num) + sizeof(((vendord_interface_t *)0)->itf_num)) //-------------------------------------------------------------------- // Application API //-------------------------------------------------------------------- -bool tud_vendor_n_mounted (uint8_t itf) { - return _vendord_itf[itf].ep_in && _vendord_itf[itf].ep_out; +bool tud_vendor_n_mounted(uint8_t itf) { + TU_VERIFY(itf < CFG_TUD_VENDOR); + vendord_interface_t* p_itf = &_vendord_itf[itf]; + return p_itf->rx.stream.ep_addr || p_itf->tx.stream.ep_addr; } //--------------------------------------------------------------------+ // Read API //--------------------------------------------------------------------+ -uint32_t tud_vendor_n_available (uint8_t itf) { +uint32_t tud_vendor_n_available(uint8_t itf) { TU_VERIFY(itf < CFG_TUD_VENDOR, 0); vendord_interface_t* p_itf = &_vendord_itf[itf]; @@ -87,7 +85,7 @@ uint32_t tud_vendor_n_available (uint8_t itf) { } bool tud_vendor_n_peek(uint8_t itf, uint8_t* u8) { - TU_VERIFY(itf < CFG_TUD_VENDOR, 0); + TU_VERIFY(itf < CFG_TUD_VENDOR); vendord_interface_t* p_itf = &_vendord_itf[itf]; return tu_edpt_stream_peek(&p_itf->rx.stream, u8); @@ -198,7 +196,7 @@ uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, ui // Find available interface vendord_interface_t* p_vendor = NULL; for(uint8_t i=0; ibEndpointAddress) == TUSB_DIR_IN) { - p_vendor->ep_in = desc_ep->bEndpointAddress; tu_edpt_stream_open(&p_vendor->tx.stream, desc_ep); tud_vendor_n_write_flush((uint8_t)(p_vendor - _vendord_itf)); } else { - p_vendor->ep_out = desc_ep->bEndpointAddress; tu_edpt_stream_open(&p_vendor->rx.stream, desc_ep); TU_ASSERT(tu_edpt_stream_read_xfer(rhport, &p_vendor->rx.stream) > 0, 0); // prepare for incoming data } diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h index ce42d7ef68..2cf11ea945 100644 --- a/src/common/tusb_private.h +++ b/src/common/tusb_private.h @@ -46,7 +46,6 @@ typedef struct { uint16_t ep_packetsize; uint16_t ep_bufsize; - uint8_t* ep_buf; // TODO xfer_fifo can skip this buffer tu_fifo_t ff; From dd1822ba032e3e86efd445cda1c3fd0e8f342bbc Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 10 Sep 2024 18:37:53 +0700 Subject: [PATCH 09/11] reduce ep stream footprint by using is_mps512 since it only support bulk so far --- src/common/tusb_private.h | 11 ++++++----- src/tusb.c | 13 ++++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h index 2cf11ea945..8a479c0424 100644 --- a/src/common/tusb_private.h +++ b/src/common/tusb_private.h @@ -41,13 +41,14 @@ typedef struct TU_ATTR_PACKED { }tu_edpt_state_t; typedef struct { - uint8_t is_host; // 1: host, 0: device + struct TU_ATTR_PACKED { + uint8_t is_host : 1; // 1: host, 0: device + uint8_t is_mps512 : 1; // 1: 512, 0: 64 since stream is used for Bulk only + }; uint8_t ep_addr; - - uint16_t ep_packetsize; uint16_t ep_bufsize; - uint8_t* ep_buf; // TODO xfer_fifo can skip this buffer + uint8_t* ep_buf; // TODO xfer_fifo can skip this buffer tu_fifo_t ff; // mutex: read if rx, otherwise write @@ -90,7 +91,7 @@ TU_ATTR_ALWAYS_INLINE static inline void tu_edpt_stream_open(tu_edpt_stream_t* s, tusb_desc_endpoint_t const *desc_ep) { tu_fifo_clear(&s->ff); s->ep_addr = desc_ep->bEndpointAddress; - s->ep_packetsize = tu_edpt_packet_size(desc_ep); + s->is_mps512 = (tu_edpt_packet_size(desc_ep) == 512) ? 1 : 0; } TU_ATTR_ALWAYS_INLINE static inline diff --git a/src/tusb.c b/src/tusb.c index 69c1f97750..bdd1fba99d 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -283,7 +283,8 @@ TU_ATTR_ALWAYS_INLINE static inline bool stream_release(uint8_t hwid, tu_edpt_st //--------------------------------------------------------------------+ bool tu_edpt_stream_write_zlp_if_needed(uint8_t hwid, tu_edpt_stream_t* s, uint32_t last_xferred_bytes) { // ZLP condition: no pending data, last transferred bytes is multiple of packet size - TU_VERIFY(!tu_fifo_count(&s->ff) && last_xferred_bytes && (0 == (last_xferred_bytes & (s->ep_packetsize - 1)))); + const uint16_t mps = s->is_mps512 ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; + TU_VERIFY(!tu_fifo_count(&s->ff) && last_xferred_bytes && (0 == (last_xferred_bytes & (mps - 1)))); TU_VERIFY(stream_claim(hwid, s)); TU_ASSERT(stream_xfer(hwid, s, 0)); return true; @@ -324,7 +325,8 @@ uint32_t tu_edpt_stream_write(uint8_t hwid, tu_edpt_stream_t* s, void const* buf // flush if fifo has more than packet size or // in rare case: fifo depth is configured too small (which never reach packet size) - if ((tu_fifo_count(&s->ff) >= s->ep_packetsize) || (tu_fifo_depth(&s->ff) < s->ep_packetsize)) { + const uint16_t mps = s->is_mps512 ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; + if ((tu_fifo_count(&s->ff) >= mps) || (tu_fifo_depth(&s->ff) < mps)) { tu_edpt_stream_write_xfer(hwid, s); } return ret; @@ -359,22 +361,23 @@ uint32_t tu_edpt_stream_read_xfer(uint8_t hwid, tu_edpt_stream_t* s) { TU_ASSERT(stream_xfer(hwid, s, s->ep_bufsize), 0); return s->ep_bufsize; } else { + const uint16_t mps = s->is_mps512 ? TUSB_EPSIZE_BULK_HS : TUSB_EPSIZE_BULK_FS; uint16_t available = tu_fifo_remaining(&s->ff); // Prepare for incoming data but only allow what we can store in the ring buffer. // TODO Actually we can still carry out the transfer, keeping count of received bytes // and slowly move it to the FIFO when read(). // This pre-check reduces endpoint claiming - TU_VERIFY(available >= s->ep_packetsize); + TU_VERIFY(available >= mps); TU_VERIFY(stream_claim(hwid, s), 0); // get available again since fifo can be changed before endpoint is claimed available = tu_fifo_remaining(&s->ff); - if (available >= s->ep_packetsize) { + if (available >= mps) { // multiple of packet size limit by ep bufsize - uint16_t count = (uint16_t) (available & ~(s->ep_packetsize - 1)); + uint16_t count = (uint16_t) (available & ~(mps - 1)); count = tu_min16(count, s->ep_bufsize); TU_ASSERT(stream_xfer(hwid, s, count), 0); return count; From 7909a6256941d001ae888530080fc572c7410b3b Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 10 Sep 2024 18:47:58 +0700 Subject: [PATCH 10/11] fix warnings --- src/tusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tusb.c b/src/tusb.c index bdd1fba99d..80073c2594 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -318,7 +318,7 @@ uint32_t tu_edpt_stream_write(uint8_t hwid, tu_edpt_stream_t* s, void const* buf TU_VERIFY(stream_claim(hwid, s), 0); const uint32_t xact_len = tu_min32(bufsize, s->ep_bufsize); memcpy(s->ep_buf, buffer, xact_len); - TU_ASSERT(stream_xfer(hwid, s, xact_len), 0); + TU_ASSERT(stream_xfer(hwid, s, (uint16_t) xact_len), 0); return xact_len; } else { const uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize); From 9b4bb61cbd1f95d4272c4bf30e843e3807d932d5 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 10 Sep 2024 20:39:29 +0700 Subject: [PATCH 11/11] ep stream init: wrap with OSAL_MUTEX_REQUIRED, only create fifo mutex if needed --- src/tusb.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/tusb.c b/src/tusb.c index 80073c2594..11690b2036 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -216,13 +216,17 @@ uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, bool tu_edpt_stream_init(tu_edpt_stream_t* s, bool is_host, bool is_tx, bool overwritable, void* ff_buf, uint16_t ff_bufsize, uint8_t* ep_buf, uint16_t ep_bufsize) { - osal_mutex_t new_mutex = osal_mutex_create(&s->ff_mutexdef); - (void) new_mutex; (void) is_tx; s->is_host = is_host; tu_fifo_config(&s->ff, ff_buf, ff_bufsize, 1, overwritable); - tu_fifo_config_mutex(&s->ff, is_tx ? new_mutex : NULL, is_tx ? NULL : new_mutex); + + #if OSAL_MUTEX_REQUIRED + if (ff_buf && ff_bufsize) { + osal_mutex_t new_mutex = osal_mutex_create(&s->ff_mutexdef); + tu_fifo_config_mutex(&s->ff, is_tx ? new_mutex : NULL, is_tx ? NULL : new_mutex); + } + #endif s->ep_buf = ep_buf; s->ep_bufsize = ep_bufsize;