Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/IRMQTTServer/IRMQTTServer.ino
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ char Hostname[kHostnameLength + 1] = "ir_server"; // Default hostname.
uint16_t *codeArray;
uint32_t lastReconnectAttempt = 0; // MQTT last attempt reconnection number
bool boot = true;
volatile bool lockIr = false; // Primitive locking for gating the IR LED.
atomic_bool lockIr = false; // Primitive locking for gating the IR LED.
uint32_t sendReqCounter = 0;
bool lastSendSucceeded = false; // Store the success status of the last send.
uint32_t lastSendTime = 0;
Expand Down
7 changes: 6 additions & 1 deletion platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,10 @@ board = nodemcuv2
board = d1_mini

[env:esp32dev]
platform = espressif32
platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.09.01/platform-espressif32.zip
board = esp32dev

# Experimental IDF 5.x support
[env:esp32devIDF5x]
platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.10.03/platform-espressif32.zip
board = esp32dev
46 changes: 34 additions & 12 deletions src/IRrecv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ namespace _IRrecv { // Namespace extension
#if defined(ESP32)
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
#endif // ESP32
volatile irparams_t params;
atomic_irparams_t params;
irparams_t *params_save; // A copy of the interrupt state while decoding.
} // namespace _IRrecv

Expand Down Expand Up @@ -242,8 +242,13 @@ static void USE_IRAM_ATTR gpio_intr() {
// @see https://github.com/espressif/arduino-esp32/blob/6b0114366baf986c155e8173ab7c22bc0c5fcedc/cores/esp32/esp32-hal-timer.c#L176-L178
timer->dev->config.alarm_en = 1;
#else // _ESP32_IRRECV_TIMER_HACK
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) )
timerAlarm(timer, MS_TO_USEC(params.timeout), ONCE, 0);
timerAttachInterrupt(timer, &read_timeout);
#else // ESP_ARDUINO_VERSION_MAJOR >= 3
timerWrite(timer, 0);
timerAlarmEnable(timer);
#endif // ESP_ARDUINO_VERSION_MAJOR >= 3
#endif // _ESP32_IRRECV_TIMER_HACK
#endif // ESP32
}
Expand Down Expand Up @@ -359,20 +364,29 @@ void IRrecv::enableIRIn(const bool pullup) {
#if defined(ESP32)
// Initialise the ESP32 timer.
// 80MHz / 80 = 1 uSec granularity.
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) )
timer = timerBegin(80);
#else // ESP_ARDUINO_VERSION_MAJOR >= 3
timer = timerBegin(_timer_num, 80, true);
#endif // ESP_ARDUINO_VERSION_MAJOR >= 3
#ifdef DEBUG
if (timer == NULL) {
DPRINT("FATAL: Unable enable system timer: ");
DPRINTLN((uint16_t)_timer_num);
}
#endif // DEBUG
assert(timer != NULL); // Check we actually got the timer.
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) )
timerAlarm(timer, MS_TO_USEC(params.timeout), ONCE, 0);
timerAttachInterrupt(timer, &read_timeout);
#else // ESP_ARDUINO_VERSION_MAJOR >= 3
// Set the timer so it only fires once, and set it's trigger in uSeconds.
timerAlarmWrite(timer, MS_TO_USEC(params.timeout), ONCE);
// Note: Interrupt needs to be attached before it can be enabled or disabled.
// Note: EDGE (true) is not supported, use LEVEL (false). Ref: #1713
// See: https://github.com/espressif/arduino-esp32/blob/caef4006af491130136b219c1205bdcf8f08bf2b/cores/esp32/esp32-hal-timer.c#L224-L227
timerAttachInterrupt(timer, &read_timeout, false);
#endif // ESP_ARDUINO_VERSION_MAJOR >= 3
#endif // ESP32

// Initialise state machine variables
Expand All @@ -398,9 +412,13 @@ void IRrecv::disableIRIn(void) {
os_timer_disarm(&timer);
#endif // ESP8266
#if defined(ESP32)
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) )
timerEnd(timer);
#else // ESP_ARDUINO_VERSION_MAJOR >= 3
timerAlarmDisable(timer);
timerDetachInterrupt(timer);
timerEnd(timer);
#endif // ESP_ARDUINO_VERSION_MAJOR >= 3
#endif // ESP32
detachInterrupt(params.recvpin);
#endif // UNIT_TEST
Expand All @@ -426,7 +444,11 @@ void IRrecv::resume(void) {
params.rawlen = 0;
params.overflow = false;
#if defined(ESP32)
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) )
timerEnd(timer);
#else // ESP_ARDUINO_VERSION_MAJOR >= 3
timerAlarmDisable(timer);
#endif // ESP_ARDUINO_VERSION_MAJOR >= 3
gpio_intr_enable((gpio_num_t)params.recvpin);
#endif // ESP32
}
Expand All @@ -437,7 +459,7 @@ void IRrecv::resume(void) {
/// i.e. In kStopState.
/// @param[in] src Pointer to an irparams_t structure to copy from.
/// @param[out] dst Pointer to an irparams_t structure to copy to.
void IRrecv::copyIrParams(volatile irparams_t *src, irparams_t *dst) {
void IRrecv::copyIrParams(atomic_irparams_t *src, irparams_t *dst) {
// Typecast src and dst addresses to (char *)
char *csrc = (char *)src; // NOLINT(readability/casting)
char *cdst = (char *)dst; // NOLINT(readability/casting)
Expand Down Expand Up @@ -503,7 +525,7 @@ void IRrecv::crudeNoiseFilter(decode_results *results, const uint16_t floor) {
results->rawbuf[i - 2] = results->rawbuf[i];
if (offset > 1) { // There is a previous pair we can add to.
// Merge this pair into into the previous space.
results->rawbuf[offset - 1] += addition;
results->rawbuf[offset - 1] = results->rawbuf[offset - 1] + addition;
}
results->rawlen -= 2; // Adjust the length.
} else {
Expand Down Expand Up @@ -1449,7 +1471,7 @@ bool IRrecv::decodeHash(decode_results *results) {
/// @return A match_result_t structure containing the success (or not), the
/// data value, and how many buffer entries were used.
match_result_t IRrecv::matchData(
volatile uint16_t *data_ptr, const uint16_t nbits, const uint16_t onemark,
atomic_uint16_t *data_ptr, const uint16_t nbits, const uint16_t onemark,
const uint32_t onespace, const uint16_t zeromark, const uint32_t zerospace,
const uint8_t tolerance, const int16_t excess, const bool MSBfirst,
const bool expectlastspace) {
Expand Down Expand Up @@ -1509,7 +1531,7 @@ match_result_t IRrecv::matchData(
/// true is Most Significant Bit First Order, false is Least Significant First
/// @param[in] expectlastspace Do we expect a space at the end of the message?
/// @return If successful, how many buffer entries were used. Otherwise 0.
uint16_t IRrecv::matchBytes(volatile uint16_t *data_ptr, uint8_t *result_ptr,
uint16_t IRrecv::matchBytes(atomic_uint16_t *data_ptr, uint8_t *result_ptr,
const uint16_t remaining, const uint16_t nbytes,
const uint16_t onemark, const uint32_t onespace,
const uint16_t zeromark, const uint32_t zerospace,
Expand Down Expand Up @@ -1561,7 +1583,7 @@ uint16_t IRrecv::matchBytes(volatile uint16_t *data_ptr, uint8_t *result_ptr,
/// @param[in] MSBfirst Bit order to save the data in. (Def: true)
/// true is Most Significant Bit First Order, false is Least Significant First
/// @return If successful, how many buffer entries were used. Otherwise 0.
uint16_t IRrecv::_matchGeneric(volatile uint16_t *data_ptr,
uint16_t IRrecv::_matchGeneric(atomic_uint16_t *data_ptr,
uint64_t *result_bits_ptr,
uint8_t *result_bytes_ptr,
const bool use_bits,
Expand Down Expand Up @@ -1663,7 +1685,7 @@ uint16_t IRrecv::_matchGeneric(volatile uint16_t *data_ptr,
/// @param[in] MSBfirst Bit order to save the data in. (Def: true)
/// true is Most Significant Bit First Order, false is Least Significant First
/// @return If successful, how many buffer entries were used. Otherwise 0.
uint16_t IRrecv::matchGeneric(volatile uint16_t *data_ptr,
uint16_t IRrecv::matchGeneric(atomic_uint16_t *data_ptr,
uint64_t *result_ptr,
const uint16_t remaining,
const uint16_t nbits,
Expand Down Expand Up @@ -1710,7 +1732,7 @@ uint16_t IRrecv::matchGeneric(volatile uint16_t *data_ptr,
/// @param[in] MSBfirst Bit order to save the data in. (Def: true)
/// true is Most Significant Bit First Order, false is Least Significant First
/// @return If successful, how many buffer entries were used. Otherwise 0.
uint16_t IRrecv::matchGeneric(volatile uint16_t *data_ptr,
uint16_t IRrecv::matchGeneric(atomic_uint16_t *data_ptr,
uint8_t *result_ptr,
const uint16_t remaining,
const uint16_t nbits,
Expand Down Expand Up @@ -1757,7 +1779,7 @@ uint16_t IRrecv::matchGeneric(volatile uint16_t *data_ptr,
/// @return If successful, how many buffer entries were used. Otherwise 0.
/// @note Parameters one + zero add up to the total time for a bit.
/// e.g. mark(one) + space(zero) is a `1`, mark(zero) + space(one) is a `0`.
uint16_t IRrecv::matchGenericConstBitTime(volatile uint16_t *data_ptr,
uint16_t IRrecv::matchGenericConstBitTime(atomic_uint16_t *data_ptr,
uint64_t *result_ptr,
const uint16_t remaining,
const uint16_t nbits,
Expand Down Expand Up @@ -1844,7 +1866,7 @@ uint16_t IRrecv::matchGenericConstBitTime(volatile uint16_t *data_ptr,
/// @return If successful, how many buffer entries were used. Otherwise 0.
/// @see https://en.wikipedia.org/wiki/Manchester_code
/// @see http://ww1.microchip.com/downloads/en/AppNotes/Atmel-9164-Manchester-Coding-Basics_Application-Note.pdf
uint16_t IRrecv::matchManchester(volatile const uint16_t *data_ptr,
uint16_t IRrecv::matchManchester(atomic_const_uint16_t *data_ptr,
uint64_t *result_ptr,
const uint16_t remaining,
const uint16_t nbits,
Expand Down Expand Up @@ -1951,7 +1973,7 @@ uint16_t IRrecv::matchManchester(volatile const uint16_t *data_ptr,
/// @see https://en.wikipedia.org/wiki/Manchester_code
/// @see http://ww1.microchip.com/downloads/en/AppNotes/Atmel-9164-Manchester-Coding-Basics_Application-Note.pdf
/// @todo Clean up and optimise this. It is just "get it working code" atm.
uint16_t IRrecv::matchManchesterData(volatile const uint16_t *data_ptr,
uint16_t IRrecv::matchManchesterData(atomic_const_uint16_t *data_ptr,
uint64_t *result_ptr,
const uint16_t remaining,
const uint16_t nbits,
Expand Down Expand Up @@ -2072,7 +2094,7 @@ uint16_t IRrecv::matchManchesterData(volatile const uint16_t *data_ptr,

#if UNIT_TEST
/// Unit test helper to get access to the params structure.
volatile irparams_t *IRrecv::_getParamsPtr(void) {
atomic_irparams_t *IRrecv::_getParamsPtr(void) {
return &params;
}
#endif // UNIT_TEST
Expand Down
29 changes: 18 additions & 11 deletions src/IRrecv.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ typedef struct {
uint8_t timeout; // Nr. of milliSeconds before we give up.
} irparams_t;

#if __cplusplus >= 202002L
typedef volatile irparams_t atomic_irparams_t;
#else
typedef volatile irparams_t atomic_irparams_t;
#endif

/// Results from a data match
typedef struct {
bool success; // Was the match successful?
Expand All @@ -111,7 +117,7 @@ class decode_results {
uint8_t state[kStateSizeMax]; // Multi-byte results.
};
uint16_t bits; // Number of bits in decoded value
volatile uint16_t *rawbuf; // Raw intervals in .5 us ticks
atomic_uint16_t *rawbuf; // Raw intervals in .5 us ticks
uint16_t rawlen; // Number of records in rawbuf.
bool overflow;
bool repeat; // Is the result a repeat code?
Expand Down Expand Up @@ -171,11 +177,11 @@ class IRrecv {
uint16_t _unknown_threshold;
#endif
#ifdef UNIT_TEST
volatile irparams_t *_getParamsPtr(void);
atomic_irparams_t *_getParamsPtr(void);
#endif // UNIT_TEST
// These are called by decode
uint8_t _validTolerance(const uint8_t percentage);
void copyIrParams(volatile irparams_t *src, irparams_t *dst);
void copyIrParams(atomic_irparams_t *src, irparams_t *dst);
uint16_t compare(const uint16_t oldval, const uint16_t newval);
uint32_t ticksLow(const uint32_t usecs,
const uint8_t tolerance = kUseDefTol,
Expand All @@ -186,7 +192,7 @@ class IRrecv {
bool matchAtLeast(const uint32_t measured, const uint32_t desired,
const uint8_t tolerance = kUseDefTol,
const uint16_t delta = 0);
uint16_t _matchGeneric(volatile uint16_t *data_ptr,
uint16_t _matchGeneric(atomic_uint16_t *data_ptr,
uint64_t *result_bits_ptr,
uint8_t *result_ptr,
const bool use_bits,
Expand All @@ -204,22 +210,22 @@ class IRrecv {
const uint8_t tolerance = kUseDefTol,
const int16_t excess = kMarkExcess,
const bool MSBfirst = true);
match_result_t matchData(volatile uint16_t *data_ptr, const uint16_t nbits,
match_result_t matchData(atomic_uint16_t *data_ptr, const uint16_t nbits,
const uint16_t onemark, const uint32_t onespace,
const uint16_t zeromark, const uint32_t zerospace,
const uint8_t tolerance = kUseDefTol,
const int16_t excess = kMarkExcess,
const bool MSBfirst = true,
const bool expectlastspace = true);
uint16_t matchBytes(volatile uint16_t *data_ptr, uint8_t *result_ptr,
uint16_t matchBytes(atomic_uint16_t *data_ptr, uint8_t *result_ptr,
const uint16_t remaining, const uint16_t nbytes,
const uint16_t onemark, const uint32_t onespace,
const uint16_t zeromark, const uint32_t zerospace,
const uint8_t tolerance = kUseDefTol,
const int16_t excess = kMarkExcess,
const bool MSBfirst = true,
const bool expectlastspace = true);
uint16_t matchGeneric(volatile uint16_t *data_ptr,
uint16_t matchGeneric(atomic_uint16_t *data_ptr,
uint64_t *result_ptr,
const uint16_t remaining, const uint16_t nbits,
const uint16_t hdrmark, const uint32_t hdrspace,
Expand All @@ -230,7 +236,8 @@ class IRrecv {
const uint8_t tolerance = kUseDefTol,
const int16_t excess = kMarkExcess,
const bool MSBfirst = true);
uint16_t matchGeneric(volatile uint16_t *data_ptr, uint8_t *result_ptr,
uint16_t matchGeneric(atomic_uint16_t *data_ptr,
uint8_t *result_ptr,
const uint16_t remaining, const uint16_t nbits,
const uint16_t hdrmark, const uint32_t hdrspace,
const uint16_t onemark, const uint32_t onespace,
Expand All @@ -241,7 +248,7 @@ class IRrecv {
const uint8_t tolerance = kUseDefTol,
const int16_t excess = kMarkExcess,
const bool MSBfirst = true);
uint16_t matchGenericConstBitTime(volatile uint16_t *data_ptr,
uint16_t matchGenericConstBitTime(atomic_uint16_t *data_ptr,
uint64_t *result_ptr,
const uint16_t remaining,
const uint16_t nbits,
Expand All @@ -255,7 +262,7 @@ class IRrecv {
const uint8_t tolerance = kUseDefTol,
const int16_t excess = kMarkExcess,
const bool MSBfirst = true);
uint16_t matchManchesterData(volatile const uint16_t *data_ptr,
uint16_t matchManchesterData(atomic_const_uint16_t *data_ptr,
uint64_t *result_ptr,
const uint16_t remaining,
const uint16_t nbits,
Expand All @@ -265,7 +272,7 @@ class IRrecv {
const int16_t excess = kMarkExcess,
const bool MSBfirst = true,
const bool GEThomas = true);
uint16_t matchManchester(volatile const uint16_t *data_ptr,
uint16_t matchManchester(atomic_const_uint16_t *data_ptr,
uint64_t *result_ptr,
const uint16_t remaining,
const uint16_t nbits,
Expand Down
12 changes: 12 additions & 0 deletions src/IRremoteESP8266.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@
#include <iostream>
#include <string>
#endif // UNIT_TEST
#if __cplusplus >= 202002L
#include <atomic>
typedef std::atomic< bool > atomic_bool;
typedef volatile uint16_t atomic_uint16_t;
typedef volatile const uint16_t atomic_const_uint16_t;
typedef volatile uint32_t atomic_uint32_t;
#else
typedef volatile bool atomic_bool;
typedef volatile uint16_t atomic_uint16_t;
typedef volatile const uint16_t atomic_const_uint16_t;
typedef volatile uint32_t atomic_uint32_t;
#endif

// Library Version Information
// Major version number (X.x.x)
Expand Down
2 changes: 1 addition & 1 deletion src/IRutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1397,7 +1397,7 @@ namespace irutils {
/// issue has been found.
uint8_t lowLevelSanityCheck(void) {
const uint64_t kExpectedBitFieldResult = 0x8000012340000039ULL;
volatile uint32_t EndianTest = 0x12345678;
atomic_uint32_t EndianTest = 0x12345678;
const uint8_t kBitFieldError = 0b01;
const uint8_t kEndiannessError = 0b10;
uint8_t result = 0;
Expand Down
2 changes: 1 addition & 1 deletion test/IRrecv_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ TEST(TestIRrecv, DecodeHeapOverflow) {
IRrecv irrecv(1);
irrecv.enableIRIn();
ASSERT_EQ(kRawBuf, irrecv.getBufSize());
volatile irparams_t *params_ptr = irrecv._getParamsPtr();
atomic_irparams_t *params_ptr = irrecv._getParamsPtr();
// replace the buffer with a slightly bigger one to see if we go past the end
// accidentally.
params_ptr->rawbuf = new uint16_t[kRawBuf + 10];
Expand Down