From 5482bf99c9e1797cd8e3d3e9c9ee4e6b8e872509 Mon Sep 17 00:00:00 2001 From: Dominik Berse Date: Wed, 15 Jun 2022 16:28:45 +0200 Subject: [PATCH 1/3] Add support for single wire --- .../SoftwareSerial/src/SoftwareSerial.cpp | 35 ++++++++++++++++--- libraries/SoftwareSerial/src/SoftwareSerial.h | 3 ++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/libraries/SoftwareSerial/src/SoftwareSerial.cpp b/libraries/SoftwareSerial/src/SoftwareSerial.cpp index 5a387ab94..815ef58c2 100644 --- a/libraries/SoftwareSerial/src/SoftwareSerial.cpp +++ b/libraries/SoftwareSerial/src/SoftwareSerial.cpp @@ -93,6 +93,8 @@ bool SoftwareSerial::listen() { if (active_object) active_object->stopListening(); + if (_singleWirePin) + setupRXPin(_singleWirePin); _buffer_overflow = false; _receive_buffer_head = _receive_buffer_tail = 0; @@ -111,6 +113,8 @@ bool SoftwareSerial::stopListening() if (active_object == this) { setRxIntMsk(false); + if (_singleWirePin) + setupTXPin(_singleWirePin); active_object = NULL; return true; } @@ -246,7 +250,8 @@ ISR(PCINT3_vect, ISR_ALIASOF(PCINT0_vect)); // // Constructor // -SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic /* = false */) : +SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic /* = false */) : + _singleWirePin(receivePin == transmitPin ? receivePin : 0), _rx_delay_centering(0), _rx_delay_intrabit(0), _rx_delay_stopbit(0), @@ -256,6 +261,9 @@ SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inv { setTX(transmitPin); setRX(receivePin); + + if (_singleWirePin) + setupTXPin(_singleWirePin); } // @@ -266,7 +274,7 @@ SoftwareSerial::~SoftwareSerial() end(); } -void SoftwareSerial::setTX(uint8_t tx) +void SoftwareSerial::setupTXPin(uint8_t tx) { // First write, then set output. If we do this the other way around, // the pin would be output low for a short while before switching to @@ -274,16 +282,30 @@ void SoftwareSerial::setTX(uint8_t tx) // is fine. With inverse logic, either order is fine. digitalWrite(tx, _inverse_logic ? LOW : HIGH); pinMode(tx, OUTPUT); +} + +void SoftwareSerial::setTX(uint8_t tx) +{ + if(!_singleWirePin) + setupTXPin(tx); + _transmitBitMask = digitalPinToBitMask(tx); uint8_t port = digitalPinToPort(tx); _transmitPortRegister = portOutputRegister(port); } -void SoftwareSerial::setRX(uint8_t rx) +void SoftwareSerial::setupRXPin(uint8_t rx) { pinMode(rx, INPUT); if (!_inverse_logic) digitalWrite(rx, HIGH); // pullup for normal logic! +} + +void SoftwareSerial::setRX(uint8_t rx) +{ + if(!_singleWirePin) + setupRXPin(rx); + _receivePin = rx; _receiveBitMask = digitalPinToBitMask(rx); uint8_t port = digitalPinToPort(rx); @@ -371,7 +393,9 @@ void SoftwareSerial::begin(long speed) pinMode(_DEBUG_PIN2, OUTPUT); #endif - listen(); + // Single-wire will be in TX mode by default + if (!_singleWirePin) + listen(); } void SoftwareSerial::setRxIntMsk(bool enable) @@ -414,6 +438,9 @@ int SoftwareSerial::available() size_t SoftwareSerial::write(uint8_t b) { + if (_singleWirePin && isListening()) + return 0; + if (_tx_delay == 0) { setWriteError(); return 0; diff --git a/libraries/SoftwareSerial/src/SoftwareSerial.h b/libraries/SoftwareSerial/src/SoftwareSerial.h index d8b88cea1..055a61df0 100644 --- a/libraries/SoftwareSerial/src/SoftwareSerial.h +++ b/libraries/SoftwareSerial/src/SoftwareSerial.h @@ -51,6 +51,7 @@ class SoftwareSerial : public Stream { private: // per object data + uint8_t _singleWirePin; uint8_t _receivePin; uint8_t _receiveBitMask; volatile uint8_t *_receivePortRegister; @@ -79,6 +80,8 @@ class SoftwareSerial : public Stream uint8_t rx_pin_read(); void setTX(uint8_t transmitPin); void setRX(uint8_t receivePin); + void setupTXPin(uint8_t transmitPin); + void setupRXPin(uint8_t receivePin); inline void setRxIntMsk(bool enable) __attribute__((__always_inline__)); // Return num - sub, or 1 if the result would be < 1 From 6e542a5119f9ad8986c37e4523af55334f8c7b4d Mon Sep 17 00:00:00 2001 From: Dominik Berse Date: Fri, 22 Jul 2022 18:23:18 +0200 Subject: [PATCH 2/3] Adapted behavior to match existing single-wire codebase from STM32/LPC1768 --- libraries/SoftwareSerial/src/SoftwareSerial.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/libraries/SoftwareSerial/src/SoftwareSerial.cpp b/libraries/SoftwareSerial/src/SoftwareSerial.cpp index 815ef58c2..dfa17ab44 100644 --- a/libraries/SoftwareSerial/src/SoftwareSerial.cpp +++ b/libraries/SoftwareSerial/src/SoftwareSerial.cpp @@ -35,6 +35,8 @@ The latest version of this library can always be found at #define _DEBUG 0 #define _DEBUG_PIN1 11 #define _DEBUG_PIN2 13 + +#define HALFDUPLEX_SWITCH_DELAY 5 // // Includes // @@ -93,8 +95,6 @@ bool SoftwareSerial::listen() { if (active_object) active_object->stopListening(); - if (_singleWirePin) - setupRXPin(_singleWirePin); _buffer_overflow = false; _receive_buffer_head = _receive_buffer_tail = 0; @@ -393,7 +393,7 @@ void SoftwareSerial::begin(long speed) pinMode(_DEBUG_PIN2, OUTPUT); #endif - // Single-wire will be in TX mode by default + // Single-wire will not listen by default if (!_singleWirePin) listen(); } @@ -439,7 +439,7 @@ int SoftwareSerial::available() size_t SoftwareSerial::write(uint8_t b) { if (_singleWirePin && isListening()) - return 0; + setupTXPin(); if (_tx_delay == 0) { setWriteError(); @@ -489,8 +489,13 @@ size_t SoftwareSerial::write(uint8_t b) *reg |= reg_mask; SREG = oldSREG; // turn interrupts back on - tunedDelay(_tx_delay); - + + if (!_singleWirePin) + tunedDelay(_tx_delay); + else if(isListening()) { + tunedDelay(_tx_delay * HALFDUPLEX_SWITCH_DELAY); + setupRXPin(_singleWirePin); + } return 1; } From 992a81fb6a371199a6aaef726e602a04f316c5c2 Mon Sep 17 00:00:00 2001 From: Dominik Berse Date: Fri, 22 Jul 2022 18:37:16 +0200 Subject: [PATCH 3/3] fix: missing argument in setupTXPin() --- libraries/SoftwareSerial/src/SoftwareSerial.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/SoftwareSerial/src/SoftwareSerial.cpp b/libraries/SoftwareSerial/src/SoftwareSerial.cpp index dfa17ab44..839534ee2 100644 --- a/libraries/SoftwareSerial/src/SoftwareSerial.cpp +++ b/libraries/SoftwareSerial/src/SoftwareSerial.cpp @@ -439,7 +439,7 @@ int SoftwareSerial::available() size_t SoftwareSerial::write(uint8_t b) { if (_singleWirePin && isListening()) - setupTXPin(); + setupTXPin(_singleWirePin); if (_tx_delay == 0) { setWriteError();