Skip to content

Commit 7d4992a

Browse files
authored
Adds C++ std::function to Serial.onReceive() (espressif#6364)
* Adds C++ std::function to Serial.onReceive() * fixes LOCK macro when disabled
1 parent 95b8e7e commit 7d4992a

File tree

4 files changed

+201
-90
lines changed

4 files changed

+201
-90
lines changed

cores/esp32/HardwareSerial.cpp

+150-9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "HardwareSerial.h"
88
#include "soc/soc_caps.h"
99
#include "driver/uart.h"
10+
#include "freertos/queue.h"
1011

1112
#ifndef SOC_RX0
1213
#if CONFIG_IDF_TARGET_ESP32
@@ -115,7 +116,131 @@ void serialEventRun(void)
115116
}
116117
#endif
117118

118-
HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL), _rxBufferSize(256) {}
119+
#if !CONFIG_DISABLE_HAL_LOCKS
120+
#define HSERIAL_MUTEX_LOCK() do {} while (xSemaphoreTake(_lock, portMAX_DELAY) != pdPASS)
121+
#define HSERIAL_MUTEX_UNLOCK() xSemaphoreGive(_lock)
122+
#else
123+
#define HSERIAL_MUTEX_LOCK()
124+
#define HSERIAL_MUTEX_UNLOCK()
125+
#endif
126+
127+
HardwareSerial::HardwareSerial(int uart_nr) :
128+
_uart_nr(uart_nr),
129+
_uart(NULL),
130+
_rxBufferSize(256),
131+
_onReceiveCB(NULL),
132+
_onReceiveErrorCB(NULL),
133+
_eventTask(NULL)
134+
#if !CONFIG_DISABLE_HAL_LOCKS
135+
,_lock(NULL)
136+
#endif
137+
{
138+
#if !CONFIG_DISABLE_HAL_LOCKS
139+
if(_lock == NULL){
140+
_lock = xSemaphoreCreateMutex();
141+
if(_lock == NULL){
142+
log_e("xSemaphoreCreateMutex failed");
143+
return;
144+
}
145+
}
146+
#endif
147+
}
148+
149+
HardwareSerial::~HardwareSerial()
150+
{
151+
end();
152+
#if !CONFIG_DISABLE_HAL_LOCKS
153+
if(_lock != NULL){
154+
vSemaphoreDelete(_lock);
155+
}
156+
#endif
157+
}
158+
159+
160+
void HardwareSerial::_createEventTask(void *args)
161+
{
162+
// Creating UART event Task
163+
xTaskCreate(_uartEventTask, "uart_event_task", 2048, this, configMAX_PRIORITIES - 1, &_eventTask);
164+
if (_eventTask == NULL) {
165+
log_e(" -- UART%d Event Task not Created!", _uart_nr);
166+
}
167+
}
168+
169+
void HardwareSerial::_destroyEventTask(void)
170+
{
171+
if (_eventTask != NULL) {
172+
vTaskDelete(_eventTask);
173+
_eventTask = NULL;
174+
}
175+
}
176+
177+
void HardwareSerial::onReceiveError(OnReceiveErrorCb function)
178+
{
179+
HSERIAL_MUTEX_LOCK();
180+
// function may be NULL to cancel onReceive() from its respective task
181+
_onReceiveErrorCB = function;
182+
// this can be called after Serial.begin(), therefore it shall create the event task
183+
if (function != NULL && _uart != NULL && _eventTask == NULL) {
184+
_createEventTask(this);
185+
}
186+
HSERIAL_MUTEX_UNLOCK();
187+
}
188+
189+
void HardwareSerial::onReceive(OnReceiveCb function)
190+
{
191+
HSERIAL_MUTEX_LOCK();
192+
// function may be NULL to cancel onReceive() from its respective task
193+
_onReceiveCB = function;
194+
// this can be called after Serial.begin(), therefore it shall create the event task
195+
if (function != NULL && _uart != NULL && _eventTask == NULL) {
196+
_createEventTask(this);
197+
}
198+
HSERIAL_MUTEX_UNLOCK();
199+
}
200+
201+
void HardwareSerial::_uartEventTask(void *args)
202+
{
203+
HardwareSerial *uart = (HardwareSerial *)args;
204+
uart_event_t event;
205+
QueueHandle_t uartEventQueue = NULL;
206+
uartGetEventQueue(uart->_uart, &uartEventQueue);
207+
if (uartEventQueue != NULL) {
208+
for(;;) {
209+
//Waiting for UART event.
210+
if(xQueueReceive(uartEventQueue, (void * )&event, (portTickType)portMAX_DELAY)) {
211+
switch(event.type) {
212+
case UART_DATA:
213+
if(uart->_onReceiveCB && uart->available() > 0) uart->_onReceiveCB();
214+
break;
215+
case UART_FIFO_OVF:
216+
log_w("UART%d FIFO Overflow. Consider adding Hardware Flow Control to your Application.", uart->_uart_nr);
217+
if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_FIFO_OVF_ERROR);
218+
break;
219+
case UART_BUFFER_FULL:
220+
log_w("UART%d Buffer Full. Consider encreasing your buffer size of your Application.", uart->_uart_nr);
221+
if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_BUFFER_FULL_ERROR);
222+
break;
223+
case UART_BREAK:
224+
log_w("UART%d RX break.", uart->_uart_nr);
225+
if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_BREAK_ERROR);
226+
break;
227+
case UART_PARITY_ERR:
228+
log_w("UART%d parity error.", uart->_uart_nr);
229+
if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_PARITY_ERROR);
230+
break;
231+
case UART_FRAME_ERR:
232+
log_w("UART%d frame error.", uart->_uart_nr);
233+
if(uart->_onReceiveErrorCB) uart->_onReceiveErrorCB(UART_FRAME_ERROR);
234+
break;
235+
default:
236+
log_w("UART%d unknown event type %d.", uart->_uart_nr, event.type);
237+
break;
238+
}
239+
}
240+
}
241+
}
242+
vTaskDelete(NULL);
243+
}
119244

120245
void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms, uint8_t rxfifo_full_thrhd)
121246
{
@@ -124,6 +249,14 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
124249
return;
125250
}
126251

252+
#if !CONFIG_DISABLE_HAL_LOCKS
253+
if(_lock == NULL){
254+
log_e("MUTEX Lock failed. Can't begin.");
255+
return;
256+
}
257+
#endif
258+
259+
HSERIAL_MUTEX_LOCK();
127260
// First Time or after end() --> set default Pins
128261
if (!uartIsDriverInstalled(_uart)) {
129262
switch (_uart_nr) {
@@ -176,26 +309,34 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
176309
_uart = NULL;
177310
}
178311
}
179-
}
180-
181-
void HardwareSerial::onReceive(void(*function)(void))
182-
{
183-
uartOnReceive(_uart, function);
312+
// create a task to deal with Serial Events when, for example, calling begin() twice to change the baudrate,
313+
// or when setting the callback before calling begin()
314+
if (_uart != NULL && (_onReceiveCB != NULL || _onReceiveErrorCB != NULL) && _eventTask == NULL) {
315+
_createEventTask(this);
316+
}
317+
HSERIAL_MUTEX_UNLOCK();
184318
}
185319

186320
void HardwareSerial::updateBaudRate(unsigned long baud)
187321
{
188322
uartSetBaudRate(_uart, baud);
189323
}
190324

191-
void HardwareSerial::end(bool turnOffDebug)
325+
void HardwareSerial::end(bool fullyTerminate)
192326
{
193-
if(turnOffDebug && uartGetDebug() == _uart_nr) {
194-
uartSetDebug(0);
327+
// default Serial.end() will completely disable HardwareSerial,
328+
// including any tasks or debug message channel (log_x()) - but not for IDF log messages!
329+
if(fullyTerminate) {
330+
_onReceiveCB = NULL;
331+
_onReceiveErrorCB = NULL;
332+
if (uartGetDebug() == _uart_nr) {
333+
uartSetDebug(0);
334+
}
195335
}
196336
delay(10);
197337
uartEnd(_uart);
198338
_uart = 0;
339+
_destroyEventTask();
199340
}
200341

201342
void HardwareSerial::setDebugOutput(bool en)

cores/esp32/HardwareSerial.h

+32-5
Original file line numberDiff line numberDiff line change
@@ -46,23 +46,40 @@
4646
#define HardwareSerial_h
4747

4848
#include <inttypes.h>
49-
49+
#include <functional>
5050
#include "Stream.h"
5151
#include "esp32-hal.h"
5252
#include "soc/soc_caps.h"
5353
#include "HWCDC.h"
5454

55+
#include "freertos/FreeRTOS.h"
56+
#include "freertos/task.h"
57+
#include "freertos/semphr.h"
58+
59+
typedef enum {
60+
UART_BREAK_ERROR,
61+
UART_BUFFER_FULL_ERROR,
62+
UART_FIFO_OVF_ERROR,
63+
UART_FRAME_ERROR,
64+
UART_PARITY_ERROR
65+
} hardwareSerial_error_t;
66+
67+
typedef std::function<void(void)> OnReceiveCb;
68+
typedef std::function<void(hardwareSerial_error_t)> OnReceiveErrorCb;
69+
5570
class HardwareSerial: public Stream
5671
{
5772
public:
5873
HardwareSerial(int uart_nr);
74+
~HardwareSerial();
5975

6076
// onReceive will setup a callback for whenever UART data is received
61-
// it will work as UART Rx interrupt
62-
void onReceive(void(*function)(void));
63-
77+
// it will work as UART Rx interrupt -- Using C++ 11 std::fuction
78+
void onReceive(OnReceiveCb function);
79+
void onReceiveError(OnReceiveErrorCb function);
80+
6481
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);
65-
void end(bool turnOffDebug = true);
82+
void end(bool fullyTerminate = true);
6683
void updateBaudRate(unsigned long baud);
6784
int available(void);
6885
int availableForWrite(void);
@@ -120,6 +137,16 @@ class HardwareSerial: public Stream
120137
int _uart_nr;
121138
uart_t* _uart;
122139
size_t _rxBufferSize;
140+
OnReceiveCb _onReceiveCB;
141+
OnReceiveErrorCb _onReceiveErrorCB;
142+
TaskHandle_t _eventTask;
143+
144+
void _createEventTask(void *args);
145+
void _destroyEventTask(void);
146+
static void _uartEventTask(void *args);
147+
#if !CONFIG_DISABLE_HAL_LOCKS
148+
SemaphoreHandle_t _lock;
149+
#endif
123150
};
124151

125152
extern void serialEventRun(void) __attribute__((weak));

0 commit comments

Comments
 (0)