CDC/ACM fifo buffer flush

Hi, I'm working on an application that transmits data via USB CDC/ACM class.
I'm trying to improve the robustness of the application, and I realised that if the USB cable is unplugged during data transmission, my next transmission gets corrupted.

In the cddc_acm implementation, a large ringbuffer (1KB) is used to store the data that is then sent to the usb endpoint. I suspect some data from the previous transmission is still stored in the buffer, but it seems there is no way to reset it.

I'm sure there is an alternative solution to avoid this issue, I would appreciate some pointers :)

PS: Here is the code that I'm currently using in the interrupt callback to transmit the data. The additional semaphore is used for synchronization purposes by the application.

static void interrupt_handler(const struct device *dev, void *user_data){

    struct context *tx = (struct context*)user_data;

    if (uart_irq_update(dev) && uart_irq_is_pending(dev)) {

        if(uart_irq_tx_ready(dev) > 0 && tx->len > 0){
            LOG_DBG("ISR TX ready, len %d", tx->len);

            int sent = uart_fifo_fill(dev, tx->data, tx->len);
            if(sent > 0){
                tx->data = tx->data+sent;
                __ASSERT_NO_MSG(tx->len >= sent);
                tx->len -= sent;
            }else{
                LOG_ERR("Failed to send data");
            }

            if(tx->len <= 0){
                LOG_DBG("ISR TX done");
                uart_irq_tx_disable(dev);
                k_sem_give(usb_iface->tx_sem);
            }
        }

        if(uart_irq_rx_ready(dev) == 1){
            static uint8_t buf[64];
            int read;
            do{
                read = uart_fifo_read(dev, buf, sizeof(buf));
                __ASSERT_NO_MSG(read >= 0);

                uint32_t bytes_written;
                int ret = k_pipe_put(usb_iface->rx_pipe, buf, read, &bytes_written, read, K_NO_WAIT);
                if(ret < 0){
                    LOG_ERR("Dropping data");
                    break;
                }
            }while(read > 0);
        }
    }
}

  • Hello,

    Could you expand a bit upon what you mean with the transmission getting corrupted? 

    Are you certain that you completely clear the buffer before releasing it to be able to be used?

    Kind regards,
    Andreas

  • With corrupted, i mean that I get some of the data from the previous transmission. For example 

    1. I start the transmission of 10Kb of 0xAA
    2. I unplug the USB cable during transmission, then plug it again
    3. I start the transmission of 10Kb of 0xBB

    At the beginning of the second transmission I get first a bunch of 0xAA bytes

    I do clear buffers on the host side. In fact, I used two different hosts for the two transmissions. However, I did not find a way to clear the cdc/acm ringbuffer, which I believe is what is causing the problem.

  • Thank you for clarifying.

    Are you able to read the current contents of the ringbuffer after you replug the USB cable? Seems like the content is still present and when you send 10kB of 0xBB it needs to go through the motions of emptying the contents thats still there.

    You can use uart_fifo_read() to read data from the CDC ACM RX ring buffer. This function should be called from the UART interrupt handler, as the CDC ACM implementation checks the context and will fail if not called from an interrupt handler. W.r.t clearing the buffer there's no API to do so other than to keep reading until no more more data is available (which empties the buffer)

    Kind regards,
    Andreas

  • thanks for clarifying that there is no way to flush it

Related