From 7c0cc53aed7744f6beeee74837c162c196cb3df0 Mon Sep 17 00:00:00 2001 From: Mark Smith <mark-github@halibut.com> Date: Fri, 21 Feb 2025 17:49:44 -0800 Subject: [PATCH 1/9] Handle Notification Endpoint, can send CTS/DSR/DCD/RI. #491 --- src/arduino/Adafruit_USBD_CDC.cpp | 44 +++++++++++++++++++++++++ src/arduino/Adafruit_USBD_CDC.h | 15 ++++++++- src/class/cdc/cdc.h | 42 +++++++++++++++++++++++ src/class/cdc/cdc_device.c | 55 ++++++++++++++++++++++++++++--- src/class/cdc/cdc_device.h | 14 ++++++++ src/common/tusb_types.h | 21 ++++++++++++ 6 files changed, 185 insertions(+), 6 deletions(-) diff --git a/src/arduino/Adafruit_USBD_CDC.cpp b/src/arduino/Adafruit_USBD_CDC.cpp index 893db83e..ce0583b7 100644 --- a/src/arduino/Adafruit_USBD_CDC.cpp +++ b/src/arduino/Adafruit_USBD_CDC.cpp @@ -170,6 +170,50 @@ int Adafruit_USBD_CDC::dtr(void) { return tud_cdc_n_connected(_instance); } +inline bool Adafruit_USBD_CDC::rts(void) { + return tud_cdc_n_get_line_state(_instance) & CDC_CONTROL_LINE_STATE_RTS; +} + +inline bool Adafruit_USBD_CDC::cts(void) { + return tud_cdc_n_get_serial_state(_instance).cts; +} + +inline bool Adafruit_USBD_CDC::dsr(void) { + return tud_cdc_n_get_serial_state(_instance).dsr; +} + +inline bool Adafruit_USBD_CDC::dcd(void) { + return tud_cdc_n_get_serial_state(_instance).dcd; +} + +inline bool Adafruit_USBD_CDC::ri(void) { + return tud_cdc_n_get_serial_state(_instance).ri; +} + +void Adafruit_USBD_CDC::cts(bool c) { + cdc_serial_state_t serial_state = tud_cdc_n_get_serial_state(_instance); + serial_state.cts = c; + tud_cdc_n_set_serial_state(_instance, serial_state); +} + +void Adafruit_USBD_CDC::dsr(bool c) { + cdc_serial_state_t serial_state = tud_cdc_n_get_serial_state(_instance); + serial_state.dsr = c; + tud_cdc_n_set_serial_state(_instance, serial_state); +} + +void Adafruit_USBD_CDC::dcd(bool c) { + cdc_serial_state_t serial_state = tud_cdc_n_get_serial_state(_instance); + serial_state.dcd = c; + tud_cdc_n_set_serial_state(_instance, serial_state); +} + +void Adafruit_USBD_CDC::ri(bool c) { + cdc_serial_state_t serial_state = tud_cdc_n_get_serial_state(_instance); + serial_state.ri = c; + tud_cdc_n_set_serial_state(_instance, serial_state); +} + Adafruit_USBD_CDC::operator bool() { if (!isValid()) { return false; diff --git a/src/arduino/Adafruit_USBD_CDC.h b/src/arduino/Adafruit_USBD_CDC.h index 9c0952f3..2fcd71ab 100644 --- a/src/arduino/Adafruit_USBD_CDC.h +++ b/src/arduino/Adafruit_USBD_CDC.h @@ -59,7 +59,20 @@ class Adafruit_USBD_CDC : public Stream, public Adafruit_USBD_Interface { uint8_t stopbits(void); uint8_t paritytype(void); uint8_t numbits(void); - int dtr(void); + + // Flow control bit getters. + int dtr(void); // pre-existing, I don't want to change the return type. + bool rts(void); + bool cts(void); + bool dsr(void); + bool dcd(void); + bool ri(void); + + // Flow control bit setters. + void cts(bool c); + void dsr(bool c); + void dcd(bool c); + void ri(bool c); // Stream API virtual int available(void); diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index da490a6d..cb31fdff 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -412,6 +412,48 @@ typedef struct TU_ATTR_PACKED TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct"); +//--------------------------------------------------------------------+ +// Notifications +//--------------------------------------------------------------------+ + +typedef struct TU_ATTR_PACKED { + uint16_t dcd :1; + uint16_t dsr :1; + uint16_t break_err :1; + uint16_t ri :1; + uint16_t frame_err :1; + uint16_t parity_err :1; + uint16_t overrun_err :1; + uint16_t cts :1; // https://community.st.com/t5/stm32-mcus-products/cts-signal-on-usb-cdc/td-p/325800 + uint16_t :8; +} cdc_serial_state_t; + +TU_VERIFY_STATIC(sizeof(cdc_serial_state_t) == 2, "size is not correct"); + +// Add more notifications here. PSTN120.pdf, Section 6.5 +typedef struct TU_ATTR_PACKED { + tusb_notification_t header; + union { + cdc_serial_state_t serial_state; + // Add more Notification "Data" payloads here as more are implemented. + }; +} cdc_notify_struct_t; + +TU_VERIFY_STATIC(sizeof(cdc_notify_struct_t) == 10, "size is not correct"); + +tu_static const cdc_notify_struct_t cdc_notify_serial_status = { + .header = { + .bmRequestType_bit = { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN, + }, + .bNotification = CDC_NOTIF_SERIAL_STATE, + .wValue = 0, + .wLength = sizeof(cdc_serial_state_t), + } +}; + TU_ATTR_PACKED_END // End of all packed definitions TU_ATTR_BIT_FIELD_ORDER_END diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index 6fccab6d..18fd3fda 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -59,6 +59,10 @@ typedef struct { // Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) uint8_t line_state; + // Notify host of flow control bits: CTS, DSR, DCD, RI, and some error flags. + cdc_serial_state_t serial_state; + bool serial_state_changed; + /*------------- From this point, data is not cleared by bus reset -------------*/ char wanted_char; TU_ATTR_ALIGNED(4) cdc_line_coding_t line_coding; @@ -76,6 +80,7 @@ typedef struct { // Endpoint Transfer buffer CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_CDC_EP_BUFSIZE]; CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_CDC_EP_BUFSIZE]; + CFG_TUSB_MEM_ALIGN cdc_notify_struct_t epnotif_buf; } cdcd_interface_t; #define ITF_MEM_RESET_SIZE offsetof(cdcd_interface_t, wanted_char) @@ -138,6 +143,18 @@ uint8_t tud_cdc_n_get_line_state(uint8_t itf) { return _cdcd_itf[itf].line_state; } +cdc_serial_state_t tud_cdc_n_get_serial_state(uint8_t itf) { + return _cdcd_itf[itf].serial_state; +} + +void tud_cdc_n_set_serial_state(uint8_t itf, cdc_serial_state_t serial_state) { + if (memcmp(&(_cdcd_itf[itf].serial_state), &serial_state, sizeof(serial_state)) != 0) { + TU_LOG_DRV(" Serial State Changed: %x -> %x\r\n", _cdcd_itf[itf].serial_state, serial_state); + _cdcd_itf[itf].serial_state_changed = true; + } + _cdcd_itf[itf].serial_state = serial_state; +} + void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t* coding) { (*coding) = _cdcd_itf[itf].line_coding; } @@ -326,10 +343,13 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1 if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) { // notification endpoint - tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) p_desc; + tusb_desc_endpoint_t desc_ep = *(tusb_desc_endpoint_t const*) p_desc; + TU_LOG_DRV(" Interval before: %d\r\n", desc_ep.bInterval); + + desc_ep.bInterval = 1; // Query every frame, 1ms at Full Speed. - TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); - p_cdc->ep_notif = desc_ep->bEndpointAddress; + TU_ASSERT(usbd_edpt_open(rhport, &desc_ep), 0); + p_cdc->ep_notif = desc_ep.bEndpointAddress; drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); @@ -437,12 +457,13 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // Identify which interface to use for (itf = 0; itf < CFG_TUD_CDC; itf++) { p_cdc = &_cdcd_itf[itf]; - if ((ep_addr == p_cdc->ep_out) || (ep_addr == p_cdc->ep_in)) break; + if ((ep_addr == p_cdc->ep_out) || (ep_addr == p_cdc->ep_in) || (ep_addr == p_cdc->ep_notif)) break; } TU_ASSERT(itf < CFG_TUD_CDC); // Received new data if (ep_addr == p_cdc->ep_out) { + TU_LOG_DRV(" XFer Out\r\n"); tu_fifo_write_n(&p_cdc->rx_ff, p_cdc->epout_buf, (uint16_t) xferred_bytes); // Check for wanted char and invoke callback if needed @@ -465,6 +486,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // Note: This will cause incorrect baudrate set in line coding. // Though maybe the baudrate is not really important !!! if (ep_addr == p_cdc->ep_in) { + TU_LOG_DRV(" XFer In\r\n"); // invoke transmit callback to possibly refill tx fifo if (tud_cdc_tx_complete_cb) tud_cdc_tx_complete_cb(itf); @@ -479,7 +501,30 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ } } - // nothing to do with notif endpoint for now + // Notifications + if (ep_addr == p_cdc->ep_notif) { + TU_LOG_DRV(" XFer Notification\r\n"); + uint8_t const rhport = 0; + + // SERIAL_STATE notification. Send flow control signals. + if (p_cdc->serial_state_changed) { + p_cdc->serial_state_changed = false; + + // Build the notification + p_cdc->epnotif_buf = cdc_notify_serial_status; + p_cdc->epnotif_buf.header.wIndex = p_cdc->itf_num; + p_cdc->epnotif_buf.serial_state = p_cdc->serial_state; + + // claim endpoint + TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_notif), 0); + + // Send notification + return usbd_edpt_xfer(rhport, p_cdc->ep_notif, (uint8_t *) &(p_cdc->epnotif_buf), sizeof(p_cdc->epnotif_buf)); + } + else { + // Send a NAK? + } + } return true; } diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index 463feedf..f7608237 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -70,6 +70,12 @@ bool tud_cdc_n_connected(uint8_t itf); // Get current line state. Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) uint8_t tud_cdc_n_get_line_state(uint8_t itf); +// Get current serial state. +cdc_serial_state_t tud_cdc_n_get_serial_state(uint8_t itf); + +// Set current serial state. +void tud_cdc_n_set_serial_state(uint8_t itf, cdc_serial_state_t ser_state); + // Get current line encoding: bit rate, stop bits parity etc .. void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t* coding); @@ -132,6 +138,14 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t tud_cdc_get_line_state(void) { return tud_cdc_n_get_line_state(0); } +TU_ATTR_ALWAYS_INLINE static inline cdc_serial_state_t tud_cdc_get_serial_state(void) { + return tud_cdc_n_get_serial_state(0); +} + +TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_set_serial_state(cdc_serial_state_t ser_state) { + return tud_cdc_n_set_serial_state(0, ser_state); +} + TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_get_line_coding(cdc_line_coding_t* coding) { tud_cdc_n_get_line_coding(0, coding); } diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index d9c6ea75..d05c75d2 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -491,6 +491,27 @@ typedef struct TU_ATTR_PACKED { TU_VERIFY_STATIC( sizeof(tusb_control_request_t) == 8, "size is not correct"); + +typedef struct TU_ATTR_PACKED { + union { + struct TU_ATTR_PACKED { + uint8_t recipient : 5; ///< Recipient type tusb_request_recipient_t. + uint8_t type : 2; ///< Request type tusb_request_type_t. + uint8_t direction : 1; ///< Direction type. tusb_dir_t + } bmRequestType_bit; + + uint8_t bmRequestType; + }; + + uint8_t bNotification; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} tusb_notification_t; + +TU_VERIFY_STATIC( sizeof(tusb_notification_t) == 8, "size is not correct"); + + TU_ATTR_PACKED_END // End of all packed definitions TU_ATTR_BIT_FIELD_ORDER_END From f4edc86969164c0f910d1cf24607505cba54bb65 Mon Sep 17 00:00:00 2001 From: Mark Smith <mark-github@halibut.com> Date: Fri, 21 Feb 2025 18:19:23 -0800 Subject: [PATCH 2/9] Fixing clang-format, white space issue. #491 #493 --- src/arduino/Adafruit_USBD_CDC.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arduino/Adafruit_USBD_CDC.h b/src/arduino/Adafruit_USBD_CDC.h index 2fcd71ab..9df29db9 100644 --- a/src/arduino/Adafruit_USBD_CDC.h +++ b/src/arduino/Adafruit_USBD_CDC.h @@ -61,7 +61,7 @@ class Adafruit_USBD_CDC : public Stream, public Adafruit_USBD_Interface { uint8_t numbits(void); // Flow control bit getters. - int dtr(void); // pre-existing, I don't want to change the return type. + int dtr(void); // pre-existing, I don't want to change the return type. bool rts(void); bool cts(void); bool dsr(void); From 0803d8e8858b9c55f53c56e54608d35d3403e0b4 Mon Sep 17 00:00:00 2001 From: Mark Smith <mark-github@halibut.com> Date: Fri, 21 Feb 2025 18:28:58 -0800 Subject: [PATCH 3/9] Nope, can't inline in a .cpp. Nothing else is inline, just remove. #491 #493 --- src/arduino/Adafruit_USBD_CDC.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/arduino/Adafruit_USBD_CDC.cpp b/src/arduino/Adafruit_USBD_CDC.cpp index ce0583b7..0c1e971b 100644 --- a/src/arduino/Adafruit_USBD_CDC.cpp +++ b/src/arduino/Adafruit_USBD_CDC.cpp @@ -170,23 +170,23 @@ int Adafruit_USBD_CDC::dtr(void) { return tud_cdc_n_connected(_instance); } -inline bool Adafruit_USBD_CDC::rts(void) { +bool Adafruit_USBD_CDC::rts(void) { return tud_cdc_n_get_line_state(_instance) & CDC_CONTROL_LINE_STATE_RTS; } -inline bool Adafruit_USBD_CDC::cts(void) { +bool Adafruit_USBD_CDC::cts(void) { return tud_cdc_n_get_serial_state(_instance).cts; } -inline bool Adafruit_USBD_CDC::dsr(void) { +bool Adafruit_USBD_CDC::dsr(void) { return tud_cdc_n_get_serial_state(_instance).dsr; } -inline bool Adafruit_USBD_CDC::dcd(void) { +bool Adafruit_USBD_CDC::dcd(void) { return tud_cdc_n_get_serial_state(_instance).dcd; } -inline bool Adafruit_USBD_CDC::ri(void) { +bool Adafruit_USBD_CDC::ri(void) { return tud_cdc_n_get_serial_state(_instance).ri; } From b0634ba347027d1415573f4bc37ecc3177e8fccc Mon Sep 17 00:00:00 2001 From: Mark Smith <mark-github@halibut.com> Date: Sat, 1 Mar 2025 09:32:55 -0800 Subject: [PATCH 4/9] Queue Notification when setting, not waiting for the callback. #491 --- src/arduino/Adafruit_USBD_CDC.cpp | 10 ----- src/arduino/Adafruit_USBD_CDC.h | 5 ++- src/class/cdc/cdc.h | 23 +++++----- src/class/cdc/cdc_device.c | 70 +++++++++++++++---------------- src/class/cdc/cdc_device.h | 2 +- 5 files changed, 51 insertions(+), 59 deletions(-) diff --git a/src/arduino/Adafruit_USBD_CDC.cpp b/src/arduino/Adafruit_USBD_CDC.cpp index 0c1e971b..5328dda6 100644 --- a/src/arduino/Adafruit_USBD_CDC.cpp +++ b/src/arduino/Adafruit_USBD_CDC.cpp @@ -174,10 +174,6 @@ bool Adafruit_USBD_CDC::rts(void) { return tud_cdc_n_get_line_state(_instance) & CDC_CONTROL_LINE_STATE_RTS; } -bool Adafruit_USBD_CDC::cts(void) { - return tud_cdc_n_get_serial_state(_instance).cts; -} - bool Adafruit_USBD_CDC::dsr(void) { return tud_cdc_n_get_serial_state(_instance).dsr; } @@ -190,12 +186,6 @@ bool Adafruit_USBD_CDC::ri(void) { return tud_cdc_n_get_serial_state(_instance).ri; } -void Adafruit_USBD_CDC::cts(bool c) { - cdc_serial_state_t serial_state = tud_cdc_n_get_serial_state(_instance); - serial_state.cts = c; - tud_cdc_n_set_serial_state(_instance, serial_state); -} - void Adafruit_USBD_CDC::dsr(bool c) { cdc_serial_state_t serial_state = tud_cdc_n_get_serial_state(_instance); serial_state.dsr = c; diff --git a/src/arduino/Adafruit_USBD_CDC.h b/src/arduino/Adafruit_USBD_CDC.h index 9df29db9..3fb61423 100644 --- a/src/arduino/Adafruit_USBD_CDC.h +++ b/src/arduino/Adafruit_USBD_CDC.h @@ -63,16 +63,17 @@ class Adafruit_USBD_CDC : public Stream, public Adafruit_USBD_Interface { // Flow control bit getters. int dtr(void); // pre-existing, I don't want to change the return type. bool rts(void); - bool cts(void); + // bool cts(void); // NOT PART OF THE CDC ACM SPEC?! bool dsr(void); bool dcd(void); bool ri(void); // Flow control bit setters. - void cts(bool c); + // void cts(bool c); // NOT PART OF CDC ACM SPEC?! void dsr(bool c); void dcd(bool c); void ri(bool c); + // Break is a little harder, it's an event, not a state. // Stream API virtual int available(void); diff --git a/src/class/cdc/cdc.h b/src/class/cdc/cdc.h index cb31fdff..a5a5c5f8 100644 --- a/src/class/cdc/cdc.h +++ b/src/class/cdc/cdc.h @@ -416,21 +416,22 @@ TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct"); // Notifications //--------------------------------------------------------------------+ -typedef struct TU_ATTR_PACKED { - uint16_t dcd :1; - uint16_t dsr :1; - uint16_t break_err :1; - uint16_t ri :1; - uint16_t frame_err :1; - uint16_t parity_err :1; - uint16_t overrun_err :1; - uint16_t cts :1; // https://community.st.com/t5/stm32-mcus-products/cts-signal-on-usb-cdc/td-p/325800 - uint16_t :8; +typedef union TU_ATTR_PACKED { + struct { + uint16_t dcd :1; + uint16_t dsr :1; + uint16_t break_err :1; + uint16_t ri :1; + uint16_t frame_err :1; + uint16_t parity_err :1; + uint16_t overrun_err :1; + uint16_t :9; + }; + uint16_t state; } cdc_serial_state_t; TU_VERIFY_STATIC(sizeof(cdc_serial_state_t) == 2, "size is not correct"); -// Add more notifications here. PSTN120.pdf, Section 6.5 typedef struct TU_ATTR_PACKED { tusb_notification_t header; union { diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index 18fd3fda..0c439d59 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -59,7 +59,7 @@ typedef struct { // Bit 0: DTR (Data Terminal Ready), Bit 1: RTS (Request to Send) uint8_t line_state; - // Notify host of flow control bits: CTS, DSR, DCD, RI, and some error flags. + // Notify host of flow control bits: DSR, DCD, RI, and some error flags. cdc_serial_state_t serial_state; bool serial_state_changed; @@ -120,6 +120,29 @@ static bool _prep_out_transaction (cdcd_interface_t* p_cdc) { } } +bool _send_serial_state_notification(cdcd_interface_t *p_cdc) { + const uint8_t rhport = 0; + + if (!p_cdc->serial_state_changed) { + // Nothing to do. + return true; + } + + if (!usbd_edpt_claim(rhport, p_cdc->ep_notif)) { + // If claim failed, we're already in the middle of a transaction. + // cdcd_xfer_cb() will pick up this change. + return true; + } + + // We have the end point. Build and send the notification. + p_cdc->serial_state_changed = false; + + p_cdc->epnotif_buf = cdc_notify_serial_status; + p_cdc->epnotif_buf.header.wIndex = p_cdc->itf_num; + p_cdc->epnotif_buf.serial_state = p_cdc->serial_state; + return usbd_edpt_xfer(rhport, p_cdc->ep_notif, (uint8_t *) &(p_cdc->epnotif_buf), sizeof(p_cdc->epnotif_buf)); +} + //--------------------------------------------------------------------+ // APPLICATION API //--------------------------------------------------------------------+ @@ -148,11 +171,12 @@ cdc_serial_state_t tud_cdc_n_get_serial_state(uint8_t itf) { } void tud_cdc_n_set_serial_state(uint8_t itf, cdc_serial_state_t serial_state) { - if (memcmp(&(_cdcd_itf[itf].serial_state), &serial_state, sizeof(serial_state)) != 0) { - TU_LOG_DRV(" Serial State Changed: %x -> %x\r\n", _cdcd_itf[itf].serial_state, serial_state); - _cdcd_itf[itf].serial_state_changed = true; + cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; + if (p_cdc->serial_state.state != serial_state.state) { + p_cdc->serial_state_changed = true; + p_cdc->serial_state = serial_state; + _send_serial_state_notification(p_cdc); } - _cdcd_itf[itf].serial_state = serial_state; } void tud_cdc_n_get_line_coding(uint8_t itf, cdc_line_coding_t* coding) { @@ -343,13 +367,10 @@ uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint1 if (TUSB_DESC_ENDPOINT == tu_desc_type(p_desc)) { // notification endpoint - tusb_desc_endpoint_t desc_ep = *(tusb_desc_endpoint_t const*) p_desc; - TU_LOG_DRV(" Interval before: %d\r\n", desc_ep.bInterval); - - desc_ep.bInterval = 1; // Query every frame, 1ms at Full Speed. + tusb_desc_endpoint_t const* desc_ep = (tusb_desc_endpoint_t const*) p_desc; - TU_ASSERT(usbd_edpt_open(rhport, &desc_ep), 0); - p_cdc->ep_notif = desc_ep.bEndpointAddress; + TU_ASSERT(usbd_edpt_open(rhport, desc_ep), 0); + p_cdc->ep_notif = desc_ep->bEndpointAddress; drv_len += tu_desc_len(p_desc); p_desc = tu_desc_next(p_desc); @@ -460,10 +481,9 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ if ((ep_addr == p_cdc->ep_out) || (ep_addr == p_cdc->ep_in) || (ep_addr == p_cdc->ep_notif)) break; } TU_ASSERT(itf < CFG_TUD_CDC); - + // Received new data if (ep_addr == p_cdc->ep_out) { - TU_LOG_DRV(" XFer Out\r\n"); tu_fifo_write_n(&p_cdc->rx_ff, p_cdc->epout_buf, (uint16_t) xferred_bytes); // Check for wanted char and invoke callback if needed @@ -486,7 +506,6 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // Note: This will cause incorrect baudrate set in line coding. // Though maybe the baudrate is not really important !!! if (ep_addr == p_cdc->ep_in) { - TU_LOG_DRV(" XFer In\r\n"); // invoke transmit callback to possibly refill tx fifo if (tud_cdc_tx_complete_cb) tud_cdc_tx_complete_cb(itf); @@ -503,27 +522,8 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // Notifications if (ep_addr == p_cdc->ep_notif) { - TU_LOG_DRV(" XFer Notification\r\n"); - uint8_t const rhport = 0; - - // SERIAL_STATE notification. Send flow control signals. - if (p_cdc->serial_state_changed) { - p_cdc->serial_state_changed = false; - - // Build the notification - p_cdc->epnotif_buf = cdc_notify_serial_status; - p_cdc->epnotif_buf.header.wIndex = p_cdc->itf_num; - p_cdc->epnotif_buf.serial_state = p_cdc->serial_state; - - // claim endpoint - TU_VERIFY(usbd_edpt_claim(rhport, p_cdc->ep_notif), 0); - - // Send notification - return usbd_edpt_xfer(rhport, p_cdc->ep_notif, (uint8_t *) &(p_cdc->epnotif_buf), sizeof(p_cdc->epnotif_buf)); - } - else { - // Send a NAK? - } + // Send any changes that may have come in while sending the previous change. + return _send_serial_state_notification(p_cdc); } return true; diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index f7608237..d5522028 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -143,7 +143,7 @@ TU_ATTR_ALWAYS_INLINE static inline cdc_serial_state_t tud_cdc_get_serial_state( } TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_set_serial_state(cdc_serial_state_t ser_state) { - return tud_cdc_n_set_serial_state(0, ser_state); + tud_cdc_n_set_serial_state(0, ser_state); } TU_ATTR_ALWAYS_INLINE static inline void tud_cdc_get_line_coding(cdc_line_coding_t* coding) { From f016dcf902f7dae598f16c659c8023b8cc8c773f Mon Sep 17 00:00:00 2001 From: Mark Smith <mark-github@halibut.com> Date: Sat, 1 Mar 2025 10:01:23 -0800 Subject: [PATCH 5/9] nrf52 core is including the wrong Adafruit_USBD_CDC.h #491 --- src/arduino/Adafruit_USBD_CDC.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/arduino/Adafruit_USBD_CDC.cpp b/src/arduino/Adafruit_USBD_CDC.cpp index 5328dda6..ceacda87 100644 --- a/src/arduino/Adafruit_USBD_CDC.cpp +++ b/src/arduino/Adafruit_USBD_CDC.cpp @@ -27,11 +27,12 @@ // esp32 use built-in core cdc #if CFG_TUD_CDC && !defined(ARDUINO_ARCH_ESP32) +#include "Adafruit_USBD_CDC.h" + #include "Arduino.h" #include "Adafruit_TinyUSB_API.h" -#include "Adafruit_USBD_CDC.h" #include "Adafruit_USBD_Device.h" #ifndef TINYUSB_API_VERSION From 5311fb83c4407041538d91791714457d66a81ae4 Mon Sep 17 00:00:00 2001 From: Mark Smith <mark-github@halibut.com> Date: Sat, 1 Mar 2025 10:24:40 -0800 Subject: [PATCH 6/9] Tests are failing, using wrong SdFat library. #491 --- examples/MassStorage/msc_external_flash/.skip.txt | 1 + examples/MassStorage/msc_external_flash_sdcard/.skip.txt | 1 + examples/MassStorage/msc_sdfat/.skip.txt | 1 + src/arduino/Adafruit_USBD_CDC.cpp | 3 +++ 4 files changed, 6 insertions(+) diff --git a/examples/MassStorage/msc_external_flash/.skip.txt b/examples/MassStorage/msc_external_flash/.skip.txt index f8e761cb..66aeeee1 100644 --- a/examples/MassStorage/msc_external_flash/.skip.txt +++ b/examples/MassStorage/msc_external_flash/.skip.txt @@ -1,2 +1,3 @@ pico_rp2040_tinyusb_host CH32V20x_EVT +feather_rp2040_tinyusb diff --git a/examples/MassStorage/msc_external_flash_sdcard/.skip.txt b/examples/MassStorage/msc_external_flash_sdcard/.skip.txt index f8e761cb..66aeeee1 100644 --- a/examples/MassStorage/msc_external_flash_sdcard/.skip.txt +++ b/examples/MassStorage/msc_external_flash_sdcard/.skip.txt @@ -1,2 +1,3 @@ pico_rp2040_tinyusb_host CH32V20x_EVT +feather_rp2040_tinyusb diff --git a/examples/MassStorage/msc_sdfat/.skip.txt b/examples/MassStorage/msc_sdfat/.skip.txt index a0185409..77a312c7 100644 --- a/examples/MassStorage/msc_sdfat/.skip.txt +++ b/examples/MassStorage/msc_sdfat/.skip.txt @@ -1 +1,2 @@ pico_rp2040_tinyusb_host +feather_rp2040_tinyusb diff --git a/src/arduino/Adafruit_USBD_CDC.cpp b/src/arduino/Adafruit_USBD_CDC.cpp index ceacda87..afe27d5f 100644 --- a/src/arduino/Adafruit_USBD_CDC.cpp +++ b/src/arduino/Adafruit_USBD_CDC.cpp @@ -27,6 +27,9 @@ // esp32 use built-in core cdc #if CFG_TUD_CDC && !defined(ARDUINO_ARCH_ESP32) +// Include before "Arduino.h" because TinyUSB is part of platform cores +// When developing TinyUSB, it needs to include the local version, not the +// platform core version, which is what gets included by Arduino.h #include "Adafruit_USBD_CDC.h" #include "Arduino.h" From b10719b7cd071a667c725aee3b7ceaa92e65ddb8 Mon Sep 17 00:00:00 2001 From: Mark Smith <mark-github@halibut.com> Date: Thu, 20 Mar 2025 15:08:06 -0700 Subject: [PATCH 7/9] RP2040 only support full speed. Advertising as USB2.0 triggers irrelevant negotiation. --- src/arduino/Adafruit_USBD_Device.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/arduino/Adafruit_USBD_Device.cpp b/src/arduino/Adafruit_USBD_Device.cpp index 068a9890..410c01d3 100644 --- a/src/arduino/Adafruit_USBD_Device.cpp +++ b/src/arduino/Adafruit_USBD_Device.cpp @@ -176,7 +176,11 @@ bool Adafruit_USBD_Device::attach(void) { return tud_connect(); } void Adafruit_USBD_Device::clearConfiguration(void) { tusb_desc_device_t const desc_dev = {.bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, +#if CFG_TUSB_MCU==OPT_MCU_RP2040 // RP2040 only supports full speed + .bcdUSB = 0x0110, +#else .bcdUSB = 0x0200, +#endif .bDeviceClass = 0, .bDeviceSubClass = 0, .bDeviceProtocol = 0, From 65dc1bdf87d85a3453b95fb1c4462189e77c957e Mon Sep 17 00:00:00 2001 From: Mark Smith <mark-github@halibut.com> Date: Thu, 20 Mar 2025 15:40:42 -0700 Subject: [PATCH 8/9] pre-commit Clang format failure. #491 --- src/arduino/Adafruit_USBD_Device.cpp | 29 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/arduino/Adafruit_USBD_Device.cpp b/src/arduino/Adafruit_USBD_Device.cpp index bb23f4db..d387a425 100644 --- a/src/arduino/Adafruit_USBD_Device.cpp +++ b/src/arduino/Adafruit_USBD_Device.cpp @@ -163,24 +163,23 @@ void Adafruit_USBD_Device::task(void) { void Adafruit_USBD_Device::clearConfiguration(void) { tusb_desc_device_t const desc_dev = {.bLength = sizeof(tusb_desc_device_t), - .bDescriptorType = TUSB_DESC_DEVICE, + .bDescriptorType = TUSB_DESC_DEVICE, #if CFG_TUSB_MCU==OPT_MCU_RP2040 // RP2040 only supports full speed - .bcdUSB = 0x0110, + .bcdUSB = 0x0110, #else - .bcdUSB = 0x0200, + .bcdUSB = 0x0200, #endif - .bDeviceClass = 0, - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, - .bMaxPacketSize0 = - CFG_TUD_ENDPOINT0_SIZE, - .idVendor = USB_VID, - .idProduct = USB_PID, - .bcdDevice = 0x0100, - .iManufacturer = STRID_MANUFACTURER, - .iProduct = STRID_PRODUCT, - .iSerialNumber = STRID_SERIAL, - .bNumConfigurations = 0x01}; + .bDeviceClass = 0, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .idVendor = USB_VID, + .idProduct = USB_PID, + .bcdDevice = 0x0100, + .iManufacturer = STRID_MANUFACTURER, + .iProduct = STRID_PRODUCT, + .iSerialNumber = STRID_SERIAL, + .bNumConfigurations = 0x01}; _desc_device = desc_dev; From 8d9ee2aa8f651614f13b84fd1f042c47b5bb6f85 Mon Sep 17 00:00:00 2001 From: Mark Smith <mark-github@halibut.com> Date: Thu, 20 Mar 2025 15:46:16 -0700 Subject: [PATCH 9/9] More Clang format changes. #491 --- src/arduino/Adafruit_USBD_Device.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/arduino/Adafruit_USBD_Device.cpp b/src/arduino/Adafruit_USBD_Device.cpp index d387a425..246bf628 100644 --- a/src/arduino/Adafruit_USBD_Device.cpp +++ b/src/arduino/Adafruit_USBD_Device.cpp @@ -162,9 +162,10 @@ void Adafruit_USBD_Device::task(void) { } void Adafruit_USBD_Device::clearConfiguration(void) { - tusb_desc_device_t const desc_dev = {.bLength = sizeof(tusb_desc_device_t), + tusb_desc_device_t const desc_dev = { + .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, -#if CFG_TUSB_MCU==OPT_MCU_RP2040 // RP2040 only supports full speed +#if CFG_TUSB_MCU == OPT_MCU_RP2040 // RP2040 only supports full speed .bcdUSB = 0x0110, #else .bcdUSB = 0x0200, @@ -179,7 +180,8 @@ void Adafruit_USBD_Device::clearConfiguration(void) { .iManufacturer = STRID_MANUFACTURER, .iProduct = STRID_PRODUCT, .iSerialNumber = STRID_SERIAL, - .bNumConfigurations = 0x01}; + .bNumConfigurations = 0x01 + }; _desc_device = desc_dev;