diff --git a/LUFA/DoxygenPages/ChangeLog.txt b/LUFA/DoxygenPages/ChangeLog.txt index 271c23d10b..e92f026cf0 100644 --- a/LUFA/DoxygenPages/ChangeLog.txt +++ b/LUFA/DoxygenPages/ChangeLog.txt @@ -34,6 +34,8 @@ * - Library Applications: * - Fixed broken RESET_TOGGLES_LIBUSB_COMPAT compile time option in the AVRISP-MKII project * - Fixed incompatibility in the CDC class bootloader on some systems (thanks to Sylvain Munaut) + * - Fixed lengthy timeouts in the USBtoSerial project if no application on the host is consuming data (thanks to Nicolas Saugnier) + * - Fixed lengthy automatic data flushing in the CDC and MIDI device class drivers * * \section Sec_ChangeLog120730 Version 120730 * New: diff --git a/LUFA/Drivers/USB/Class/Device/CDCClassDevice.c b/LUFA/Drivers/USB/Class/Device/CDCClassDevice.c index ff0f9bb552..61f4be9d76 100644 --- a/LUFA/Drivers/USB/Class/Device/CDCClassDevice.c +++ b/LUFA/Drivers/USB/Class/Device/CDCClassDevice.c @@ -138,7 +138,10 @@ void CDC_Device_USBTask(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo) return; #if !defined(NO_CLASS_DRIVER_AUTOFLUSH) - CDC_Device_Flush(CDCInterfaceInfo); + Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataINEndpoint.Address); + + if (Endpoint_IsINReady()) + CDC_Device_Flush(CDCInterfaceInfo); #endif } diff --git a/LUFA/Drivers/USB/Class/Device/MIDIClassDevice.c b/LUFA/Drivers/USB/Class/Device/MIDIClassDevice.c index c9553a4135..5defa142aa 100644 --- a/LUFA/Drivers/USB/Class/Device/MIDIClassDevice.c +++ b/LUFA/Drivers/USB/Class/Device/MIDIClassDevice.c @@ -59,7 +59,10 @@ void MIDI_Device_USBTask(USB_ClassInfo_MIDI_Device_t* const MIDIInterfaceInfo) return; #if !defined(NO_CLASS_DRIVER_AUTOFLUSH) - MIDI_Device_Flush(MIDIInterfaceInfo); + Endpoint_SelectEndpoint(MIDIInterfaceInfo->Config.DataINEndpoint.Address); + + if (Endpoint_IsINReady()) + MIDI_Device_Flush(MIDIInterfaceInfo); #endif } diff --git a/Projects/USBtoSerial/USBtoSerial.c b/Projects/USBtoSerial/USBtoSerial.c index 7fe67da447..a0b8de4c4e 100644 --- a/Projects/USBtoSerial/USBtoSerial.c +++ b/Projects/USBtoSerial/USBtoSerial.c @@ -108,21 +108,32 @@ int main(void) uint16_t BufferCount = RingBuffer_GetCount(&USARTtoUSB_Buffer); if ((TIFR0 & (1 << TOV0)) || (BufferCount > (uint8_t)(sizeof(USARTtoUSB_Buffer_Data) * .75))) { - /* Clear flush timer expiry flag */ - TIFR0 |= (1 << TOV0); - - /* Read bytes from the USART receive buffer into the USB IN endpoint */ - while (BufferCount--) + Endpoint_SelectEndpoint(VirtualSerial_CDC_Interface.Config.DataINEndpoint.Address); + + /* Check if a packet is already enqueued to the host - if so, we shouldn't try to send more data + * until it completes as there is a chance nothing is listening and a lengthy timeout could occur */ + if (Endpoint_IsINReady()) { - /* Try to send the next byte of data to the host, abort if there is an error without dequeuing */ - if (CDC_Device_SendByte(&VirtualSerial_CDC_Interface, - RingBuffer_Peek(&USARTtoUSB_Buffer)) != ENDPOINT_READYWAIT_NoError) + /* Clear flush timer expiry flag */ + TIFR0 |= (1 << TOV0); + + /* Never send more than one bank size less one byte to the host at a time, so that we don't block + * while a Zero Length Packet (ZLP) to terminate the transfer is sent if the host isn't listening */ + uint8_t BytesToSend = MIN(BufferCount, (CDC_TXRX_EPSIZE - 1)); + + /* Read bytes from the USART receive buffer into the USB IN endpoint */ + while (BytesToSend--) { - break; - } + /* Try to send the next byte of data to the host, abort if there is an error without dequeuing */ + if (CDC_Device_SendByte(&VirtualSerial_CDC_Interface, + RingBuffer_Peek(&USARTtoUSB_Buffer)) != ENDPOINT_READYWAIT_NoError) + { + break; + } - /* Dequeue the already sent byte from the buffer now we have confirmed that no transmission error occurred */ - RingBuffer_Remove(&USARTtoUSB_Buffer); + /* Dequeue the already sent byte from the buffer now we have confirmed that no transmission error occurred */ + RingBuffer_Remove(&USARTtoUSB_Buffer); + } } }