Skip to content

Commit a95f9db

Browse files
authored
reintroduced RX buffer to implement available/peek/read methods
Note that due to not being interrupt driven, the private method fillRxBuffer() is frequently called to see if there is new data to be added to the buffer. It attempts to read for a few ms, to prevent underruns. Note however that this may have unwanted delays as a side effect.
1 parent c40c5c8 commit a95f9db

File tree

2 files changed

+93
-3
lines changed

2 files changed

+93
-3
lines changed

cores/arduino/HardwareSerial.cpp

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,30 +140,105 @@ void HardwareSerial::begin(unsigned long baud, byte config)
140140
uart_init(&_serial, (uint32_t)baud, databits, parity, stopbits);
141141
}
142142

143+
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
144+
void HardwareSerial::fillRxBuffer(void) // private method: read all characters that can be read
145+
{
146+
// Fill RX buffer during read/available calls
147+
// Newly received characters are added to the buffer
148+
// _rx_buffer_head is the location of the new character
149+
// _rx_buffer_tail is the location of the oldest character that is not read yet
150+
unsigned char c;
151+
/*
152+
while(uart_getc(&_serial, &c) == 0)
153+
{
154+
_rx_buffer[_rx_buffer_head]=c;
155+
_rx_buffer_head = (rx_buffer_index_t)(_rx_buffer_head + 1) % SERIAL_RX_BUFFER_SIZE;
156+
}
157+
*/
158+
// To avoid buffer underruns, we try to read during at least a few millis.
159+
// Perhaps there is a better way, but for now it works.
160+
// Maybe we should also do something to handle disruption of interrupts
161+
/*
162+
#define SERIAL_WAIT_FOR_RX 5000L
163+
uint32_t uStart=micros();
164+
while((micros()-uStart)<SERIAL_WAIT_FOR_RX)
165+
*/
166+
#define SERIAL_WAIT_FOR_RX 3
167+
uint32_t uStart=millis();
168+
while((millis()-uStart)<SERIAL_WAIT_FOR_RX)
169+
{
170+
if(uart_getc(&_serial, &c) == 0)
171+
{
172+
/*
173+
_rx_buffer[_rx_buffer_head]=c;
174+
_rx_buffer_head = (rx_buffer_index_t)(_rx_buffer_head + 1) % SERIAL_RX_BUFFER_SIZE;
175+
/**/
176+
rx_buffer_index_t i = (unsigned int)(_rx_buffer_head + 1) % SERIAL_RX_BUFFER_SIZE;
177+
178+
// if we should be storing the received character into the location
179+
// just before the tail (meaning that the head would advance to the
180+
// current location of the tail), we're about to overflow the buffer
181+
// and so we don't write the character or advance the head.
182+
if (i != _rx_buffer_tail) {
183+
_rx_buffer[_rx_buffer_head] = c;
184+
_rx_buffer_head = i;
185+
}
186+
/**/
187+
}
188+
}
189+
}
190+
143191
void HardwareSerial::end()
144192
{
193+
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
194+
// clear any received data
195+
_rx_buffer_head = _rx_buffer_tail;
196+
145197
uart_deinit(&_serial);
146198
}
147199

148200
int HardwareSerial::available(void)
149201
{
150-
return -1;
202+
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
203+
//return -1;
204+
fillRxBuffer();
205+
return ((unsigned int)(SERIAL_RX_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail)) % SERIAL_RX_BUFFER_SIZE;
151206
}
152207

153208
int HardwareSerial::peek(void)
154209
{
155-
return -1;
210+
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
211+
//return -1;
212+
fillRxBuffer(); // MMOLE 240316: Serial.parseInt() uses peek() with timeout to see if more data is available
213+
if (_rx_buffer_head == _rx_buffer_tail) {
214+
return -1;
215+
} else {
216+
return _rx_buffer[_rx_buffer_tail];
217+
}
156218
}
157219

158220
int HardwareSerial::read(void)
159221
{
160-
161222
unsigned char c;
223+
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
224+
/*
162225
if(uart_getc(&_serial, &c) == 0){
163226
return c;
164227
}else{
165228
return -1;
166229
}
230+
*/
231+
// Fill RX buffer during read/available calls
232+
fillRxBuffer();
233+
234+
// if the head isn't ahead of the tail, we don't have any characters
235+
if (_rx_buffer_head == _rx_buffer_tail) {
236+
return -1;
237+
} else {
238+
unsigned char c = _rx_buffer[_rx_buffer_tail];
239+
_rx_buffer_tail = (rx_buffer_index_t)(_rx_buffer_tail + 1) % SERIAL_RX_BUFFER_SIZE;
240+
return c;
241+
}
167242
}
168243

169244

cores/arduino/HardwareSerial.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
Modified 14 August 2012 by Alarus
2121
Modified 3 December 2013 by Matthijs Kooijman
2222
Modified 1 may 2023 by TempersLee
23+
Modified 13 October 2023 by Maxint R&D
2324
*/
2425

2526
#ifndef HardwareSerial_h
@@ -109,6 +110,17 @@ class HardwareSerial : public Stream {
109110
{
110111
begin(baud, SERIAL_8N1); //SERIAL_9E1_5 SERIAL_8N1
111112
}
113+
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
114+
volatile rx_buffer_index_t _rx_buffer_head;
115+
volatile rx_buffer_index_t _rx_buffer_tail;
116+
//volatile tx_buffer_index_t _tx_buffer_head;
117+
//volatile tx_buffer_index_t _tx_buffer_tail;
118+
119+
// Don't put any members after these buffers, since only the first
120+
// 32 bytes of this struct can be accessed quickly using the ldd
121+
// instruction.
122+
unsigned char _rx_buffer[SERIAL_RX_BUFFER_SIZE];
123+
//unsigned char _tx_buffer[SERIAL_TX_BUFFER_SIZE];
112124
void begin(unsigned long, uint8_t);
113125
void end();
114126

@@ -159,6 +171,9 @@ class HardwareSerial : public Stream {
159171
uint8_t _config;
160172
unsigned long _baud;
161173
void init(PinName _rx, PinName _tx, PinName _rts = NC, PinName _cts = NC);
174+
175+
// MMOLE: reintroduced RX buffer to properly implement read/available/peek methods
176+
void fillRxBuffer(void); // read all characters that can be read
162177
};
163178

164179
#if defined(USART1)

0 commit comments

Comments
 (0)