diff --git a/src/SoftwareSerial.cpp b/src/SoftwareSerial.cpp index ef8bf4b..f044854 100644 --- a/src/SoftwareSerial.cpp +++ b/src/SoftwareSerial.cpp @@ -87,6 +87,7 @@ void UARTBase::begin(uint32_t baud, Config config, m_stopBits = 1 + ((config & 0300) ? 1 : 0); m_pduBits = m_dataBits + static_cast(m_parityMode) + m_stopBits; m_bitTicks = (microsToTicks(1000000UL) + baud / 2) / baud; + m_origBitTicks = m_bitTicks; m_intTxEnabled = true; } @@ -153,6 +154,12 @@ void UARTBase::enableIntTx(bool on) { m_intTxEnabled = on; } +void UARTBase::enableAutoBaud(bool on, uint8_t sep) { + m_autoBaudEnabled = on; + m_autoBaud = false; + m_frameSep = sep; +} + void UARTBase::enableRxGPIOPullUp(bool on) { m_rxGPIOPullUpEnabled = on; setRxGPIOPinMode(); @@ -163,6 +170,12 @@ void UARTBase::enableTxGPIOOpenDrain(bool on) { setTxGPIOPinMode(); } +#ifdef xTaskNotify +void UARTBase::enableNotify(TaskHandle_t task) { + m_notifyTask = task; +} +#endif + void UARTBase::enableTx(bool on) { if (m_txValid && m_oneWire) { if (on) { @@ -493,6 +506,11 @@ void UARTBase::rxBits(const uint32_t isrTick) { uint32_t ticksDiff = isrTick - m_isrLastTick; m_isrLastTick = isrTick; + if (m_autoBaudEnabled && (ticksDiff > m_origBitTicks*(m_pduBits+1))) { + m_autoBaud = true; + m_bitTicks = m_origBitTicks; + } + uint32_t bits = ticksDiff / m_bitTicks; if (ticksDiff % m_bitTicks > (m_bitTicks >> 1)) ++bits; while (bits > 0) { @@ -502,6 +520,9 @@ void UARTBase::rxBits(const uint32_t isrTick) { if (level) break; m_rxLastBit = -1; --bits; + if (m_autoBaud) { + m_rxByteTicks = 0; + } continue; } // data bits @@ -511,6 +532,9 @@ void UARTBase::rxBits(const uint32_t isrTick) { bits -= dataBits; m_rxCurByte >>= dataBits; if (level) { m_rxCurByte |= (BYTE_ALL_BITS_SET << (8 - dataBits)); } + if (m_autoBaud) { + m_rxByteTicks += ticksDiff; + } continue; } // parity bit @@ -525,6 +549,10 @@ void UARTBase::rxBits(const uint32_t isrTick) { // if not high stop bit level, discard word if (bits >= static_cast(m_pduBits - 1 - m_rxLastBit) && level) { m_rxCurByte >>= (sizeof(uint8_t) * 8 - m_dataBits); + if (m_autoBaud && (m_rxCurByte == m_frameSep)) { + m_bitTicks = (m_rxByteTicks + (m_dataBits>>1)) / m_dataBits; + m_autoBaud = false; + } if (!m_buffer->push(m_rxCurByte)) { m_overflow = true; } @@ -545,6 +573,11 @@ void UARTBase::rxBits(const uint32_t isrTick) { } } } +#ifdef xTaskNotify + if (m_notifyTask) { + xTaskNotify(m_notifyTask, 0, eSetValueWithOverwrite); + } +#endif } m_rxLastBit = m_pduBits - 1; // reset to 0 is important for masked bit logic diff --git a/src/SoftwareSerial.h b/src/SoftwareSerial.h index 4ddb157..2fbec2d 100644 --- a/src/SoftwareSerial.h +++ b/src/SoftwareSerial.h @@ -194,10 +194,16 @@ class UARTBase : public Stream { void setTransmitEnablePin(int8_t txEnablePin); /// Enable (default) or disable interrupts during tx. void enableIntTx(bool on); + /// Enable baud rate estimation based on frame separator + void enableAutoBaud(bool on, uint8_t sep = 0x55); /// Enable (default) or disable internal rx GPIO pull-up. void enableRxGPIOPullUp(bool on); /// Enable or disable (default) tx GPIO output mode. void enableTxGPIOOpenDrain(bool on); +#ifdef xTaskNotify + /// Enable or disable (default) FreeRTOS task notify + void enableNotify(TaskHandle_t task); +#endif bool overflow(); @@ -371,7 +377,12 @@ class UARTBase : public Stream { uint8_t m_stopBits; bool m_lastReadParity; bool m_overflow = false; + bool m_autoBaud = false; + bool m_autoBaudEnabled = false; + uint8_t m_frameSep; + uint32_t m_rxByteTicks; uint32_t m_bitTicks; + uint32_t m_origBitTicks; uint8_t m_parityInPos; uint8_t m_parityOutPos; int8_t m_rxLastBit; // 0 thru (m_pduBits - m_stopBits - 1): data/parity bits. -1: start bit. (m_pduBits - 1): stop bit. @@ -380,6 +391,9 @@ class UARTBase : public Stream { std::unique_ptr > m_parityBuffer; uint32_t m_periodStart; uint32_t m_periodDuration; +#ifdef xTaskNotify + TaskHandle_t m_notifyTask = nullptr; +#endif #ifndef ESP32 static uint32_t m_savedPS; #else