From fa3293a1f9e27f1326d2182b0af87fe7e1502b56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Mon, 30 Apr 2018 18:08:20 +0200 Subject: [PATCH] USB: fix packet loss --- lib/usb_cdcacm.c | 56 ++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/lib/usb_cdcacm.c b/lib/usb_cdcacm.c index ea0655f..8c3829b 100644 --- a/lib/usb_cdcacm.c +++ b/lib/usb_cdcacm.c @@ -43,7 +43,6 @@ volatile bool usb_cdcacm_connecting = false; static uint8_t usbd_control_buffer[128] = {0}; /**< buffer to be used for control requests */ static usbd_device *usb_device = NULL; /**< structure holding all the info related to the USB device */ -static volatile bool usb_tx_ongoing = false; /**< if USB transmission is already ongoing */ static volatile bool first_connection = false; /**< used to detect when the first connection occurred */ /* output ring buffer, index, and available memory */ @@ -345,21 +344,6 @@ static enum usbd_request_return_codes usb_cdcacm_control_request(usbd_device *us return USBD_REQ_HANDLED; } -/** USB CDC ACM communication callback - * @note if transmission happens before the control setting is complete with a response form the communication endpoint, Linux echoes back the data - * @param[in] usbd_dev USB device descriptor - * @param[in] ep endpoint where data came in - */ -static void usb_cdcacm_communication_cb(usbd_device *usbd_dev, uint8_t ep) -{ - (void)ep; // not used - - first_connection |= usb_cdcacm_connecting; // check if port has been opened - if (usbd_dev && tx_used>0 && !usb_tx_ongoing && first_connection) { // if buffer is not empty - usbd_ep_write_packet(usbd_dev, usb_cdcacm_data_endpoints[1].bEndpointAddress, NULL, 0); // trigger tx callback - } -} - /** USB CDC ACM data received callback * @note called when data has been received * @param[in] usbd_dev USB device descriptor @@ -389,28 +373,46 @@ static void usb_cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep) static void usb_cdcacm_data_tx_cb(usbd_device *usbd_dev, uint8_t ep) { (void)ep; // not used + static bool usb_tx_ongoing = false; // if USB transmission is already ongoing - if (!usbd_dev || 0==tx_used || !first_connection) { // verify if we can send and there is something to send + if (!usbd_dev && usb_tx_ongoing) { // putchar is trying to send data but a transmission is already ongoing + return; + } + if (0==tx_used || !first_connection) { // verify if we can send and there is something to send usb_tx_ongoing = false; // transmission ended return; } - if (!tx_lock) { + if (!tx_lock) { // ensure no data is in being put in the buffer + tx_lock = true; // get the lock (no dead lock should occur since putchar should not be used in interrupts) usb_tx_ongoing = true; // remember we started transmission uint16_t usb_length = (tx_used > USB_DATA_TRANSFER_SIZE ? USB_DATA_TRANSFER_SIZE : tx_used); // length of data to be transmitted (respect max packet size) usb_length = (usb_length > (LENGTH(tx_buffer)-tx_i) ? LENGTH(tx_buffer)-tx_i : usb_length); // since here we use the source array not as ring buffer, only go up to the end - uint8_t usb_data[USB_DATA_TRANSFER_SIZE]; // buffer to transmit data - for (uint16_t i=0; i0 && first_connection) { // if buffer is not empty + usb_cdcacm_data_tx_cb(NULL, 0); // send available data + } +} + /** set USB CDC ACM configuration * @param[in] usbd_dev USB device descriptor * @param[in] wValue not used @@ -425,7 +427,7 @@ static void usb_cdcacm_set_config(usbd_device *usbd_dev, uint16_t wValue) usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, usb_cdcacm_control_request); } - + void usb_cdcacm_setup(void) { // initialize USB @@ -442,7 +444,6 @@ void usb_cdcacm_setup(void) tx_used = 0; tx_lock = false; // release lock usb_cdcacm_connecting = false; // clear flag - usb_tx_ongoing = false; // clear transmission lock first_connection = false; // reset first connection detection } @@ -451,6 +452,7 @@ void usb_cdcacm_putchar(char c) if (!usb_device) { return; } + while (tx_lock); // wait for lock to be released tx_lock = true; // put lock on transmit buffer if (tx_used0 && usb_device && !usb_tx_ongoing) { // if buffer is not empty anymore - usbd_ep_write_packet(usb_device, usb_cdcacm_data_endpoints[1].bEndpointAddress, NULL, 0); // trigger tx callback - } + usb_cdcacm_data_tx_cb(NULL, 0); // send data over USB when possible } /** USB interrupt service routine called when data is received */