--- LUFA-120219/Projects/USBtoSerial/USBtoSerial.h
+++ LUFA-120219/Projects/USBtoSerial/USBtoSerial.h
@@ -68,6 +68,9 @@
 
 	/* Function Prototypes: */
 		void SetupHardware(void);
+		void cdc_send_byte(USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, uint8_t data);
+        void cdc_send_USB_data( USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo );
+
 
 		void EVENT_USB_Device_Connect(void);
 		void EVENT_USB_Device_Disconnect(void);


--- LUFA-120219/Projects/USBtoSerial/USBtoSerial.c
+++ LUFA-120219/Projects/USBtoSerial/USBtoSerial.c
@@ -48,6 +48,11 @@ static RingBuffer_t USARTtoUSB_Buffer;
 /** Underlying data buffer for \ref USARTtoUSB_Buffer, where the stored bytes are located. */
 static uint8_t      USARTtoUSB_Buffer_Data[128];
 
+/** Flag used when an additional, empty packet needs to be sent to properly conclude an USB transfer */
+uint8_t needEmptyPacket = false; 
+
+#define min(x,y)                 ( ((x)<(y)) ? (x) : (y) )
+
 /** LUFA CDC Class driver interface configuration and state information. This structure is
  *  passed to all CDC Class driver functions, so that multiple instances of the same class
  *  within a device can be differentiated from one another.
@@ -98,37 +103,58 @@ int main(void)
 			  RingBuffer_Insert(&USBtoUSART_Buffer, ReceivedByte);
 		}
 
-		/* Check if the UART receive buffer flush timer has expired or the buffer is nearly full */
-		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--)
-			{
-				/* 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);
-			}
-		}
-
 		/* Load the next byte from the USART transmit buffer into the USART */
 		if (!(RingBuffer_IsEmpty(&USBtoUSART_Buffer)))
 		  Serial_SendByte(RingBuffer_Remove(&USBtoUSART_Buffer));
 
-		CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
+		cdc_send_USB_data(&VirtualSerial_CDC_Interface);
 		USB_USBTask();
 	}
 }
 
+
+void cdc_send_byte( USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo, uint8_t data){ // TODO inline ?
+	RingBuffer_Insert(&USARTtoUSB_Buffer, data);
+    TIFR0 |= (1 << TOV0); // Clear timer
+}
+
+void cdc_send_USB_data( USB_ClassInfo_CDC_Device_t* const CDCInterfaceInfo ){
+    
+	// process outgoing USB data
+	Endpoint_SelectEndpoint(CDCInterfaceInfo->Config.DataINEndpointNumber); // select IN endpoint to restore its registers
+	if ( UEINTX & (1<<TXINI) ){ // if we can write on the outgoing data bank
+		uint8_t BufferCount = RingBuffer_GetCount(&USARTtoUSB_Buffer);
+		
+		if (BufferCount) {
+			uint8_t bank_size = CDCInterfaceInfo->Config.DataINEndpointSize;
+	
+			// if there are more bytes in the buffer than what can be put in the data bank OR there are a few bytes and they have been waiting for too long
+			if ( BufferCount >= bank_size || (TIFR0 & (1 << TOV0)) ){
+				// Clear flush timer expiry flag
+			    TIFR0 |= (1 << TOV0);
+				
+				// load the IN data bank until full or until we loaded all the bytes we know we have
+				uint8_t nb_to_write = min(BufferCount, bank_size );					
+				while (nb_to_write--){
+                	uint8_t Data = RingBuffer_Remove(&USARTtoUSB_Buffer);
+					Endpoint_Write_8(Data);
+				}
+				
+				// if the bank is full (== we can't write to it anymore), we might need an empty packet after this one
+				needEmptyPacket = ! Endpoint_IsReadWriteAllowed();
+				
+				Endpoint_ClearIN(); // allow the hardware to send the content of the bank
+			}
+		} else if (needEmptyPacket) {
+			// send an empty packet to end the transfer
+			needEmptyPacket = false;
+			Endpoint_ClearIN(); // allow the hardware to send the content of the bank
+		}
+		
+	}
+}
+
+
 /** Configures the board hardware and chip peripherals for the demo's functionality. */
 void SetupHardware(void)
 {
@@ -183,7 +209,7 @@ ISR(USART1_RX_vect, ISR_BLOCK)
 	uint8_t ReceivedByte = UDR1;
 
 	if (USB_DeviceState == DEVICE_STATE_Configured)
-	  RingBuffer_Insert(&USARTtoUSB_Buffer, ReceivedByte);
+	  cdc_send_byte(&VirtualSerial_CDC_Interface, ReceivedByte);
 }
 
 /** Event handler for the CDC Class driver Line Encoding Changed event.

 
 
 