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