Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 4c8d8f1

Browse files
d-a-vdevyte
authored andcommittedDec 10, 2018
uart: BW improvements (#4620)
* uart fixes and BW improvements * uart: read_char straightly use hw buffer * +attributes for functions called by ISR * uart: BW improvements read_char straightly use hw buffer (+ ~10%bw) read by block (+ ~190%bw) (instead of generic Stream::readBytes) attributes for functions called by ISR remove overrun message remove some ISR flags which were not honoured * fix merge * fix buffer overflow * serial stress test sketch * astyle * serial stress example: interactive keyboard, stop reading, overrun * serial device test: bandwidth & overrun * update + HardwareSerial::hasError() * interactive overrun in example * astyle * Test using @plerup's SoftwareSerial as submodule (tag 3.4.1) * update upstream ref (fix warning) * host mock uart/read(buf,size) * reset style changes in submodules before style diff * update build_boards_manager_package.sh for submodules * trigger CI (removing space) * cannot reproduce locally the CI issue, setting bash -x option to get live trace * remove previously added (in this PR) 'set -e' in package builder (passes local tests, not real CI) script-comment new recipe.hooks.core.prebuild.3 (along with already commented .1 and .2) moved CI package test to be first on the test list remove 'set -x', wish me luck
1 parent 8a88488 commit 4c8d8f1

File tree

11 files changed

+545
-44
lines changed

11 files changed

+545
-44
lines changed
 

‎.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@
44
[submodule "tools/sdk/ssl/bearssl"]
55
path = tools/sdk/ssl/bearssl
66
url = https://github.com/earlephilhower/bearssl-esp8266
7+
[submodule "libraries/SoftwareSerial"]
8+
path = libraries/SoftwareSerial
9+
url = https://github.com/plerup/espsoftwareserial.git

‎.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ cache:
88

99
matrix:
1010
include:
11+
- env:
12+
- BUILD_TYPE=package
1113
- env:
1214
- BUILD_TYPE=build_even
1315
- env:
@@ -22,8 +24,6 @@ matrix:
2224
- BUILD_TYPE=platformio_odd
2325
- env:
2426
- BUILD_TYPE=docs
25-
- env:
26-
- BUILD_TYPE=package
2727
- env:
2828
- BUILD_TYPE=host_tests
2929
- env:

‎cores/esp8266/HardwareSerial.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ class HardwareSerial: public Stream
8888
void end();
8989

9090
size_t setRxBufferSize(size_t size);
91+
size_t getRxBufferSize()
92+
{
93+
return uart_get_rx_buffer_size(_uart);
94+
}
9195

9296
void swap()
9397
{
@@ -120,14 +124,22 @@ class HardwareSerial: public Stream
120124

121125
int peek(void) override
122126
{
123-
// this may return -1, but that's okay
127+
// return -1 when data is unvailable (arduino api)
124128
return uart_peek_char(_uart);
125129
}
126130
int read(void) override
127131
{
128-
// this may return -1, but that's okay
132+
// return -1 when data is unvailable (arduino api)
129133
return uart_read_char(_uart);
130134
}
135+
size_t readBytes(char* buffer, size_t size) override
136+
{
137+
return uart_read(_uart, buffer, size);
138+
}
139+
size_t readBytes(uint8_t* buffer, size_t size) override
140+
{
141+
return uart_read(_uart, (char*)buffer, size);
142+
}
131143
int availableForWrite(void)
132144
{
133145
return static_cast<int>(uart_tx_free(_uart));
@@ -184,6 +196,11 @@ class HardwareSerial: public Stream
184196
return uart_has_overrun(_uart);
185197
}
186198

199+
bool hasRxError(void)
200+
{
201+
return uart_has_rx_error(_uart);
202+
}
203+
187204
void startDetectBaudrate();
188205

189206
unsigned long testBaudrate();

‎cores/esp8266/uart.c

Lines changed: 111 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@
4747
#include "user_interface.h"
4848
#include "uart_register.h"
4949

50-
const char overrun_str [] PROGMEM STORE_ATTR = "uart input full!\r\n";
50+
//const char overrun_str [] PROGMEM STORE_ATTR = "uart input full!\r\n";
5151
static int s_uart_debug_nr = UART0;
5252

5353

54-
struct uart_rx_buffer_
54+
struct uart_rx_buffer_
5555
{
5656
size_t size;
5757
size_t rpos;
@@ -65,7 +65,8 @@ struct uart_
6565
int baud_rate;
6666
bool rx_enabled;
6767
bool tx_enabled;
68-
bool overrun;
68+
bool rx_overrun;
69+
bool rx_error;
6970
uint8_t rx_pin;
7071
uint8_t tx_pin;
7172
struct uart_rx_buffer_ * rx_buffer;
@@ -85,7 +86,8 @@ struct uart_
8586

8687

8788

88-
inline size_t
89+
// called by ISR
90+
inline size_t ICACHE_RAM_ATTR
8991
uart_rx_fifo_available(const int uart_nr)
9092
{
9193
return (USS(uart_nr) >> USRXC) & 0xFF;
@@ -110,11 +112,11 @@ uart_rx_available_unsafe(uart_t* uart)
110112
return uart_rx_buffer_available_unsafe(uart->rx_buffer) + uart_rx_fifo_available(uart->uart_nr);
111113
}
112114

113-
114115
//#define UART_DISCARD_NEWEST
115116

116117
// Copy all the rx fifo bytes that fit into the rx buffer
117-
inline void
118+
// called by ISR
119+
inline void ICACHE_RAM_ATTR
118120
uart_rx_copy_fifo_to_buffer_unsafe(uart_t* uart)
119121
{
120122
struct uart_rx_buffer_ *rx_buffer = uart->rx_buffer;
@@ -124,11 +126,10 @@ uart_rx_copy_fifo_to_buffer_unsafe(uart_t* uart)
124126
size_t nextPos = (rx_buffer->wpos + 1) % rx_buffer->size;
125127
if(nextPos == rx_buffer->rpos)
126128
{
127-
128-
if (!uart->overrun)
129+
if (!uart->rx_overrun)
129130
{
130-
uart->overrun = true;
131-
os_printf_plus(overrun_str);
131+
uart->rx_overrun = true;
132+
//os_printf_plus(overrun_str);
132133
}
133134

134135
// a choice has to be made here,
@@ -158,25 +159,27 @@ uart_peek_char_unsafe(uart_t* uart)
158159

159160
//without the following if statement and body, there is a good chance of a fifo overrun
160161
if (uart_rx_buffer_available_unsafe(uart->rx_buffer) == 0)
162+
// hw fifo can't be peeked, data need to be copied to sw
161163
uart_rx_copy_fifo_to_buffer_unsafe(uart);
162164

163165
return uart->rx_buffer->buffer[uart->rx_buffer->rpos];
164166
}
165167

166-
inline int
168+
// taking data straight from hw fifo: loopback-test BW jumps by 19%
169+
inline int
167170
uart_read_char_unsafe(uart_t* uart)
168171
{
169-
int data = uart_peek_char_unsafe(uart);
170-
if(data != -1)
172+
if (uart_rx_buffer_available_unsafe(uart->rx_buffer))
173+
{
174+
// take oldest sw data
175+
int ret = uart->rx_buffer->buffer[uart->rx_buffer->rpos];
171176
uart->rx_buffer->rpos = (uart->rx_buffer->rpos + 1) % uart->rx_buffer->size;
172-
return data;
177+
return ret;
178+
}
179+
// unavailable
180+
return -1;
173181
}
174182

175-
176-
/**********************************************************/
177-
178-
179-
180183
size_t
181184
uart_rx_available(uart_t* uart)
182185
{
@@ -204,14 +207,47 @@ uart_peek_char(uart_t* uart)
204207

205208
int
206209
uart_read_char(uart_t* uart)
210+
{
211+
uint8_t ret;
212+
return uart_read(uart, (char*)&ret, 1)? ret: -1;
213+
}
214+
215+
// loopback-test BW jumps by 190%
216+
size_t
217+
uart_read(uart_t* uart, char* userbuffer, size_t usersize)
207218
{
208219
if(uart == NULL || !uart->rx_enabled)
209-
return -1;
210-
220+
return 0;
221+
222+
size_t ret = 0;
211223
ETS_UART_INTR_DISABLE();
212-
int data = uart_read_char_unsafe(uart);
224+
225+
while (ret < usersize && uart_rx_available_unsafe(uart))
226+
{
227+
if (!uart_rx_buffer_available_unsafe(uart->rx_buffer))
228+
{
229+
// no more data in sw buffer, take them from hw fifo
230+
while (ret < usersize && uart_rx_fifo_available(uart->uart_nr))
231+
userbuffer[ret++] = USF(uart->uart_nr);
232+
233+
// no more sw/hw data available
234+
break;
235+
}
236+
237+
// pour sw buffer to user's buffer
238+
// get largest linear length from sw buffer
239+
size_t chunk = uart->rx_buffer->rpos < uart->rx_buffer->wpos?
240+
uart->rx_buffer->wpos - uart->rx_buffer->rpos:
241+
uart->rx_buffer->size - uart->rx_buffer->rpos;
242+
if (ret + chunk > usersize)
243+
chunk = usersize - ret;
244+
memcpy(userbuffer + ret, uart->rx_buffer->buffer + uart->rx_buffer->rpos, chunk);
245+
uart->rx_buffer->rpos = (uart->rx_buffer->rpos + chunk) % uart->rx_buffer->size;
246+
ret += chunk;
247+
}
248+
213249
ETS_UART_INTR_ENABLE();
214-
return data;
250+
return ret;
215251
}
216252

217253
size_t
@@ -231,6 +267,8 @@ uart_resize_rx_buffer(uart_t* uart, size_t new_size)
231267
ETS_UART_INTR_DISABLE();
232268
while(uart_rx_available_unsafe(uart) && new_wpos < new_size)
233269
new_buf[new_wpos++] = uart_read_char_unsafe(uart); //if uart_rx_available_unsafe() returns non-0, uart_read_char_unsafe() can't return -1
270+
if (new_wpos == new_size)
271+
new_wpos = 0;
234272

235273
uint8_t * old_buf = uart->rx_buffer->buffer;
236274
uart->rx_buffer->rpos = 0;
@@ -242,22 +280,39 @@ uart_resize_rx_buffer(uart_t* uart, size_t new_size)
242280
return uart->rx_buffer->size;
243281
}
244282

283+
size_t
284+
uart_get_rx_buffer_size(uart_t* uart)
285+
{
286+
return uart && uart->rx_enabled? uart->rx_buffer->size: 0;
287+
}
245288

246289

247290
void ICACHE_RAM_ATTR
248291
uart_isr(void * arg)
249292
{
250293
uart_t* uart = (uart_t*)arg;
294+
uint32_t usis = USIS(uart->uart_nr);
295+
251296
if(uart == NULL || !uart->rx_enabled)
252297
{
253-
USIC(uart->uart_nr) = USIS(uart->uart_nr);
298+
USIC(uart->uart_nr) = usis;
254299
ETS_UART_INTR_DISABLE();
255300
return;
256301
}
257-
if(USIS(uart->uart_nr) & ((1 << UIFF) | (1 << UITO)))
302+
303+
if(usis & (1 << UIFF))
258304
uart_rx_copy_fifo_to_buffer_unsafe(uart);
305+
306+
if((usis & (1 << UIOF)) && !uart->rx_overrun)
307+
{
308+
uart->rx_overrun = true;
309+
//os_printf_plus(overrun_str);
310+
}
259311

260-
USIC(uart->uart_nr) = USIS(uart->uart_nr);
312+
if (usis & ((1 << UIFR) | (1 << UIPE) | (1 << UITO)))
313+
uart->rx_error = true;
314+
315+
USIC(uart->uart_nr) = usis;
261316
}
262317

263318
static void
@@ -270,9 +325,22 @@ uart_start_isr(uart_t* uart)
270325
// triggers the IRS very often. A value of 127 would not leave much time
271326
// for ISR to clear fifo before the next byte is dropped. So pick a value
272327
// in the middle.
273-
USC1(uart->uart_nr) = (100 << UCFFT) | (0x02 << UCTOT) | (1 <<UCTOE );
328+
// update: loopback test @ 3Mbauds/8n1 (=2343Kibits/s):
329+
// - 4..120 give > 2300Kibits/s
330+
// - 1, 2, 3 are below
331+
// was 100, use 16 to stay away from overrun
332+
#define INTRIGG 16
333+
334+
//was:USC1(uart->uart_nr) = (INTRIGG << UCFFT) | (0x02 << UCTOT) | (1 <<UCTOE);
335+
USC1(uart->uart_nr) = (INTRIGG << UCFFT);
274336
USIC(uart->uart_nr) = 0xffff;
275-
USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIFR) | (1 << UITO);
337+
//was: USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIFR) | (1 << UITO);
338+
// UIFF: rx fifo full
339+
// UIOF: rx fifo overflow (=overrun)
340+
// UIFR: frame error
341+
// UIPE: parity error
342+
// UITO: rx fifo timeout
343+
USIE(uart->uart_nr) = (1 << UIFF) | (1 << UIOF) | (1 << UIFR) | (1 << UIPE) | (1 << UITO);
276344
ETS_UART_INTR_ATTACH(uart_isr, (void *)uart);
277345
ETS_UART_INTR_ENABLE();
278346
}
@@ -415,7 +483,8 @@ uart_init(int uart_nr, int baudrate, int config, int mode, int tx_pin, size_t rx
415483
return NULL;
416484

417485
uart->uart_nr = uart_nr;
418-
uart->overrun = false;
486+
uart->rx_overrun = false;
487+
uart->rx_error = false;
419488

420489
switch(uart->uart_nr)
421490
{
@@ -678,11 +747,22 @@ uart_rx_enabled(uart_t* uart)
678747
bool
679748
uart_has_overrun (uart_t* uart)
680749
{
681-
if (uart == NULL || !uart->overrun)
750+
if (uart == NULL || !uart->rx_overrun)
751+
return false;
752+
753+
// clear flag
754+
uart->rx_overrun = false;
755+
return true;
756+
}
757+
758+
bool
759+
uart_has_rx_error (uart_t* uart)
760+
{
761+
if (uart == NULL || !uart->rx_error)
682762
return false;
683763

684764
// clear flag
685-
uart->overrun = false;
765+
uart->rx_error = false;
686766
return true;
687767
}
688768

‎cores/esp8266/uart.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,17 +126,20 @@ void uart_set_baudrate(uart_t* uart, int baud_rate);
126126
int uart_get_baudrate(uart_t* uart);
127127

128128
size_t uart_resize_rx_buffer(uart_t* uart, size_t new_size);
129+
size_t uart_get_rx_buffer_size(uart_t* uart);
129130

130131
size_t uart_write_char(uart_t* uart, char c);
131132
size_t uart_write(uart_t* uart, const char* buf, size_t size);
132133
int uart_read_char(uart_t* uart);
133134
int uart_peek_char(uart_t* uart);
135+
size_t uart_read(uart_t* uart, char* buffer, size_t size);
134136
size_t uart_rx_available(uart_t* uart);
135137
size_t uart_tx_free(uart_t* uart);
136138
void uart_wait_tx_empty(uart_t* uart);
137139
void uart_flush(uart_t* uart);
138140

139141
bool uart_has_overrun (uart_t* uart); // returns then clear overrun flag
142+
bool uart_has_rx_error (uart_t* uart); // returns then clear rxerror flag
140143

141144
void uart_set_debug(int uart_nr);
142145
int uart_get_debug();

‎libraries/SoftwareSerial

Submodule SoftwareSerial added at 23ae000
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
2+
/*
3+
Serial read/write/verify/benchmark
4+
Using internal loopback
5+
Using SoftwareSerial library for logging
6+
7+
Sketch meant for debugging only
8+
Released to public domain
9+
*/
10+
11+
#include <ESP8266WiFi.h>
12+
#include <SoftwareSerial.h>
13+
14+
#define SSBAUD 115200 // logger on console for humans
15+
#define BAUD 3000000 // hardware serial stress test
16+
#define BUFFER_SIZE 4096 // may be useless to use more than 2*SERIAL_SIZE_RX
17+
#define SERIAL_SIZE_RX 1024 // Serial.setRxBufferSize()
18+
19+
#define TIMEOUT 5000
20+
#define DEBUG(x...) //x
21+
22+
uint8_t buf [BUFFER_SIZE];
23+
uint8_t temp [BUFFER_SIZE];
24+
bool reading = true;
25+
26+
static size_t out_idx = 0, in_idx = 0;
27+
static size_t local_receive_size = 0;
28+
static size_t size_for_1sec, size_for_led = 0;
29+
static size_t maxavail = 0;
30+
static uint64_t in_total = 0, in_prev = 0;
31+
static uint64_t start_ms, last_ms;
32+
static uint64_t timeout;
33+
34+
Stream* logger;
35+
36+
void error(const char* what) {
37+
logger->printf("\nerror: %s after %ld minutes\nread idx: %d\nwrite idx: %d\ntotal: %ld\nlast read: %d\nmaxavail: %d\n",
38+
what, (long)((millis() - start_ms) / 60000), in_idx, out_idx, (long)in_total, (int)local_receive_size, maxavail);
39+
if (Serial.hasOverrun()) {
40+
logger->printf("overrun!\n");
41+
}
42+
logger->printf("should be (size=%d idx=%d..%d):\n ", BUFFER_SIZE, in_idx, in_idx + local_receive_size - 1);
43+
for (size_t i = in_idx; i < in_idx + local_receive_size; i++) {
44+
logger->printf("%02x(%c) ", buf[i], (unsigned char)((buf[i] > 31 && buf[i] < 128) ? buf[i] : '.'));
45+
}
46+
logger->print("\n\nis: ");
47+
for (size_t i = 0; i < local_receive_size; i++) {
48+
logger->printf("%02x(%c) ", temp[i], (unsigned char)((temp[i] > 31 && temp[i] < 128) ? temp[i] : '.'));
49+
}
50+
logger->println("\n\n");
51+
52+
while (true) {
53+
delay(1000);
54+
}
55+
}
56+
57+
void preinit() {
58+
// (no C++ in function)
59+
// disable wifi
60+
ESP8266WiFiClass::preinitWiFiOff();
61+
}
62+
63+
void setup() {
64+
pinMode(LED_BUILTIN, OUTPUT);
65+
66+
Serial.begin(BAUD);
67+
Serial.swap(); // RX=GPIO13 TX=GPIO15
68+
Serial.setRxBufferSize(SERIAL_SIZE_RX);
69+
70+
// using HardwareSerial0 pins,
71+
// so we can still log to the regular usbserial chips
72+
SoftwareSerial* ss = new SoftwareSerial(3, 1);
73+
ss->begin(SSBAUD);
74+
logger = ss;
75+
logger->println();
76+
logger->printf("\n\nOn Software Serial for logging\n");
77+
78+
int baud = Serial.baudRate();
79+
logger->printf(ESP.getFullVersion().c_str());
80+
logger->printf("\n\nBAUD: %d - CoreRxBuffer: %d bytes - TestBuffer: %d bytes\n",
81+
baud, SERIAL_SIZE_RX, BUFFER_SIZE);
82+
83+
size_for_1sec = baud / 10; // 8n1=10baudFor8bits
84+
logger->printf("led changes state every %zd bytes (= 1 second)\n", size_for_1sec);
85+
logger->printf("press 's' to stop reading, not writing (induces overrun)\n");
86+
87+
// prepare send/compare buffer
88+
for (size_t i = 0; i < sizeof buf; i++) {
89+
buf[i] = (uint8_t)i;
90+
}
91+
92+
// bind RX and TX
93+
USC0(0) |= (1 << UCLBE);
94+
95+
while (Serial.read() == -1);
96+
if (Serial.hasOverrun()) {
97+
logger->print("overrun?\n");
98+
}
99+
100+
timeout = (start_ms = last_ms = millis()) + TIMEOUT;
101+
logger->println("setup done");
102+
}
103+
104+
void loop() {
105+
size_t maxlen = Serial.availableForWrite();
106+
// check remaining space in buffer
107+
if (maxlen > BUFFER_SIZE - out_idx) {
108+
maxlen = BUFFER_SIZE - out_idx;
109+
}
110+
// check if not cycling more than buffer size relatively to input
111+
size_t in_out = out_idx == in_idx ?
112+
BUFFER_SIZE :
113+
(in_idx + BUFFER_SIZE - out_idx - 1) % BUFFER_SIZE;
114+
if (maxlen > in_out) {
115+
maxlen = in_out;
116+
}
117+
DEBUG(logger->printf("(aw%i/w%i", Serial.availableForWrite(), maxlen));
118+
size_t local_written_size = Serial.write(buf + out_idx, maxlen);
119+
DEBUG(logger->printf(":w%i/aw%i/ar%i)\n", local_written_size, Serial.availableForWrite(), Serial.available()));
120+
if (local_written_size > maxlen) {
121+
error("bad write");
122+
}
123+
if ((out_idx += local_written_size) == BUFFER_SIZE) {
124+
out_idx = 0;
125+
}
126+
delay(0);
127+
128+
DEBUG(logger->printf("----------\n"));
129+
130+
if (Serial.hasOverrun()) {
131+
logger->printf("rx overrun!\n");
132+
}
133+
if (Serial.hasRxError()) {
134+
logger->printf("rx error!\n");
135+
}
136+
137+
if (reading) {
138+
// receive data
139+
maxlen = Serial.available();
140+
if (maxlen > maxavail) {
141+
maxavail = maxlen;
142+
}
143+
// check space in temp receive buffer
144+
if (maxlen > BUFFER_SIZE - in_idx) {
145+
maxlen = BUFFER_SIZE - in_idx;
146+
}
147+
DEBUG(logger->printf("(ar%i/r%i", Serial.available(), maxlen));
148+
local_receive_size = Serial.readBytes(temp, maxlen);
149+
DEBUG(logger->printf(":r%i/ar%i)\n", local_receive_size, Serial.available()));
150+
if (local_receive_size > maxlen) {
151+
error("bad read");
152+
}
153+
if (local_receive_size) {
154+
if (memcmp(buf + in_idx, temp, local_receive_size) != 0) {
155+
error("fail");
156+
}
157+
if ((in_idx += local_receive_size) == BUFFER_SIZE) {
158+
in_idx = 0;
159+
}
160+
in_total += local_receive_size;
161+
}
162+
DEBUG(logger->printf("r(%d) ok\n", local_receive_size));
163+
}
164+
165+
// say something on data every second
166+
if ((size_for_led += local_written_size) >= size_for_1sec || millis() > timeout) {
167+
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
168+
size_for_led = 0;
169+
170+
if (in_prev == in_total) {
171+
error("receiving nothing?\n");
172+
}
173+
174+
unsigned long now_ms = millis();
175+
int bwkbps_avg = ((((uint64_t)in_total) * 8000) / (now_ms - start_ms)) >> 10;
176+
int bwkbps_now = (((in_total - in_prev) * 8000) / (now_ms - last_ms)) >> 10 ;
177+
logger->printf("bwavg=%d bwnow=%d kbps maxavail=%i\n", bwkbps_avg, bwkbps_now, maxavail);
178+
179+
in_prev = in_total;
180+
timeout = (last_ms = now_ms) + TIMEOUT;
181+
}
182+
183+
if (logger->read() == 's') {
184+
logger->println("now stopping reading, keeping writing");
185+
reading = false;
186+
}
187+
}

‎package/build_boards_manager_package.sh

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#!/bin/bash
22
#
33

4+
#set -x
5+
46
# Extract next version from platform.txt
57
next=`sed -n -E 's/version=([0-9.]+)/\1/p' ../platform.txt`
68

@@ -16,6 +18,9 @@ else
1618
plain_ver=$ver
1719
fi
1820

21+
# 'set -e' breaks CI but not local tests
22+
#set -e
23+
1924
package_name=esp8266-$ver
2025
echo "Version: $ver"
2126
echo "Package name: $package_name"
@@ -44,10 +49,20 @@ srcdir=$PWD
4449
rm -rf package/versions/$ver
4550
mkdir -p $outdir
4651

52+
# Get submodules
53+
modules=libraries/SoftwareSerial
54+
for mod in $modules; do
55+
echo "refreshing submodule: $mod"
56+
git submodule update --init -- $mod
57+
(cd $mod && git reset --hard)
58+
done
59+
echo "done with submodules"
60+
4761
# Some files should be excluded from the package
4862
cat << EOF > exclude.txt
4963
.git
5064
.gitignore
65+
.gitmodules
5166
.travis.yml
5267
package
5368
doc
@@ -58,15 +73,6 @@ git ls-files --other --directory >> exclude.txt
5873
rsync -a --exclude-from 'exclude.txt' $srcdir/ $outdir/
5974
rm exclude.txt
6075

61-
# Get additional libraries (TODO: add them as git submodule or subtree?)
62-
63-
# SoftwareSerial library
64-
curl -L -o SoftwareSerial.zip https://github.com/plerup/espsoftwareserial/archive/3.4.1.zip
65-
unzip -q SoftwareSerial.zip
66-
rm -rf SoftwareSerial.zip
67-
mv espsoftwareserial-* SoftwareSerial
68-
mv SoftwareSerial $outdir/libraries
69-
7076
# For compatibility, on OS X we need GNU sed which is usually called 'gsed'
7177
if [ "$(uname)" == "Darwin" ]; then
7278
SED=gsed
@@ -83,6 +89,7 @@ $SED 's/tools.esptool.path={runtime.platform.path}\/tools\/esptool/tools.esptool
8389
$SED 's/tools.mkspiffs.path={runtime.platform.path}\/tools\/mkspiffs/tools.mkspiffs.path=\{runtime.tools.mkspiffs.path\}/g' |\
8490
$SED 's/recipe.hooks.core.prebuild.1.pattern.*//g' |\
8591
$SED 's/recipe.hooks.core.prebuild.2.pattern.*//g' |\
92+
$SED 's/recipe.hooks.core.prebuild.3.pattern.*//g' |\
8693
$SED "s/version=.*/version=$ver/g" |\
8794
$SED -E "s/name=([a-zA-Z0-9\ -]+).*/name=\1($ver)/g"\
8895
> $outdir/platform.txt
@@ -154,3 +161,5 @@ python ../../merge_packages.py $new_json $old_json >tmp && mv tmp $new_json && r
154161

155162
popd
156163
popd
164+
165+
echo "All done"

‎tests/common.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,9 @@ function check_examples_style()
248248
--suffix=none \
249249
--options=$TRAVIS_BUILD_DIR/tests/examples_style.conf {} \;
250250

251+
# we have no control over submodules
252+
git submodule foreach --recursive git reset --hard
253+
251254
git diff --exit-code -- $TRAVIS_BUILD_DIR/libraries
252255

253256
echo -e "travis_fold:end:check_examples_style"
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
#include <BSTest.h>
2+
BS_ENV_DECLARE();
3+
4+
// this is the serialStress.ino example, stripped down
5+
6+
/*
7+
Serial read/write/verify/benchmark
8+
Using internal loopback
9+
10+
Released to public domain
11+
*/
12+
13+
#include <ESP8266WiFi.h>
14+
15+
#define SSBAUD 115200 // console for humans
16+
#define BAUD 3000000 // hardware serial stress test
17+
#define BUFFER_SIZE 4096 // may be useless to use more than 2*SERIAL_SIZE_RX
18+
#define SERIAL_SIZE_RX 1024 // Serial.setRxBufferSize()
19+
20+
#define TIMEOUT 5000
21+
#define DEBUG(x...) //x
22+
23+
uint8_t buf [BUFFER_SIZE];
24+
uint8_t temp [BUFFER_SIZE];
25+
bool reading = true;
26+
bool overrun = false;
27+
28+
static size_t out_idx = 0, in_idx = 0;
29+
static size_t local_receive_size = 0;
30+
static size_t size_for_1sec, size_for_led = 0;
31+
static size_t maxavail = 0;
32+
static uint64_t in_total = 0, in_prev = 0;
33+
static uint64_t start_ms, last_ms;
34+
static uint64_t timeout;
35+
36+
void preinit() {
37+
// (no C++ in function)
38+
// disable wifi
39+
ESP8266WiFiClass::preinitWiFiOff();
40+
}
41+
42+
void setup()
43+
{
44+
Serial.begin(SSBAUD);
45+
46+
int baud = BAUD;
47+
size_for_1sec = baud / 10; // 8n1=10baudFor8bits
48+
//Serial.printf(ESP.getFullVersion().c_str());
49+
//Serial.printf("\n\nBAUD: %d - CoreRxBuffer: %d bytes - TestBuffer: %d bytes\n",
50+
// baud, SERIAL_SIZE_RX, BUFFER_SIZE);
51+
52+
//Serial.printf("led changes state every %zd bytes (= 1 second)\n", size_for_1sec);
53+
//Serial.printf("press 's' to stop reading, not writing (induces overrun)\n");
54+
55+
BS_RUN(Serial);
56+
}
57+
58+
void test_setup()
59+
{
60+
Serial.begin(BAUD);
61+
62+
// bind RX and TX
63+
USC0(0) |= (1 << UCLBE);
64+
65+
Serial.flush();
66+
while (Serial.read() != -1);
67+
timeout = (start_ms = last_ms = millis()) + TIMEOUT;
68+
}
69+
70+
void test_setdown ()
71+
{
72+
// unbind RX and TX
73+
Serial.flush();
74+
USC0(0) &= ~(1 << UCLBE);
75+
while (Serial.read() != -1);
76+
Serial.begin(SSBAUD);
77+
}
78+
79+
int bwkbps_avg = 0;
80+
81+
bool test_loop ()
82+
{
83+
size_t maxlen = Serial.availableForWrite();
84+
// check remaining space in buffer
85+
if (maxlen > BUFFER_SIZE - out_idx) {
86+
maxlen = BUFFER_SIZE - out_idx;
87+
}
88+
// check if not cycling more than buffer size relatively to input
89+
size_t in_out = out_idx == in_idx ?
90+
BUFFER_SIZE :
91+
(in_idx + BUFFER_SIZE - out_idx - 1) % BUFFER_SIZE;
92+
if (maxlen > in_out) {
93+
maxlen = in_out;
94+
}
95+
size_t local_written_size = Serial.write(buf + out_idx, maxlen);
96+
if (local_written_size > maxlen) {
97+
return false;
98+
}
99+
if ((out_idx += local_written_size) == BUFFER_SIZE) {
100+
out_idx = 0;
101+
}
102+
delay(0);
103+
104+
if (Serial.hasOverrun()) {
105+
overrun = true;
106+
}
107+
if (Serial.hasRxError()) {
108+
}
109+
110+
if (reading)
111+
{
112+
// receive data
113+
maxlen = Serial.available();
114+
if (maxlen > maxavail) {
115+
maxavail = maxlen;
116+
}
117+
// check space in temp receive buffer
118+
if (maxlen > BUFFER_SIZE - in_idx) {
119+
maxlen = BUFFER_SIZE - in_idx;
120+
}
121+
local_receive_size = Serial.readBytes(temp, maxlen);
122+
if (local_receive_size > maxlen) {
123+
return false;
124+
}
125+
if (local_receive_size) {
126+
if (memcmp(buf + in_idx, temp, local_receive_size) != 0) {
127+
return false;
128+
}
129+
if ((in_idx += local_receive_size) == BUFFER_SIZE) {
130+
in_idx = 0;
131+
}
132+
in_total += local_receive_size;
133+
}
134+
}
135+
136+
// say something on data every second
137+
if ((size_for_led += local_written_size) >= size_for_1sec || millis() > timeout) {
138+
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
139+
size_for_led = 0;
140+
141+
if (in_prev == in_total) {
142+
return false;
143+
}
144+
145+
unsigned long now_ms = millis();
146+
bwkbps_avg = ((((uint64_t)in_total) * 8000) / (now_ms - start_ms)) >> 10;
147+
//bwkbps_now = (((in_total - in_prev) * 8000) / (now_ms - last_ms)) >> 10 ;
148+
149+
in_prev = in_total;
150+
timeout = (last_ms = now_ms) + TIMEOUT;
151+
}
152+
153+
if (millis() > 5000)
154+
{
155+
reading = false;
156+
}
157+
if (millis() > 6000)
158+
{
159+
return false;
160+
}
161+
162+
return true;
163+
}
164+
165+
TEST_CASE("bandwidth and overrun", "[serial]")
166+
{
167+
overrun = false;
168+
bwkbps_avg = 0;
169+
CHECK(overrun == false);
170+
CHECK(bwkbps_avg == 0);
171+
172+
// let serial flush its BS output before flushing and switching to 3MBPS
173+
delay(100);
174+
175+
test_setup();
176+
while (test_loop());
177+
test_setdown();
178+
179+
Serial.printf("bandwidth = %d kbps - overrun=%d\n", bwkbps_avg, overrun);
180+
181+
// BAUD*10/8/1000 =>kbps *9/10 => 90% at least
182+
CHECK(bwkbps_avg > ((((BAUD*8/10)/1000)*9)/10));
183+
CHECK(overrun == true);
184+
185+
while (Serial.read() != -1);
186+
Serial.flush();
187+
}
188+
189+
void loop ()
190+
{
191+
}

‎tests/host/common/MockSerial.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,11 @@ size_t uart_write (uart_t* uart, const char* buf, size_t size)
109109
return write(1, buf, size);
110110
}
111111

112+
size_t uart_read(uart_t* uart, char* userbuffer, size_t usersize)
113+
{
114+
///XXXTODO
115+
(void)uart;
116+
return read(0, userbuffer, usersize);
117+
}
118+
112119
} // extern "C"

5 commit comments

Comments
 (5)

JAndrassy commented on Dec 23, 2018

@JAndrassy
Contributor

arduino api: Stream.readBytes implementation should be blocking with timeout set by setTimeout. is it now here? see default implementation of readBytes in Stream class

d-a-v commented on Dec 23, 2018

@d-a-v
CollaboratorAuthor

This behavior is not implemented. You are right.

JAndrassy commented on Dec 25, 2018

@JAndrassy
Contributor

do not override them. as no other from the "// parsing methods" section in Stream.h

Client.h has read(buffer, size), Stream.h doesn't. it should have it, but it is hard to convince Arduino to make a change

d-a-v commented on Dec 27, 2018

@d-a-v
CollaboratorAuthor

fixed and kept overridden by #5558

but it is hard to convince Arduino to make a change

True. But if you make a PR here for that matter, we will consider it as long as it doesn't break compatibility.
In the meantime, HardwareSerial::read(buffer, size) is still available without timeout.

d-a-v commented on Jan 8, 2019

@d-a-v
CollaboratorAuthor

@JAndrassy #5558 is merged, please check, and report if there is still an issue.

Please sign in to comment.