USB: fix packet loss
This commit is contained in:
parent
76994571b5
commit
fa3293a1f9
|
@ -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; i<usb_length && i<USB_DATA_TRANSFER_SIZE; i++) { // copy data to be transferred so it can not be tempered with
|
||||
usb_data[i] = tx_buffer[tx_i+i];
|
||||
}
|
||||
while (usb_length != usbd_ep_write_packet(usb_device, usb_cdcacm_data_endpoints[1].bEndpointAddress, (void*)(usb_data), usb_length)); // ensure data is written into transmit buffer
|
||||
usb_length = usbd_ep_write_packet(usb_device, 0x82, (void*)(&tx_buffer[tx_i]), usb_length); // transmit data (put into USB FIFO)
|
||||
tx_i = (tx_i+usb_length)%LENGTH(tx_buffer); // update location on buffer
|
||||
tx_used -= usb_length; // update used size
|
||||
tx_lock = false; // release lock
|
||||
} else {
|
||||
usbd_ep_write_packet(usb_device, usb_cdcacm_data_endpoints[1].bEndpointAddress, NULL, 0); // trigger empty tx for a later callback
|
||||
}
|
||||
usbd_poll(usb_device); // ensure the data gets sent
|
||||
}
|
||||
|
||||
/** 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
|
||||
(void)usbd_dev; // not used
|
||||
|
||||
first_connection |= usb_cdcacm_connecting; // check if port has been opened
|
||||
if (tx_used>0 && 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
|
||||
|
@ -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_used<LENGTH(tx_buffer)) { // buffer not full
|
||||
tx_buffer[(tx_i+tx_used)%LENGTH(tx_buffer)] = c; // put character in buffer
|
||||
|
@ -460,9 +462,7 @@ void usb_cdcacm_putchar(char c)
|
|||
tx_buffer[(tx_i+tx_used)%LENGTH(tx_buffer)] = c; // overwrite old data
|
||||
}
|
||||
tx_lock = false; // release lock on transmit buffer
|
||||
if (tx_used>0 && 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 */
|
||||
|
|
Loading…
Reference in New Issue