Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
129 changes: 87 additions & 42 deletions RCSwitch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@

#include "RCSwitch.h"

#if (defined(ARDUINO_ARCH_RP2040) || defined(STM32_CORE_VERSION))
#include <functional>
#endif

#ifdef RaspberryPi
// PROGMEM and _P functions are for AVR based microprocessors,
// so we must normalize these for the ARM processor:
Expand Down Expand Up @@ -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;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't find where nReceiveTolerance is set on the new version, do I miss something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,
yes it's part of the class and in RCSwitch.h file

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() {
Expand All @@ -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
}

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
}
}
Expand All @@ -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 */
Expand All @@ -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
* _________
Expand All @@ -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 {
Expand All @@ -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<RCSwitch*>(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
Expand All @@ -706,7 +749,9 @@ void RECEIVE_ATTR RCSwitch::handleInterrupt() {
repeatCount = 0;
}

RCSwitch::timings[changeCount++] = duration;
timings[changeCount++] = duration;
lastTime = time;
}
#endif

#endif
26 changes: 18 additions & 8 deletions RCSwitch.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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


Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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)
Expand Down