diff --git a/.gitignore b/.gitignore index d0972bb..e85efba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Platformio stuff +.pio + # Mac stuff .DS_Store diff --git a/RCSwitch.cpp b/RCSwitch.cpp index 99d3cc1..05d2a83 100644 --- a/RCSwitch.cpp +++ b/RCSwitch.cpp @@ -1,7 +1,7 @@ /* 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 @@ -13,8 +13,7 @@ - Robert ter Vehn / .(at)gmail(dot)com - Johann Richard / .(at)gmail(dot)com - Vlad Gheorghe / .(at)gmail(dot)com https://github.com/vgheo - - Matias Cuenca-Acuna - + Project home: https://github.com/sui77/rc-switch/ This library is free software; you can redistribute it and/or @@ -55,42 +54,105 @@ #endif -/* Format for protocol definitions: - * {pulselength, Sync bit, "0" bit, "1" bit, invertedSignal} - * - * 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: +/* Protocol description format + * + * { + * Pulse length, + * + * PreambleFactor, + * Preamble {high,low}, + * + * HeaderFactor, + * Header {high,low}, + * + * "0" bit {high,low}, + * "1" bit {high,low}, + * + * Inverted Signal, + * Guard time + * } + * + * Pulse length: pulse duration (Te) in microseconds, + * for example 350 + * PreambleFactor: Number of high and low states to send + * (One pulse = 2 states, in orther words, number of pulses is + * ceil(PreambleFactor/2).) + * Preamble: Pulse shape which defines a preamble bit. + * Sent ceil(PreambleFactor/2) times. + * For example, {1, 2} with factor 3 would send + * _ _ + * | |__| |__ (each horizontal bar has a duration of Te, + * vertical bars are ignored) + * HeaderFactor: Number of times to send the header pulse. + * Header: Pulse shape which defines a header (or "sync"/"clock") pulse. + * {1, 31} means one pulse of duration 1 Te high and 31 Te low * _ * | |_______________________________ (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: + * + * "0" bit: pulse shape defining a data bit, which is a logical "0" + * {1, 3} means 1 pulse duration Te high level and 3 low * _ * | |___ - * "1" bit: waveform for a data bit of value "1", e.g. {3,1}: + * + * "1" bit: pulse shape that defines the data bit, which is a logical "1" + * {3, 1} means 3 pulses with a duration of Te high level and 1 low * ___ * | |_ * - * These are combined to form Tri-State bits when sending or receiving codes. + * (note: to form the state bit Z (Tri-State bit), two codes are combined) + * + * Inverted Signal: Signal inversion - if true the signal is inverted + * replacing high to low in a transmitted / received packet + * Guard time: Separation time between two retries. It will be followed by the + * next preamble of the next packet. In number of Te. + * e.g. 39 pulses of duration Te low level */ + #if defined(ESP8266) || defined(ESP32) static const VAR_ISR_ATTR 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) - { 200, { 3, 130}, { 7, 16 }, { 3, 16}, false}, // protocol 8 Conrad RS-200 RX - { 200, { 130, 7 }, { 16, 7 }, { 16, 3 }, true}, // protocol 9 Conrad RS-200 TX - { 365, { 18, 1 }, { 3, 1 }, { 1, 3 }, true }, // protocol 10 (1ByOne Doorbell) - { 270, { 36, 1 }, { 1, 2 }, { 2, 1 }, true }, // protocol 11 (HT12E) - { 320, { 36, 1 }, { 1, 2 }, { 2, 1 }, true } // protocol 12 (SM5212) + { 350, 0, { 0, 0 }, 1, { 1, 31 }, { 1, 3 }, { 3, 1 }, false, 0 }, // 01 (Princeton, PT-2240) + { 650, 0, { 0, 0 }, 1, { 1, 10 }, { 1, 2 }, { 2, 1 }, false, 0 }, // 02 + { 100, 0, { 0, 0 }, 1, { 30, 71 }, { 4, 11 }, { 9, 6 }, false, 0 }, // 03 + { 380, 0, { 0, 0 }, 1, { 1, 6 }, { 1, 3 }, { 3, 1 }, false, 0 }, // 04 + { 500, 0, { 0, 0 }, 1, { 6, 14 }, { 1, 2 }, { 2, 1 }, false, 0 }, // 05 + { 450, 0, { 0, 0 }, 1, { 23, 1 }, { 1, 2 }, { 2, 1 }, true, 0 }, // 06 (HT6P20B) + { 150, 0, { 0, 0 }, 1, { 2, 62 }, { 1, 6 }, { 6, 1 }, false, 0 }, // 07 (HS2303-PT, i. e. used in AUKEY Remote) + { 320, 0, { 0, 0 }, 1, { 36, 1 }, { 1, 2 }, { 2, 1 }, true, 0 }, // 08 (Came 12bit, HT12E) + { 700, 0, { 0, 0 }, 1, { 32, 1 }, { 1, 2 }, { 2, 1 }, true, 0 }, // 09 (Nice_Flo 12bit) + { 420, 0, { 0, 0 }, 1, { 60, 6 }, { 1, 2 }, { 2, 1 }, true, 0 }, // 10 (V2 phoenix) + { 500, 2, { 3, 3 }, 0, { 0, 0 }, { 1, 2 }, { 2, 1 }, false, 37 }, // 11 (Nice_FloR-S 52bit) + { 400, 23, { 1, 1 }, 1, { 0, 9 }, { 2, 1 }, { 1, 2 }, false, 39 }, // 12 Placeholder not working! (Keeloq 64/66) + { 300, 6, { 2, 2 }, 3, { 8, 3 }, { 2, 2 }, { 3, 3 }, false, 0 }, // 13 test (CFM) + { 250, 12, { 4, 4 }, 0, { 0, 0 }, { 1, 1 }, { 2, 2 }, false, 0 }, // 14 test (StarLine) + { 500, 0, { 0, 0 }, 0, { 100, 1 }, { 1, 2 }, { 2, 1 }, false, 35 }, // 15 + + { 361, 0, { 0, 0 }, 1, { 52, 1 }, { 1, 3 }, { 3, 1 }, true, 0 }, // 16 (Einhell) + { 500, 0, { 0, 0 }, 1, { 1, 23 }, { 1, 2 }, { 2, 1 }, false, 0 }, // 17 (InterTechno PAR-1000) + { 180, 0, { 0, 0 }, 1, { 1, 15 }, { 1, 1 }, { 1, 8 }, false, 0 }, // 18 (Intertechno ITT-1500) + { 350, 0, { 0, 0 }, 1, { 1, 2 }, { 0, 2 }, { 3, 2 }, false, 0 }, // 19 (Murcury) + { 150, 0, { 0, 0 }, 1, { 34, 3 }, { 1, 3 }, { 3, 1 }, false, 0 }, // 20 (AC114) + { 360, 0, { 0, 0 }, 1, { 13, 4 }, { 1, 2 }, { 2, 1 }, false, 0 }, // 21 (DC250) + { 650, 0, { 0, 0 }, 1, { 1, 10 }, { 1, 2 }, { 2, 1 }, true, 0 }, // 22 (Mandolyn/Lidl TR-502MSV/RC-402/RC-402DX) + { 641, 0, { 0, 0 }, 1, { 115, 1 }, { 1, 2 }, { 2, 1 }, true, 0 }, // 23 (Lidl TR-502MSV/RC-402 - Flavien) + { 620, 0, { 0, 0 }, 1, { 0, 64 }, { 0, 1 }, { 1, 0 }, false, 0 }, // 24 (Lidl TR-502MSV/RC701) + { 560, 0, { 0, 0 }, 1, { 16, 8 }, { 1, 1 }, { 1, 3 }, false, 0 }, // 25 (NEC) + { 385, 0, { 0, 0 }, 1, { 1, 17 }, { 1, 2 }, { 2, 1 }, false, 0 }, // 26 (Arlec RC210) + { 188, 0, { 0, 0 }, 1, { 1, 31 }, { 1, 3 }, { 3, 1 }, false, 0 }, // 27 (Zap, FHT-7901) + + { 700, 1, { 0, 1 }, 1, { 116, 0 }, { 1, 2 }, { 2, 1 }, true, 0 }, // 28 (Quigg GT-7000) from @Tho85 https://github.com/sui77/rc-switch/pull/115 + { 220, 0, { 0, 0 }, 1, { 1, 46 }, { 1, 6 }, { 1, 1 }, false, 2 }, // 29 (NEXA) + { 260, 0, { 0, 0 }, 1, { 1, 8 }, { 1, 4 }, { 4, 1 }, true, 0 }, // 30 (Anima) + + { 400, 0, { 0, 0 }, 1, { 1, 1 }, { 1, 2 }, { 2, 1 }, false, 43 }, // 31 (Mertik Maxitrol G6R-H4T1) + { 365, 0, { 0, 0 }, 1, { 18, 1 }, { 3, 1 }, { 1, 3 }, true, 0 }, // 32 (1ByOne Doorbell) from @Fatbeard https://github.com/sui77/rc-switch/pull/277 + { 340, 0, { 0, 0 }, 1, { 14, 4 }, { 1, 2 }, { 2, 1 }, false, 0 }, // 33 (Dooya Control DC2708L) + { 120, 0, { 0, 0 }, 1, { 1, 28 }, { 1, 3 }, { 3, 1 }, false, 0 }, // 34 DIGOO SD10 - so as to use this protocol RCSWITCH_SEPARATION_LIMIT must be set to 2600 + { 20, 0, { 0, 0 }, 1, { 239, 78 }, {20, 35 }, {35, 20}, false, 10000},// 35 Dooya 5-Channel blinds remote DC1603 + { 250, 0, { 0, 0 }, 1, { 18, 6 }, { 1, 3 }, { 3, 1 }, false, 0 }, // 36 Dooya remote DC2700AC for Dooya DT82TV curtains motor + { 200, 0, { 0, 0 }, 0, { 0, 0 }, { 1, 3 }, { 3, 1} , false, 20} // 37 DEWENWILS Power Strip }; enum { @@ -98,29 +160,32 @@ enum { }; #if not defined( RCSwitchDisableReceiving ) -volatile unsigned long RCSwitch::nReceivedValue = 0; +volatile unsigned long long RCSwitch::nReceivedValue = 0; +volatile unsigned long long RCSwitch::nReceiveProtocolMask; 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; -// 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. +const unsigned int RCSwitch::nSeparationLimit = RCSWITCH_SEPARATION_LIMIT; unsigned int RCSwitch::timings[RCSWITCH_MAX_CHANGES]; +unsigned int RCSwitch::buftimings[4]; #endif RCSwitch::RCSwitch() { this->nTransmitterPin = -1; - this->setRepeatTransmit(10); + this->setRepeatTransmit(5); this->setProtocol(1); #if not defined( RCSwitchDisableReceiving ) this->nReceiverInterrupt = -1; this->setReceiveTolerance(60); RCSwitch::nReceivedValue = 0; + RCSwitch::nReceiveProtocolMask = (1ULL << numProto)-1; //pow(2,numProto)-1; #endif } +uint8_t RCSwitch::getNumProtos() { + return numProto; +} /** * Sets the protocol to send. */ @@ -172,8 +237,12 @@ void RCSwitch::setRepeatTransmit(int nRepeatTransmit) { void RCSwitch::setReceiveTolerance(int nPercent) { RCSwitch::nReceiveTolerance = nPercent; } + +void RCSwitch::setReceiveProtocolMask(unsigned long long mask) { + RCSwitch::nReceiveProtocolMask = mask; +} #endif - + /** * Enable transmissions @@ -376,7 +445,7 @@ char* RCSwitch::getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus 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'; @@ -412,7 +481,7 @@ char* RCSwitch::getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus * * 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 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) * @@ -452,7 +521,7 @@ char* RCSwitch::getCodeWordD(char sGroup, int nDevice, bool bStatus) { */ void RCSwitch::sendTriState(const char* sCodeWord) { // turn the tristate code word into the corresponding bit pattern, then send it - unsigned long code = 0; + unsigned long long code = 0; unsigned int length = 0; for (const char* p = sCodeWord; *p; p++) { code <<= 2L; @@ -462,11 +531,11 @@ void RCSwitch::sendTriState(const char* sCodeWord) { break; case 'F': // bit pattern 01 - code |= 1L; + code |= 1ULL; break; case '1': // bit pattern 11 - code |= 3L; + code |= 3ULL; break; } length += 2; @@ -474,17 +543,37 @@ void RCSwitch::sendTriState(const char* sCodeWord) { this->send(code, length); } +/** + * @param duration no. of microseconds to delay + */ +static inline void safeDelayMicroseconds(unsigned long duration) { +#if defined(ESP8266) || defined(ESP32) + if (duration > 10000) { + // if delay > 10 milliseconds, use yield() to avoid wdt reset + unsigned long start = micros(); + while ((micros() - start) < duration) { + yield(); + } + } + else { + delayMicroseconds(duration); + } +#else + delayMicroseconds(duration); +#endif +} + /** * @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 long long code = 0; unsigned int length = 0; for (const char* p = sCodeWord; *p; p++) { - code <<= 1L; + code <<= 1ULL; if (*p != '0') - code |= 1L; + code |= 1ULL; length++; } this->send(code, length); @@ -495,7 +584,7 @@ void RCSwitch::send(const char* sCodeWord) { * 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) { +void RCSwitch::send(unsigned long long code, unsigned int length) { if (this->nTransmitterPin == -1) return; @@ -507,14 +596,41 @@ void RCSwitch::send(unsigned long code, unsigned int length) { } #endif + // repeat sending the packet nRepeatTransmit times for (int nRepeat = 0; nRepeat < nRepeatTransmit; nRepeat++) { - for (int i = length-1; i >= 0; i--) { - if (code & (1L << i)) + // send the preamble + for (int i = 0; i < ((protocol.PreambleFactor / 2) + (protocol.PreambleFactor %2 )); i++) { + this->transmit({protocol.Preamble.high, protocol.Preamble.low}); + } + // send the header + if (protocol.HeaderFactor > 0) { + for (int i = 0; i < protocol.HeaderFactor; i++) { + this->transmit(protocol.Header); + } + } + // send the code + for (int i = length - 1; i >= 0; i--) { + if (code & (1ULL << i)) this->transmit(protocol.one); else this->transmit(protocol.zero); } - this->transmit(protocol.syncFactor); + // for kilok, there should be a duration of 66, and 64 significant data codes are stored + // send two more bits for even count + if (length == 64) { + if (nRepeat == 0) { + this->transmit(protocol.zero); + this->transmit(protocol.zero); + } else { + this->transmit(protocol.one); + this->transmit(protocol.one); + } + } + // Set the guard Time + if (protocol.Guard > 0) { + digitalWrite(this->nTransmitterPin, LOW); + safeDelayMicroseconds(this->protocol.pulseLength * protocol.Guard); + } } // Disable transmit after sending (i.e., for inverted protocols) @@ -534,11 +650,15 @@ void RCSwitch::send(unsigned long code, unsigned int length) { 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 (pulses.high > 0) { + digitalWrite(this->nTransmitterPin, firstLogicLevel); + delayMicroseconds( this->protocol.pulseLength * pulses.high); + } + if (pulses.low > 0) { + digitalWrite(this->nTransmitterPin, secondLogicLevel); + delayMicroseconds( this->protocol.pulseLength * pulses.low); + } } @@ -581,7 +701,7 @@ void RCSwitch::resetAvailable() { RCSwitch::nReceivedValue = 0; } -unsigned long RCSwitch::getReceivedValue() { +unsigned long long RCSwitch::getReceivedValue() { return RCSwitch::nReceivedValue; } @@ -617,12 +737,41 @@ bool RECEIVE_ATTR RCSwitch::receiveProtocol(const int p, unsigned int changeCoun 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; + unsigned long long code = 0; + unsigned int FirstTiming = 0; + if (pro.PreambleFactor > 0) { + FirstTiming = pro.PreambleFactor + 1; + } + unsigned int BeginData = 0; + if (pro.HeaderFactor > 0) { + BeginData = (pro.invertedSignal) ? (2) : (1); + // Header pulse count correction for more than one + if (pro.HeaderFactor > 1) { + BeginData += (pro.HeaderFactor - 1) * 2; + } + } + //Assuming the longer pulse length is the pulse captured in timings[FirstTiming] + // берем наибольшее значение из Header + const unsigned int syncLengthInPulses = ((pro.Header.low) > (pro.Header.high)) ? (pro.Header.low) : (pro.Header.high); + // определяем длительность Te как длительность первого импульса header деленную на количество импульсов в нем + // или как длительность импульса preamble деленную на количество Te в нем + unsigned int sdelay = 0; + if (syncLengthInPulses > 0) { + sdelay = RCSwitch::timings[FirstTiming] / syncLengthInPulses; + } else if (pro.PreambleFactor > 0) { + sdelay = RCSwitch::timings[FirstTiming-2] / pro.PreambleFactor; + } + const unsigned int delay = sdelay; + // nReceiveTolerance = 60 + // допустимое отклонение длительностей импульсов на 60 % const unsigned int delayTolerance = delay * RCSwitch::nReceiveTolerance / 100; - + + // 0 - sync перед preamble или data + // BeginData - сдвиг на 1 или 2 от sync к preamble/data + // FirstTiming - сдвиг на preamble к header + // firstDataTiming первый импульс data + // bitChangeCount - количество импульсов в data + /* For protocols that start low, the sync period looks like * _________ * _____________| |XXXXXXXXXXXX| @@ -640,9 +789,16 @@ bool RECEIVE_ATTR RCSwitch::receiveProtocol(const int p, unsigned int changeCoun * * The 2nd saved duration starts the data */ - const unsigned int firstDataTiming = (pro.invertedSignal) ? (2) : (1); + // если invertedSignal=false, то сигнал начинается с 1 элемента массива (высокий уровень) + // если invertedSignal=true, то сигнал начинается со 2 элемента массива (низкий уровень) + // добавляем поправку на Преамбулу и Хедер + const unsigned int firstDataTiming = BeginData + FirstTiming; + unsigned int bitChangeCount = changeCount - firstDataTiming - 1 + pro.invertedSignal; + if (bitChangeCount > 128) { + bitChangeCount = 128; + } - for (unsigned int i = firstDataTiming; i < changeCount - 1; i += 2) { + for (unsigned int i = firstDataTiming; i < firstDataTiming + bitChangeCount; i += 2) { code <<= 1; if (diff(RCSwitch::timings[i], delay * pro.zero.high) < delayTolerance && diff(RCSwitch::timings[i + 1], delay * pro.zero.low) < delayTolerance) { @@ -657,9 +813,9 @@ 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 + if (bitChangeCount > 14) { // ignore very short transmissions: no device sends them, so this must be noise RCSwitch::nReceivedValue = code; - RCSwitch::nReceivedBitlength = (changeCount - 1) / 2; + RCSwitch::nReceivedBitlength = bitChangeCount / 2; RCSwitch::nReceivedDelay = delay; RCSwitch::nReceivedProtocol = p; return true; @@ -672,41 +828,81 @@ void RECEIVE_ATTR RCSwitch::handleInterrupt() { static unsigned int changeCount = 0; static unsigned long lastTime = 0; - static unsigned int repeatCount = 0; + static byte repeatCount = 0; const long time = micros(); const unsigned int duration = time - lastTime; - if (duration > RCSwitch::nSeparationLimit) { + RCSwitch::buftimings[3]=RCSwitch::buftimings[2]; + RCSwitch::buftimings[2]=RCSwitch::buftimings[1]; + RCSwitch::buftimings[1]=RCSwitch::buftimings[0]; + RCSwitch::buftimings[0]=duration; + + if (duration > RCSwitch::nSeparationLimit || + changeCount == 156 || + (diff(RCSwitch::buftimings[3], RCSwitch::buftimings[2]) < 50 && + diff(RCSwitch::buftimings[2], RCSwitch::buftimings[1]) < 50 && + changeCount > 25)) { + // принят длинный импульс продолжительностью более nSeparationLimit (4300) // 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 (diff(duration, RCSwitch::timings[0]) < 400 || + changeCount == 156 || + (diff(RCSwitch::buftimings[3], RCSwitch::timings[1]) < 50 && + diff(RCSwitch::buftimings[2], RCSwitch::timings[2]) < 50 && + diff(RCSwitch::buftimings[1], RCSwitch::timings[3]) < 50 && + changeCount > 25)) { + // если его длительность отличается от первого импульса, + // который приняли раньше, менее чем на +-200 (исходно 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 == 1) { + unsigned long long thismask = 1; for(unsigned int i = 1; i <= numProto; i++) { - if (receiveProtocol(i, changeCount)) { - // receive succeeded for protocol i - break; + if (RCSwitch::nReceiveProtocolMask & thismask) { + if (receiveProtocol(i, changeCount)) { + // receive succeeded for protocol i + break; + } } + thismask <<= 1; } + // очищаем количество повторных пакетов repeatCount = 0; } } + // дительность отличается более чем на +-200 от первого + // принятого ранее, очищаем счетчик для приема нового пакета changeCount = 0; + if (diff(RCSwitch::buftimings[3], RCSwitch::buftimings[2]) < 50 && + diff(RCSwitch::buftimings[2], RCSwitch::buftimings[1]) < 50) { + RCSwitch::timings[1]=RCSwitch::buftimings[3]; + RCSwitch::timings[2]=RCSwitch::buftimings[2]; + RCSwitch::timings[3]=RCSwitch::buftimings[1]; + changeCount = 4; + } } - + // detect overflow if (changeCount >= RCSWITCH_MAX_CHANGES) { changeCount = 0; repeatCount = 0; } - RCSwitch::timings[changeCount++] = duration; - lastTime = time; + // заносим в массив длительность очередного принятого импульса + if (changeCount > 0 && duration < 100) { // игнорируем шумовые всплески менее 100 мкс + RCSwitch::timings[changeCount-1] += duration; + } else { + RCSwitch::timings[changeCount++] = duration; + } + lastTime = time; } #endif diff --git a/RCSwitch.h b/RCSwitch.h index b7755e0..6d660c0 100644 --- a/RCSwitch.h +++ b/RCSwitch.h @@ -10,7 +10,7 @@ - Frank Oltmanns / .(at)gmail(dot)com - Max Horn / max(at)quendi(dot)de - Robert ter Vehn / .(at)gmail(dot)com - + Project home: https://github.com/sui77/rc-switch/ This library is free software; you can redistribute it and/or @@ -58,13 +58,20 @@ // Number of maximum high/Low changes per packet. // We can handle up to (unsigned long) => 32 bit * 2 H/L changes per bit + 2 for sync -#define RCSWITCH_MAX_CHANGES 67 +// Для keeloq нужно увеличить RCSWITCH_MAX_CHANGES до 23+1+66*2+1=157 +#define RCSWITCH_MAX_CHANGES 67 // default 67 + +// 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. +// should be set to the minimum value of pulselength * the sync signal +#define RCSWITCH_SEPARATION_LIMIT 4100 class RCSwitch { public: RCSwitch(); - + void switchOn(int nGroupNumber, int nSwitchNumber); void switchOff(int nGroupNumber, int nSwitchNumber); void switchOn(const char* sGroup, int nSwitchNumber); @@ -77,9 +84,9 @@ class RCSwitch { void switchOff(char sGroup, int nDevice); void sendTriState(const char* sCodeWord); - void send(unsigned long code, unsigned int length); + void send(unsigned long long code, unsigned int length); void send(const char* sCodeWord); - + #if not defined( RCSwitchDisableReceiving ) void enableReceive(int interrupt); void enableReceive(); @@ -87,19 +94,21 @@ class RCSwitch { bool available(); void resetAvailable(); - unsigned long getReceivedValue(); + unsigned long long getReceivedValue(); unsigned int getReceivedBitlength(); unsigned int getReceivedDelay(); unsigned int getReceivedProtocol(); unsigned int* getReceivedRawdata(); + uint8_t getNumProtos(); #endif - + void enableTransmit(int nTransmitterPin); void disableTransmit(); void setPulseLength(int nPulseLength); void setRepeatTransmit(int nRepeatTransmit); #if not defined( RCSwitchDisableReceiving ) void setReceiveTolerance(int nPercent); + void setReceiveProtocolMask(unsigned long long mask); #endif /** @@ -120,8 +129,11 @@ class RCSwitch { struct Protocol { /** base pulse length in microseconds, e.g. 350 */ uint16_t pulseLength; + uint8_t PreambleFactor; + HighLow Preamble; + uint8_t HeaderFactor; + HighLow Header; - HighLow syncFactor; HighLow zero; HighLow one; @@ -142,6 +154,7 @@ class RCSwitch { * FOO.low*pulseLength microseconds. */ bool invertedSignal; + uint16_t Guard; }; void setProtocol(Protocol protocol); @@ -162,23 +175,25 @@ class RCSwitch { #endif int nTransmitterPin; int nRepeatTransmit; - Protocol protocol; #if not defined( RCSwitchDisableReceiving ) static int nReceiveTolerance; - volatile static unsigned long nReceivedValue; + volatile static unsigned long long nReceivedValue; + volatile static unsigned long long nReceiveProtocolMask; volatile static unsigned int nReceivedBitlength; volatile static unsigned int nReceivedDelay; volatile static unsigned int nReceivedProtocol; const static unsigned int nSeparationLimit; - /* + /* * timings[0] contains sync timing, followed by a number of bits */ static unsigned int timings[RCSWITCH_MAX_CHANGES]; + // буфер длительностей последних четырех пакетов, [0] - последний + static unsigned int buftimings[4]; #endif - + }; #endif diff --git a/examples/ReceiveDemo_Advanced/platformio.ini b/examples/ReceiveDemo_Advanced/platformio.ini new file mode 120000 index 0000000..08b42b6 --- /dev/null +++ b/examples/ReceiveDemo_Advanced/platformio.ini @@ -0,0 +1 @@ +../platformio.ini \ No newline at end of file diff --git a/examples/ReceiveDemo_Advanced/ReceiveDemo_Advanced.ino b/examples/ReceiveDemo_Advanced/src/ReceiveDemo_Advanced.ino similarity index 67% rename from examples/ReceiveDemo_Advanced/ReceiveDemo_Advanced.ino rename to examples/ReceiveDemo_Advanced/src/ReceiveDemo_Advanced.ino index 18380d3..2da3b59 100644 --- a/examples/ReceiveDemo_Advanced/ReceiveDemo_Advanced.ino +++ b/examples/ReceiveDemo_Advanced/src/ReceiveDemo_Advanced.ino @@ -12,8 +12,14 @@ RCSwitch mySwitch = RCSwitch(); void setup() { - Serial.begin(9600); - mySwitch.enableReceive(0); // Receiver on interrupt 0 => that is pin #2 + Serial.begin(MONITOR_SPEED); + + delay(1000); + Serial.print("Listening on pin "); + Serial.println(RCSWITCH_RECIEVE_PIN); + + pinMode(RCSWITCH_RECIEVE_PIN, INPUT); + mySwitch.enableReceive(RCSWITCH_RECIEVE_PIN); // see platformio_shared.ini } void loop() { diff --git a/examples/ReceiveDemo_Advanced/output.ino b/examples/ReceiveDemo_Advanced/src/output.ino similarity index 100% rename from examples/ReceiveDemo_Advanced/output.ino rename to examples/ReceiveDemo_Advanced/src/output.ino diff --git a/examples/ReceiveDemo_Simple/platformio.ini b/examples/ReceiveDemo_Simple/platformio.ini new file mode 120000 index 0000000..08b42b6 --- /dev/null +++ b/examples/ReceiveDemo_Simple/platformio.ini @@ -0,0 +1 @@ +../platformio.ini \ No newline at end of file diff --git a/examples/ReceiveDemo_Simple/ReceiveDemo_Simple.ino b/examples/ReceiveDemo_Simple/src/ReceiveDemo_Simple.ino similarity index 67% rename from examples/ReceiveDemo_Simple/ReceiveDemo_Simple.ino rename to examples/ReceiveDemo_Simple/src/ReceiveDemo_Simple.ino index bb10763..bd4e449 100644 --- a/examples/ReceiveDemo_Simple/ReceiveDemo_Simple.ino +++ b/examples/ReceiveDemo_Simple/src/ReceiveDemo_Simple.ino @@ -9,8 +9,13 @@ RCSwitch mySwitch = RCSwitch(); void setup() { - Serial.begin(9600); - mySwitch.enableReceive(0); // Receiver on interrupt 0 => that is pin #2 + Serial.begin(MONITOR_SPEED); + delay(1000); + Serial.print("Listening on pin "); + Serial.println(RCSWITCH_RECIEVE_PIN); + + pinMode(RCSWITCH_RECIEVE_PIN, INPUT); + mySwitch.enableReceive(RCSWITCH_RECIEVE_PIN); // see platformio_shared.ini } void loop() { diff --git a/examples/SendDemo/platformio.ini b/examples/SendDemo/platformio.ini new file mode 120000 index 0000000..08b42b6 --- /dev/null +++ b/examples/SendDemo/platformio.ini @@ -0,0 +1 @@ +../platformio.ini \ No newline at end of file diff --git a/examples/SendDemo/SendDemo.ino b/examples/SendDemo/src/SendDemo.ino similarity index 90% rename from examples/SendDemo/SendDemo.ino rename to examples/SendDemo/src/SendDemo.ino index 5acb495..c6572f4 100644 --- a/examples/SendDemo/SendDemo.ino +++ b/examples/SendDemo/src/SendDemo.ino @@ -11,10 +11,9 @@ RCSwitch mySwitch = RCSwitch(); void setup() { - Serial.begin(9600); + Serial.begin(MONITOR_SPEED); - // Transmitter is connected to Arduino Pin #10 - mySwitch.enableTransmit(10); + mySwitch.enableTransmit(RCSWITCH_TRANSMIT_PIN); // see platformio_shared.ini // Optional set protocol (default is 1, will work for most outlets) // mySwitch.setProtocol(2); diff --git a/examples/TypeA_WithDIPSwitches/platformio.ini b/examples/TypeA_WithDIPSwitches/platformio.ini new file mode 120000 index 0000000..08b42b6 --- /dev/null +++ b/examples/TypeA_WithDIPSwitches/platformio.ini @@ -0,0 +1 @@ +../platformio.ini \ No newline at end of file diff --git a/examples/TypeA_WithDIPSwitches/TypeA_WithDIPSwitches.ino b/examples/TypeA_WithDIPSwitches/src/TypeA_WithDIPSwitches.ino similarity index 90% rename from examples/TypeA_WithDIPSwitches/TypeA_WithDIPSwitches.ino rename to examples/TypeA_WithDIPSwitches/src/TypeA_WithDIPSwitches.ino index 14f7d2a..f3234c0 100644 --- a/examples/TypeA_WithDIPSwitches/TypeA_WithDIPSwitches.ino +++ b/examples/TypeA_WithDIPSwitches/src/TypeA_WithDIPSwitches.ino @@ -11,7 +11,7 @@ RCSwitch mySwitch = RCSwitch(); void setup() { // Transmitter is connected to Arduino Pin #10 - mySwitch.enableTransmit(10); + mySwitch.enableTransmit(RCSWITCH_TRANSMIT_PIN); // see platformio_shared.ini // Optional set pulse length. // mySwitch.setPulseLength(320); diff --git a/examples/TypeA_WithDIPSwitches_Lightweight/platformio.ini b/examples/TypeA_WithDIPSwitches_Lightweight/platformio.ini new file mode 120000 index 0000000..08b42b6 --- /dev/null +++ b/examples/TypeA_WithDIPSwitches_Lightweight/platformio.ini @@ -0,0 +1 @@ +../platformio.ini \ No newline at end of file diff --git a/examples/TypeA_WithDIPSwitches_Lightweight/TypeA_WithDIPSwitches_Lightweight.ino b/examples/TypeA_WithDIPSwitches_Lightweight/src/TypeA_WithDIPSwitches_Lightweight.ino similarity index 93% rename from examples/TypeA_WithDIPSwitches_Lightweight/TypeA_WithDIPSwitches_Lightweight.ino rename to examples/TypeA_WithDIPSwitches_Lightweight/src/TypeA_WithDIPSwitches_Lightweight.ino index 214daf4..c18553f 100644 --- a/examples/TypeA_WithDIPSwitches_Lightweight/TypeA_WithDIPSwitches_Lightweight.ino +++ b/examples/TypeA_WithDIPSwitches_Lightweight/src/TypeA_WithDIPSwitches_Lightweight.ino @@ -6,7 +6,7 @@ https://github.com/sui77/rc-switch/ */ -int RCLpin = 7; +int RCLpin = RCSWITCH_TRANSMIT_PIN; // see platformio_shared.ini; void setup() { pinMode(RCLpin, OUTPUT); diff --git a/examples/TypeB_WithRotaryOrSlidingSwitches/platformio.ini b/examples/TypeB_WithRotaryOrSlidingSwitches/platformio.ini new file mode 120000 index 0000000..08b42b6 --- /dev/null +++ b/examples/TypeB_WithRotaryOrSlidingSwitches/platformio.ini @@ -0,0 +1 @@ +../platformio.ini \ No newline at end of file diff --git a/examples/TypeB_WithRotaryOrSlidingSwitches/TypeB_WithRotaryOrSlidingSwitches.ino b/examples/TypeB_WithRotaryOrSlidingSwitches/src/TypeB_WithRotaryOrSlidingSwitches.ino similarity index 100% rename from examples/TypeB_WithRotaryOrSlidingSwitches/TypeB_WithRotaryOrSlidingSwitches.ino rename to examples/TypeB_WithRotaryOrSlidingSwitches/src/TypeB_WithRotaryOrSlidingSwitches.ino diff --git a/examples/TypeC_Intertechno/platformio.ini b/examples/TypeC_Intertechno/platformio.ini new file mode 120000 index 0000000..08b42b6 --- /dev/null +++ b/examples/TypeC_Intertechno/platformio.ini @@ -0,0 +1 @@ +../platformio.ini \ No newline at end of file diff --git a/examples/TypeC_Intertechno/TypeC_Intertechno.ino b/examples/TypeC_Intertechno/src/TypeC_Intertechno.ino similarity index 88% rename from examples/TypeC_Intertechno/TypeC_Intertechno.ino rename to examples/TypeC_Intertechno/src/TypeC_Intertechno.ino index 0fc69c7..f8a8f3d 100644 --- a/examples/TypeC_Intertechno/TypeC_Intertechno.ino +++ b/examples/TypeC_Intertechno/src/TypeC_Intertechno.ino @@ -10,8 +10,7 @@ RCSwitch mySwitch = RCSwitch(); void setup() { - // Transmitter is connected to Arduino Pin #10 - mySwitch.enableTransmit(10); + mySwitch.enableTransmit(RCSWITCH_TRANSMIT_PIN); // see platformio_shared.ini // Optional set pulse length. // mySwitch.setPulseLength(320); @@ -37,4 +36,4 @@ void loop() { // Wait another second delay(1000); -} \ No newline at end of file +} diff --git a/examples/TypeD_REV/platformio.ini b/examples/TypeD_REV/platformio.ini new file mode 120000 index 0000000..08b42b6 --- /dev/null +++ b/examples/TypeD_REV/platformio.ini @@ -0,0 +1 @@ +../platformio.ini \ No newline at end of file diff --git a/examples/TypeD_REV/TypeD_REV.ino b/examples/TypeD_REV/src/TypeD_REV.ino similarity index 88% rename from examples/TypeD_REV/TypeD_REV.ino rename to examples/TypeD_REV/src/TypeD_REV.ino index 8782729..b61d3f7 100644 --- a/examples/TypeD_REV/TypeD_REV.ino +++ b/examples/TypeD_REV/src/TypeD_REV.ino @@ -12,8 +12,7 @@ RCSwitch mySwitch = RCSwitch(); void setup() { - // Transmitter is connected to Arduino Pin #10 - mySwitch.enableTransmit(10); + mySwitch.enableTransmit(RCSWITCH_TRANSMIT_PIN); // see platformio_shared.ini // set pulse length. mySwitch.setPulseLength(360); diff --git a/examples/Webserver/platformio.ini b/examples/Webserver/platformio.ini new file mode 120000 index 0000000..08b42b6 --- /dev/null +++ b/examples/Webserver/platformio.ini @@ -0,0 +1 @@ +../platformio.ini \ No newline at end of file diff --git a/examples/Webserver/Webserver.ino b/examples/Webserver/src/Webserver.ino similarity index 98% rename from examples/Webserver/Webserver.ino rename to examples/Webserver/src/Webserver.ino index 66668e7..c6c2ad8 100644 --- a/examples/Webserver/Webserver.ino +++ b/examples/Webserver/src/Webserver.ino @@ -15,7 +15,7 @@ EthernetServer server(80); // Server Port 80 // RCSwitch configuration RCSwitch mySwitch = RCSwitch(); -int RCTransmissionPin = 7; +int RCTransmissionPin = RCSWITCH_TRANSMIT_PIN; // see platformio_shared.ini // More to do... // You should also modify the processCommand() and @@ -151,4 +151,4 @@ char* httpServer() { return sReturnCommand; } return '\0'; -} \ No newline at end of file +} diff --git a/examples/platformio.ini b/examples/platformio.ini new file mode 100644 index 0000000..120dde8 --- /dev/null +++ b/examples/platformio.ini @@ -0,0 +1,13 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[platformio] +this_lib = ../.. +extra_configs = ../../platformio_shared.ini diff --git a/platformio_shared.ini b/platformio_shared.ini new file mode 100644 index 0000000..a3fb097 --- /dev/null +++ b/platformio_shared.ini @@ -0,0 +1,49 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[platformio] +default_envs = lolin32 +;default_envs = esp32c3_cdc + +[common] +framework = arduino +monitor_speed = 921600 +build_flags = + -D MONITOR_SPEED=${common.monitor_speed} +lib_deps = + ${platformio.this_lib} + +[env:lolin32] +platform = espressif32 +board = lolin32 +upload_protocol = esptool +framework = ${common.framework} +lib_deps = ${common.lib_deps} +monitor_speed = ${common.monitor_speed} +build_flags = + ${common.build_flags} + -D RCSWITCH_RECIEVE_PIN=16 + -D RCSWITCH_TRANSMIT_PIN=17 + + +[env:esp32c3_cdc] +platform = espressif32 +board = airm2m_core_esp32c3 +upload_protocol = esptool +framework = ${common.framework} +lib_deps = ${common.lib_deps} +monitor_speed = ${common.monitor_speed} +build_flags = + -D CONFIG_ESP_CONSOLE_UART=1 ; settings for esp32c3 without uart + -D ARDUINO_USB_MODE=1 + -D ARDUINO_USB_CDC_ON_BOOT=1 + ${common.build_flags} + -D RCSWITCH_RECIEVE_PIN=1 + -D RCSWITCH_TRANSMIT_PIN=0