Skip to content

Commit a1f8cfb

Browse files
committed
Adds C++ std::function to Serial.onReceive()
1 parent 50e9772 commit a1f8cfb

File tree

4 files changed

+201
-90
lines changed

4 files changed

+201
-90
lines changed

cores/esp32/HardwareSerial.cpp

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

120242
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)
121243
{
@@ -124,6 +246,14 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
124246
return;
125247
}
126248

249+
#if !CONFIG_DISABLE_HAL_LOCKS
250+
if(_lock == NULL){
251+
log_e("MUTEX Lock failed. Can't begin.");
252+
return;
253+
}
254+
#endif
255+
256+
HSERIAL_MUTEX_LOCK();
127257
// First Time or after end() --> set default Pins
128258
if (!uartIsDriverInstalled(_uart)) {
129259
switch (_uart_nr) {
@@ -176,26 +306,34 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
176306
_uart = NULL;
177307
}
178308
}
179-
}
180-
181-
void HardwareSerial::onReceive(void(*function)(void))
182-
{
183-
uartOnReceive(_uart, function);
309+
// create a task to deal with Serial Events when, for example, calling begin() twice to change the baudrate,
310+
// or when setting the callback before calling begin()
311+
if (_uart != NULL && (_onReceiveCB != NULL || _onReceiveErrorCB != NULL) && _eventTask == NULL) {
312+
_createEventTask(this);
313+
}
314+
HSERIAL_MUTEX_UNLOCK();
184315
}
185316

186317
void HardwareSerial::updateBaudRate(unsigned long baud)
187318
{
188319
uartSetBaudRate(_uart, baud);
189320
}
190321

191-
void HardwareSerial::end(bool turnOffDebug)
322+
void HardwareSerial::end(bool fullyTerminate)
192323
{
193-
if(turnOffDebug && uartGetDebug() == _uart_nr) {
194-
uartSetDebug(0);
324+
// default Serial.end() will completely disable HardwareSerial,
325+
// including any tasks or debug message channel (log_x()) - but not for IDF log messages!
326+
if(fullyTerminate) {
327+
_onReceiveCB = NULL;
328+
_onReceiveErrorCB = NULL;
329+
if (uartGetDebug() == _uart_nr) {
330+
uartSetDebug(0);
331+
}
195332
}
196333
delay(10);
197334
uartEnd(_uart);
198335
_uart = 0;
336+
_destroyEventTask();
199337
}
200338

201339
void HardwareSerial::setDebugOutput(bool en)

cores/esp32/HardwareSerial.h

Lines changed: 32 additions & 5 deletions
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)