| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701 |
- /*
- RCSwitch - Arduino libary for remote control outlet switches
- Copyright (c) 2011 Suat Özgür. All right reserved.
-
- Contributors:
- - Andre Koehler / info(at)tomate-online(dot)de
- - Gordeev Andrey Vladimirovich / gordeev(at)openpyro(dot)com
- - Skineffect / http://forum.ardumote.com/viewtopic.php?f=2&t=46
- - Dominik Fischer / dom_fischer(at)web(dot)de
- - Frank Oltmanns / <first name>.<last name>(at)gmail(dot)com
- - Andreas Steinel / A.<lastname>(at)gmail(dot)com
- - Max Horn / max(at)quendi(dot)de
- - Robert ter Vehn / <first name>.<last name>(at)gmail(dot)com
- - Johann Richard / <first name>.<last name>(at)gmail(dot)com
- - Vlad Gheorghe / <first name>.<last name>(at)gmail(dot)com https://github.com/vgheo
-
- Project home: https://github.com/sui77/rc-switch/
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
- #include "RCSwitch.h"
- #ifdef RaspberryPi
- // PROGMEM and _P functions are for AVR based microprocessors,
- // so we must normalize these for the ARM processor:
- #define PROGMEM
- #define memcpy_P(dest, src, num) memcpy((dest), (src), (num))
- #endif
- #if defined(ESP8266) || defined(ESP32)
- // interrupt handler and related code must be in RAM on ESP8266,
- // according to issue #46.
- #define RECEIVE_ATTR ICACHE_RAM_ATTR
- #else
- #define RECEIVE_ATTR
- #endif
- /* Format for protocol definitions:
- * {pulselength, Sync bit, "0" bit, "1" bit}
- *
- * pulselength: pulse length in microseconds, e.g. 350
- * Sync bit: {1, 31} means 1 high pulse and 31 low pulses
- * (perceived as a 31*pulselength long pulse, total length of sync bit is
- * 32*pulselength microseconds), i.e:
- * _
- * | |_______________________________ (don't count the vertical bars)
- * "0" bit: waveform for a data bit of value "0", {1, 3} means 1 high pulse
- * and 3 low pulses, total length (1+3)*pulselength, i.e:
- * _
- * | |___
- * "1" bit: waveform for a data bit of value "1", e.g. {3,1}:
- * ___
- * | |_
- *
- * These are combined to form Tri-State bits when sending or receiving codes.
- */
- #if defined(ESP8266) || defined(ESP32)
- static const RCSwitch::Protocol proto[] = {
- #else
- static const RCSwitch::Protocol PROGMEM proto[] = {
- #endif
- { 350, { 1, 31 }, { 1, 3 }, { 3, 1 }, false }, // protocol 1
- { 650, { 1, 10 }, { 1, 2 }, { 2, 1 }, false }, // protocol 2
- { 100, { 30, 71 }, { 4, 11 }, { 9, 6 }, false }, // protocol 3
- { 380, { 1, 6 }, { 1, 3 }, { 3, 1 }, false }, // protocol 4
- { 500, { 6, 14 }, { 1, 2 }, { 2, 1 }, false }, // protocol 5
- { 450, { 23, 1 }, { 1, 2 }, { 2, 1 }, true }, // protocol 6 (HT6P20B)
- { 150, { 2, 62 }, { 1, 6 }, { 6, 1 }, false } // protocol 7 (HS2303-PT, i. e. used in AUKEY Remote)
- };
- enum {
- numProto = sizeof(proto) / sizeof(proto[0])
- };
- #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 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() {
- this->nTransmitterPin = -1;
- this->setRepeatTransmit(10);
- this->setProtocol(1);
- #if not defined( RCSwitchDisableReceiving )
- this->nReceiverInterrupt = -1;
- this->setReceiveTolerance(60);
- RCSwitch::nReceivedValue = 0;
- #endif
- }
- /**
- * Sets the protocol to send.
- */
- void RCSwitch::setProtocol(Protocol protocol) {
- this->protocol = protocol;
- }
- /**
- * Sets the protocol to send, from a list of predefined protocols
- */
- void RCSwitch::setProtocol(int nProtocol) {
- if (nProtocol < 1 || nProtocol > numProto) {
- nProtocol = 1; // TODO: trigger an error, e.g. "bad protocol" ???
- }
- #if defined(ESP8266) || defined(ESP32)
- this->protocol = proto[nProtocol-1];
- #else
- memcpy_P(&this->protocol, &proto[nProtocol-1], sizeof(Protocol));
- #endif
- }
- /**
- * Sets the protocol to send with pulse length in microseconds.
- */
- void RCSwitch::setProtocol(int nProtocol, int nPulseLength) {
- setProtocol(nProtocol);
- this->setPulseLength(nPulseLength);
- }
- /**
- * Sets pulse length in microseconds
- */
- void RCSwitch::setPulseLength(int nPulseLength) {
- this->protocol.pulseLength = nPulseLength;
- }
- /**
- * Sets Repeat Transmits
- */
- void RCSwitch::setRepeatTransmit(int nRepeatTransmit) {
- this->nRepeatTransmit = nRepeatTransmit;
- }
- /**
- * Set Receiving Tolerance
- */
- #if not defined( RCSwitchDisableReceiving )
- void RCSwitch::setReceiveTolerance(int nPercent) {
- RCSwitch::nReceiveTolerance = nPercent;
- }
- #endif
-
- /**
- * Enable transmissions
- *
- * @param nTransmitterPin Arduino Pin to which the sender is connected to
- */
- void RCSwitch::enableTransmit(int nTransmitterPin) {
- this->nTransmitterPin = nTransmitterPin;
- pinMode(this->nTransmitterPin, OUTPUT);
- }
- /**
- * Disable transmissions
- */
- void RCSwitch::disableTransmit() {
- this->nTransmitterPin = -1;
- }
- /**
- * Switch a remote switch on (Type D REV)
- *
- * @param sGroup Code of the switch group (A,B,C,D)
- * @param nDevice Number of the switch itself (1..3)
- */
- void RCSwitch::switchOn(char sGroup, int nDevice) {
- this->sendTriState( this->getCodeWordD(sGroup, nDevice, true) );
- }
- /**
- * Switch a remote switch off (Type D REV)
- *
- * @param sGroup Code of the switch group (A,B,C,D)
- * @param nDevice Number of the switch itself (1..3)
- */
- void RCSwitch::switchOff(char sGroup, int nDevice) {
- this->sendTriState( this->getCodeWordD(sGroup, nDevice, false) );
- }
- /**
- * Switch a remote switch on (Type C Intertechno)
- *
- * @param sFamily Familycode (a..f)
- * @param nGroup Number of group (1..4)
- * @param nDevice Number of device (1..4)
- */
- void RCSwitch::switchOn(char sFamily, int nGroup, int nDevice) {
- this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, true) );
- }
- /**
- * Switch a remote switch off (Type C Intertechno)
- *
- * @param sFamily Familycode (a..f)
- * @param nGroup Number of group (1..4)
- * @param nDevice Number of device (1..4)
- */
- void RCSwitch::switchOff(char sFamily, int nGroup, int nDevice) {
- this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, false) );
- }
- /**
- * Switch a remote switch on (Type B with two rotary/sliding switches)
- *
- * @param nAddressCode Number of the switch group (1..4)
- * @param nChannelCode Number of the switch itself (1..4)
- */
- void RCSwitch::switchOn(int nAddressCode, int nChannelCode) {
- this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, true) );
- }
- /**
- * Switch a remote switch off (Type B with two rotary/sliding switches)
- *
- * @param nAddressCode Number of the switch group (1..4)
- * @param nChannelCode Number of the switch itself (1..4)
- */
- void RCSwitch::switchOff(int nAddressCode, int nChannelCode) {
- this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, false) );
- }
- /**
- * Deprecated, use switchOn(const char* sGroup, const char* sDevice) instead!
- * Switch a remote switch on (Type A with 10 pole DIP switches)
- *
- * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
- * @param nChannelCode Number of the switch itself (1..5)
- */
- void RCSwitch::switchOn(const char* sGroup, int nChannel) {
- const char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" };
- this->switchOn(sGroup, code[nChannel]);
- }
- /**
- * Deprecated, use switchOff(const char* sGroup, const char* sDevice) instead!
- * Switch a remote switch off (Type A with 10 pole DIP switches)
- *
- * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
- * @param nChannelCode Number of the switch itself (1..5)
- */
- void RCSwitch::switchOff(const char* sGroup, int nChannel) {
- const char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" };
- this->switchOff(sGroup, code[nChannel]);
- }
- /**
- * Switch a remote switch on (Type A with 10 pole DIP switches)
- *
- * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
- * @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111")
- */
- void RCSwitch::switchOn(const char* sGroup, const char* sDevice) {
- this->sendTriState( this->getCodeWordA(sGroup, sDevice, true) );
- }
- /**
- * Switch a remote switch off (Type A with 10 pole DIP switches)
- *
- * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111")
- * @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111")
- */
- void RCSwitch::switchOff(const char* sGroup, const char* sDevice) {
- this->sendTriState( this->getCodeWordA(sGroup, sDevice, false) );
- }
- /**
- * Returns a char[13], representing the code word to be send.
- *
- */
- char* RCSwitch::getCodeWordA(const char* sGroup, const char* sDevice, bool bStatus) {
- static char sReturn[13];
- int nReturnPos = 0;
- for (int i = 0; i < 5; i++) {
- sReturn[nReturnPos++] = (sGroup[i] == '0') ? 'F' : '0';
- }
- for (int i = 0; i < 5; i++) {
- sReturn[nReturnPos++] = (sDevice[i] == '0') ? 'F' : '0';
- }
- sReturn[nReturnPos++] = bStatus ? '0' : 'F';
- sReturn[nReturnPos++] = bStatus ? 'F' : '0';
- sReturn[nReturnPos] = '\0';
- return sReturn;
- }
- /**
- * Encoding for type B switches with two rotary/sliding switches.
- *
- * The code word is a tristate word and with following bit pattern:
- *
- * +-----------------------------+-----------------------------+----------+------------+
- * | 4 bits address | 4 bits address | 3 bits | 1 bit |
- * | switch group | switch number | not used | on / off |
- * | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | FFF | on=F off=0 |
- * +-----------------------------+-----------------------------+----------+------------+
- *
- * @param nAddressCode Number of the switch group (1..4)
- * @param nChannelCode Number of the switch itself (1..4)
- * @param bStatus Whether to switch on (true) or off (false)
- *
- * @return char[13], representing a tristate code word of length 12
- */
- char* RCSwitch::getCodeWordB(int nAddressCode, int nChannelCode, bool bStatus) {
- static char sReturn[13];
- int nReturnPos = 0;
- if (nAddressCode < 1 || nAddressCode > 4 || nChannelCode < 1 || nChannelCode > 4) {
- return 0;
- }
- for (int i = 1; i <= 4; i++) {
- sReturn[nReturnPos++] = (nAddressCode == i) ? '0' : 'F';
- }
- for (int i = 1; i <= 4; i++) {
- sReturn[nReturnPos++] = (nChannelCode == i) ? '0' : 'F';
- }
- sReturn[nReturnPos++] = 'F';
- sReturn[nReturnPos++] = 'F';
- sReturn[nReturnPos++] = 'F';
- sReturn[nReturnPos++] = bStatus ? 'F' : '0';
- sReturn[nReturnPos] = '\0';
- return sReturn;
- }
- /**
- * Like getCodeWord (Type C = Intertechno)
- */
- char* RCSwitch::getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus) {
- static char sReturn[13];
- int nReturnPos = 0;
- int nFamily = (int)sFamily - 'a';
- if ( nFamily < 0 || nFamily > 15 || nGroup < 1 || nGroup > 4 || nDevice < 1 || nDevice > 4) {
- return 0;
- }
-
- // encode the family into four bits
- sReturn[nReturnPos++] = (nFamily & 1) ? 'F' : '0';
- sReturn[nReturnPos++] = (nFamily & 2) ? 'F' : '0';
- sReturn[nReturnPos++] = (nFamily & 4) ? 'F' : '0';
- sReturn[nReturnPos++] = (nFamily & 8) ? 'F' : '0';
- // encode the device and group
- sReturn[nReturnPos++] = ((nDevice-1) & 1) ? 'F' : '0';
- sReturn[nReturnPos++] = ((nDevice-1) & 2) ? 'F' : '0';
- sReturn[nReturnPos++] = ((nGroup-1) & 1) ? 'F' : '0';
- sReturn[nReturnPos++] = ((nGroup-1) & 2) ? 'F' : '0';
- // encode the status code
- sReturn[nReturnPos++] = '0';
- sReturn[nReturnPos++] = 'F';
- sReturn[nReturnPos++] = 'F';
- sReturn[nReturnPos++] = bStatus ? 'F' : '0';
- sReturn[nReturnPos] = '\0';
- return sReturn;
- }
- /**
- * Encoding for the REV Switch Type
- *
- * The code word is a tristate word and with following bit pattern:
- *
- * +-----------------------------+-------------------+----------+--------------+
- * | 4 bits address | 3 bits address | 3 bits | 2 bits |
- * | switch group | device number | not used | on / off |
- * | A=1FFF B=F1FF C=FF1F D=FFF1 | 1=0FF 2=F0F 3=FF0 | 000 | on=10 off=01 |
- * +-----------------------------+-------------------+----------+--------------+
- *
- * Source: http://www.the-intruder.net/funksteckdosen-von-rev-uber-arduino-ansteuern/
- *
- * @param sGroup Name of the switch group (A..D, resp. a..d)
- * @param nDevice Number of the switch itself (1..3)
- * @param bStatus Whether to switch on (true) or off (false)
- *
- * @return char[13], representing a tristate code word of length 12
- */
- char* RCSwitch::getCodeWordD(char sGroup, int nDevice, bool bStatus) {
- static char sReturn[13];
- int nReturnPos = 0;
- // sGroup must be one of the letters in "abcdABCD"
- int nGroup = (sGroup >= 'a') ? (int)sGroup - 'a' : (int)sGroup - 'A';
- if ( nGroup < 0 || nGroup > 3 || nDevice < 1 || nDevice > 3) {
- return 0;
- }
- for (int i = 0; i < 4; i++) {
- sReturn[nReturnPos++] = (nGroup == i) ? '1' : 'F';
- }
- for (int i = 1; i <= 3; i++) {
- sReturn[nReturnPos++] = (nDevice == i) ? '1' : 'F';
- }
- sReturn[nReturnPos++] = '0';
- sReturn[nReturnPos++] = '0';
- sReturn[nReturnPos++] = '0';
- sReturn[nReturnPos++] = bStatus ? '1' : '0';
- sReturn[nReturnPos++] = bStatus ? '0' : '1';
- sReturn[nReturnPos] = '\0';
- return sReturn;
- }
- /**
- * @param sCodeWord a tristate code word consisting of the letter 0, 1, F
- */
- void RCSwitch::sendTriState(const char* sCodeWord) {
- // turn the tristate code word into the corresponding bit pattern, then send it
- unsigned long code = 0;
- unsigned int length = 0;
- for (const char* p = sCodeWord; *p; p++) {
- code <<= 2L;
- switch (*p) {
- case '0':
- // bit pattern 00
- break;
- case 'F':
- // bit pattern 01
- code |= 1L;
- break;
- case '1':
- // bit pattern 11
- code |= 3L;
- break;
- }
- length += 2;
- }
- this->send(code, length);
- }
- /**
- * @param sCodeWord a binary code word consisting of the letter 0, 1
- */
- void RCSwitch::send(const char* sCodeWord) {
- // turn the tristate code word into the corresponding bit pattern, then send it
- unsigned long code = 0;
- unsigned int length = 0;
- for (const char* p = sCodeWord; *p; p++) {
- code <<= 1L;
- if (*p != '0')
- code |= 1L;
- length++;
- }
- this->send(code, length);
- }
- /**
- * Transmit the first 'length' bits of the integer 'code'. The
- * bits are sent from MSB to LSB, i.e., first the bit at position length-1,
- * then the bit at position length-2, and so on, till finally the bit at position 0.
- */
- void RCSwitch::send(unsigned long code, unsigned int length) {
- if (this->nTransmitterPin == -1)
- return;
- #if not defined( RCSwitchDisableReceiving )
- // make sure the receiver is disabled while we transmit
- int nReceiverInterrupt_backup = nReceiverInterrupt;
- if (nReceiverInterrupt_backup != -1) {
- this->disableReceive();
- }
- #endif
- for (int nRepeat = 0; nRepeat < nRepeatTransmit; nRepeat++) {
- for (int i = length-1; i >= 0; i--) {
- if (code & (1L << i))
- this->transmit(protocol.one);
- else
- this->transmit(protocol.zero);
- }
- this->transmit(protocol.syncFactor);
- }
- // Disable transmit after sending (i.e., for inverted protocols)
- digitalWrite(this->nTransmitterPin, LOW);
- #if not defined( RCSwitchDisableReceiving )
- // enable receiver again if we just disabled it
- if (nReceiverInterrupt_backup != -1) {
- this->enableReceive(nReceiverInterrupt_backup);
- }
- #endif
- }
- /**
- * Transmit a single high-low pulse.
- */
- void RCSwitch::transmit(HighLow pulses) {
- uint8_t firstLogicLevel = (this->protocol.invertedSignal) ? LOW : HIGH;
- uint8_t secondLogicLevel = (this->protocol.invertedSignal) ? HIGH : LOW;
-
- digitalWrite(this->nTransmitterPin, firstLogicLevel);
- delayMicroseconds( this->protocol.pulseLength * pulses.high);
- digitalWrite(this->nTransmitterPin, secondLogicLevel);
- delayMicroseconds( this->protocol.pulseLength * pulses.low);
- }
- #if not defined( RCSwitchDisableReceiving )
- /**
- * Enable receiving data
- */
- void RCSwitch::enableReceive(int interrupt) {
- this->nReceiverInterrupt = interrupt;
- this->enableReceive();
- }
- void RCSwitch::enableReceive() {
- if (this->nReceiverInterrupt != -1) {
- RCSwitch::nReceivedValue = 0;
- RCSwitch::nReceivedBitlength = 0;
- #if defined(RaspberryPi) // Raspberry Pi
- wiringPiISR(this->nReceiverInterrupt, INT_EDGE_BOTH, &handleInterrupt);
- #else // Arduino
- attachInterrupt(this->nReceiverInterrupt, handleInterrupt, CHANGE);
- #endif
- }
- }
- /**
- * Disable receiving data
- */
- void RCSwitch::disableReceive() {
- #if not defined(RaspberryPi) // Arduino
- detachInterrupt(this->nReceiverInterrupt);
- #endif // For Raspberry Pi (wiringPi) you can't unregister the ISR
- this->nReceiverInterrupt = -1;
- }
- bool RCSwitch::available() {
- return RCSwitch::nReceivedValue != 0;
- }
- void RCSwitch::resetAvailable() {
- RCSwitch::nReceivedValue = 0;
- }
- unsigned long RCSwitch::getReceivedValue() {
- return RCSwitch::nReceivedValue;
- }
- unsigned int RCSwitch::getReceivedBitlength() {
- return RCSwitch::nReceivedBitlength;
- }
- unsigned int RCSwitch::getReceivedDelay() {
- return RCSwitch::nReceivedDelay;
- }
- unsigned int RCSwitch::getReceivedProtocol() {
- return RCSwitch::nReceivedProtocol;
- }
- unsigned int* RCSwitch::getReceivedRawdata() {
- return RCSwitch::timings;
- }
- /* helper function for the receiveProtocol method */
- static inline unsigned int diff(int A, int B) {
- return abs(A - B);
- }
- /**
- *
- */
- bool RECEIVE_ATTR RCSwitch::receiveProtocol(const int p, unsigned int changeCount) {
- #if defined(ESP8266) || defined(ESP32)
- const Protocol &pro = proto[p-1];
- #else
- Protocol pro;
- memcpy_P(&pro, &proto[p-1], sizeof(Protocol));
- #endif
- 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;
-
- /* For protocols that start low, the sync period looks like
- * _________
- * _____________| |XXXXXXXXXXXX|
- *
- * |--1st dur--|-2nd dur-|-Start data-|
- *
- * The 3rd saved duration starts the data.
- *
- * For protocols that start high, the sync period looks like
- *
- * ______________
- * | |____________|XXXXXXXXXXXXX|
- *
- * |-filtered out-|--1st dur--|--Start data--|
- *
- * The 2nd saved duration starts the data
- */
- const unsigned int firstDataTiming = (pro.invertedSignal) ? (2) : (1);
- 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) {
- // zero
- } else if (diff(RCSwitch::timings[i], delay * pro.one.high) < delayTolerance &&
- diff(RCSwitch::timings[i + 1], delay * pro.one.low) < delayTolerance) {
- // one
- code |= 1;
- } else {
- // Failed
- return false;
- }
- }
- 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;
- }
- void RECEIVE_ATTR RCSwitch::handleInterrupt() {
- static unsigned int changeCount = 0;
- static unsigned long lastTime = 0;
- static unsigned int repeatCount = 0;
- 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 (diff(duration, RCSwitch::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) {
- for(unsigned int i = 1; i <= numProto; i++) {
- if (receiveProtocol(i, changeCount)) {
- // receive succeeded for protocol i
- break;
- }
- }
- repeatCount = 0;
- }
- }
- changeCount = 0;
- }
-
- // detect overflow
- if (changeCount >= RCSWITCH_MAX_CHANGES) {
- changeCount = 0;
- repeatCount = 0;
- }
- RCSwitch::timings[changeCount++] = duration;
- lastTime = time;
- }
- #endif
|