Skip to content

Commit 3b07562

Browse files
authored
Adds C++ std::function to Serial.onReceive() PR6364 upstream
1 parent 3b325ca commit 3b07562

File tree

4 files changed

+207
-23
lines changed

4 files changed

+207
-23
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
}
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();
179315
}
180316

181-
//void HardwareSerial::onReceive(void(*function)(void))
182-
//{
183-
// uartOnReceive(_uart, function);
184-
//}
185-
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));

cores/esp32/esp32-hal-uart.c

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ struct uart_struct_t {
3434
uint8_t num;
3535
bool has_peek;
3636
uint8_t peek_byte;
37+
QueueHandle_t uart_event_queue; // export it by some uartGetEventQueue() function
3738
};
3839

3940
#if CONFIG_DISABLE_HAL_LOCKS
@@ -42,12 +43,12 @@ struct uart_struct_t {
4243
#define UART_MUTEX_UNLOCK()
4344

4445
static uart_t _uart_bus_array[] = {
45-
{0, false, 0},
46+
{0, false, 0, NULL},
4647
#if SOC_UART_NUM > 1
47-
{1, false, 0},
48+
{1, false, 0, NULL},
4849
#endif
4950
#if SOC_UART_NUM > 2
50-
{2, false, 0},
51+
{2, false, 0, NULL},
5152
#endif
5253
};
5354

@@ -57,12 +58,12 @@ static uart_t _uart_bus_array[] = {
5758
#define UART_MUTEX_UNLOCK() xSemaphoreGive(uart->lock)
5859

5960
static uart_t _uart_bus_array[] = {
60-
{NULL, 0, false, 0},
61+
{NULL, 0, false, 0, NULL},
6162
#if SOC_UART_NUM > 1
62-
{NULL, 1, false, 0},
63+
{NULL, 1, false, 0, NULL},
6364
#endif
6465
#if SOC_UART_NUM > 2
65-
{NULL, 2, false, 0},
66+
{NULL, 2, false, 0, NULL},
6667
#endif
6768
};
6869

@@ -81,10 +82,25 @@ uint32_t _get_effective_baudrate(uint32_t baudrate)
8182
}
8283
}
8384

85+
// Routines that take care of UART events will be in the HardwareSerial Class code
86+
void uartGetEventQueue(uart_t* uart, QueueHandle_t *q)
87+
{
88+
// passing back NULL for the Queue pointer when UART is not initialized yet
89+
*q = NULL;
90+
if(uart == NULL) {
91+
return;
92+
}
93+
// MUTEX will lock for the case that another task is executing begin() on the same UART and has not finished
94+
//UART_MUTEX_LOCK();
95+
*q = uart->uart_event_queue;
96+
//UART_MUTEX_UNLOCK();
97+
return;
98+
}
99+
84100
bool uartIsDriverInstalled(uart_t* uart)
85101
{
86102
if(uart == NULL) {
87-
return 0;
103+
return false;
88104
}
89105

90106
if (uart_is_driver_installed(uart->num)) {
@@ -150,7 +166,7 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
150166
uart_config.source_clk = UART_SCLK_APB;
151167

152168

153-
ESP_ERROR_CHECK(uart_driver_install(uart_nr, 2*queueLen, 0, 0, NULL, 0));
169+
ESP_ERROR_CHECK(uart_driver_install(uart_nr, 2*queueLen, 0, 20, &(uart->uart_event_queue), 0));
154170
ESP_ERROR_CHECK(uart_param_config(uart_nr, &uart_config));
155171
ESP_ERROR_CHECK(uart_set_pin(uart_nr, txPin, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
156172

cores/esp32/esp32-hal-uart.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ extern "C" {
2222
#include <stdint.h>
2323
#include <stdbool.h>
2424
#include <stdlib.h>
25+
#include "freertos/FreeRTOS.h"
26+
#include "freertos/queue.h"
2527

2628
#define SERIAL_5N1 0x8000010
2729
#define SERIAL_6N1 0x8000014
@@ -62,7 +64,8 @@ typedef struct uart_struct_t uart_t;
6264
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted, uint8_t rxfifo_full_thrhd);
6365
void uartEnd(uart_t* uart);
6466

65-
//void uartOnReceive(uart_t* uart, void(*function)(void));
67+
// This is used to retrieve the Event Queue pointer from a UART IDF Driver in order to allow user to deal with its events
68+
void uartGetEventQueue(uart_t* uart, QueueHandle_t *q);
6669

6770
uint32_t uartAvailable(uart_t* uart);
6871
uint32_t uartAvailableForWrite(uart_t* uart);

0 commit comments

Comments
 (0)