Skip to content

Commit

Permalink
Release 7.0.0 (#267)
Browse files Browse the repository at this point in the history
* Breaking change, rx interrupt triggered receive callback instead of polling.

* uint rollover (regression) fixed

* GCC and constexpr member function fix.
  • Loading branch information
dok-net authored Dec 31, 2022
1 parent 12f8480 commit 56d19bf
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 51 deletions.
1 change: 0 additions & 1 deletion keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ end KEYWORD2
isListening KEYWORD2
stopListening KEYWORD2
onReceive KEYWORD2
perform_work KEYWORD2

#######################################
# Constants (LITERAL1)
Expand Down
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "EspSoftwareSerial",
"version": "6.17.1",
"version": "7.0.0",
"description": "Implementation of the Arduino software serial for ESP8266/ESP32.",
"keywords": [
"serial", "io", "softwareserial"
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=EspSoftwareSerial
version=6.17.1
version=7.0.0
author=Dirk Kaar, Peter Lerup
maintainer=Dirk Kaar <dok@dok-net.net>
sentence=Implementation of the Arduino software serial for ESP8266/ESP32.
Expand Down
58 changes: 21 additions & 37 deletions src/SoftwareSerial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,15 @@ SoftwareSerial::~SoftwareSerial() {
end();
}

#if __GNUC__ >= 10
constexpr
#endif
bool SoftwareSerial::isValidGPIOpin(int8_t pin) const {
constexpr bool SoftwareSerial::isValidGPIOpin(int8_t pin) {
#if defined(ESP8266)
return (pin >= 0 && pin <= 16) && !isFlashInterfacePin(pin);
#elif defined(ESP32)
// Remove the strapping pins as defined in the datasheets, they affect bootup and other critical operations
// Remmove the flash memory pins on related devices, since using these causes memory access issues.
#ifdef CONFIG_IDF_TARGET_ESP32
// Datasheet https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf,
// Pinout https://docs.espressif.com/projects/esp-idf/en/latest/esp32/_images/esp32-devkitC-v4-pinout.jpg
// Pinout https://docs.espressif.com/projects/esp-idf/en/latest/esp32/_images/esp32-devkitC-v4-pinout.jpg
return (pin == 1) || (pin >= 3 && pin <= 5) ||
(pin >= 12 && pin <= 15) ||
(!psramFound() && pin >= 16 && pin <= 17) ||
Expand All @@ -91,32 +88,26 @@ bool SoftwareSerial::isValidGPIOpin(int8_t pin) const {
// Pinout https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/_images/esp32-s2_saola1-pinout.jpg
return (pin >= 1 && pin <= 21) || (pin >= 33 && pin <= 44);
#elif CONFIG_IDF_TARGET_ESP32C3
// Datasheet https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf,
// Datasheet https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf,
// Pinout https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/_images/esp32-c3-devkitm-1-v1-pinout.jpg
return (pin >= 0 && pin <= 1) || (pin >= 3 && pin <= 7) || (pin >= 18 && pin <= 21);
#else
#else
return pin >= 0;
#endif
#else
return pin >= 0;
#endif
}

#if __GNUC__ >= 10
constexpr
#endif
bool SoftwareSerial::isValidRxGPIOpin(int8_t pin) const {
constexpr bool SoftwareSerial::isValidRxGPIOpin(int8_t pin) {
return isValidGPIOpin(pin)
#if defined(ESP8266)
&& (pin != 16)
#endif
;
}

#if __GNUC__ >= 10
constexpr
#endif
bool SoftwareSerial::isValidTxGPIOpin(int8_t pin) const {
constexpr bool SoftwareSerial::isValidTxGPIOpin(int8_t pin) {
return isValidGPIOpin(pin)
#if defined(ESP32)
#ifdef CONFIG_IDF_TARGET_ESP32
Expand All @@ -130,10 +121,7 @@ bool SoftwareSerial::isValidTxGPIOpin(int8_t pin) const {
;
}

#if __GNUC__ >= 10
constexpr
#endif
bool SoftwareSerial::hasRxGPIOPullUp(int8_t pin) const {
constexpr bool SoftwareSerial::hasRxGPIOPullUp(int8_t pin) {
#if defined(ESP32)
return !(pin >= 34 && pin <= 39);
#else
Expand Down Expand Up @@ -342,7 +330,7 @@ void SoftwareSerial::lazyDelay() {
if (!m_intTxEnabled) { restoreInterrupts(); }
const auto expired = microsToTicks(micros()) - m_periodStart;
const int32_t remaining = m_periodDuration - expired;
const int32_t ms = remaining > 0 ? static_cast<int32_t>(ticksToMicros(remaining) / 1000L) : 0;
const uint32_t ms = remaining > 0 ? ticksToMicros(remaining) / 1000UL : 0;
if (ms > 0)
{
delay(ms);
Expand All @@ -359,11 +347,9 @@ void SoftwareSerial::lazyDelay() {

void IRAM_ATTR SoftwareSerial::preciseDelay() {
uint32_t ticks;
uint32_t expired;
do {
ticks = microsToTicks(micros());
expired = ticks - m_periodStart;
} while (static_cast<int32_t>(m_periodDuration - expired) > 0);
} while ((ticks - m_periodStart) < m_periodDuration);
m_periodDuration = 0;
m_periodStart = ticks;
}
Expand Down Expand Up @@ -634,19 +620,23 @@ void SoftwareSerial::rxBits(const uint32_t isrTick) {
}

void IRAM_ATTR SoftwareSerial::rxBitISR(SoftwareSerial* self) {
uint32_t curTick = microsToTicks(micros());
bool level = *self->m_rxReg & self->m_rxBitMask;
const bool level = *self->m_rxReg & self->m_rxBitMask;
const uint32_t curTick = microsToTicks(micros());
const bool empty = !self->m_isrBuffer->available();

// Store level and tick in the buffer unless we have an overflow
// tick's LSB is repurposed for the level bit
if (!self->m_isrBuffer->push((curTick | 1U) ^ !level)) self->m_isrOverflow.store(true);
// Trigger rx callback only when receiver is starved
if (empty && self->m_rxHandler) self->m_rxHandler();
}

void IRAM_ATTR SoftwareSerial::rxBitSyncISR(SoftwareSerial* self) {
uint32_t start = microsToTicks(micros());
bool level = self->m_invert;
const uint32_t start = microsToTicks(micros());
uint32_t wait = self->m_bitTicks - microsToTicks(2U);
const bool empty = !self->m_isrBuffer->available();

bool level = self->m_invert;
// Store level and tick in the buffer unless we have an overflow
// tick's LSB is repurposed for the level bit
if (!self->m_isrBuffer->push(((start + wait) | 1U) ^ !level)) self->m_isrOverflow.store(true);
Expand All @@ -663,17 +653,11 @@ void IRAM_ATTR SoftwareSerial::rxBitSyncISR(SoftwareSerial* self) {
level = !level;
}
}
// Trigger rx callback only when receiver is starved
if (empty && self->m_rxHandler) self->m_rxHandler();
}

void SoftwareSerial::onReceive(Delegate<void(int available), void*> handler) {
receiveHandler = handler;
void SoftwareSerial::onReceive(Delegate<void(), void*> handler) {
m_rxHandler = handler;
}

void SoftwareSerial::perform_work() {
if (!m_rxValid) { return; }
rxBits();
if (receiveHandler) {
int avail = m_buffer->available();
if (avail) { receiveHandler(avail); }
}
}
24 changes: 13 additions & 11 deletions src/SoftwareSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,12 +203,13 @@ class SoftwareSerial : public Stream {
bool isListening() { return m_rxEnabled; }
bool stopListening() { enableRx(false); return true; }

/// Set an event handler for received data.
void onReceive(Delegate<void(int available), void*> handler);

/// Run the internal processing and event engine. Can be iteratively called
/// from loop, or otherwise scheduled.
void perform_work();
/// onReceive sets a callback that will be called in interrupt context
/// when data is received.
/// More precisely, the callback is triggered when EspSoftwareSerial detects
/// a new reception, which may not yet have completed on invocation.
/// Reading - never from this interrupt context - should therefore be
/// delayed for the duration of one incoming word.
void onReceive(Delegate<void(), void*> handler);

using Print::write;

Expand All @@ -223,11 +224,11 @@ class SoftwareSerial : public Stream {
// If offCycle == 0, the level remains unchanged from dutyCycle.
void writePeriod(
uint32_t dutyCycle, uint32_t offCycle, bool withStopBit);
constexpr bool isValidGPIOpin(int8_t pin) const;
constexpr bool isValidRxGPIOpin(int8_t pin) const;
constexpr bool isValidTxGPIOpin(int8_t pin) const;
static constexpr bool isValidGPIOpin(int8_t pin);
static constexpr bool isValidRxGPIOpin(int8_t pin);
static constexpr bool isValidTxGPIOpin(int8_t pin);
// result is only defined for a valid Rx GPIO pin
constexpr bool hasRxGPIOPullUp(int8_t pin) const;
static constexpr bool hasRxGPIOPullUp(int8_t pin);
// safely set the pin mode for the Rx GPIO pin
void setRxGPIOPinMode();
// safely set the pin mode for the Tx GPIO pin
Expand Down Expand Up @@ -295,7 +296,8 @@ class SoftwareSerial : public Stream {
std::atomic<bool> m_isrOverflow;
uint32_t m_isrLastTick;
bool m_rxCurParity = false;
Delegate<void(int available), void*> receiveHandler;
Delegate<void(), void*> m_rxHandler;
};

#endif // __SoftwareSerial_h

0 comments on commit 56d19bf

Please sign in to comment.