Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 7d4992a

Browse filesBrowse 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
Copy full SHA for 7d4992a

File tree

Expand file treeCollapse file tree

4 files changed

+201
-90
lines changed
Filter options
Expand file treeCollapse file tree

4 files changed

+201
-90
lines changed

‎cores/esp32/HardwareSerial.cpp

Copy file name to clipboardExpand all lines: cores/esp32/HardwareSerial.cpp
+150-9Lines changed: 150 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,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

Copy file name to clipboardExpand all lines: cores/esp32/HardwareSerial.h
+32-5Lines 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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.