aboutsummaryrefslogtreecommitdiff
path: root/cores/arduino/CDC.cpp
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 /cores/arduino/CDC.cpp
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.
Diffstat (limited to 'cores/arduino/CDC.cpp')
-rw-r--r--cores/arduino/CDC.cpp67
1 files changed, 51 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)