Transparent CDC to NUS bridge

Hi I'm trying to create a transparent CDC to NUS bridge, this is based on the nrf52840 dongle.

The Aim of this is to send binary files to our device from a PC, our device is running NUS Peripheral. 

The PC will control the chunk sizes and speed as to not overload the NUS

Issue i'm having is on the CDC, for some reason the CDC is halting after one reception.

 

Below is the CDC RX event done case

 

        case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
            {
                NRF_LOG_INFO("CDC_ACM_USER_EVT_RX_DONE");
            
                size_t size;
                ret_code_t ret;
                
                /*Get amount of data transferred*/
                size = app_usbd_cdc_acm_rx_size(p_cdc_acm);

                NRF_LOG_INFO("CDC RX: size: %lu", size);

                /* Fetch data until internal buffer is empty */
                ret = app_usbd_cdc_acm_read(&m_app_cdc_acm,
                                            &m_cdc_data_array[0],
                                            size);
                if (ret == NRF_SUCCESS)
                {
                    NRF_LOG_INFO("NUS TX: size: %lu", size);

                    ret = ble_nus_c_string_send(&m_ble_nus_c,
                                            (uint8_t *)&m_cdc_data_array[0],
                                            size);
                }

  • This seemed to work

            case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
                {
                    ret_code_t ret;
                    size_t total = 0;
    
                    do
                    {
                        /*Get amount of data transfered*/
                        size_t size = app_usbd_cdc_acm_rx_size(p_cdc_acm);
    
                        /* Fetch data until internal buffer is empty */
                        ret = app_usbd_cdc_acm_read(p_cdc_acm,
                                                    &m_cdc_data_array[0],
                                                    size);
                        total += size;
    
                    } while (ret == NRF_SUCCESS);
    
                    NRF_LOG_INFO("CDC RX: size: %lu", total);
    
                    ret = ble_nus_c_string_send(&m_ble_nus_c,
                                            (uint8_t *)&m_cdc_data_array[0],
                                            total);
    
                    NRF_LOG_INFO("NUS TX: size: %lu", total);
    

  • I see that you were able to solve this.

    Let us know if you need anything else, and feel free to press "verify as answer" on your solution to close this ticket

  • This is not solved but it could be my understanding of the APP_USBD_CDC_ACM_USER_EVT_RX_DONE event.

    What I'm wanting to do is send a binary file. This will be sent in 64B(this could be bigger or smaller does not matter really) chunks.

    APP_USBD_CDC_ACM_USER_EVT_RX_DONE seems to be call every byte

  •   can you help please

    app_usbd_cdc_acm_read is called in APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN

    I'm assuming this just sets up the buffer and transfer size ?

    So when data arrives you will get a APP_USBD_CDC_ACM_USER_EVT_RX_DONE event, this means the data of transfer size was moved to the buffer that was specified ?

    Surely it would be better to have this when APP_USBD_CDC_ACM_USER_EVT_RX_DONE is triggered

    Query amount of data received, and then transfer that data to your buffer ? 

  • Hi Lee

    I will help Sigurd with this case as I have more experience with the nRF5 SDK. 

    sleeper said:

    app_usbd_cdc_acm_read is called in APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN

    I'm assuming this just sets up the buffer and transfer size ?

    Correct. You need to provide a read buffer to the driver, and define the size of the buffer. 

    In the standard example the buffer is set to 1 byte, in order to provide an interrupt for every received byte. Did you try to increase this value? 

    sleeper said:
    So when data arrives you will get a APP_USBD_CDC_ACM_USER_EVT_RX_DONE event, this means the data of transfer size was moved to the buffer that was specified ?

    Correct. In case you provide a larger buffer I think you can also receive smaller updates (where the size is smaller than the buffer size), in case a small packet is sent from the host side, which is why you need to read the rx_size as shown in the example. 

    Regarding your program flow, you might want to consider using some kind of FIFO in main to buffer the data before you send it over BLE. 

    Technically it should be fine to call BLE functions directly from the callback, since the USB callback is run from main context through the call to app_usbd_event_queue_process(), but decoupling the BLE transmission from the callback still has advantages. For one thing it would allow you to wait to send anything over BLE until you have received enough data to fully utilize the BLE data length (244 bytes ideally). Second, it would allow you to properly handle the case where the BLE send call fails because of full buffers in the SoftDevice. 

    Best regards
    Torbjørn

Related