diff --git a/RCSwitch.cpp b/RCSwitch.cpp index 99d3cc1..dbf0fc3 100644 --- a/RCSwitch.cpp +++ b/RCSwitch.cpp @@ -34,6 +34,10 @@ #include "RCSwitch.h" +#if (defined(ARDUINO_ARCH_RP2040) || defined(STM32_CORE_VERSION)) +#include +#endif + #ifdef RaspberryPi // PROGMEM and _P functions are for AVR based microprocessors, // so we must normalize these for the ARM processor: @@ -98,16 +102,12 @@ enum { }; #if not defined( RCSwitchDisableReceiving ) -volatile unsigned long RCSwitch::nReceivedValue = 0; -volatile unsigned int RCSwitch::nReceivedBitlength = 0; -volatile unsigned int RCSwitch::nReceivedDelay = 0; -volatile unsigned int RCSwitch::nReceivedProtocol = 0; -int RCSwitch::nReceiveTolerance = 60; -const unsigned int VAR_ISR_ATTR RCSwitch::nSeparationLimit = 4300; + +const unsigned int RCSwitch::nSeparationLimit = 4300; + // separationLimit: minimum microseconds between received codes, closer codes are ignored. // according to discussion on issue #14 it might be more suitable to set the separation // limit to the same time as the 'low' part of the sync signal for the current protocol. -unsigned int RCSwitch::timings[RCSWITCH_MAX_CHANGES]; #endif RCSwitch::RCSwitch() { @@ -117,7 +117,10 @@ RCSwitch::RCSwitch() { #if not defined( RCSwitchDisableReceiving ) this->nReceiverInterrupt = -1; this->setReceiveTolerance(60); - RCSwitch::nReceivedValue = 0; + this->nReceivedValue = 0; + this->nReceivedBitlength = 0; + this->nReceivedDelay = 0; + this->nReceivedProtocol = 0; #endif } @@ -170,7 +173,7 @@ void RCSwitch::setRepeatTransmit(int nRepeatTransmit) { */ #if not defined( RCSwitchDisableReceiving ) void RCSwitch::setReceiveTolerance(int nPercent) { - RCSwitch::nReceiveTolerance = nPercent; + this->nReceiveTolerance = nPercent; } #endif @@ -553,12 +556,18 @@ void RCSwitch::enableReceive(int interrupt) { void RCSwitch::enableReceive() { if (this->nReceiverInterrupt != -1) { - RCSwitch::nReceivedValue = 0; - RCSwitch::nReceivedBitlength = 0; + this->nReceivedValue = 0; + this->nReceivedBitlength = 0; #if defined(RaspberryPi) // Raspberry Pi wiringPiISR(this->nReceiverInterrupt, INT_EDGE_BOTH, &handleInterrupt); -#else // Arduino - attachInterrupt(this->nReceiverInterrupt, handleInterrupt, CHANGE); +#elif defined(ARDUINO_ARCH_RP2040) + attachInterruptParam(this->nReceiverInterrupt, &RCSwitch::handleInterrupt, CHANGE, this); +#elif defined(STM32_CORE_VERSION) + attachInterrupt(this->nReceiverInterrupt, std::bind(&RCSwitch::handleInterrupt, this), CHANGE); +#else // Arduino + attachInterrupt(this->nReceiverInterrupt, &RCSwitch::handleInterrupt, CHANGE); + //attachInterrupt(this->nReceiverInterrupt, handleInterrupt, CHANGE); + //#error not supported #endif } } @@ -574,31 +583,31 @@ void RCSwitch::disableReceive() { } bool RCSwitch::available() { - return RCSwitch::nReceivedValue != 0; + return this->nReceivedValue != 0; } void RCSwitch::resetAvailable() { - RCSwitch::nReceivedValue = 0; + this->nReceivedValue = 0; } unsigned long RCSwitch::getReceivedValue() { - return RCSwitch::nReceivedValue; + return this->nReceivedValue; } unsigned int RCSwitch::getReceivedBitlength() { - return RCSwitch::nReceivedBitlength; + return this->nReceivedBitlength; } unsigned int RCSwitch::getReceivedDelay() { - return RCSwitch::nReceivedDelay; + return this->nReceivedDelay; } unsigned int RCSwitch::getReceivedProtocol() { - return RCSwitch::nReceivedProtocol; + return this->nReceivedProtocol; } unsigned int* RCSwitch::getReceivedRawdata() { - return RCSwitch::timings; + return this->timings; } /* helper function for the receiveProtocol method */ @@ -620,8 +629,8 @@ bool RECEIVE_ATTR RCSwitch::receiveProtocol(const int p, unsigned int changeCoun unsigned long code = 0; //Assuming the longer pulse length is the pulse captured in timings[0] const unsigned int syncLengthInPulses = ((pro.syncFactor.low) > (pro.syncFactor.high)) ? (pro.syncFactor.low) : (pro.syncFactor.high); - const unsigned int delay = RCSwitch::timings[0] / syncLengthInPulses; - const unsigned int delayTolerance = delay * RCSwitch::nReceiveTolerance / 100; + const unsigned int delay = this->timings[0] / syncLengthInPulses; + const unsigned int delayTolerance = delay * this->nReceiveTolerance / 100; /* For protocols that start low, the sync period looks like * _________ @@ -644,11 +653,11 @@ bool RECEIVE_ATTR RCSwitch::receiveProtocol(const int p, unsigned int changeCoun for (unsigned int i = firstDataTiming; i < changeCount - 1; i += 2) { code <<= 1; - if (diff(RCSwitch::timings[i], delay * pro.zero.high) < delayTolerance && - diff(RCSwitch::timings[i + 1], delay * pro.zero.low) < delayTolerance) { + if (diff(this->timings[i], delay * pro.zero.high) < delayTolerance && + diff(this->timings[i + 1], delay * pro.zero.low) < delayTolerance) { // zero - } else if (diff(RCSwitch::timings[i], delay * pro.one.high) < delayTolerance && - diff(RCSwitch::timings[i + 1], delay * pro.one.low) < delayTolerance) { + } else if (diff(this->timings[i], delay * pro.one.high) < delayTolerance && + diff(this->timings[i + 1], delay * pro.one.low) < delayTolerance) { // one code |= 1; } else { @@ -657,37 +666,71 @@ bool RECEIVE_ATTR RCSwitch::receiveProtocol(const int p, unsigned int changeCoun } } - if (changeCount > 7) { // ignore very short transmissions: no device sends them, so this must be noise - RCSwitch::nReceivedValue = code; - RCSwitch::nReceivedBitlength = (changeCount - 1) / 2; - RCSwitch::nReceivedDelay = delay; - RCSwitch::nReceivedProtocol = p; - return true; - } - return false; + this->nReceivedValue = code; + this->nReceivedBitlength = (changeCount - 1) / 2; + this->nReceivedDelay = delay; + this->nReceivedProtocol = p; + return true; + } -void RECEIVE_ATTR RCSwitch::handleInterrupt() { +#if defined(ARDUINO_ARCH_RP2040) +void RCSwitch::handleInterrupt(void* obj) +{ + RCSwitch* thiz = static_cast(obj); + const long time = micros(); + const unsigned int duration = time - thiz->lastTime; + + if (duration > RCSwitch::nSeparationLimit) { + // A long stretch without signal level change occurred. This could + // be the gap between two transmission. + if ((thiz->repeatCount==0) || (diff(duration, thiz->timings[0]) < 200)) { + // This long signal is close in length to the long signal which + // started the previously recorded timings; this suggests that + // it may indeed by a a gap between two transmissions (we assume + // here that a sender will send the signal multiple times, + // with roughly the same gap between them). + thiz->repeatCount++; + if (thiz->repeatCount == 2 && thiz->changeCount > 7) { // ignore very short transmissions: no device sends them, so this must be noise) + for(unsigned int i = 1; i <= numProto; i++) { + if (thiz->receiveProtocol(i, thiz->changeCount)) { + // receive succeeded for protocol i + break; + } + } + thiz->repeatCount = 0; + } + } + thiz->changeCount = 0; + } + + // detect overflow + if (thiz->changeCount >= RCSWITCH_MAX_CHANGES) { + thiz->changeCount = 0; + thiz->repeatCount = 0; + } - static unsigned int changeCount = 0; - static unsigned long lastTime = 0; - static unsigned int repeatCount = 0; + thiz->timings[thiz->changeCount++] = duration; + thiz->lastTime = time; +} +#else +void RECEIVE_ATTR RCSwitch::handleInterrupt() { const long time = micros(); const unsigned int duration = time - lastTime; - + if (duration > RCSwitch::nSeparationLimit) { // A long stretch without signal level change occurred. This could // be the gap between two transmission. - if ((repeatCount==0) || (diff(duration, RCSwitch::timings[0]) < 200)) { + if ((repeatCount==0) || (diff(duration, timings[0]) < 200)) { // This long signal is close in length to the long signal which // started the previously recorded timings; this suggests that // it may indeed by a a gap between two transmissions (we assume // here that a sender will send the signal multiple times, // with roughly the same gap between them). repeatCount++; - if (repeatCount == 2) { + if (repeatCount == 2 && changeCount > 7) { // ignore very short transmissions: no device sends them, so this must be noise) for(unsigned int i = 1; i <= numProto; i++) { if (receiveProtocol(i, changeCount)) { // receive succeeded for protocol i @@ -706,7 +749,9 @@ void RECEIVE_ATTR RCSwitch::handleInterrupt() { repeatCount = 0; } - RCSwitch::timings[changeCount++] = duration; + timings[changeCount++] = duration; lastTime = time; } #endif + +#endif diff --git a/RCSwitch.h b/RCSwitch.h index b7755e0..9821488 100644 --- a/RCSwitch.h +++ b/RCSwitch.h @@ -156,8 +156,12 @@ class RCSwitch { void transmit(HighLow pulses); #if not defined( RCSwitchDisableReceiving ) - static void handleInterrupt(); - static bool receiveProtocol(const int p, unsigned int changeCount); + #if defined(ARDUINO_ARCH_RP2040) + static void handleInterrupt(void*); + #else + void handleInterrupt(); + #endif + bool receiveProtocol(const int p, unsigned int changeCount); int nReceiverInterrupt; #endif int nTransmitterPin; @@ -166,16 +170,22 @@ class RCSwitch { Protocol protocol; #if not defined( RCSwitchDisableReceiving ) - static int nReceiveTolerance; - volatile static unsigned long nReceivedValue; - volatile static unsigned int nReceivedBitlength; - volatile static unsigned int nReceivedDelay; - volatile static unsigned int nReceivedProtocol; + int nReceiveTolerance; + volatile unsigned long nReceivedValue; + volatile unsigned int nReceivedBitlength; + volatile unsigned int nReceivedDelay; + volatile unsigned int nReceivedProtocol; const static unsigned int nSeparationLimit; + /* + * Required values for interrupt handler + */ + unsigned int changeCount = 0; + unsigned long lastTime = 0; + unsigned int repeatCount = 0; /* * timings[0] contains sync timing, followed by a number of bits */ - static unsigned int timings[RCSWITCH_MAX_CHANGES]; + unsigned int timings[RCSWITCH_MAX_CHANGES]; #endif diff --git a/README.md b/README.md index f6a679c..fd110f5 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,17 @@ +#This library compiles for STM32 and RP2040 but not Arduino AVR like Nano +to add support one has to figure out how to pass a non-static class member with `this` object to the attachInterupt +function. +other repos for future reference +https://github.com/maniacbug/StandardCplusplus +https://github.com/kekyo/BoostForArduino +https://github.com/vancegroup/arduino-boost +https://github.com/Stivius/callable-wrapper +https://github.com/fopeczek/function_objects +https://github.com/danyhm/functional +I could get std::bind to work on Arduino Nano however I can't convert it back to c style function pointer. +It seems it's possible to do it using boost library. however i couldn't get it to compile on Arduino. +another method is to change Arduino Core files to implement attachInterruptEx or attachInterruptParam + # rc-switch [![arduino-library-badge](https://www.ardu-badge.com/badge/rc-switch.svg?)](https://www.ardu-badge.com/rc-switch) [![Build Status](https://travis-ci.org/sui77/rc-switch.svg?branch=master)](https://travis-ci.org/sui77/rc-switch)