Skip to content

Commit c26e3f4

Browse files
Adds HardwareSerial::setRxTimeout() (#6397)
* Adds HardwareSerial::onReceiveTimeout() * Fixed typo * Changes requested * Fix eventQueueReset * Changed _onReceiveTimeout to _rxTimeout for consistency * Uniform uart_set_rx_timeout condition * test _uart not NULL in eventQueueReset() check if _uart is not NULL before using it. * revert last commit - no need for it reverting last change made - it is not necessary. * adds onReceive() parameter In order to allow the user to choose if onReceive() call back will be called only when UART Rx timeout happens or also when UART FIFO gets 120 bytes, a new parameter has been added to onReceive() with the default behavior based on timeout. void onReceive(OnReceiveCb function, bool onlyOnTimeout = true); onReceive will setup a callback that will be called whenever an UART interruption occurs (UART_INTR_RXFIFO_FULL or UART_INTR_RXFIFO_TOUT) UART_INTR_RXFIFO_FULL interrupt triggers at UART_FULL_THRESH_DEFAULT bytes received (defined as 120 bytes by default in IDF) UART_INTR_RXFIFO_TOUT interrupt triggers at UART_TOUT_THRESH_DEFAULT symbols passed without any reception (defined as 10 symbos by default in IDF) onlyOnTimeout parameter will define how onReceive will behave: Default: true -- The callback will only be called when RX Timeout happens. Whole stream of bytes will be ready for being read on the callback function at once. This option may lead to Rx Overflow depending on the Rx Buffer Size and number of bytes received in the streaming false -- The callback will be called when FIFO reaches 120 bytes and also on RX Timeout. The stream of incommig bytes will be "split" into blocks of 120 bytes on each callback. This option avoid any sort of Rx Overflow, but leaves the UART packet reassembling work to the Application. * Adds onReceive() parameter for timeout only * Adds back setRxTimeout() * Adds setRxTimeout() * CI Syntax error - "," missing Co-authored-by: Rodrigo Garcia <rodrigo.garcia@espressif.com>
1 parent ab34321 commit c26e3f4

File tree

2 files changed

+73
-8
lines changed

2 files changed

+73
-8
lines changed

Diff for: cores/esp32/HardwareSerial.cpp

+46-5
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,13 @@ void serialEventRun(void)
122122

123123
HardwareSerial::HardwareSerial(int uart_nr) :
124124
_uart_nr(uart_nr),
125-
_uart(NULL),
125+
_uart(NULL),
126126
_rxBufferSize(256),
127127
_txBufferSize(0),
128128
_onReceiveCB(NULL),
129129
_onReceiveErrorCB(NULL),
130+
_onReceiveTimeout(true),
131+
_rxTimeout(10),
130132
_eventTask(NULL)
131133
#if !CONFIG_DISABLE_HAL_LOCKS
132134
,_lock(NULL)
@@ -183,18 +185,49 @@ void HardwareSerial::onReceiveError(OnReceiveErrorCb function)
183185
HSERIAL_MUTEX_UNLOCK();
184186
}
185187

186-
void HardwareSerial::onReceive(OnReceiveCb function)
188+
void HardwareSerial::onReceive(OnReceiveCb function, bool onlyOnTimeout)
187189
{
188190
HSERIAL_MUTEX_LOCK();
189191
// function may be NULL to cancel onReceive() from its respective task
190192
_onReceiveCB = function;
193+
// When Rx timeout is Zero (disabled), there is only one possible option that is callback when FIFO reaches 120 bytes
194+
_onReceiveTimeout = _rxTimeout > 0 ? onlyOnTimeout : false;
195+
191196
// this can be called after Serial.begin(), therefore it shall create the event task
192197
if (function != NULL && _uart != NULL && _eventTask == NULL) {
193-
_createEventTask(this);
198+
_createEventTask(this); // Create event task
194199
}
195200
HSERIAL_MUTEX_UNLOCK();
196201
}
197202

203+
// timout is calculates in time to receive UART symbols at the UART baudrate.
204+
// the estimation is about 11 bits per symbol (SERIAL_8N1)
205+
void HardwareSerial::setRxTimeout(uint8_t symbols_timeout)
206+
{
207+
HSERIAL_MUTEX_LOCK();
208+
209+
// Zero disables timeout, thus, onReceive callback will only be called when RX FIFO reaches 120 bytes
210+
// Any non-zero value will activate onReceive callback based on UART baudrate with about 11 bits per symbol
211+
_rxTimeout = symbols_timeout;
212+
if (!symbols_timeout) _onReceiveTimeout = false; // only when RX timeout is disabled, we also must disable this flag
213+
214+
if(_uart != NULL) uart_set_rx_timeout(_uart_nr, _rxTimeout); // Set new timeout
215+
216+
HSERIAL_MUTEX_UNLOCK();
217+
}
218+
219+
void HardwareSerial::eventQueueReset()
220+
{
221+
QueueHandle_t uartEventQueue = NULL;
222+
if (_uart == NULL) {
223+
return;
224+
}
225+
uartGetEventQueue(_uart, &uartEventQueue);
226+
if (uartEventQueue != NULL) {
227+
xQueueReset(uartEventQueue);
228+
}
229+
}
230+
198231
void HardwareSerial::_uartEventTask(void *args)
199232
{
200233
HardwareSerial *uart = (HardwareSerial *)args;
@@ -207,14 +240,16 @@ void HardwareSerial::_uartEventTask(void *args)
207240
if(xQueueReceive(uartEventQueue, (void * )&event, (portTickType)portMAX_DELAY)) {
208241
switch(event.type) {
209242
case UART_DATA:
210-
if(uart->_onReceiveCB && uart->available() > 0) uart->_onReceiveCB();
243+
if(uart->_onReceiveCB && uart->available() > 0 &&
244+
((uart->_onReceiveTimeout && event.timeout_flag) || !uart->_onReceiveTimeout) )
245+
uart->_onReceiveCB();
211246
break;
212247
case UART_FIFO_OVF:
213248
log_w("UART%d FIFO Overflow. Consider adding Hardware Flow Control to your Application.", uart->_uart_nr);
214249
if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_FIFO_OVF_ERROR);
215250
break;
216251
case UART_BUFFER_FULL:
217-
log_w("UART%d Buffer Full. Consider encreasing your buffer size of your Application.", uart->_uart_nr);
252+
log_w("UART%d Buffer Full. Consider increasing your buffer size of your Application.", uart->_uart_nr);
218253
if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_BUFFER_FULL_ERROR);
219254
break;
220255
case UART_BREAK:
@@ -317,6 +352,12 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
317352
if (_uart != NULL && (_onReceiveCB != NULL || _onReceiveErrorCB != NULL) && _eventTask == NULL) {
318353
_createEventTask(this);
319354
}
355+
356+
// Set UART RX timeout
357+
if (_uart != NULL) {
358+
uart_set_rx_timeout(_uart_nr, _rxTimeout);
359+
}
360+
320361
HSERIAL_MUTEX_UNLOCK();
321362
}
322363

Diff for: cores/esp32/HardwareSerial.h

+27-3
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,31 @@ class HardwareSerial: public Stream
7373
HardwareSerial(int uart_nr);
7474
~HardwareSerial();
7575

76-
// onReceive will setup a callback for whenever UART data is received
77-
// it will work as UART Rx interrupt -- Using C++ 11 std::fuction
78-
void onReceive(OnReceiveCb function);
76+
// setRxTimeout sets the timeout after which onReceive callback will be called (after receiving data, it waits for this time of UART rx inactivity to call the callback fnc)
77+
// param symbols_timeout defines a timeout threshold in uart symbol periods. Setting 0 symbol timeout disables the callback call by timeout.
78+
// Maximum timeout setting is calculacted automatically by IDF. If set above the maximum, it is ignored and an error is printed on Serial0 (check console).
79+
// Examples: Maximum for 11 bits symbol is 92 (SERIAL_8N2, SERIAL_8E1, SERIAL_8O1, etc), Maximum for 10 bits symbol is 101 (SERIAL_8N1).
80+
// For example symbols_timeout=1 defines a timeout equal to transmission time of one symbol (~11 bit) on current baudrate.
81+
// For a baudrate of 9600, SERIAL_8N1 (10 bit symbol) and symbols_timeout = 3, the timeout would be 3 / (9600 / 10) = 3.125 ms
82+
void setRxTimeout(uint8_t symbols_timeout);
83+
84+
// onReceive will setup a callback that will be called whenever an UART interruption occurs (UART_INTR_RXFIFO_FULL or UART_INTR_RXFIFO_TOUT)
85+
// UART_INTR_RXFIFO_FULL interrupt triggers at UART_FULL_THRESH_DEFAULT bytes received (defined as 120 bytes by default in IDF)
86+
// UART_INTR_RXFIFO_TOUT interrupt triggers at UART_TOUT_THRESH_DEFAULT symbols passed without any reception (defined as 10 symbos by default in IDF)
87+
// onlyOnTimeout parameter will define how onReceive will behave:
88+
// Default: true -- The callback will only be called when RX Timeout happens.
89+
// Whole stream of bytes will be ready for being read on the callback function at once.
90+
// This option may lead to Rx Overflow depending on the Rx Buffer Size and number of bytes received in the streaming
91+
// false -- The callback will be called when FIFO reaches 120 bytes and also on RX Timeout.
92+
// The stream of incommig bytes will be "split" into blocks of 120 bytes on each callback.
93+
// This option avoid any sort of Rx Overflow, but leaves the UART packet reassembling work to the Application.
94+
void onReceive(OnReceiveCb function, bool onlyOnTimeout = true);
95+
96+
// onReceive will be called on error events (see hardwareSerial_error_t)
7997
void onReceiveError(OnReceiveErrorCb function);
98+
99+
// eventQueueReset clears all events in the queue (the events that trigger onReceive and onReceiveError) - maybe usefull in some use cases
100+
void eventQueueReset();
80101

81102
void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1, bool invert=false, unsigned long timeout_ms = 20000UL, uint8_t rxfifo_full_thrhd = 112);
82103
void end(bool fullyTerminate = true);
@@ -140,6 +161,9 @@ class HardwareSerial: public Stream
140161
size_t _rxBufferSize;
141162
size_t _txBufferSize;
142163
OnReceiveCb _onReceiveCB;
164+
// _onReceive and _rxTimeout have be consistent when timeout is disabled
165+
bool _onReceiveTimeout;
166+
uint8_t _rxTimeout;
143167
OnReceiveErrorCb _onReceiveErrorCB;
144168
TaskHandle_t _eventTask;
145169

0 commit comments

Comments
 (0)