From 909891325ad6867fc6d9596bfe0e27d6033c3d48 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 21 Mar 2019 14:52:56 -0700 Subject: [PATCH] Fix slow CDC OUT by NAKing This NAKs CDC OUT packets when the ring buffer doesn't have enough space for it. This makes CDC OUT reliable rather than allowing overwriting into the ring buffer. --- src/class/cdc/cdc_device.c | 39 ++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c index 0cfb2377..43af2a50 100644 --- a/src/class/cdc/cdc_device.c +++ b/src/class/cdc/cdc_device.c @@ -87,6 +87,24 @@ typedef struct //--------------------------------------------------------------------+ CFG_TUSB_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC] = { { 0 } }; +bool pending_read_from_host; +static void _prep_next_transaction(void) { + uint8_t const itf = 0; + cdcd_interface_t* p_cdc = &_cdcd_itf[itf]; + + // skip if previous transfer not complete + if (pending_read_from_host) { + return; + } + + // Prepare for incoming data but only allow what we can store in the ring buffer. + uint16_t max_read = tu_fifo_remaining(&p_cdc->rx_ff); + if (max_read >= CFG_TUD_CDC_EPSIZE) { + dcd_edpt_xfer(TUD_OPT_RHPORT, p_cdc->ep_out, p_cdc->epout_buf, CFG_TUD_CDC_EPSIZE); + pending_read_from_host = true; + } +} + //--------------------------------------------------------------------+ // APPLICATION API //--------------------------------------------------------------------+ @@ -123,12 +141,19 @@ uint32_t tud_cdc_n_available(uint8_t itf) char tud_cdc_n_read_char(uint8_t itf) { char ch; - return tu_fifo_read(&_cdcd_itf[itf].rx_ff, &ch) ? ch : (-1); + if (!tu_fifo_read(&_cdcd_itf[itf].rx_ff, &ch)) { + ch = -1; + } + + _prep_next_transaction(); + return ch; } uint32_t tud_cdc_n_read(uint8_t itf, void* buffer, uint32_t bufsize) { - return tu_fifo_read_n(&_cdcd_itf[itf].rx_ff, buffer, bufsize); + uint32_t num_read = tu_fifo_read_n(&_cdcd_itf[itf].rx_ff, buffer, bufsize); + _prep_next_transaction(); + return num_read; } char tud_cdc_n_peek(uint8_t itf, int pos) @@ -140,6 +165,7 @@ char tud_cdc_n_peek(uint8_t itf, int pos) void tud_cdc_n_read_flush (uint8_t itf) { tu_fifo_clear(&_cdcd_itf[itf].rx_ff); + _prep_next_transaction(); } //--------------------------------------------------------------------+ @@ -207,7 +233,7 @@ void cdcd_init(void) p_cdc->line_coding.data_bits = 8; // config fifo - tu_fifo_config(&p_cdc->rx_ff, p_cdc->rx_ff_buf, CFG_TUD_CDC_RX_BUFSIZE, 1, true); + tu_fifo_config(&p_cdc->rx_ff, p_cdc->rx_ff_buf, CFG_TUD_CDC_RX_BUFSIZE, 1, false); tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, CFG_TUD_CDC_TX_BUFSIZE, 1, false); #if CFG_FIFO_MUTEX @@ -290,7 +316,8 @@ bool cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t } // Prepare for incoming data - TU_ASSERT( dcd_edpt_xfer(rhport, p_cdc->ep_out, p_cdc->epout_buf, CFG_TUD_CDC_EPSIZE) ); + pending_read_from_host = false; + _prep_next_transaction(); return true; } @@ -383,8 +410,8 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_ // invoke receive callback (if there is still data) if (tud_cdc_rx_cb && tu_fifo_count(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf); - // prepare for incoming data - TU_ASSERT( dcd_edpt_xfer(rhport, p_cdc->ep_out, p_cdc->epout_buf, CFG_TUD_CDC_EPSIZE) ); + pending_read_from_host = false; + _prep_next_transaction(); } // nothing to do with in and notif endpoint