diff --git a/examples/device/cdc_dual_ports/src/main.c b/examples/device/cdc_dual_ports/src/main.c index d6e38df85..198c4252b 100644 --- a/examples/device/cdc_dual_ports/src/main.c +++ b/examples/device/cdc_dual_ports/src/main.c @@ -83,6 +83,8 @@ static void cdc_task(void) for (itf = 0; itf < CFG_TUD_CDC; itf++) { + // connected() check for DTR bit + // Most but not all terminal client set this when making connection if ( tud_cdc_n_connected(itf) ) { if ( tud_cdc_n_available(itf) ) diff --git a/examples/device/cdc_msc/src/main.c b/examples/device/cdc_msc/src/main.c index a407e2ddd..a20a80fcd 100644 --- a/examples/device/cdc_msc/src/main.c +++ b/examples/device/cdc_msc/src/main.c @@ -105,7 +105,9 @@ void tud_resume_cb(void) //--------------------------------------------------------------------+ void cdc_task(void) { - if ( tud_cdc_connected() ) + // connected() check for DTR bit + // Most but not all terminal client set this when making connection + // if ( tud_cdc_connected() ) { // connected and there are data available if ( tud_cdc_available() ) @@ -131,12 +133,14 @@ void cdc_task(void) void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) { (void) itf; + (void) rts; // connected - if ( dtr && rts ) + if ( dtr ) { // print initial message when connected tud_cdc_write_str("\r\nTinyUSB CDC MSC device example\r\n"); + tud_cdc_write_flush(); } } diff --git a/examples/device/cdc_msc_freertos/src/main.c b/examples/device/cdc_msc_freertos/src/main.c index 1371b84c3..e90c3f0d9 100644 --- a/examples/device/cdc_msc_freertos/src/main.c +++ b/examples/device/cdc_msc_freertos/src/main.c @@ -168,9 +168,11 @@ void cdc_task(void* params) // RTOS forever loop while ( 1 ) { - if ( tud_cdc_connected() ) + // connected() check for DTR bit + // Most but not all terminal client set this when making connection + // if ( tud_cdc_connected() ) { - // connected and there are data available + // There are data available if ( tud_cdc_available() ) { uint8_t buf[64]; @@ -198,12 +200,14 @@ void cdc_task(void* params) void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) { (void) itf; + (void) rts; // connected - if ( dtr && rts ) + if ( dtr ) { // print initial message when connected tud_cdc_write_str("\r\nTinyUSB CDC MSC device with FreeRTOS example\r\n"); + tud_cdc_write_flush(); } } diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index 2933dcd3d..58f485a5d 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -178,6 +178,9 @@ uint32_t tud_cdc_n_write_flush (uint8_t itf) { cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; + // Skip if usb is not ready yet + TU_VERIFY( tud_ready(), 0 ); + // No data to send if ( !tu_fifo_count(&p_cdc->tx_ff) ) return 0; @@ -189,7 +192,7 @@ uint32_t tud_cdc_n_write_flush (uint8_t itf) // Pull data from FIFO uint16_t const count = tu_fifo_read_n(&p_cdc->tx_ff, p_cdc->epin_buf, sizeof(p_cdc->epin_buf)); - if ( count && tud_cdc_n_connected(itf) ) + if ( count ) { TU_ASSERT( usbd_edpt_xfer(rhport, p_cdc->ep_in, p_cdc->epin_buf, count), 0 ); return count; @@ -207,6 +210,10 @@ uint32_t tud_cdc_n_write_available (uint8_t itf) return tu_fifo_remaining(&_cdcd_itf[itf].tx_ff); } +bool tud_cdc_n_write_clear (uint8_t itf) +{ + return tu_fifo_clear(&_cdcd_itf[itf].tx_ff); +} //--------------------------------------------------------------------+ // USBD Driver API @@ -227,9 +234,13 @@ void cdcd_init(void) p_cdc->line_coding.parity = 0; p_cdc->line_coding.data_bits = 8; - // config fifo + // Config RX fifo tu_fifo_config(&p_cdc->rx_ff, p_cdc->rx_ff_buf, TU_ARRAY_SIZE(p_cdc->rx_ff_buf), 1, false); - tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, false); + + // Config TX fifo as overwritable at initialization and will be changed to non-overwritable + // if terminal supports DTR bit. Without DTR we do not know if data is actually polled by terminal. + // In this way, the most current data is prioritized. + tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, TU_ARRAY_SIZE(p_cdc->tx_ff_buf), 1, true); #if CFG_FIFO_MUTEX tu_fifo_config_mutex(&p_cdc->rx_ff, osal_mutex_create(&p_cdc->rx_ff_mutex)); @@ -244,9 +255,12 @@ void cdcd_reset(uint8_t rhport) for(uint8_t i=0; irx_ff); + tu_fifo_clear(&p_cdc->tx_ff); + tu_fifo_set_overwritable(&p_cdc->tx_ff, true); } } @@ -372,6 +386,9 @@ bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t bool const rts = tu_bit_test(request->wValue, 1); p_cdc->line_state = (uint8_t) request->wValue; + + // Disable fifo overwriting if DTR bit is set + tu_fifo_set_overwritable(&p_cdc->tx_ff, !dtr); TU_LOG2(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts); diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h index 3e68e2a88..62dcd3c0a 100644 --- a/src/class/cdc/cdc_device.h +++ b/src/class/cdc/cdc_device.h @@ -102,6 +102,9 @@ uint32_t tud_cdc_n_write_flush (uint8_t itf); // Return the number of bytes (characters) available for writing to TX FIFO buffer in a single n_write operation. uint32_t tud_cdc_n_write_available (uint8_t itf); +// Clear the transmit FIFO +bool tud_cdc_n_write_clear (uint8_t itf); + //--------------------------------------------------------------------+ // Application API (Single Port) //--------------------------------------------------------------------+ @@ -121,6 +124,7 @@ static inline uint32_t tud_cdc_write (void const* buffer, uint32_t buf static inline uint32_t tud_cdc_write_str (char const* str); static inline uint32_t tud_cdc_write_flush (void); static inline uint32_t tud_cdc_write_available (void); +static inline bool tud_cdc_write_clear (void); //--------------------------------------------------------------------+ // Application Callback API (weak is optional) @@ -230,6 +234,11 @@ static inline uint32_t tud_cdc_write_available(void) return tud_cdc_n_write_available(0); } +static inline bool tud_cdc_write_clear(void) +{ + return tud_cdc_n_write_clear(0); +} + /** @} */ /** @} */ diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c index f41cf9f6c..608bfd081 100644 --- a/src/common/tusb_fifo.c +++ b/src/common/tusb_fifo.c @@ -597,6 +597,27 @@ bool tu_fifo_clear(tu_fifo_t *f) return true; } +/******************************************************************************/ +/*! + @brief Change the fifo mode to overwritable or not overwritable + + @param[in] f + Pointer to the FIFO buffer to manipulate + @param[in] overwritable + Overwritable mode the fifo is set to +*/ +/******************************************************************************/ +bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) +{ + tu_fifo_lock(f); + + f->overwritable = overwritable; + + tu_fifo_unlock(f); + + return true; +} + /******************************************************************************/ /*! @brief Advance write pointer - intended to be used in combination with DMA. diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h index b87695743..b965386ab 100644 --- a/src/common/tusb_fifo.h +++ b/src/common/tusb_fifo.h @@ -89,6 +89,7 @@ typedef struct .non_used_index_space = 0xFFFF - 2*_depth-1, \ } +bool tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable); bool tu_fifo_clear(tu_fifo_t *f); bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable);