From 52237c845b5371b229dee0152ceaae62e1998bdd Mon Sep 17 00:00:00 2001
From: Cristian Maglie <c.maglie@arduino.cc>
Date: Fri, 13 Feb 2015 16:46:58 +0100
Subject: [PATCH]  CDC-ACM bugfix

---
 cores/arduino/USB/CDC.cpp         | 25 +++++++++++++------------
 cores/arduino/USB/USBCore.cpp     | 17 +++++++++++------
 cores/arduino/USB/samd21_device.c | 31 ++++++++++++++++---------------
 3 files changed, 40 insertions(+), 33 deletions(-)

diff --git a/cores/arduino/USB/CDC.cpp b/cores/arduino/USB/CDC.cpp
index 40fadaa2..33c7b7e8 100644
--- a/cores/arduino/USB/CDC.cpp
+++ b/cores/arduino/USB/CDC.cpp
@@ -160,25 +160,26 @@ void Serial_::end(void)
 
 void Serial_::accept(void)
 {
-	ring_buffer *buffer = &cdc_rx_buffer;
-	uint32_t i = (uint32_t)(buffer->head+1) % CDC_SERIAL_BUFFER_SIZE;
+	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;
 
 	// 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.
-	while (i != buffer->tail) {
-		uint32_t c;
-		if (!USBD_Available(CDC_ENDPOINT_OUT)) {
-            UDD_ReleaseRX(CDC_ENDPOINT_OUT);
-			break;
-		}
-		c = USBD_Recv(CDC_ENDPOINT_OUT);
-		buffer->buffer[buffer->head] = c;
-		buffer->head = i;
-
+	uint32_t k = 0;
+	i = (i + 1) % CDC_SERIAL_BUFFER_SIZE;
+	while (i != ringBuffer->tail && len>0) {
+		len--;
+		ringBuffer->buffer[ringBuffer->head] = buffer[k++];
+		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 41285d4f..8164f252 100644
--- a/cores/arduino/USB/USBCore.cpp
+++ b/cores/arduino/USB/USBCore.cpp
@@ -108,12 +108,17 @@ uint32_t USBD_Recv(uint32_t ep, void* d, uint32_t len)
 	if (!_usbConfiguration)
 		return -1;
 
-	uint32_t n = UDD_FifoByteCount(ep);
-	len = min(n,len);
-	n = len;
-	uint8_t* dst = (uint8_t*)d;
-	while (n--)
-		*dst++ = UDD_Recv_data(ep, 8);
+	uint8_t *buffer;
+	uint8_t *data = (uint8_t *)d;
+
+	len = min(UDD_FifoByteCount(ep), len);
+
+	UDD_Recv_data(ep, len);
+	UDD_Recv(ep, &buffer);
+	for (uint32_t i=0; i<len; i++) {
+		data[i] = buffer[i];
+	}
+
 	if (len && !UDD_FifoByteCount(ep)) // release empty buffer
 		UDD_ReleaseRX(ep);
 
diff --git a/cores/arduino/USB/samd21_device.c b/cores/arduino/USB/samd21_device.c
index 82342405..271243a3 100644
--- a/cores/arduino/USB/samd21_device.c
+++ b/cores/arduino/USB/samd21_device.c
@@ -266,22 +266,23 @@ uint32_t UDD_Send(uint32_t ep, const void* data, uint32_t len)
 	return len;
 }
 
-uint8_t UDD_Recv_data(uint32_t ep, uint32_t len)
-{
-	TRACE_DEVICE(printf("=> UDD_Recvdata : ep=%d\r\n", (char)ep);)
-
-	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;
+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;
 	udd_OUT_transfer_allowed(ep);
-	TRACE_DEVICE(printf("=> UDD_Recv_data : data=%lu\r\n", (unsigned long)data);)
-
-	/* Wait for transfer to complete */
-	while (!udd_is_OUT_transf_cplt(ep));
-	/* Clear Transfer complete 0 flag */
-	udd_clear_OUT_transf_cplt(ep);
-
-	return udd_ep_out_cache_buffer[ep][0];
+	TRACE_DEVICE(printf("=> UDD_Recv_data : data=%lu\r\n", (unsigned long)data);)
+
+	/* Wait for transfer to complete */
+	while (!udd_is_OUT_transf_cplt(ep));
+	/* Clear Transfer complete 0 flag */
+	udd_clear_OUT_transf_cplt(ep);
+
+	return udd_ep_out_cache_buffer[ep][0];
 }
 
 void UDD_Recv(uint32_t ep, uint8_t** ppData)
-- 
GitLab