This commit is contained in:
xin
2025-07-08 08:54:35 +08:00
parent bc81bd41ac
commit 6de3458dfc
376 changed files with 68605 additions and 246 deletions

View File

@ -0,0 +1,71 @@
#include "SoftwareSerial.h"
#ifndef D5
#if defined(ESP8266)
#define D8 (15)
#define D5 (14)
#define D7 (13)
#define D6 (12)
#define RX (3)
#define TX (1)
#elif defined(ESP32)
#define D8 (5)
#define D5 (18)
#define D7 (23)
#define D6 (19)
#define RX (3)
#define TX (1)
#endif
#endif
SoftwareSerial swSer;
#ifdef ESP8266
auto logSer = SoftwareSerial(-1, TX);
auto hwSer = Serial;
#else
auto logSer = Serial;
auto hwSer = Serial1;
#endif
constexpr uint32_t TESTBPS = 115200;
void setup() {
delay(2000);
#ifdef ESP8266
hwSer.begin(TESTBPS, SERIAL_8N1);
hwSer.swap();
#else
hwSer.begin(TESTBPS, SERIAL_8N1, D6, D5);
#endif
logSer.begin(115200);
logSer.println(PSTR("\nOne Wire Half Duplex Bitpattern and Datarate Test"));
swSer.begin(TESTBPS, SWSERIAL_8N1, D6, D5);
swSer.enableIntTx(true);
logSer.println(PSTR("Tx on swSer"));
}
uint8_t val = 0xff;
void loop() {
swSer.write((uint8_t)0x00);
swSer.write(val);
swSer.write(val);
auto start = ESP.getCycleCount();
int rxCnt = 0;
while (ESP.getCycleCount() - start < ESP.getCpuFreqMHz() * 1000000 / 10) {
if (hwSer.available()) {
auto rxVal = hwSer.read();
if ((!rxCnt && rxVal) || (rxCnt && rxVal != val)) {
logSer.printf(PSTR("Rx bit error: tx = 0x%02x, rx = 0x%02x\n"), val, rxVal);
}
++rxCnt;
}
}
if (rxCnt != 3) {
logSer.printf(PSTR("Rx cnt error, tx = 0x%02x\n"), val);
}
++val;
if (!val) {
logSer.println("Starting over");
}
}

View File

@ -0,0 +1,279 @@
#include <SoftwareSerial.h>
// On ESP8266:
// Local SoftwareSerial loopback, connect D5 (rx) and D6 (tx).
// For local hardware loopback, connect D5 to D8 (tx), D6 to D7 (rx).
// For hardware send/sink, connect D7 (rx) and D8 (tx).
// Hint: The logger is run at 9600bps such that enableIntTx(true) can remain unchanged. Blocking
// interrupts severely impacts the ability of the SoftwareSerial devices to operate concurrently
// and/or in duplex mode.
// Operating in software serial full duplex mode, runs at 19200bps and few errors (~2.5%).
// Operating in software serial half duplex mode (both loopback and repeater),
// runs at 57600bps with nearly no errors.
// Operating loopback in full duplex, and repeater in half duplex, runs at 38400bps with nearly no errors.
// On ESP32:
// For SoftwareSerial or hardware send/sink, connect D5 (rx) and D6 (tx).
// Hardware Serial2 defaults to D4 (rx), D3 (tx).
// For local hardware loopback, connect D5 (rx) to D3 (tx), D6 (tx) to D4 (rx).
#ifndef D5
#if defined(ESP8266)
#define D8 (15)
#define D5 (14)
#define D7 (13)
#define D6 (12)
#define RX (3)
#define TX (1)
#elif defined(ESP32)
#define D8 (5)
#define D5 (18)
#define D7 (23)
#define D6 (19)
#define RX (3)
#define TX (1)
#endif
#endif
// Pick only one of HWLOOPBACK, HWSOURCESWSINK, or HWSOURCESINK
//#define HWLOOPBACK 1
//#define HWSOURCESWSINK 1
//#define HWSOURCESINK 1
#define HALFDUPLEX 1
#ifdef ESP32
constexpr int IUTBITRATE = 19200;
#else
constexpr int IUTBITRATE = 19200;
#endif
#if defined(ESP8266)
constexpr SoftwareSerialConfig swSerialConfig = SWSERIAL_8E1;
constexpr SerialConfig hwSerialConfig = SERIAL_8E1;
#elif defined(ESP32)
constexpr SoftwareSerialConfig swSerialConfig = SWSERIAL_8E1;
constexpr uint32_t hwSerialConfig = SERIAL_8E1;
#else
constexpr unsigned swSerialConfig = 3;
#endif
constexpr bool invert = false;
constexpr int BLOCKSIZE = 16; // use fractions of 256
unsigned long start;
const char effTxTxt[] PROGMEM = "eff. tx: ";
const char effRxTxt[] PROGMEM = "eff. rx: ";
int txCount;
int rxCount;
int expected;
int rxErrors;
int rxParityErrors;
constexpr int ReportInterval = IUTBITRATE / 8;
#if defined(ESP8266)
#if defined(HWLOOPBACK) || defined(HWSOURCESWSINK)
HardwareSerial& hwSerial(Serial);
SoftwareSerial serialIUT;
SoftwareSerial logger;
#elif defined(HWSOURCESINK)
HardwareSerial& serialIUT(Serial);
SoftwareSerial logger;
#else
SoftwareSerial serialIUT;
HardwareSerial& logger(Serial);
#endif
#elif defined(ESP32)
#if defined(HWLOOPBACK) || defined (HWSOURCESWSINK)
HardwareSerial& hwSerial(Serial2);
SoftwareSerial serialIUT;
#elif defined(HWSOURCESINK)
HardwareSerial& serialIUT(Serial2);
#else
SoftwareSerial serialIUT;
#endif
HardwareSerial& logger(Serial);
#else
SoftwareSerial serialIUT(14, 12);
HardwareSerial& logger(Serial);
#endif
void setup() {
#if defined(ESP8266)
#if defined(HWLOOPBACK) || defined(HWSOURCESINK) || defined(HWSOURCESWSINK)
Serial.begin(IUTBITRATE, hwSerialConfig, SERIAL_FULL, 1, invert);
Serial.swap();
Serial.setRxBufferSize(2 * BLOCKSIZE);
logger.begin(9600, SWSERIAL_8N1, -1, TX);
#else
logger.begin(9600);
#endif
#if !defined(HWSOURCESINK)
serialIUT.begin(IUTBITRATE, swSerialConfig, D5, D6, invert, 2 * BLOCKSIZE);
#ifdef HALFDUPLEX
serialIUT.enableIntTx(false);
#endif
#endif
#elif defined(ESP32)
#if defined(HWLOOPBACK) || defined(HWSOURCESWSINK)
Serial2.begin(IUTBITRATE, hwSerialConfig, D4, D3, invert);
Serial2.setRxBufferSize(2 * BLOCKSIZE);
#elif defined(HWSOURCESINK)
serialIUT.begin(IUTBITRATE, hwSerialConfig, D5, D6, invert);
serialIUT.setRxBufferSize(2 * BLOCKSIZE);
#endif
#if !defined(HWSOURCESINK)
serialIUT.begin(IUTBITRATE, swSerialConfig, D5, D6, invert, 2 * BLOCKSIZE);
#ifdef HALFDUPLEX
serialIUT.enableIntTx(false);
#endif
#endif
logger.begin(9600);
#else
#if !defined(HWSOURCESINK)
serialIUT.begin(IUTBITRATE);
#endif
logger.begin(9600);
#endif
logger.println(PSTR("Loopback example for EspSoftwareSerial"));
start = micros();
txCount = 0;
rxCount = 0;
rxErrors = 0;
rxParityErrors = 0;
expected = -1;
}
unsigned char c = 0;
void loop() {
#ifdef HALFDUPLEX
char block[BLOCKSIZE];
#endif
char inBuf[BLOCKSIZE];
for (int i = 0; i < BLOCKSIZE; ++i) {
#ifndef HALFDUPLEX
#ifdef HWSOURCESWSINK
hwSerial.write(c);
#else
serialIUT.write(c);
#endif
#ifdef HWLOOPBACK
int avail = hwSerial.available();
while ((0 == (i % 8)) && avail > 0) {
int inCnt = hwSerial.read(inBuf, min(avail, min(BLOCKSIZE, hwSerial.availableForWrite())));
hwSerial.write(inBuf, inCnt);
avail -= inCnt;
}
#endif
#else
block[i] = c;
#endif
c = (c + 1) % 256;
++txCount;
}
#ifdef HALFDUPLEX
#ifdef HWSOURCESWSINK
hwSerial.write(block, BLOCKSIZE);
#else
serialIUT.write(block, BLOCKSIZE);
#endif
#endif
#ifdef HWSOURCESINK
#if defined(ESP8266)
if (serialIUT.hasOverrun()) { logger.println(PSTR("serialIUT.overrun")); }
#endif
#else
if (serialIUT.overflow()) { logger.println(PSTR("serialIUT.overflow")); }
#endif
int inCnt;
uint32_t deadlineStart;
#ifdef HWLOOPBACK
// starting deadline for the first bytes to become readable
deadlineStart = ESP.getCycleCount();
inCnt = 0;
while ((ESP.getCycleCount() - deadlineStart) < (1000000UL * 12 * BLOCKSIZE) / IUTBITRATE * 24 * ESP.getCpuFreqMHz()) {
int avail = hwSerial.available();
inCnt += hwSerial.read(&inBuf[inCnt], min(avail, min(BLOCKSIZE - inCnt, hwSerial.availableForWrite())));
if (inCnt >= BLOCKSIZE) { break; }
// wait for more outstanding bytes to trickle in
if (avail) deadlineStart = ESP.getCycleCount();
}
hwSerial.write(inBuf, inCnt);
#endif
// starting deadline for the first bytes to come in
deadlineStart = ESP.getCycleCount();
inCnt = 0;
while ((ESP.getCycleCount() - deadlineStart) < (1000000UL * 12 * BLOCKSIZE) / IUTBITRATE * 8 * ESP.getCpuFreqMHz()) {
int avail;
if (0 != (swSerialConfig & 070))
avail = serialIUT.available();
else
avail = serialIUT.read(inBuf, BLOCKSIZE);
for (int i = 0; i < avail; ++i)
{
unsigned char r;
if (0 != (swSerialConfig & 070))
r = serialIUT.read();
else
r = inBuf[i];
if (expected == -1) { expected = r; }
else {
expected = (expected + 1) % (1UL << (5 + swSerialConfig % 4));
}
if (r != expected) {
++rxErrors;
expected = -1;
}
#ifndef HWSOURCESINK
if (serialIUT.readParity() != (static_cast<bool>(swSerialConfig & 010) ? serialIUT.parityOdd(r) : serialIUT.parityEven(r)))
{
++rxParityErrors;
}
#elif defined(ESP8266)
// current ESP8266 API does not flag parity errors separately
if (serialIUT.hasRxError())
{
++rxParityErrors;
}
#endif
++rxCount;
++inCnt;
}
if (inCnt >= BLOCKSIZE) { break; }
// wait for more outstanding bytes to trickle in
if (avail) deadlineStart = ESP.getCycleCount();
}
const uint32_t interval = micros() - start;
if (txCount >= ReportInterval && interval) {
uint8_t wordBits = (5 + swSerialConfig % 4) + static_cast<bool>(swSerialConfig & 070) + 1 + ((swSerialConfig & 0300) ? 1 : 0);
logger.println(String(PSTR("tx/rx: ")) + txCount + PSTR("/") + rxCount);
const long txCps = txCount * (1000000.0 / interval);
const long rxCps = rxCount * (1000000.0 / interval);
logger.print(String(FPSTR(effTxTxt)) + wordBits * txCps + PSTR("bps, ")
+ effRxTxt + wordBits * rxCps + PSTR("bps, ")
+ rxErrors + PSTR(" errors (") + 100.0 * rxErrors / (!rxErrors ? 1 : rxCount) + PSTR("%)"));
if (0 != (swSerialConfig & 070))
{
logger.print(PSTR(" (")); logger.print(rxParityErrors); logger.println(PSTR(" parity errors)"));
}
else
{
logger.println();
}
txCount = 0;
rxCount = 0;
rxErrors = 0;
rxParityErrors = 0;
expected = -1;
// resync
delay(1000UL * 12 * BLOCKSIZE / IUTBITRATE * 16);
serialIUT.flush();
start = micros();
}
}

View File

@ -0,0 +1,59 @@
#include "SoftwareSerial.h"
#ifndef D5
#if defined(ESP8266)
#define D5 (14)
#define D6 (12)
#elif defined(ESP32)
#define D5 (18)
#define D6 (19)
#endif
#endif
SoftwareSerial swSer1;
SoftwareSerial swSer2;
void setup() {
delay(2000);
Serial.begin(115200);
Serial.println(PSTR("\nOne Wire Half Duplex Serial Tester"));
swSer1.begin(115200, SWSERIAL_8N1, D6, D6, false, 256);
// high speed half duplex, turn off interrupts during tx
swSer1.enableIntTx(false);
swSer2.begin(115200, SWSERIAL_8N1, D5, D5, false, 256);
// high speed half duplex, turn off interrupts during tx
swSer2.enableIntTx(false);
}
void loop() {
Serial.println(PSTR("\n\nTesting on swSer1"));
Serial.print(PSTR("Enter something to send using swSer1."));
checkSwSerial(&swSer1);
Serial.println(PSTR("\n\nTesting on swSer2"));
Serial.print(PSTR("Enter something to send using swSer2."));
checkSwSerial(&swSer2);
}
void checkSwSerial(SoftwareSerial* ss) {
byte ch;
while (!Serial.available());
ss->enableTx(true);
while (Serial.available()) {
ch = Serial.read();
ss->write(ch);
}
ss->enableTx(false);
// wait 1 second for the reply from SOftwareSerial if any
delay(1000);
if (ss->available()) {
Serial.print(PSTR("\nResult:"));
while (ss->available()) {
ch = (byte)ss->read();
Serial.print(ch < 0x10 ? PSTR(" 0") : PSTR(" "));
Serial.print(ch, HEX);
}
Serial.println();
}
}

View File

@ -0,0 +1,199 @@
#include <SoftwareSerial.h>
// On ESP8266:
// SoftwareSerial loopback for remote source (loopback.ino), or hardware loopback.
// Connect source D5 (rx) to local D8 (tx), source D6 (tx) to local D7 (rx).
// Hint: The logger is run at 9600bps such that enableIntTx(true) can remain unchanged. Blocking
// interrupts severely impacts the ability of the SoftwareSerial devices to operate concurrently
// and/or in duplex mode.
// On ESP32:
// For software or hardware loopback, connect source rx to local D8 (tx), source tx to local D7 (rx).
#ifndef D5
#if defined(ESP8266)
#define D8 (15)
#define D5 (14)
#define D7 (13)
#define D6 (12)
#define RX (3)
#define TX (1)
#elif defined(ESP32)
#define D8 (5)
#define D5 (18)
#define D7 (23)
#define D6 (19)
#define RX (3)
#define TX (1)
#endif
#endif
#define HWLOOPBACK 1
#define HALFDUPLEX 1
#ifdef ESP32
constexpr int IUTBITRATE = 19200;
#else
constexpr int IUTBITRATE = 19200;
#endif
#if defined(ESP8266)
constexpr SoftwareSerialConfig swSerialConfig = SWSERIAL_8E1;
constexpr SerialConfig hwSerialConfig = SERIAL_8E1;
#elif defined(ESP32)
constexpr SoftwareSerialConfig swSerialConfig = SWSERIAL_8E1;
constexpr uint32_t hwSerialConfig = SERIAL_8E1;
#else
constexpr unsigned swSerialConfig = 3;
#endif
constexpr bool invert = false;
constexpr int BLOCKSIZE = 16; // use fractions of 256
unsigned long start;
const char bitRateTxt[] PROGMEM = "Effective data rate: ";
int rxCount;
int seqErrors;
int parityErrors;
int expected;
constexpr int ReportInterval = IUTBITRATE / 8;
#if defined(ESP8266)
#if defined(HWLOOPBACK)
HardwareSerial& repeater(Serial);
SoftwareSerial logger;
#else
SoftwareSerial repeater;
HardwareSerial& logger(Serial);
#endif
#elif defined(ESP32)
#if defined(HWLOOPBACK)
HardwareSerial& repeater(Serial2);
#else
SoftwareSerial repeater;
#endif
HardwareSerial& logger(Serial);
#else
SoftwareSerial repeater(14, 12);
HardwareSerial& logger(Serial);
#endif
void setup() {
#if defined(ESP8266)
#if defined(HWLOOPBACK)
repeater.begin(IUTBITRATE, hwSerialConfig, SERIAL_FULL, 1, invert);
repeater.swap();
repeater.setRxBufferSize(2 * BLOCKSIZE);
logger.begin(9600, SWSERIAL_8N1, -1, TX);
#else
repeater.begin(IUTBITRATE, swSerialConfig, D7, D8, invert, 4 * BLOCKSIZE);
#ifdef HALFDUPLEX
repeater.enableIntTx(false);
#endif
logger.begin(9600);
#endif
#elif defined(ESP32)
#if defined(HWLOOPBACK)
repeater.begin(IUTBITRATE, hwSerialConfig, D7, D8, invert);
repeater.setRxBufferSize(2 * BLOCKSIZE);
#else
repeater.begin(IUTBITRATE, swSerialConfig, D7, D8, invert, 4 * BLOCKSIZE);
#ifdef HALFDUPLEX
repeater.enableIntTx(false);
#endif
#endif
logger.begin(9600);
#else
repeater.begin(IUTBITRATE);
logger.begin(9600);
#endif
logger.println(PSTR("Repeater example for EspSoftwareSerial"));
start = micros();
rxCount = 0;
seqErrors = 0;
parityErrors = 0;
expected = -1;
}
void loop() {
#ifdef HWLOOPBACK
#if defined(ESP8266)
if (repeater.hasOverrun()) { logger.println(PSTR("repeater.overrun")); }
#endif
#else
if (repeater.overflow()) { logger.println(PSTR("repeater.overflow")); }
#endif
#ifdef HALFDUPLEX
char block[BLOCKSIZE];
#endif
// starting deadline for the first bytes to come in
uint32_t deadlineStart = ESP.getCycleCount();
int inCnt = 0;
while ((ESP.getCycleCount() - deadlineStart) < (1000000UL * 12 * BLOCKSIZE) / IUTBITRATE * 24 * ESP.getCpuFreqMHz()) {
int avail = repeater.available();
for (int i = 0; i < avail; ++i)
{
int r = repeater.read();
if (r == -1) { logger.println(PSTR("read() == -1")); }
if (expected == -1) { expected = r; }
else {
expected = (expected + 1) % (1UL << (5 + swSerialConfig % 4));
}
if (r != expected) {
++seqErrors;
expected = -1;
}
#ifndef HWLOOPBACK
if (repeater.readParity() != (static_cast<bool>(swSerialConfig & 010) ? repeater.parityOdd(r) : repeater.parityEven(r)))
{
++parityErrors;
}
#elif defined(ESP8266)
// current ESP8266 API does not flag parity errors separately
if (repeater.hasRxError())
{
++parityErrors;
}
#endif
++rxCount;
#ifdef HALFDUPLEX
block[inCnt] = r;
#else
repeater.write(r);
#endif
if (++inCnt >= BLOCKSIZE) { break; }
}
if (inCnt >= BLOCKSIZE) { break; }
// wait for more outstanding bytes to trickle in
if (avail) deadlineStart = ESP.getCycleCount();
}
#ifdef HALFDUPLEX
repeater.write(block, inCnt);
#endif
if (rxCount >= ReportInterval) {
auto end = micros();
unsigned long interval = end - start;
long cps = rxCount * (1000000.0 / interval);
long seqErrorsps = seqErrors * (1000000.0 / interval);
logger.print(String(FPSTR(bitRateTxt)) + 10 * cps + PSTR("bps, ")
+ seqErrorsps + PSTR("cps seq. errors (") + 100.0 * seqErrors / rxCount + PSTR("%)"));
#ifndef HWLOOPBACK
if (0 != (swSerialConfig & 070))
{
logger.print(PSTR(" (")); logger.print(parityErrors); logger.println(PSTR(" parity errors)"));
}
else
#endif
{
logger.println();
}
start = end;
rxCount = 0;
seqErrors = 0;
parityErrors = 0;
expected = -1;
}
}

View File

@ -0,0 +1,113 @@
#include <SoftwareSerial.h>
SoftwareSerial swSer;
byte buf[10] = { 0xFA, 0xAF,0x00,0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0xED };
const byte cmd[10] PROGMEM = { 0xFA, 0xAF,0x00,0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0xED };
void setup() {
delay(2000);
Serial.begin(115200);
Serial.println(PSTR("\nAlpha 1S Servo Tester"));
swSer.begin(115200, SWSERIAL_8N1, 12, 12, false, 256);
}
void loop() {
for (int i = 1; i <= 32; i++) {
GetVersion(i);
delay(100);
}
SetLED(1, 0);
GoPos(1, 0, 50);
delay(1000);
GoPos(1, 90, 50);
delay(1000);
GoPos(1, 100, 50);
delay(1000);
SetLED(1, 1);
delay(2000);
}
void GetVersion(byte id) {
memcpy_P(buf, cmd, 10);
buf[0] = 0xFC;
buf[1] = 0xCF;
buf[2] = id;
buf[3] = 0x01;
SendCommand();
}
void GoPos(byte id, byte Pos, byte Time) {
memcpy_P(buf, cmd, 10);
buf[2] = id;
buf[3] = 0x01;
buf[4] = Pos;
buf[5] = Time;
buf[6] = 0x00;
buf[7] = Time;
SendCommand();
}
void GetPos(byte id) {
memcpy_P(buf, cmd, 10);
buf[2] = id;
buf[3] = 0x02;
SendCommand();
}
void SetLED(byte id, byte mode) {
memcpy_P(buf, cmd, 10);
buf[2] = id;
buf[3] = 0x04;
buf[4] = mode;
SendCommand();
}
void SendCommand() {
SendCommand(true);
}
void SendCommand(bool checkResult) {
byte sum = 0;
for (int i = 2; i < 8; i++) {
sum += buf[i];
}
buf[8] = sum;
ShowCommand();
swSer.flush();
swSer.enableTx(true);
swSer.write(buf, 10);
swSer.enableTx(false);
if (checkResult) checkReturn();
}
void ShowCommand() {
Serial.print(millis());
Serial.print(PSTR(" OUT>>"));
for (int i = 0; i < 10; i++) {
Serial.print(buf[i] < 0x10 ? PSTR(" 0") : PSTR(" "));
Serial.print(buf[i], HEX);
}
Serial.println();
}
void checkReturn() {
unsigned long startMs = millis();
while (((millis() - startMs) < 500) && (!swSer.available()));
if (swSer.available()) {
Serial.print(millis());
Serial.print(PSTR(" IN>>>"));
while (swSer.available()) {
byte ch = (byte)swSer.read();
Serial.print((ch < 0x10 ? PSTR(" 0") : PSTR(" ")));
Serial.print(ch, HEX);
}
Serial.println();
}
}

View File

@ -0,0 +1,79 @@
// On ESP8266:
// At 80MHz runs up 57600ps, and at 160MHz CPU frequency up to 115200bps with only negligible errors.
// Connect pin 13 to 15.
// For verification and as a example for how to use SW serial on the USB to PC connection,
// which allows the use of HW Serial on GPIO13 and GPIO15 instead, #define SWAPSERIAL below.
// Notice how the bitrates are also swapped then between RX/TX and GPIO13/GPIO15.
// Builtin debug output etc. must be stopped on HW Serial in this case, as it would interfere with the
// external communication on GPIO13/GPIO15.
#include <SoftwareSerial.h>
#ifndef D5
#if defined(ESP8266)
#define D8 (15)
#define D5 (14)
#define D7 (13)
#define D6 (12)
#define RX (3)
#define TX (1)
#elif defined(ESP32)
#define D8 (5)
#define D5 (18)
#define D7 (23)
#define D6 (19)
#define RX (3)
#define TX (1)
#endif
#endif
#ifdef ESP32
#define BAUD_RATE 57600
#else
#define BAUD_RATE 57600
#endif
#undef SWAPSERIAL
#ifndef SWAPSERIAL
auto& usbSerial = Serial;
SoftwareSerial testSerial;
#else
SoftwareSerial usbSerial;
auto& testSerial = Serial;
#endif
void setup() {
#ifndef SWAPSERIAL
usbSerial.begin(115200);
// Important: the buffer size optimizations here, in particular the isrBufSize (11) that is only sufficiently
// large to hold a single word (up to start - 8 data - parity - stop), are on the basis that any char written
// to the loopback SoftwareSerial adapter gets read before another write is performed.
// Block writes with a size greater than 1 would usually fail. Do not copy this into your own project without
// reading the documentation.
testSerial.begin(BAUD_RATE, SWSERIAL_8N1, D7, D8, false, 95, 11);
#else
testSerial.begin(115200);
testSerial.setDebugOutput(false);
testSerial.swap();
usbSerial.begin(BAUD_RATE, SWSERIAL_8N1, RX, TX, false, 95);
#endif
usbSerial.println(PSTR("\nSoftware serial test started"));
for (char ch = ' '; ch <= 'z'; ch++) {
testSerial.write(ch);
}
testSerial.println();
}
void loop() {
while (testSerial.available() > 0) {
usbSerial.write(testSerial.read());
yield();
}
while (usbSerial.available() > 0) {
testSerial.write(usbSerial.read());
yield();
}
}