From 24c78da6fe3d211aaca341619cb8e729dc8f0902 Mon Sep 17 00:00:00 2001 From: August Quint <49277349+AugustQu@users.noreply.github.com> Date: Wed, 5 Feb 2020 16:44:21 +0100 Subject: [PATCH] Add files via upload --- .../examples/loopback/loopback.ino | 263 ++++++++++++++++++ .../examples/onewiretest/onewiretest.ino | 48 ++++ .../examples/repeater/repeater.ino | 183 ++++++++++++ .../examples/servoTester/servoTester.ino | 115 ++++++++ .../examples/swsertest/swsertest.ino | 47 ++++ 5 files changed, 656 insertions(+) create mode 100644 lib/EspSoftwareSerial/examples/loopback/loopback.ino create mode 100644 lib/EspSoftwareSerial/examples/onewiretest/onewiretest.ino create mode 100644 lib/EspSoftwareSerial/examples/repeater/repeater.ino create mode 100644 lib/EspSoftwareSerial/examples/servoTester/servoTester.ino create mode 100644 lib/EspSoftwareSerial/examples/swsertest/swsertest.ino diff --git a/lib/EspSoftwareSerial/examples/loopback/loopback.ino b/lib/EspSoftwareSerial/examples/loopback/loopback.ino new file mode 100644 index 00000000..b612bdec --- /dev/null +++ b/lib/EspSoftwareSerial/examples/loopback/loopback.ino @@ -0,0 +1,263 @@ +#include + +// 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). + +#if defined(ESP8266) && !defined(D5) +#define D5 (14) +#define D6 (12) +#define D7 (13) +#define D8 (15) +#define TX (1) +#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; +String effTxTxt("eff. tx: "); +String effRxTxt("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("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("serialIUT.overrun"); } +#endif +#else + if (serialIUT.overflow()) { logger.println("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(swSerialConfig & 010) ? serialIUT.parityOdd(r) : serialIUT.parityEven(r))) + { + ++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(swSerialConfig & 070) + 1 + ((swSerialConfig & 0300) ? 1 : 0); + logger.println(String("tx/rx: ") + txCount + "/" + rxCount); + const long txCps = txCount * (1000000.0 / interval); + const long rxCps = rxCount * (1000000.0 / interval); + logger.print(effTxTxt + wordBits * txCps + "bps, " + + effRxTxt + wordBits * rxCps + "bps, " + + rxErrors + " errors (" + 100.0 * rxErrors / (!rxErrors ? 1 : rxCount) + "%)"); + if (0 != (swSerialConfig & 070)) + { + logger.print(" ("); logger.print(rxParityErrors); logger.println(" 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(); + } +} diff --git a/lib/EspSoftwareSerial/examples/onewiretest/onewiretest.ino b/lib/EspSoftwareSerial/examples/onewiretest/onewiretest.ino new file mode 100644 index 00000000..3e96401b --- /dev/null +++ b/lib/EspSoftwareSerial/examples/onewiretest/onewiretest.ino @@ -0,0 +1,48 @@ +#include +#include "SoftwareSerial.h" + +SoftwareSerial swSer1; +SoftwareSerial swSer2; + +void setup() { + delay(2000); + Serial.begin(115200); + Serial.println("\nOne Wire Half Duplex Serial Tester"); + swSer1.begin(115200, SWSERIAL_8N1, 12, 12, false, 256); + swSer1.enableIntTx(true); + swSer2.begin(115200, SWSERIAL_8N1, 14, 14, false, 256); + swSer2.enableIntTx(true); +} + +void loop() { + Serial.println("\n\nTesting on swSer1"); + Serial.print("Enter something to send using swSer1."); + checkSwSerial(&swSer1); + + Serial.println("\n\nTesting on swSer2"); + Serial.print("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("\nResult:"); + while (ss->available()) { + ch = (byte)ss->read(); + Serial.print(ch < 0x01 ? " 0" : " "); + Serial.print(ch, HEX); + } + Serial.println(); + } +} diff --git a/lib/EspSoftwareSerial/examples/repeater/repeater.ino b/lib/EspSoftwareSerial/examples/repeater/repeater.ino new file mode 100644 index 00000000..fa5566de --- /dev/null +++ b/lib/EspSoftwareSerial/examples/repeater/repeater.ino @@ -0,0 +1,183 @@ +#include + +// 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). + +#if defined(ESP8266) && !defined(D5) +#define D5 (14) +#define D6 (12) +#define D7 (13) +#define D8 (15) +#define TX (1) +#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; +String bitRateTxt("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("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("repeater.overrun"); } +#endif +#else + if (repeater.overflow()) { logger.println("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("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(swSerialConfig & 010) ? repeater.parityOdd(r) : repeater.parityEven(r))) + { + ++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(bitRateTxt + 10 * cps + "bps, " + + seqErrorsps + "cps seq. errors (" + 100.0 * seqErrors / rxCount + "%)"); +#ifndef HWLOOPBACK + if (0 != (swSerialConfig & 070)) + { + logger.print(" ("); logger.print(parityErrors); logger.print(" parity errors)"); + } + else +#endif + { + logger.println(); + } + start = end; + rxCount = 0; + seqErrors = 0; + parityErrors = 0; + expected = -1; + } +} diff --git a/lib/EspSoftwareSerial/examples/servoTester/servoTester.ino b/lib/EspSoftwareSerial/examples/servoTester/servoTester.ino new file mode 100644 index 00000000..cbc784d8 --- /dev/null +++ b/lib/EspSoftwareSerial/examples/servoTester/servoTester.ino @@ -0,0 +1,115 @@ +#include +#include + +SoftwareSerial swSer; + +byte buf[10] = { 0xFA, 0xAF,0x00,0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0xED }; +byte cmd[10] = { 0xFA, 0xAF,0x00,0x00,0x00, 0x00, 0x00, 0x00, 0x00, 0xED }; +byte ver[10] = { 0xFC, 0xCF,0x00,0xAA,0x41, 0x16, 0x51, 0x01, 0x00, 0xED }; + + +void setup() { + delay(2000); + Serial.begin(115200); + Serial.println("\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(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(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(buf, cmd, 10); + buf[2] = id; + buf[3] = 0x02; + SendCommand(); +} + + +void SetLED(byte id, byte mode) { + memcpy(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(" OUT>>"); + for (int i = 0; i < 10; i++) { + Serial.print((buf[i] < 0x10 ? " 0" : " ")); + 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(" IN>>>"); + while (swSer.available()) { + byte ch = (byte)swSer.read(); + Serial.print((ch < 0x10 ? " 0" : " ")); + Serial.print(ch, HEX); + } + Serial.println(); + } +} diff --git a/lib/EspSoftwareSerial/examples/swsertest/swsertest.ino b/lib/EspSoftwareSerial/examples/swsertest/swsertest.ino new file mode 100644 index 00000000..a047c1be --- /dev/null +++ b/lib/EspSoftwareSerial/examples/swsertest/swsertest.ino @@ -0,0 +1,47 @@ +// On ESP8266: +// At 80MHz runs up 57600ps, and at 160MHz CPU frequency up to 115200bps with only negligible errors. +// Connect pin 12 to 14. + +#include + +#if defined(ESP8266) && !defined(D5) +#define D5 (14) +#define D6 (12) +#define D7 (13) +#define D8 (15) +#endif + +#ifdef ESP32 +#define BAUD_RATE 57600 +#else +#define BAUD_RATE 57600 +#endif + +// Reminder: the buffer size optimizations here, in particular the isrBufSize that only accommodates +// a single 8N1 word, 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. +SoftwareSerial swSer; + +void setup() { + Serial.begin(115200); + swSer.begin(BAUD_RATE, SWSERIAL_8N1, D5, D6, false, 95, 11); + + Serial.println("\nSoftware serial test started"); + + for (char ch = ' '; ch <= 'z'; ch++) { + swSer.write(ch); + } + swSer.println(""); +} + +void loop() { + while (swSer.available() > 0) { + Serial.write(swSer.read()); + yield(); + } + while (Serial.available() > 0) { + swSer.write(Serial.read()); + yield(); + } + +}