aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZach Eveland <zeveland@blacklabel-development.com>2011-12-18 17:52:35 -0500
committerZach Eveland <zeveland@blacklabel-development.com>2011-12-18 17:52:35 -0500
commit58fc0d17cc2d7c5dfb4ce268b7e43d35eebac342 (patch)
tree062e7f2a87d4ae1878d75ed093c9f6a7f846ebc4
parent177641003c53844ad73584553a9d44f2da4648e2 (diff)
added asynchronous buffering of received CDC characters
This fixes the issue Federico reported where bytes written by host but not read by sketch would cause serial connection to lock up. Ring buffer implementation is based on HardwareSerial.cpp. Adds public accept() method to CDC.
-rw-r--r--cores/arduino/CDC.cpp67
-rw-r--r--cores/arduino/USBAPI.h3
-rw-r--r--cores/arduino/USBCore.cpp2
3 files changed, 56 insertions, 16 deletions
diff --git a/cores/arduino/CDC.cpp b/cores/arduino/CDC.cpp
index 14a0eae..8605ce3 100644
--- a/cores/arduino/CDC.cpp
+++ b/cores/arduino/CDC.cpp
@@ -30,6 +30,25 @@ void Reboot()
asm volatile("jmp 0x7800"); // jump to bootloader - DiskLoader takes up last 2 kB
}
+// Define constants and variables for buffering incoming serial data. We're
+// using a ring buffer (I think), in which head is the index of the location
+// to which to write the next incoming character and tail is the index of the
+// location from which to read.
+#if (RAMEND < 1000)
+#define SERIAL_BUFFER_SIZE 16
+#else
+#define SERIAL_BUFFER_SIZE 64
+#endif
+
+struct ring_buffer
+{
+ unsigned char buffer[SERIAL_BUFFER_SIZE];
+ volatile int head;
+ volatile int tail;
+};
+
+ring_buffer cdc_rx_buffer = { { 0 }, 0, 0};
+
typedef struct
{
u32 dwDTERate;
@@ -111,33 +130,49 @@ void Serial_::end(void)
{
}
+void Serial_::accept(void)
+{
+ ring_buffer *buffer = &cdc_rx_buffer;
+ int c = USB_Recv(CDC_RX);
+ int i = (unsigned int)(buffer->head+1) % SERIAL_BUFFER_SIZE;
+
+ // 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.
+ if (i != buffer->tail) {
+ buffer->buffer[buffer->head] = c;
+ buffer->head = i;
+ }
+}
+
int Serial_::available(void)
{
- u8 avail = USB_Available(CDC_RX);
- if (_serialPeek != -1)
- avail++;
- return avail;
+ ring_buffer *buffer = &cdc_rx_buffer;
+ return (unsigned int)(SERIAL_BUFFER_SIZE + buffer->head - buffer->tail) % SERIAL_BUFFER_SIZE;
}
-// peek is nasty
int Serial_::peek(void)
{
- if (_serialPeek == -1)
- _serialPeek = read();
- return _serialPeek;
+ ring_buffer *buffer = &cdc_rx_buffer;
+ if (buffer->head == buffer->tail) {
+ return -1;
+ } else {
+ return buffer->buffer[buffer->tail];
+ }
}
int Serial_::read(void)
{
- int c;
- if (_serialPeek != -1)
- {
- c = _serialPeek;
- _serialPeek = -1;
+ ring_buffer *buffer = &cdc_rx_buffer;
+ // if the head isn't ahead of the tail, we don't have any characters
+ if (buffer->head == buffer->tail) {
+ return -1;
} else {
- c = USB_Recv(CDC_RX);
- }
- return c;
+ unsigned char c = buffer->buffer[buffer->tail];
+ buffer->tail = (unsigned int)(buffer->tail + 1) % SERIAL_BUFFER_SIZE;
+ return c;
+ }
}
void Serial_::flush(void)
diff --git a/cores/arduino/USBAPI.h b/cores/arduino/USBAPI.h
index 26a2032..1772c3c 100644
--- a/cores/arduino/USBAPI.h
+++ b/cores/arduino/USBAPI.h
@@ -27,11 +27,14 @@ extern USB_ USB;
class Serial_ : public Stream
{
+private:
+ ring_buffer *_cdc_rx_buffer;
public:
void begin(uint16_t baud_count);
void end(void);
virtual int available(void);
+ virtual void accept(void);
virtual int peek(void);
virtual int read(void);
virtual void flush(void);
diff --git a/cores/arduino/USBCore.cpp b/cores/arduino/USBCore.cpp
index 398bc73..7924078 100644
--- a/cores/arduino/USBCore.cpp
+++ b/cores/arduino/USBCore.cpp
@@ -599,6 +599,8 @@ ISR(USB_GEN_vect)
{
#ifdef CDC_ENABLED
USB_Flush(CDC_TX); // Send a tx frame if found
+ while (USB_Available(CDC_RX)) // Handle received bytes (if any)
+ Serial.accept();
#endif
// check whether the one-shot period has elapsed. if so, turn off the LED