mirror of
https://github.com/arduino/Arduino.git
synced 2025-02-19 13:54:23 +01:00
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.
This commit is contained in:
parent
6a44faedbb
commit
fd28193336
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
int Serial_::available(void)
|
||||
void Serial_::accept(void)
|
||||
{
|
||||
u8 avail = USB_Available(CDC_RX);
|
||||
if (_serialPeek != -1)
|
||||
avail++;
|
||||
return avail;
|
||||
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)
|
||||
{
|
||||
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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user