/* SoftwareSerial.h SoftwareSerial.cpp - Implementation of the Arduino software serial for ESP8266/ESP32. Copyright (c) 2015-2016 Peter Lerup. All rights reserved. Copyright (c) 2018-2019 Dirk O. Kaar. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __SoftwareSerial_h #define __SoftwareSerial_h #include "circular_queue/circular_queue.h" #include enum SoftwareSerialParity : uint8_t { SWSERIAL_PARITY_NONE = 000, SWSERIAL_PARITY_EVEN = 020, SWSERIAL_PARITY_ODD = 030, SWSERIAL_PARITY_MARK = 040, SWSERIAL_PARITY_SPACE = 070, }; enum SoftwareSerialConfig { SWSERIAL_5N1 = SWSERIAL_PARITY_NONE, SWSERIAL_6N1, SWSERIAL_7N1, SWSERIAL_8N1, SWSERIAL_5E1 = SWSERIAL_PARITY_EVEN, SWSERIAL_6E1, SWSERIAL_7E1, SWSERIAL_8E1, SWSERIAL_5O1 = SWSERIAL_PARITY_ODD, SWSERIAL_6O1, SWSERIAL_7O1, SWSERIAL_8O1, SWSERIAL_5M1 = SWSERIAL_PARITY_MARK, SWSERIAL_6M1, SWSERIAL_7M1, SWSERIAL_8M1, SWSERIAL_5S1 = SWSERIAL_PARITY_SPACE, SWSERIAL_6S1, SWSERIAL_7S1, SWSERIAL_8S1, SWSERIAL_5N2 = 0200 | SWSERIAL_PARITY_NONE, SWSERIAL_6N2, SWSERIAL_7N2, SWSERIAL_8N2, SWSERIAL_5E2 = 0200 | SWSERIAL_PARITY_EVEN, SWSERIAL_6E2, SWSERIAL_7E2, SWSERIAL_8E2, SWSERIAL_5O2 = 0200 | SWSERIAL_PARITY_ODD, SWSERIAL_6O2, SWSERIAL_7O2, SWSERIAL_8O2, SWSERIAL_5M2 = 0200 | SWSERIAL_PARITY_MARK, SWSERIAL_6M2, SWSERIAL_7M2, SWSERIAL_8M2, SWSERIAL_5S2 = 0200 | SWSERIAL_PARITY_SPACE, SWSERIAL_6S2, SWSERIAL_7S2, SWSERIAL_8S2, }; /// This class is compatible with the corresponding AVR one, however, /// the constructor takes no arguments, for compatibility with the /// HardwareSerial class. /// Instead, the begin() function handles pin assignments and logic inversion. /// It also has optional input buffer capacity arguments for byte buffer and ISR bit buffer. /// Bitrates up to at least 115200 can be used. class SoftwareSerial : public Stream { public: SoftwareSerial(); /// Ctor to set defaults for pins. /// @param rxPin the GPIO pin used for RX /// @param txPin -1 for onewire protocol, GPIO pin used for twowire TX SoftwareSerial(int8_t rxPin, int8_t txPin = -1, bool invert = false); SoftwareSerial(const SoftwareSerial&) = delete; SoftwareSerial& operator= (const SoftwareSerial&) = delete; virtual ~SoftwareSerial(); /// Configure the SoftwareSerial object for use. /// @param baud the TX/RX bitrate /// @param config sets databits, parity, and stop bit count /// @param rxPin -1 or default: either no RX pin, or keeps the rxPin set in the ctor /// @param txPin -1 or default: either no TX pin (onewire), or keeps the txPin set in the ctor /// @param invert true: uses invert line level logic /// @param bufCapacity the capacity for the received bytes buffer /// @param isrBufCapacity 0: derived from bufCapacity. The capacity of the internal asynchronous /// bit receive buffer, a suggested size is bufCapacity times the sum of /// start, data, parity and stop bit count. void begin(uint32_t baud, SoftwareSerialConfig config, int8_t rxPin, int8_t txPin, bool invert, int bufCapacity = 64, int isrBufCapacity = 0); void begin(uint32_t baud, SoftwareSerialConfig config, int8_t rxPin, int8_t txPin) { begin(baud, config, rxPin, txPin, m_invert); } void begin(uint32_t baud, SoftwareSerialConfig config, int8_t rxPin) { begin(baud, config, rxPin, m_txPin, m_invert); } void begin(uint32_t baud, SoftwareSerialConfig config = SWSERIAL_8N1) { begin(baud, config, m_rxPin, m_txPin, m_invert); } uint32_t baudRate(); /// Transmit control pin. void setTransmitEnablePin(int8_t txEnablePin); /// Enable or disable interrupts during tx. void enableIntTx(bool on); bool overflow(); int available() override; int availableForWrite() { if (!m_txValid) return 0; return 1; } int peek() override; int read() override; /// @returns The verbatim parity bit associated with the last read() or peek() call bool readParity() { return m_lastReadParity; } /// @returns The calculated bit for even parity of the parameter byte static bool parityEven(uint8_t byte) { byte ^= byte >> 4; byte &= 0xf; return (0x6996 >> byte) & 1; } /// @returns The calculated bit for odd parity of the parameter byte static bool parityOdd(uint8_t byte) { byte ^= byte >> 4; byte &= 0xf; return (0x9669 >> byte) & 1; } /// The read(buffer, size) functions are non-blocking, the same as readBytes but without timeout size_t read(uint8_t* buffer, size_t size); /// The read(buffer, size) functions are non-blocking, the same as readBytes but without timeout size_t read(char* buffer, size_t size) { return read(reinterpret_cast(buffer), size); } /// @returns The number of bytes read into buffer, up to size. Times out if the limit set through /// Stream::setTimeout() is reached. size_t readBytes(uint8_t* buffer, size_t size) override; /// @returns The number of bytes read into buffer, up to size. Times out if the limit set through /// Stream::setTimeout() is reached. size_t readBytes(char* buffer, size_t size) override { return readBytes(reinterpret_cast(buffer), size); } void flush() override; size_t write(uint8_t byte) override; size_t write(uint8_t byte, SoftwareSerialParity parity); size_t write(const uint8_t* buffer, size_t size) override; size_t write(const char* buffer, size_t size) { return write(reinterpret_cast(buffer), size); } size_t write(const uint8_t* buffer, size_t size, SoftwareSerialParity parity); size_t write(const char* buffer, size_t size, SoftwareSerialParity parity) { return write(reinterpret_cast(buffer), size, parity); } operator bool() const { return m_rxValid || m_txValid; } /// Disable or enable interrupts on the rx pin. void enableRx(bool on); /// One wire control. void enableTx(bool on); // AVR compatibility methods. bool listen() { enableRx(true); return true; } void end(); bool isListening() { return m_rxEnabled; } bool stopListening() { enableRx(false); return true; } /// Set an event handler for received data. void onReceive(Delegate handler); /// Run the internal processing and event engine. Can be iteratively called /// from loop, or otherwise scheduled. void perform_work(); using Print::write; private: // If sync is false, it's legal to exceed the deadline, for instance, // by enabling interrupts. void preciseDelay(bool sync); // If withStopBit is set, either cycle contains a stop bit. // If dutyCycle == 0, the level is not forced to HIGH. // If offCycle == 0, the level remains unchanged from dutyCycle. void writePeriod( uint32_t dutyCycle, uint32_t offCycle, bool withStopBit); bool isValidGPIOpin(int8_t pin); /* check m_rxValid that calling is safe */ void rxBits(); void rxBits(const uint32_t& isrCycle); static void rxBitISR(SoftwareSerial* self); static void rxBitSyncISR(SoftwareSerial* self); // Member variables int8_t m_rxPin = -1; int8_t m_txPin = -1; int8_t m_txEnablePin = -1; uint8_t m_dataBits; bool m_oneWire; bool m_rxValid = false; bool m_rxEnabled = false; bool m_txValid = false; bool m_txEnableValid = false; bool m_invert; /// PDU bits include data, parity and stop bits; the start bit is not counted. uint8_t m_pduBits; bool m_intTxEnabled; SoftwareSerialParity m_parityMode; uint8_t m_stopBits; bool m_lastReadParity; bool m_overflow = false; uint32_t m_bitCycles; uint8_t m_parityInPos; uint8_t m_parityOutPos; int8_t m_rxCurBit; // 0 thru (m_pduBits - m_stopBits - 1): data/parity bits. -1: start bit. (m_pduBits - 1): stop bit. uint8_t m_rxCurByte = 0; std::unique_ptr > m_buffer; std::unique_ptr > m_parityBuffer; uint32_t m_periodStart; uint32_t m_periodDuration; uint32_t m_savedPS = 0; // the ISR stores the relative bit times in the buffer. The inversion corrected level is used as sign bit (2's complement): // 1 = positive including 0, 0 = negative. std::unique_ptr > m_isrBuffer; std::atomic m_isrOverflow; uint32_t m_isrLastCycle; bool m_rxCurParity = false; Delegate receiveHandler; }; #endif // __SoftwareSerial_h