From d1813604258488b65973f4fb8e6c4c97af0ce82e Mon Sep 17 00:00:00 2001
From: Cristian Maglie <c.maglie@arduino.cc>
Date: Fri, 6 Mar 2015 15:11:56 +0100
Subject: [PATCH]  Fixed incorrect CDC-USB buffer handling

---
 cores/arduino/USB/CDC.cpp         | 33 +++++++++++++++++++++----------
 cores/arduino/USB/USBCore.cpp     | 29 +++++++++++++++------------
 cores/arduino/USB/samd21_device.c | 24 +++++-----------------
 3 files changed, 44 insertions(+), 42 deletions(-)

diff --git a/cores/arduino/USB/CDC.cpp b/cores/arduino/USB/CDC.cpp
index 33c7b7e8..139e96fe 100644
--- a/cores/arduino/USB/CDC.cpp
+++ b/cores/arduino/USB/CDC.cpp
@@ -34,7 +34,7 @@
 
 #ifdef CDC_ENABLED
 
-#define CDC_SERIAL_BUFFER_SIZE	64
+#define CDC_SERIAL_BUFFER_SIZE	512
 
 /* For information purpose only since RTS is not always handled by the terminal application */
 #define CDC_LINESTATE_DTR		0x01 // Data Terminal Ready
@@ -160,26 +160,39 @@ void Serial_::end(void)
 
 void Serial_::accept(void)
 {
+	volatile uint32_t len,k=0, size=0;
 	uint8_t buffer[CDC_SERIAL_BUFFER_SIZE];
-	uint32_t len = USBD_Recv(CDC_ENDPOINT_OUT, (void*)&buffer, CDC_SERIAL_BUFFER_SIZE);
 
-	noInterrupts();
 	ring_buffer *ringBuffer = &cdc_rx_buffer;
-	uint32_t i = ringBuffer->head;
+	uint32_t i = (uint32_t)(ringBuffer->head+1) % CDC_SERIAL_BUFFER_SIZE;
+
+	size = 0;
+	do
+	{
+		len = USBD_Recv(CDC_ENDPOINT_OUT, (void*)&buffer+size, CDC_SERIAL_BUFFER_SIZE);
+		size += len;
+		if( size >= 512) break;
+	} while(len != 0 );
+
+	udd_clear_OUT_transf_cplt(CDC_ENDPOINT_OUT);
 
 	// if we should be storing the received character into the location
 	// just before the tail (meaning that the head would advance to the
 	// current location of the tail), we're about to overflow the buffer
 	// and so we don't write the character or advance the head.
-	uint32_t k = 0;
-	i = (i + 1) % CDC_SERIAL_BUFFER_SIZE;
-	while (i != ringBuffer->tail && len>0) {
-		len--;
-		ringBuffer->buffer[ringBuffer->head] = buffer[k++];
+	while (i != ringBuffer->tail) {
+		uint32_t c;
+		if (size == 0) {  // if (!USBD_Available(CDC_RX)) { udd_ack_fifocon(CDC_RX);
+			break;
+		}
+		size--;
+		c = buffer[k++];
+		// c = UDD_Recv8(CDC_RX & 0xF);
+		ringBuffer->buffer[ringBuffer->head] = c;
 		ringBuffer->head = i;
+
 		i = (i + 1) % CDC_SERIAL_BUFFER_SIZE;
 	}
-	interrupts();
 }
 
 int Serial_::available(void)
diff --git a/cores/arduino/USB/USBCore.cpp b/cores/arduino/USB/USBCore.cpp
index 8164f252..6addf5db 100644
--- a/cores/arduino/USB/USBCore.cpp
+++ b/cores/arduino/USB/USBCore.cpp
@@ -105,24 +105,27 @@ uint32_t USBD_Available(uint32_t ep)
 //	Return number of bytes read
 uint32_t USBD_Recv(uint32_t ep, void* d, uint32_t len)
 {
-	if (!_usbConfiguration)
-		return -1;
-
-	uint8_t *buffer;
+	uint8_t *tmpbuffer;
 	uint8_t *data = (uint8_t *)d;
 
-	len = min(UDD_FifoByteCount(ep), len);
+	if (!_usbConfiguration || len < 0)
+		return -1;
 
-	UDD_Recv_data(ep, len);
-	UDD_Recv(ep, &buffer);
-	for (uint32_t i=0; i<len; i++) {
-		data[i] = buffer[i];
+	uint32_t n = UDD_FifoByteCount(ep);
+	
+// 	len = min(n,len);
+// 	n = len;
+
+	UDD_Recv_data(ep, n);
+	UDD_Recv(ep, &tmpbuffer);
+	for (int i=0; i<n; i++) {
+		data[i] = tmpbuffer[i];
 	}
 
-	if (len && !UDD_FifoByteCount(ep)) // release empty buffer
-		UDD_ReleaseRX(ep);
+// 	if (n && !UDD_FifoByteCount(ep)) // release empty buffer
+// 		UDD_ReleaseRX(ep);
 
-	return len;
+	return n;
 }
 
 //	Recv 1 byte if ready
@@ -206,7 +209,7 @@ uint32_t USBD_RecvControl(void* d, uint32_t len)
 		read = len;
 	UDD_Recv(EP0, &buffer);
 	while (!udd_is_OUT_transf_cplt(EP0));
-	for (uint32_t i=0; i<read; i++) {
+	for (int i=0; i<read; i++) {
 		data[i] = buffer[i];
 	}
 	udd_OUT_transfer_allowed(EP0);
diff --git a/cores/arduino/USB/samd21_device.c b/cores/arduino/USB/samd21_device.c
index 271243a3..e73bf194 100644
--- a/cores/arduino/USB/samd21_device.c
+++ b/cores/arduino/USB/samd21_device.c
@@ -25,17 +25,11 @@
 #include "USB/samd21_device.h"
 #include "sam.h"
 
-#ifdef __cplusplus
-extern "C"{
-#endif // __cplusplus
-
-#ifdef SAMD_SERIES
-
 //#define TRACE_DEVICE(x)	x
 #define TRACE_DEVICE(x)
 
-__attribute__((__aligned__(4))) /*__attribute__((__section__(".bss_hram0")))*/ uint8_t udd_ep_out_cache_buffer[4][64];
-__attribute__((__aligned__(4))) /*__attribute__((__section__(".bss_hram0")))*/ uint8_t udd_ep_in_cache_buffer[4][128];
+__attribute__((__aligned__(4)))   __attribute__((__section__(".bss_hram0"))) uint8_t udd_ep_out_cache_buffer[4][64];
+__attribute__((__aligned__(4)))   __attribute__((__section__(".bss_hram0"))) uint8_t udd_ep_in_cache_buffer[4][128];
 
 /**
  * USB SRAM data containing pipe descriptor table
@@ -270,7 +264,6 @@ uint8_t UDD_Recv_data(uint32_t ep, uint32_t len)
 {
 	TRACE_DEVICE(printf("=> UDD_Recvdata : ep=%d\r\n", (char)ep);)
 
-	if (len>64) len=64;
 	usb_endpoint_table[ep].DeviceDescBank[0].ADDR.reg = (uint32_t)&udd_ep_out_cache_buffer[ep];
 	usb_endpoint_table[ep].DeviceDescBank[0].PCKSIZE.bit.MULTI_PACKET_SIZE = len;
 	usb_endpoint_table[ep].DeviceDescBank[0].PCKSIZE.bit.BYTE_COUNT = 0;
@@ -280,7 +273,7 @@ uint8_t UDD_Recv_data(uint32_t ep, uint32_t len)
 	/* Wait for transfer to complete */
 	while (!udd_is_OUT_transf_cplt(ep));
 	/* Clear Transfer complete 0 flag */
-	udd_clear_OUT_transf_cplt(ep);
+//	udd_clear_OUT_transf_cplt(ep);
 
 	return udd_ep_out_cache_buffer[ep][0];
 }
@@ -309,7 +302,7 @@ void UDD_ReleaseRX(uint32_t ep)
 	// The RAM Buffer is empty: we can receive data
 	udd_OUT_transfer_allowed(ep);
 	/* Clear Transfer complete 0 flag */
-	udd_clear_OUT_transf_cplt(ep);
+//	udd_clear_OUT_transf_cplt(ep);
 }
 
 void UDD_ReleaseTX(uint32_t ep)
@@ -318,7 +311,7 @@ void UDD_ReleaseTX(uint32_t ep)
 	// The RAM Buffer is full: we can send data
     udd_IN_transfer_allowed(ep);
  	/* Clear the transfer complete flag  */
-    udd_clear_IN_transf_cplt(ep);
+   // udd_clear_IN_transf_cplt(ep);
 }
 
 void UDD_SetAddress(uint32_t addr)
@@ -342,10 +335,3 @@ uint32_t UDD_GetFrameNumber(void)
 {
 	return udd_frame_number();
 }
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* SAMD_SERIES */
-
-- 
GitLab