Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrote library to allow for multiple RX pins #2

wants to merge 3 commits into
base: master


None yet
3 participants
Copy link

commented Jul 7, 2016

WARNING: This breaks the current API (although a fix is simple enough).

Rewrote example (ReceiveDemo_Advanced.ino) to use the new API.
The number of RX pins must be defined at compile-time with #define RCSWITCH_MAX_RX_PINS.

Root cause

Previously, if multiple pins were enabled at once (with enableReceive(int interrupt)), the interrupt handler for decoding signals was attached to both(/all) pins. But because interrupts must interface with the main program solely through global/static variables, and have no other information (e.g. callbacks), there is no way for the interrupt handler to know what pin actually triggered the interrupt. Therefore, when multiple pins were naïvely attached, noise from each pin--which would normally be filtered out--would be present, making it impossible to work with the data.

There is the additional issue that the version of RCSwitch that Particle uses (repo here) is very out-of-date, which causes a few extra problems. The implementation of many functions is different from those in the official version, there is missing support for many protocols, and the API is slightly different. For the official RCSwitch library, there have been attempts in the past to implement multiple-pin RX (see here and here), but none have been successful. I have opened an issue detailing the changes needed to get multiple-pin RX actually working, but due to how behind the Particle library is, patching it into the official library is non-trivial (will either require porting or updating Particle's library to match the current official repo).


To address this issue, the simplest solution is to separate the global/static data used in the interrupt handler into different sets per RX pin (create an array), and size it based off a #defined variable. (e.g. #define RCSWITCH_MAX_RX_PINS 2). This use of a macro #define is acceptable because the number of RX pins needed is something that changes infrequently and is well-known to the developer, and also because this library is intended as performant embedded code (e.g. for MCUs like the ATtiny).

I refactored all the data used in the interrupt handler into a struct (RCSwitch::InterruptData). The static variables are then replaced with an array of these, one per RX pin (RCSwitch::receiverInterrupts[RCSWITCH_MAX_RX_PINS]). All of the code was simply extended to handle the array, and in most cases an additional parameter was added to specify which interrupt pin was intended. There is the issue of identifying each element of the array: I included a RCSwitch::InterruptData.interrupt member in the struct for this purpose. (std::map would be more straightforward but it is a lot of overhead.) There are also convenience functions which convert from array index to interrupt pin, and these functions should be inverses of the process since each pin can only be used for a single interrupt. (To actually perform the conversion, the array is simply searched for a matching interrupt pin. This is acceptable because RCSWITCH_MAX_RX_PINS should be small, and this search should have a negligible performance impact.) Another thing to note: functions might take arguments dealing with array index or interrupt pin, and these different arguments are differentiated with int interrupt_i and int interrupt, respectively. (Most of the functions taking int interrupt_i should be private.)

I also added an additional member, int nInterruptSourcePin, which is updated with the last RX pin to go high. This can be used to fetch which pin triggered the interrupt. In the interrupt handler itself, the data (in the RCSwitch::InterruptData array) is tracked separately for each pin, with a new isPinPrevHigh member in the data struct. This ensures that the correct member of RCSwitch::receiverInterrupts is updated by the handler.

Rewrote library to allow for multiple RX pins
WARNING: This breaks the current API (although a fix is simple enough).

Rewrote example (`ReceiveDemo_Advanced.ino`) to use the new API.
The number of RX pins must be defined at compile-time with #define

This comment has been minimized.

Copy link

commented Jul 7, 2016

I can add functions which will fix the API if you would like.


This comment has been minimized.

Copy link

commented Jul 24, 2016

Hi Ernest! Sorry for very long response time! I will test it out tomorrow and let you know if everything works as expected!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.