Skip to content

Commit 28552b8

Browse files
author
Veijo Pesonen
committed
Initial UART HW flow control support
1 parent 4c58514 commit 28552b8

File tree

5 files changed

+120
-24
lines changed

5 files changed

+120
-24
lines changed

ESP8266/ESP8266.cpp

Lines changed: 81 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,29 @@
1515
*/
1616

1717
#include "ESP8266.h"
18-
#include "mbed_debug.h"
18+
#include "Callback.h"
19+
#include "mbed_error.h"
1920
#include "nsapi_types.h"
21+
#include "PinNames.h"
2022

2123
#include <cstring>
2224

2325
#define ESP8266_DEFAULT_BAUD_RATE 115200
2426
#define ESP8266_ALL_SOCKET_IDS -1
2527

26-
ESP8266::ESP8266(PinName tx, PinName rx, bool debug)
27-
: _serial(tx, rx, ESP8266_DEFAULT_BAUD_RATE),
28-
_parser(&_serial),
29-
_packets(0),
28+
ESP8266::ESP8266(PinName tx, PinName rx, bool debug, PinName rts, PinName cts)
29+
: _serial(tx, rx, ESP8266_DEFAULT_BAUD_RATE),
30+
_serial_rts(rts),
31+
_serial_cts(cts),
32+
_parser(&_serial),
33+
_packets(0),
3034
_packets_end(&_packets),
3135
_connect_error(0),
3236
_fail(false),
3337
_closed(false),
3438
_socket_open(),
35-
_connection_status(NSAPI_STATUS_DISCONNECTED)
39+
_connection_status(NSAPI_STATUS_DISCONNECTED),
40+
_heap_usage(0)
3641
{
3742
_serial.set_baud( ESP8266_DEFAULT_BAUD_RATE );
3843
_parser.debug_on(debug);
@@ -70,6 +75,34 @@ int ESP8266::get_firmware_version()
7075
}
7176
}
7277

78+
bool ESP8266::start_uart_hw_flow_ctrl(void)
79+
{
80+
bool done = true;
81+
82+
if (_serial_rts != NC && _serial_cts != NC) {
83+
// Start board's flow control
84+
_serial.set_flow_control(SerialBase::RTSCTS, _serial_rts, _serial_cts);
85+
86+
// Start ESP8266's flow control
87+
done = _parser.send("AT+UART_CUR=%u,8,1,0,3", ESP8266_DEFAULT_BAUD_RATE)
88+
&& _parser.recv("OK\n");
89+
90+
} else if (_serial_rts != NC) {
91+
_serial.set_flow_control(SerialBase::RTS, _serial_rts, NC);
92+
93+
done = _parser.send("AT+UART_CUR=%u,8,1,0,2", ESP8266_DEFAULT_BAUD_RATE)
94+
&& _parser.recv("OK\n");
95+
96+
} else if (_serial_cts != NC) {
97+
done = _parser.send("AT+UART_CUR=%u,8,1,0,1", ESP8266_DEFAULT_BAUD_RATE)
98+
&& _parser.recv("OK\n");
99+
100+
_serial.set_flow_control(SerialBase::CTS, NC, _serial_cts);
101+
}
102+
103+
return done;
104+
}
105+
73106
bool ESP8266::startup(int mode)
74107
{
75108
if (!(mode == WIFIMODE_STATION || mode == WIFIMODE_SOFTAP
@@ -361,7 +394,10 @@ nsapi_error_t ESP8266::send(int id, const void *data, uint32_t amount)
361394
if (_parser.send("AT+CIPSEND=%d,%lu", id, amount)
362395
&& _parser.recv(">")
363396
&& _parser.write((char*)data, (int)amount) >= 0) {
364-
while (_parser.process_oob()); // multiple sends in a row require this
397+
// No flow control, data overrun is possible
398+
if (_serial_rts == NC) {
399+
while (_parser.process_oob()); // Drain USART receive register
400+
}
365401
_smutex.unlock();
366402
return NSAPI_ERROR_OK;
367403
}
@@ -376,25 +412,37 @@ void ESP8266::_packet_handler()
376412
{
377413
int id;
378414
int amount;
415+
int pdu_len;
379416

380417
// parse out the packet
381418
if (!_parser.recv(",%d,%d:", &id, &amount)) {
382419
return;
383420
}
384421

385-
struct packet *packet = (struct packet*)malloc(
386-
sizeof(struct packet) + amount);
422+
pdu_len = sizeof(struct packet) + amount;
423+
424+
if ((_heap_usage + pdu_len) > MBED_CONF_ESP8266_SOCKET_BUFSIZE) {
425+
MBED_WARNING(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENOBUFS), \
426+
"ESP8266::_packet_handler(): \"esp8266.socket-bufsize\"-limit exceeded, packet dropped");
427+
return;
428+
}
429+
430+
struct packet *packet = (struct packet*)malloc(pdu_len);
387431
if (!packet) {
388-
debug("ESP8266: could not allocate memory for RX data\n");
432+
MBED_WARNING(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENOMEM), \
433+
"ESP8266::_packet_handler(): Could not allocate memory for RX data");
389434
return;
390435
}
436+
_heap_usage += pdu_len;
391437

392438
packet->id = id;
393439
packet->len = amount;
440+
packet->alloc_len = amount;
394441
packet->next = 0;
395442

396443
if (_parser.read((char*)(packet + 1), amount) < amount) {
397444
free(packet);
445+
_heap_usage -= pdu_len;
398446
return;
399447
}
400448

@@ -403,17 +451,23 @@ void ESP8266::_packet_handler()
403451
_packets_end = &packet->next;
404452
}
405453

454+
void ESP8266::process_oob(uint32_t timeout, bool all) {
455+
setTimeout(timeout);
456+
// Poll for inbound packets
457+
while (_parser.process_oob() && all) {
458+
}
459+
setTimeout();
460+
}
461+
406462
int32_t ESP8266::recv_tcp(int id, void *data, uint32_t amount, uint32_t timeout)
407463
{
408464
_smutex.lock();
409-
setTimeout(timeout);
410465

411-
// Poll for inbound packets
412-
while (_parser.process_oob()) {
466+
// No flow control, drain the USART receive register ASAP to avoid data overrun
467+
if (_serial_rts == NC) {
468+
process_oob(timeout, true);
413469
}
414470

415-
setTimeout();
416-
417471
// check if any packets are ready for us
418472
for (struct packet **p = &_packets; *p; p = &(*p)->next) {
419473
if ((*p)->id == id) {
@@ -426,10 +480,13 @@ int32_t ESP8266::recv_tcp(int id, void *data, uint32_t amount, uint32_t timeout)
426480
_packets_end = p;
427481
}
428482
*p = (*p)->next;
483+
429484
_smutex.unlock();
430485

486+
uint32_t pdu_len = sizeof(struct packet) + q->alloc_len;
431487
uint32_t len = q->len;
432488
free(q);
489+
_heap_usage -= pdu_len;
433490
return len;
434491
} else { // return only partial packet
435492
memcpy(data, q+1, amount);
@@ -446,6 +503,11 @@ int32_t ESP8266::recv_tcp(int id, void *data, uint32_t amount, uint32_t timeout)
446503
_smutex.unlock();
447504
return 0;
448505
}
506+
507+
// Flow control, read from USART receive register only when no more data is buffered, and as little as possible
508+
if (_serial_rts != NC) {
509+
process_oob(timeout, false);
510+
}
449511
_smutex.unlock();
450512

451513
return NSAPI_ERROR_WOULD_BLOCK;
@@ -477,7 +539,9 @@ int32_t ESP8266::recv_udp(int id, void *data, uint32_t amount, uint32_t timeout)
477539
*p = (*p)->next;
478540
_smutex.unlock();
479541

542+
uint32_t pdu_len = sizeof(struct packet) + q->alloc_len;
480543
free(q);
544+
_heap_usage -= pdu_len;
481545
return len;
482546
}
483547
}
@@ -493,13 +557,14 @@ void ESP8266::_clear_socket_packets(int id)
493557
while (*p) {
494558
if ((*p)->id == id || id == ESP8266_ALL_SOCKET_IDS) {
495559
struct packet *q = *p;
560+
int pdu_len = sizeof(struct packet) + q->alloc_len;
496561

497562
if (_packets_end == &(*p)->next) {
498563
_packets_end = p; // Set last packet next field/_packets
499564
}
500565
*p = (*p)->next;
501-
502566
free(q);
567+
_heap_usage -= pdu_len;
503568
} else {
504569
// Point to last packet next field
505570
p = &(*p)->next;

ESP8266/ESP8266.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
class ESP8266
4242
{
4343
public:
44-
ESP8266(PinName tx, PinName rx, bool debug=false);
44+
ESP8266(PinName tx, PinName rx, bool debug=false, PinName rts=NC, PinName cts=NC);
4545

4646
/**
4747
* Check firmware version of ESP8266
@@ -265,20 +265,30 @@ class ESP8266
265265
*/
266266
nsapi_connection_status_t get_connection_status() const;
267267

268+
/**
269+
* Start board's and ESP8266's UART flow control
270+
*
271+
* @return true if started
272+
*/
273+
bool start_uart_hw_flow_ctrl();
274+
268275
static const int8_t WIFIMODE_STATION = 1;
269276
static const int8_t WIFIMODE_SOFTAP = 2;
270277
static const int8_t WIFIMODE_STATION_SOFTAP = 3;
271278
static const int8_t SOCKET_COUNT = 5;
272279

273280
private:
274281
UARTSerial _serial;
282+
PinName _serial_rts;
283+
PinName _serial_cts;
275284
ATCmdParser _parser;
276285
Mutex _smutex; // Protect serial port access
277286

278287
struct packet {
279288
struct packet *next;
280289
int id;
281-
uint32_t len;
290+
uint32_t len; // Remaining length
291+
uint32_t alloc_len; // Original length
282292
// data follows
283293
} *_packets, **_packets_end;
284294
void _packet_handler();
@@ -292,6 +302,7 @@ class ESP8266
292302
void _connection_status_handler();
293303
void _oob_socket_close_error();
294304
void _clear_socket_packets(int id);
305+
void process_oob(uint32_t timeout, bool all);
295306

296307
char _ip_buffer[16];
297308
char _gateway_buffer[16];
@@ -304,6 +315,7 @@ class ESP8266
304315
int _socket_open[SOCKET_COUNT];
305316
nsapi_connection_status_t _connection_status;
306317
Callback<void(nsapi_event_t, intptr_t)> _connection_status_cb;
318+
size_t _heap_usage;
307319
};
308320

309321
#endif

ESP8266Interface.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
#define ESP8266_VERSION 2
4242

4343
ESP8266Interface::ESP8266Interface()
44-
: _esp(MBED_CONF_ESP8266_TX, MBED_CONF_ESP8266_RX, MBED_CONF_ESP8266_DEBUG),
44+
: _esp(MBED_CONF_ESP8266_TX, MBED_CONF_ESP8266_RX, MBED_CONF_ESP8266_DEBUG, MBED_CONF_ESP8266_RTS, MBED_CONF_ESP8266_CTS),
4545
_initialized(false),
4646
_started(false)
4747
{
@@ -57,8 +57,8 @@ ESP8266Interface::ESP8266Interface()
5757
}
5858

5959
// ESP8266Interface implementation
60-
ESP8266Interface::ESP8266Interface(PinName tx, PinName rx, bool debug)
61-
: _esp(tx, rx, debug),
60+
ESP8266Interface::ESP8266Interface(PinName tx, PinName rx, bool debug, PinName rts, PinName cts)
61+
: _esp(tx, rx, debug, rts, cts),
6262
_initialized(false),
6363
_started(false)
6464
{
@@ -267,6 +267,9 @@ bool ESP8266Interface::_disable_default_softap()
267267
nsapi_error_t ESP8266Interface::_init(void)
268268
{
269269
if (!_initialized) {
270+
if (!_esp.start_uart_hw_flow_ctrl()) {
271+
return NSAPI_ERROR_DEVICE_ERROR;
272+
}
270273
if (!_esp.reset()) {
271274
return NSAPI_ERROR_DEVICE_ERROR;
272275
}

ESP8266Interface.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class ESP8266Interface : public NetworkStack, public WiFiInterface
4040
* @param rx RX pin
4141
* @param debug Enable debugging
4242
*/
43-
ESP8266Interface(PinName tx, PinName rx, bool debug = false);
43+
ESP8266Interface(PinName tx, PinName rx, bool debug=false, PinName rts=NC, PinName cts=NC);
4444

4545
/** Start the interface
4646
*

mbed_lib.json

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,19 @@
33
"config": {
44
"tx": {
55
"help": "TX pin for serial connection",
6-
"value": null
6+
"value": "D1"
77
},
88
"rx": {
99
"help": "RX pin for serial connection",
10-
"value": null
10+
"value": "D0"
11+
},
12+
"rts": {
13+
"help": "RTS pin for serial connection",
14+
"value": "NC"
15+
},
16+
"cts": {
17+
"help": "CTS pin for serial connection",
18+
"value": "NC"
1119
},
1220
"debug": {
1321
"help": "Enable debug logs",
@@ -16,6 +24,10 @@
1624
"provide-default": {
1725
"help": "Provide default WifiInterface. [true/false]",
1826
"value": false
27+
},
28+
"socket-bufsize": {
29+
"help": "Size of the socket data buffer",
30+
"value": 102400
1931
}
2032
},
2133
"target_overrides": {
@@ -30,6 +42,10 @@
3042
"NUCLEO_F411RE": {
3143
"tx": "D8",
3244
"rx": "D2"
45+
},
46+
"NUCLEO_F429ZI": {
47+
"rts": "NC",
48+
"cts": "NC"
3349
}
3450
}
3551
}

0 commit comments

Comments
 (0)