From af0dabe394d9389a2293ed94624b5d23fe95e018 Mon Sep 17 00:00:00 2001 From: Gonzalo Brusco Date: Tue, 8 Mar 2022 17:40:50 -0300 Subject: [PATCH 01/13] Adds HardwareSerial::onReceiveTimeout() --- cores/esp32/HardwareSerial.cpp | 32 +++++++++++++++++++++++++++++--- cores/esp32/HardwareSerial.h | 15 ++++++++++++++- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 61c41cebfb0..281e2ecfc42 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -128,7 +128,8 @@ HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL), _rxBufferSize(256), -_onReceiveCB(NULL), +_onReceiveCB(NULL), +_onReceiveTimeout(10), _onReceiveErrorCB(NULL), _eventTask(NULL) #if !CONFIG_DISABLE_HAL_LOCKS @@ -191,10 +192,27 @@ void HardwareSerial::onReceive(OnReceiveCb function) HSERIAL_MUTEX_LOCK(); // function may be NULL to cancel onReceive() from its respective task _onReceiveCB = function; + // this can be called after Serial.begin(), therefore it shall create the event task if (function != NULL && _uart != NULL && _eventTask == NULL) { - _createEventTask(this); + _createEventTask(this); // Create event task + } + HSERIAL_MUTEX_UNLOCK(); +} + +void HardwareSerial::onReceiveTimeout(uint8_t symbols_timeout) +{ + HSERIAL_MUTEX_LOCK(); + + if(symbols_timeout == 0) { + _onReceiveTimeout = 1; // Never disable timeout + } + else { + _onReceiveTimeout = symbols_timeout; } + + if(_uart != NULL) uart_set_rx_timeout(_uart_nr, _onReceiveTimeout); // Set new timeout + HSERIAL_MUTEX_UNLOCK(); } @@ -210,15 +228,17 @@ void HardwareSerial::_uartEventTask(void *args) if(xQueueReceive(uartEventQueue, (void * )&event, (portTickType)portMAX_DELAY)) { switch(event.type) { case UART_DATA: - if(uart->_onReceiveCB && uart->available() > 0) uart->_onReceiveCB(); + if(uart->_onReceiveCB && uart->available() > 0 && event.timeout_flag) uart->_onReceiveCB(); break; case UART_FIFO_OVF: log_w("UART%d FIFO Overflow. Consider adding Hardware Flow Control to your Application.", uart->_uart_nr); if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_FIFO_OVF_ERROR); + xQueueReset(uartEventQueue); break; case UART_BUFFER_FULL: log_w("UART%d Buffer Full. Consider encreasing your buffer size of your Application.", uart->_uart_nr); if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_BUFFER_FULL_ERROR); + xQueueReset(uartEventQueue); break; case UART_BREAK: log_w("UART%d RX break.", uart->_uart_nr); @@ -314,6 +334,12 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in if (_uart != NULL && (_onReceiveCB != NULL || _onReceiveErrorCB != NULL) && _eventTask == NULL) { _createEventTask(this); } + + // Set UART RX timeout + if (_uart != NULL && _onReceiveCB != NULL) { + uart_set_rx_timeout(_uart_nr, _onReceiveTimeout); + } + HSERIAL_MUTEX_UNLOCK(); } diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index 7a25b64e37f..1547c83c319 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -73,9 +73,21 @@ class HardwareSerial: public Stream HardwareSerial(int uart_nr); ~HardwareSerial(); - // onReceive will setup a callback for whenever UART data is received + // onReceive will setup a callback for whenever UART data is received and a later timeout occurs (no receiving data after specified time): + // param function is the callback to be called after reception timeout + // it will work as UART Rx interrupt -- Using C++ 11 std::fuction void onReceive(OnReceiveCb function); + + // onReceiveTimeout 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) + // param symbols_timeout defines a timeout threshold in uart symbol periods. + // Minimum is 1 symbol timeout. Maximum is calculacted automatically by IDF. If set above the maximum, it is ignored and an error is printed on Serial0 (check console). + // Examples: Maximum for 11 bits symbol is 92 (SERIAL_8N2, SERIAL_8E1, SERIAL_8O1, etc), Maximum for 11 bits symbol is 101 (SERIAL_8N1). + // For example symbols_timeout=1 defines a timeout equal to transmission time of one symbol (~11 bit) on current baudrate. + // For a baudrate of 9600, SERIAL_8N1 (10 bit symbol) and symbols_timeout = 3, the timeout would be 3 / (9600 / 10) = 3.125 ms + void onReceiveTimeout(uint8_t symbols_timeout); + + // onReceive will be called on error events (see hardwareSerial_error_t) void onReceiveError(OnReceiveErrorCb function); 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); @@ -138,6 +150,7 @@ class HardwareSerial: public Stream uart_t* _uart; size_t _rxBufferSize; OnReceiveCb _onReceiveCB; + uint8_t _onReceiveTimeout; OnReceiveErrorCb _onReceiveErrorCB; TaskHandle_t _eventTask; From fa717e7da7619a572bfbe7ded8fcd6c37ed16ff2 Mon Sep 17 00:00:00 2001 From: Gonzalo Brusco Date: Mon, 14 Mar 2022 08:34:04 -0300 Subject: [PATCH 02/13] Fixed typo --- cores/esp32/HardwareSerial.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index 1547c83c319..be68aa6c25d 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -82,7 +82,7 @@ class HardwareSerial: public Stream // onReceiveTimeout 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) // param symbols_timeout defines a timeout threshold in uart symbol periods. // Minimum is 1 symbol timeout. Maximum is calculacted automatically by IDF. If set above the maximum, it is ignored and an error is printed on Serial0 (check console). - // Examples: Maximum for 11 bits symbol is 92 (SERIAL_8N2, SERIAL_8E1, SERIAL_8O1, etc), Maximum for 11 bits symbol is 101 (SERIAL_8N1). + // Examples: Maximum for 11 bits symbol is 92 (SERIAL_8N2, SERIAL_8E1, SERIAL_8O1, etc), Maximum for 10 bits symbol is 101 (SERIAL_8N1). // For example symbols_timeout=1 defines a timeout equal to transmission time of one symbol (~11 bit) on current baudrate. // For a baudrate of 9600, SERIAL_8N1 (10 bit symbol) and symbols_timeout = 3, the timeout would be 3 / (9600 / 10) = 3.125 ms void onReceiveTimeout(uint8_t symbols_timeout); From 951ad8761a80f6d9a609e0cf56aea13b901105d2 Mon Sep 17 00:00:00 2001 From: gonzabrusco Date: Mon, 21 Mar 2022 17:02:00 -0300 Subject: [PATCH 03/13] Changes requested --- cores/esp32/HardwareSerial.cpp | 22 ++++++++++++---------- cores/esp32/HardwareSerial.h | 21 +++++++++++++-------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index a99b8b14092..806dca086e5 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -200,22 +200,26 @@ void HardwareSerial::onReceive(OnReceiveCb function) HSERIAL_MUTEX_UNLOCK(); } -void HardwareSerial::onReceiveTimeout(uint8_t symbols_timeout) +void HardwareSerial::setRxTimeout(uint8_t symbols_timeout) { HSERIAL_MUTEX_LOCK(); - if(symbols_timeout == 0) { - _onReceiveTimeout = 1; // Never disable timeout - } - else { - _onReceiveTimeout = symbols_timeout; - } + _onReceiveTimeout = symbols_timeout; if(_uart != NULL) uart_set_rx_timeout(_uart_nr, _onReceiveTimeout); // Set new timeout HSERIAL_MUTEX_UNLOCK(); } +void HardwareSerial::eventQueueReset() +{ + QueueHandle_t uartEventQueue = NULL; + uartGetEventQueue(uart->_uart, &uartEventQueue); + if (uartEventQueue != NULL) { + xQueueReset(uartEventQueue); + } +} + void HardwareSerial::_uartEventTask(void *args) { HardwareSerial *uart = (HardwareSerial *)args; @@ -228,17 +232,15 @@ void HardwareSerial::_uartEventTask(void *args) if(xQueueReceive(uartEventQueue, (void * )&event, (portTickType)portMAX_DELAY)) { switch(event.type) { case UART_DATA: - if(uart->_onReceiveCB && uart->available() > 0 && event.timeout_flag) uart->_onReceiveCB(); + if(uart->_onReceiveCB && uart->available() > 0) uart->_onReceiveCB(event.timeout_flag); break; case UART_FIFO_OVF: log_w("UART%d FIFO Overflow. Consider adding Hardware Flow Control to your Application.", uart->_uart_nr); if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_FIFO_OVF_ERROR); - xQueueReset(uartEventQueue); break; case UART_BUFFER_FULL: log_w("UART%d Buffer Full. Consider encreasing your buffer size of your Application.", uart->_uart_nr); if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_BUFFER_FULL_ERROR); - xQueueReset(uartEventQueue); break; case UART_BREAK: log_w("UART%d RX break.", uart->_uart_nr); diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index be68aa6c25d..3b1de95bb79 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -64,7 +64,7 @@ typedef enum { UART_PARITY_ERROR } hardwareSerial_error_t; -typedef std::function OnReceiveCb; +typedef std::function OnReceiveCb; typedef std::function OnReceiveErrorCb; class HardwareSerial: public Stream @@ -73,22 +73,27 @@ class HardwareSerial: public Stream HardwareSerial(int uart_nr); ~HardwareSerial(); - // onReceive will setup a callback for whenever UART data is received and a later timeout occurs (no receiving data after specified time): + // 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) + // The prototype of the callback function passed must be as defined by OnReceiveCb (void callbackFunction(bool timeout)) + // The bool parameter in the callback function prototype informs the callback function if the callback was called because a timeout (true) or because the RX FIFO reached 120 bytes (false) // param function is the callback to be called after reception timeout - - // it will work as UART Rx interrupt -- Using C++ 11 std::fuction void onReceive(OnReceiveCb function); - // onReceiveTimeout 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) - // param symbols_timeout defines a timeout threshold in uart symbol periods. - // Minimum is 1 symbol timeout. Maximum is calculacted automatically by IDF. If set above the maximum, it is ignored and an error is printed on Serial0 (check console). + // 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) + // param symbols_timeout defines a timeout threshold in uart symbol periods. Setting 0 symbol timeout disables the callback call by timeout. + // 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). // Examples: Maximum for 11 bits symbol is 92 (SERIAL_8N2, SERIAL_8E1, SERIAL_8O1, etc), Maximum for 10 bits symbol is 101 (SERIAL_8N1). // For example symbols_timeout=1 defines a timeout equal to transmission time of one symbol (~11 bit) on current baudrate. // For a baudrate of 9600, SERIAL_8N1 (10 bit symbol) and symbols_timeout = 3, the timeout would be 3 / (9600 / 10) = 3.125 ms - void onReceiveTimeout(uint8_t symbols_timeout); + void setRxTimeout(uint8_t symbols_timeout); // onReceive will be called on error events (see hardwareSerial_error_t) void onReceiveError(OnReceiveErrorCb function); + + // eventQueueReset clears all events in the queue (the events that trigger onReceive and onReceiveError) + void eventQueueReset() 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); void end(bool fullyTerminate = true); From 8db240098f36365794e4c6ce1af296fe55f5b574 Mon Sep 17 00:00:00 2001 From: gonzabrusco Date: Mon, 21 Mar 2022 17:13:56 -0300 Subject: [PATCH 04/13] Fix eventQueueReset --- cores/esp32/HardwareSerial.cpp | 2 +- cores/esp32/HardwareSerial.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 806dca086e5..44b2e3c968b 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -214,7 +214,7 @@ void HardwareSerial::setRxTimeout(uint8_t symbols_timeout) void HardwareSerial::eventQueueReset() { QueueHandle_t uartEventQueue = NULL; - uartGetEventQueue(uart->_uart, &uartEventQueue); + uartGetEventQueue(_uart, &uartEventQueue); if (uartEventQueue != NULL) { xQueueReset(uartEventQueue); } diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index 3b1de95bb79..5b96611d2a2 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -93,7 +93,7 @@ class HardwareSerial: public Stream void onReceiveError(OnReceiveErrorCb function); // eventQueueReset clears all events in the queue (the events that trigger onReceive and onReceiveError) - void eventQueueReset() + void eventQueueReset(); 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); void end(bool fullyTerminate = true); From 1aff6b149f1b91de59c37c4fa91c0b781e912866 Mon Sep 17 00:00:00 2001 From: Gonzalo Brusco Date: Mon, 21 Mar 2022 19:00:02 -0300 Subject: [PATCH 05/13] Changed _onReceiveTimeout to _rxTimeout for consistency --- cores/esp32/HardwareSerial.cpp | 8 ++++---- cores/esp32/HardwareSerial.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 44b2e3c968b..df7a8563d50 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -129,7 +129,7 @@ _uart_nr(uart_nr), _uart(NULL), _rxBufferSize(256), _onReceiveCB(NULL), -_onReceiveTimeout(10), +_rxTimeout(10), _onReceiveErrorCB(NULL), _eventTask(NULL) #if !CONFIG_DISABLE_HAL_LOCKS @@ -204,9 +204,9 @@ void HardwareSerial::setRxTimeout(uint8_t symbols_timeout) { HSERIAL_MUTEX_LOCK(); - _onReceiveTimeout = symbols_timeout; + _rxTimeout = symbols_timeout; - if(_uart != NULL) uart_set_rx_timeout(_uart_nr, _onReceiveTimeout); // Set new timeout + if(_uart != NULL) uart_set_rx_timeout(_uart_nr, _rxTimeout); // Set new timeout HSERIAL_MUTEX_UNLOCK(); } @@ -345,7 +345,7 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in // Set UART RX timeout if (_uart != NULL && _onReceiveCB != NULL) { - uart_set_rx_timeout(_uart_nr, _onReceiveTimeout); + uart_set_rx_timeout(_uart_nr, _rxTimeout); } HSERIAL_MUTEX_UNLOCK(); diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index 5b96611d2a2..84d0c5462a4 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -155,7 +155,7 @@ class HardwareSerial: public Stream uart_t* _uart; size_t _rxBufferSize; OnReceiveCb _onReceiveCB; - uint8_t _onReceiveTimeout; + uint8_t _rxTimeout; OnReceiveErrorCb _onReceiveErrorCB; TaskHandle_t _eventTask; From 42fe78f8b8931858ba49c99894fae67fddd6d02b Mon Sep 17 00:00:00 2001 From: gonzabrusco Date: Tue, 22 Mar 2022 08:37:55 -0300 Subject: [PATCH 06/13] Uniform uart_set_rx_timeout condition --- cores/esp32/HardwareSerial.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index df7a8563d50..afb410c5730 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -344,7 +344,7 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in } // Set UART RX timeout - if (_uart != NULL && _onReceiveCB != NULL) { + if (_uart != NULL) { uart_set_rx_timeout(_uart_nr, _rxTimeout); } From 83ff56d1ca9a41b6fe8aaac874f757cf4f332269 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Tue, 22 Mar 2022 15:07:36 -0300 Subject: [PATCH 07/13] test _uart not NULL in eventQueueReset() check if _uart is not NULL before using it. --- cores/esp32/HardwareSerial.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index afb410c5730..7e479267d04 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -214,6 +214,9 @@ void HardwareSerial::setRxTimeout(uint8_t symbols_timeout) void HardwareSerial::eventQueueReset() { QueueHandle_t uartEventQueue = NULL; + if (_uart == NULL) { + return; + } uartGetEventQueue(_uart, &uartEventQueue); if (uartEventQueue != NULL) { xQueueReset(uartEventQueue); From be508185ebe442262cbfc7424d3b663fa3815d28 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Tue, 22 Mar 2022 15:46:05 -0300 Subject: [PATCH 08/13] revert last commit - no need for it reverting last change made - it is not necessary. --- cores/esp32/HardwareSerial.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 7e479267d04..afb410c5730 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -214,9 +214,6 @@ void HardwareSerial::setRxTimeout(uint8_t symbols_timeout) void HardwareSerial::eventQueueReset() { QueueHandle_t uartEventQueue = NULL; - if (_uart == NULL) { - return; - } uartGetEventQueue(_uart, &uartEventQueue); if (uartEventQueue != NULL) { xQueueReset(uartEventQueue); From 807d7505500d39209ad50bc7196d1651ebfcc620 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Thu, 24 Mar 2022 19:53:28 -0300 Subject: [PATCH 09/13] 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. --- cores/esp32/HardwareSerial.cpp | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index afb410c5730..ab164a527ca 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -129,7 +129,7 @@ _uart_nr(uart_nr), _uart(NULL), _rxBufferSize(256), _onReceiveCB(NULL), -_rxTimeout(10), +_onReceiveTimeout(true), _onReceiveErrorCB(NULL), _eventTask(NULL) #if !CONFIG_DISABLE_HAL_LOCKS @@ -187,11 +187,12 @@ void HardwareSerial::onReceiveError(OnReceiveErrorCb function) HSERIAL_MUTEX_UNLOCK(); } -void HardwareSerial::onReceive(OnReceiveCb function) +void HardwareSerial::onReceive(OnReceiveCb function, bool onlyOnTimeout) { HSERIAL_MUTEX_LOCK(); // function may be NULL to cancel onReceive() from its respective task _onReceiveCB = function; + _onReceiveTimeout = onlyOnTimeout; // this can be called after Serial.begin(), therefore it shall create the event task if (function != NULL && _uart != NULL && _eventTask == NULL) { @@ -200,20 +201,12 @@ void HardwareSerial::onReceive(OnReceiveCb function) HSERIAL_MUTEX_UNLOCK(); } -void HardwareSerial::setRxTimeout(uint8_t symbols_timeout) -{ - HSERIAL_MUTEX_LOCK(); - - _rxTimeout = symbols_timeout; - - if(_uart != NULL) uart_set_rx_timeout(_uart_nr, _rxTimeout); // Set new timeout - - HSERIAL_MUTEX_UNLOCK(); -} - void HardwareSerial::eventQueueReset() { QueueHandle_t uartEventQueue = NULL; + if (_uart == NULL) { + return; + } uartGetEventQueue(_uart, &uartEventQueue); if (uartEventQueue != NULL) { xQueueReset(uartEventQueue); @@ -232,14 +225,16 @@ void HardwareSerial::_uartEventTask(void *args) if(xQueueReceive(uartEventQueue, (void * )&event, (portTickType)portMAX_DELAY)) { switch(event.type) { case UART_DATA: - if(uart->_onReceiveCB && uart->available() > 0) uart->_onReceiveCB(event.timeout_flag); + if(uart->_onReceiveCB && uart->available() > 0 && + ((uart->_onReceiveTimeout && event.timeout_flag) || !uart->_onReceiveTimeout) ) + uart->_onReceiveCB(); break; case UART_FIFO_OVF: log_w("UART%d FIFO Overflow. Consider adding Hardware Flow Control to your Application.", uart->_uart_nr); if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_FIFO_OVF_ERROR); break; case UART_BUFFER_FULL: - log_w("UART%d Buffer Full. Consider encreasing your buffer size of your Application.", uart->_uart_nr); + log_w("UART%d Buffer Full. Consider increasing your buffer size of your Application.", uart->_uart_nr); if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_BUFFER_FULL_ERROR); break; case UART_BREAK: @@ -343,11 +338,6 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in _createEventTask(this); } - // Set UART RX timeout - if (_uart != NULL) { - uart_set_rx_timeout(_uart_nr, _rxTimeout); - } - HSERIAL_MUTEX_UNLOCK(); } From d5de62c4cd2bd071ba01e382a853f0f155ee16c1 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Thu, 24 Mar 2022 19:54:43 -0300 Subject: [PATCH 10/13] Adds onReceive() parameter for timeout only --- cores/esp32/HardwareSerial.h | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index 84d0c5462a4..ce9731c17af 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -64,7 +64,7 @@ typedef enum { UART_PARITY_ERROR } hardwareSerial_error_t; -typedef std::function OnReceiveCb; +typedef std::function OnReceiveCb; typedef std::function OnReceiveErrorCb; class HardwareSerial: public Stream @@ -76,23 +76,19 @@ class HardwareSerial: public Stream // 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) - // The prototype of the callback function passed must be as defined by OnReceiveCb (void callbackFunction(bool timeout)) - // The bool parameter in the callback function prototype informs the callback function if the callback was called because a timeout (true) or because the RX FIFO reached 120 bytes (false) - // param function is the callback to be called after reception timeout - void onReceive(OnReceiveCb function); - - // 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) - // param symbols_timeout defines a timeout threshold in uart symbol periods. Setting 0 symbol timeout disables the callback call by timeout. - // 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). - // Examples: Maximum for 11 bits symbol is 92 (SERIAL_8N2, SERIAL_8E1, SERIAL_8O1, etc), Maximum for 10 bits symbol is 101 (SERIAL_8N1). - // For example symbols_timeout=1 defines a timeout equal to transmission time of one symbol (~11 bit) on current baudrate. - // For a baudrate of 9600, SERIAL_8N1 (10 bit symbol) and symbols_timeout = 3, the timeout would be 3 / (9600 / 10) = 3.125 ms - void setRxTimeout(uint8_t symbols_timeout); + // 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. + void onReceive(OnReceiveCb function, bool onlyOnTimeout = true); // onReceive will be called on error events (see hardwareSerial_error_t) void onReceiveError(OnReceiveErrorCb function); - // eventQueueReset clears all events in the queue (the events that trigger onReceive and onReceiveError) + // eventQueueReset clears all events in the queue (the events that trigger onReceive and onReceiveError) - maybe usefull in some use cases void eventQueueReset(); 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); @@ -155,7 +151,7 @@ class HardwareSerial: public Stream uart_t* _uart; size_t _rxBufferSize; OnReceiveCb _onReceiveCB; - uint8_t _rxTimeout; + bool _onReceiveTimeout; OnReceiveErrorCb _onReceiveErrorCB; TaskHandle_t _eventTask; From c1b08e880131de3b00765c437c3453295613f3d6 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Fri, 25 Mar 2022 08:45:22 -0300 Subject: [PATCH 11/13] Adds back setRxTimeout() --- cores/esp32/HardwareSerial.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index ab164a527ca..995efc5fa83 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -130,6 +130,7 @@ _uart(NULL), _rxBufferSize(256), _onReceiveCB(NULL), _onReceiveTimeout(true), +_rxTimeout(10), _onReceiveErrorCB(NULL), _eventTask(NULL) #if !CONFIG_DISABLE_HAL_LOCKS @@ -192,7 +193,8 @@ void HardwareSerial::onReceive(OnReceiveCb function, bool onlyOnTimeout) HSERIAL_MUTEX_LOCK(); // function may be NULL to cancel onReceive() from its respective task _onReceiveCB = function; - _onReceiveTimeout = onlyOnTimeout; + // When Rx timeout is Zero (disabled), there is only one possible option that is callback when FIFO reaches 120 bytes + _onReceiveTimeout = _rxTimeout > 0 ? onlyOnTimeout : false; // this can be called after Serial.begin(), therefore it shall create the event task if (function != NULL && _uart != NULL && _eventTask == NULL) { @@ -201,6 +203,22 @@ void HardwareSerial::onReceive(OnReceiveCb function, bool onlyOnTimeout) HSERIAL_MUTEX_UNLOCK(); } +// timout is calculates in time to receive UART symbols at the UART baudrate. +// the estimation is about 11 bits per symbol (SERIAL_8N1) +void HardwareSerial::setRxTimeout(uint8_t symbols_timeout) +{ + HSERIAL_MUTEX_LOCK(); + + // Zero disables timeout, thus, onReceive callback will only be called when RX FIFO reaches 120 bytes + // Any non-zero value will activate onReceive callback based on UART baudrate with about 11 bits per symbol + _rxTimeout = symbols_timeout; + if (!symbols_timeout) _onReceiveTimeout = false; // only when RX timeout is disabled, we also must disable this flag + + if(_uart != NULL) uart_set_rx_timeout(_uart_nr, _rxTimeout); // Set new timeout + + HSERIAL_MUTEX_UNLOCK(); +} + void HardwareSerial::eventQueueReset() { QueueHandle_t uartEventQueue = NULL; @@ -338,6 +356,11 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in _createEventTask(this); } + // Set UART RX timeout + if (_uart != NULL) { + uart_set_rx_timeout(_uart_nr, _rxTimeout); + } + HSERIAL_MUTEX_UNLOCK(); } From 20ecdae3ae82191812b62e84f6ef2065c1a66292 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Fri, 25 Mar 2022 08:48:19 -0300 Subject: [PATCH 12/13] Adds setRxTimeout() --- cores/esp32/HardwareSerial.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index ce9731c17af..b58035f9ce7 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -64,7 +64,7 @@ typedef enum { UART_PARITY_ERROR } hardwareSerial_error_t; -typedef std::function OnReceiveCb; +typedef std::function OnReceiveCb; typedef std::function OnReceiveErrorCb; class HardwareSerial: public Stream @@ -73,6 +73,14 @@ class HardwareSerial: public Stream HardwareSerial(int uart_nr); ~HardwareSerial(); + // 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) + // param symbols_timeout defines a timeout threshold in uart symbol periods. Setting 0 symbol timeout disables the callback call by timeout. + // 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). + // Examples: Maximum for 11 bits symbol is 92 (SERIAL_8N2, SERIAL_8E1, SERIAL_8O1, etc), Maximum for 10 bits symbol is 101 (SERIAL_8N1). + // For example symbols_timeout=1 defines a timeout equal to transmission time of one symbol (~11 bit) on current baudrate. + // For a baudrate of 9600, SERIAL_8N1 (10 bit symbol) and symbols_timeout = 3, the timeout would be 3 / (9600 / 10) = 3.125 ms + void setRxTimeout(uint8_t symbols_timeout); + // 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) @@ -151,7 +159,9 @@ class HardwareSerial: public Stream uart_t* _uart; size_t _rxBufferSize; OnReceiveCb _onReceiveCB; + // _onReceive and _rxTimeout have be consistent when timeout is disabled bool _onReceiveTimeout; + uint8_t _rxTimeout; OnReceiveErrorCb _onReceiveErrorCB; TaskHandle_t _eventTask; From e67d1d2e7502249f31b419b0e4257fdda46dd619 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Mon, 28 Mar 2022 07:58:19 -0300 Subject: [PATCH 13/13] CI Syntax error - "," missing --- cores/esp32/HardwareSerial.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 90a118a344a..323482a6bbf 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -127,9 +127,9 @@ _rxBufferSize(256), _txBufferSize(0), _onReceiveCB(NULL), _onReceiveErrorCB(NULL), -_eventTask(NULL) _onReceiveTimeout(true), _rxTimeout(10), +_eventTask(NULL) #if !CONFIG_DISABLE_HAL_LOCKS ,_lock(NULL) #endif