Skip to content

Commit 56d19bf

Browse files
authored
Release 7.0.0 (plerup#267)
* Breaking change, rx interrupt triggered receive callback instead of polling. * uint rollover (regression) fixed * GCC and constexpr member function fix.
1 parent 12f8480 commit 56d19bf

File tree

5 files changed

+36
-51
lines changed

5 files changed

+36
-51
lines changed

keywords.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ end KEYWORD2
3030
isListening KEYWORD2
3131
stopListening KEYWORD2
3232
onReceive KEYWORD2
33-
perform_work KEYWORD2
3433

3534
#######################################
3635
# Constants (LITERAL1)

library.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "EspSoftwareSerial",
3-
"version": "6.17.1",
3+
"version": "7.0.0",
44
"description": "Implementation of the Arduino software serial for ESP8266/ESP32.",
55
"keywords": [
66
"serial", "io", "softwareserial"

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=EspSoftwareSerial
2-
version=6.17.1
2+
version=7.0.0
33
author=Dirk Kaar, Peter Lerup
44
maintainer=Dirk Kaar <dok@dok-net.net>
55
sentence=Implementation of the Arduino software serial for ESP8266/ESP32.

src/SoftwareSerial.cpp

Lines changed: 21 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,15 @@ SoftwareSerial::~SoftwareSerial() {
6969
end();
7070
}
7171

72-
#if __GNUC__ >= 10
73-
constexpr
74-
#endif
75-
bool SoftwareSerial::isValidGPIOpin(int8_t pin) const {
72+
constexpr bool SoftwareSerial::isValidGPIOpin(int8_t pin) {
7673
#if defined(ESP8266)
7774
return (pin >= 0 && pin <= 16) && !isFlashInterfacePin(pin);
7875
#elif defined(ESP32)
7976
// Remove the strapping pins as defined in the datasheets, they affect bootup and other critical operations
8077
// Remmove the flash memory pins on related devices, since using these causes memory access issues.
8178
#ifdef CONFIG_IDF_TARGET_ESP32
8279
// Datasheet https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf,
83-
// Pinout https://docs.espressif.com/projects/esp-idf/en/latest/esp32/_images/esp32-devkitC-v4-pinout.jpg
80+
// Pinout https://docs.espressif.com/projects/esp-idf/en/latest/esp32/_images/esp32-devkitC-v4-pinout.jpg
8481
return (pin == 1) || (pin >= 3 && pin <= 5) ||
8582
(pin >= 12 && pin <= 15) ||
8683
(!psramFound() && pin >= 16 && pin <= 17) ||
@@ -91,32 +88,26 @@ bool SoftwareSerial::isValidGPIOpin(int8_t pin) const {
9188
// Pinout https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/_images/esp32-s2_saola1-pinout.jpg
9289
return (pin >= 1 && pin <= 21) || (pin >= 33 && pin <= 44);
9390
#elif CONFIG_IDF_TARGET_ESP32C3
94-
// Datasheet https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf,
91+
// Datasheet https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf,
9592
// Pinout https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/_images/esp32-c3-devkitm-1-v1-pinout.jpg
9693
return (pin >= 0 && pin <= 1) || (pin >= 3 && pin <= 7) || (pin >= 18 && pin <= 21);
97-
#else
94+
#else
9895
return pin >= 0;
9996
#endif
10097
#else
10198
return pin >= 0;
10299
#endif
103100
}
104101

105-
#if __GNUC__ >= 10
106-
constexpr
107-
#endif
108-
bool SoftwareSerial::isValidRxGPIOpin(int8_t pin) const {
102+
constexpr bool SoftwareSerial::isValidRxGPIOpin(int8_t pin) {
109103
return isValidGPIOpin(pin)
110104
#if defined(ESP8266)
111105
&& (pin != 16)
112106
#endif
113107
;
114108
}
115109

116-
#if __GNUC__ >= 10
117-
constexpr
118-
#endif
119-
bool SoftwareSerial::isValidTxGPIOpin(int8_t pin) const {
110+
constexpr bool SoftwareSerial::isValidTxGPIOpin(int8_t pin) {
120111
return isValidGPIOpin(pin)
121112
#if defined(ESP32)
122113
#ifdef CONFIG_IDF_TARGET_ESP32
@@ -130,10 +121,7 @@ bool SoftwareSerial::isValidTxGPIOpin(int8_t pin) const {
130121
;
131122
}
132123

133-
#if __GNUC__ >= 10
134-
constexpr
135-
#endif
136-
bool SoftwareSerial::hasRxGPIOPullUp(int8_t pin) const {
124+
constexpr bool SoftwareSerial::hasRxGPIOPullUp(int8_t pin) {
137125
#if defined(ESP32)
138126
return !(pin >= 34 && pin <= 39);
139127
#else
@@ -342,7 +330,7 @@ void SoftwareSerial::lazyDelay() {
342330
if (!m_intTxEnabled) { restoreInterrupts(); }
343331
const auto expired = microsToTicks(micros()) - m_periodStart;
344332
const int32_t remaining = m_periodDuration - expired;
345-
const int32_t ms = remaining > 0 ? static_cast<int32_t>(ticksToMicros(remaining) / 1000L) : 0;
333+
const uint32_t ms = remaining > 0 ? ticksToMicros(remaining) / 1000UL : 0;
346334
if (ms > 0)
347335
{
348336
delay(ms);
@@ -359,11 +347,9 @@ void SoftwareSerial::lazyDelay() {
359347

360348
void IRAM_ATTR SoftwareSerial::preciseDelay() {
361349
uint32_t ticks;
362-
uint32_t expired;
363350
do {
364351
ticks = microsToTicks(micros());
365-
expired = ticks - m_periodStart;
366-
} while (static_cast<int32_t>(m_periodDuration - expired) > 0);
352+
} while ((ticks - m_periodStart) < m_periodDuration);
367353
m_periodDuration = 0;
368354
m_periodStart = ticks;
369355
}
@@ -634,19 +620,23 @@ void SoftwareSerial::rxBits(const uint32_t isrTick) {
634620
}
635621

636622
void IRAM_ATTR SoftwareSerial::rxBitISR(SoftwareSerial* self) {
637-
uint32_t curTick = microsToTicks(micros());
638-
bool level = *self->m_rxReg & self->m_rxBitMask;
623+
const bool level = *self->m_rxReg & self->m_rxBitMask;
624+
const uint32_t curTick = microsToTicks(micros());
625+
const bool empty = !self->m_isrBuffer->available();
639626

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

645634
void IRAM_ATTR SoftwareSerial::rxBitSyncISR(SoftwareSerial* self) {
646-
uint32_t start = microsToTicks(micros());
635+
bool level = self->m_invert;
636+
const uint32_t start = microsToTicks(micros());
647637
uint32_t wait = self->m_bitTicks - microsToTicks(2U);
638+
const bool empty = !self->m_isrBuffer->available();
648639

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

668-
void SoftwareSerial::onReceive(Delegate<void(int available), void*> handler) {
669-
receiveHandler = handler;
660+
void SoftwareSerial::onReceive(Delegate<void(), void*> handler) {
661+
m_rxHandler = handler;
670662
}
671663

672-
void SoftwareSerial::perform_work() {
673-
if (!m_rxValid) { return; }
674-
rxBits();
675-
if (receiveHandler) {
676-
int avail = m_buffer->available();
677-
if (avail) { receiveHandler(avail); }
678-
}
679-
}

src/SoftwareSerial.h

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -203,12 +203,13 @@ class SoftwareSerial : public Stream {
203203
bool isListening() { return m_rxEnabled; }
204204
bool stopListening() { enableRx(false); return true; }
205205

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

213214
using Print::write;
214215

@@ -223,11 +224,11 @@ class SoftwareSerial : public Stream {
223224
// If offCycle == 0, the level remains unchanged from dutyCycle.
224225
void writePeriod(
225226
uint32_t dutyCycle, uint32_t offCycle, bool withStopBit);
226-
constexpr bool isValidGPIOpin(int8_t pin) const;
227-
constexpr bool isValidRxGPIOpin(int8_t pin) const;
228-
constexpr bool isValidTxGPIOpin(int8_t pin) const;
227+
static constexpr bool isValidGPIOpin(int8_t pin);
228+
static constexpr bool isValidRxGPIOpin(int8_t pin);
229+
static constexpr bool isValidTxGPIOpin(int8_t pin);
229230
// result is only defined for a valid Rx GPIO pin
230-
constexpr bool hasRxGPIOPullUp(int8_t pin) const;
231+
static constexpr bool hasRxGPIOPullUp(int8_t pin);
231232
// safely set the pin mode for the Rx GPIO pin
232233
void setRxGPIOPinMode();
233234
// safely set the pin mode for the Tx GPIO pin
@@ -295,7 +296,8 @@ class SoftwareSerial : public Stream {
295296
std::atomic<bool> m_isrOverflow;
296297
uint32_t m_isrLastTick;
297298
bool m_rxCurParity = false;
298-
Delegate<void(int available), void*> receiveHandler;
299+
Delegate<void(), void*> m_rxHandler;
299300
};
300301

301302
#endif // __SoftwareSerial_h
303+

0 commit comments

Comments
 (0)