Library to switch 433MHz remote controlled sockets.
Revision 0:6f4be1a7962c, committed 2014-10-12
- Comitter:
- TheChrisyd
- Date:
- Sun Oct 12 09:57:12 2014 +0000
- Commit message:
- Initial commit
Changed in this revision
RCSwitch.cpp | Show annotated file Show diff for this revision Revisions of this file |
RCSwitch.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r 6f4be1a7962c RCSwitch.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RCSwitch.cpp Sun Oct 12 09:57:12 2014 +0000 @@ -0,0 +1,858 @@ +/* + RCSwitch - Ported from the 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 + - Chris Dick / Porting to mbed + + Project home: http://code.google.com/p/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" + + unsigned long RCSwitch::nReceivedValue = NULL; + unsigned int RCSwitch::nReceivedBitlength = 0; + unsigned int RCSwitch::nReceivedDelay = 0; + unsigned int RCSwitch::nReceivedProtocol = 0; + int RCSwitch::nReceiveTolerance = 60; + unsigned int RCSwitch::timings[RCSWITCH_MAX_CHANGES]; + bool RCSwitch::TransmitEnablePin = false; + bool RCSwitch::ReceiveEnabled = true; + bool RCSwitch::TransmitEnable = true; + +/** Class constructor. + * The constructor assigns the specified pinout, attatches + * an Interrupt to the receive pin. for the LPC1768 this must not + * be pins 19 and 20. For the KL25Z, the pin must be on ports A or C + * @param tx Transmitter pin of the RF module. + * @param rx Receiver pin of the RF module. + */ +RCSwitch::RCSwitch(PinName tx, PinName rx) +: + _tx(DigitalOut(tx)), + _rx(InterruptIn(rx)), + _tx_en(NC) +{ + nReceivedDelay = 0; + RCSwitch::nReceivedValue = NULL; + nReceivedBitlength = 0; + ReceiveEnabled = true; + TransmitEnable = true; + TransmitEnablePin = false; + setRepeatTransmit(15); + setProtocol(1); + setReceiveTolerance(60); + _rx.rise(this, &RCSwitch::RCSwitchRxPinChange); + _rx.fall(this, &RCSwitch::RCSwitchRxPinChange); + timer.start(); +} + + /** Class constructor. + * The constructor assigns the specified pinout, attatches + * an Interrupt to the receive pin. for the LPC1768 this must not + * be pins 19 and 20. For the KL25Z, the pin must be on ports A or C + * @param tx Transmitter pin of the RF module. + * @param rx Receiver pin of the RF module. + * @param tx_en Enable pin of the transmitter + */ +RCSwitch::RCSwitch(PinName tx, PinName rx, PinName tx_en) +: + _tx(DigitalOut(tx)), + _rx(InterruptIn(rx)), + _tx_en(DigitalOut(tx_en)) +{ + nReceivedDelay = 0; + RCSwitch::nReceivedValue = NULL; + nReceivedBitlength = 0; + ReceiveEnabled = true; + TransmitEnable = false; + TransmitEnablePin = true; + setRepeatTransmit(15); + setProtocol(1); + setReceiveTolerance(60); + _rx.rise(this, &RCSwitch::RCSwitchRxPinChange); + _rx.fall(this, &RCSwitch::RCSwitchRxPinChange); + timer.start(); + +} + +/** + * Set protocol to be used in transmission + * @param nProtocol Protocol type ot transmit + */ +void RCSwitch::setProtocol(int nProtocol) { + this->nProtocol = nProtocol; + if (nProtocol == 1){ + this->setPulseLength(350); + } + else if (nProtocol == 2) { + this->setPulseLength(650); + } + else if (nProtocol == 3) { + this->setPulseLength(100); + } +} + +/** + * Set protocol to be used in transmission + * @param nProtocol Protocol type ot transmit + * @param nPulseLength Length of each pulse + */ +void RCSwitch::setProtocol(int nProtocol, int nPulseLength) { + this->nProtocol = nProtocol; + this->setPulseLength(nPulseLength); +} + + +/** + * Set pulse length in micro seconds + * @param nPulseLength the Length of the pulse + */ +void RCSwitch::setPulseLength(int nPulseLength) { + this->nPulseLength = nPulseLength; +} + +/** + * Set number of times to repeat transmission + * @param nRepeat Number of repeats + */ +void RCSwitch::setRepeatTransmit(int nRepeatTransmit) { + this->nRepeatTransmit = nRepeatTransmit; +} + +/** + * Set receive tolerance + * @param nPercent Percentage tolerance of the receiver + */ +void RCSwitch::setReceiveTolerance(int nPercent) { + RCSwitch::nReceiveTolerance = nPercent; +} + + +/** + * Enable the transmitter + */ +void RCSwitch::enableTransmit() { + if (TransmitEnablePin == true) + { + _tx_en = true; + } + TransmitEnable = true; +} + +/** + * Disable the transmitter + */ +void RCSwitch::disableTransmit() { + if (TransmitEnablePin == true) + { + _tx_en = false; + } + TransmitEnable = false; +} + +/** + * 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(char* sGroup, 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(char* sGroup, int nChannel) { + char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" }; + this->switchOn(sGroup, code[nChannel]); +} + +/** + * Deprecated, use switchOff(char* sGroup, 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(char* sGroup, int nChannel) { + 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(char* sGroup, 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(char* sGroup, char* sDevice) { + this->sendTriState( this->getCodeWordA(sGroup, sDevice, false) ); +} + +/** + * Returns a char[13], representing the Code Word to be send. + * A Code Word consists of 9 address bits, 3 data bits and one sync bit but in our case only the first 8 address bits and the last 2 data bits were used. + * A Code Bit can have 4 different states: "F" (floating), "0" (low), "1" (high), "S" (synchronous bit) + * + * +-------------------------------+--------------------------------+-----------------------------------------+-----------------------------------------+----------------------+------------+ + * | 4 bits address (switch group) | 4 bits address (switch number) | 1 bit address (not used, so never mind) | 1 bit address (not used, so never mind) | 2 data bits (on|off) | 1 sync bit | + * | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | F | F | on=FF off=F0 | S | + * +-------------------------------+--------------------------------+-----------------------------------------+-----------------------------------------+----------------------+------------+ + * + * @param nAddressCode Number of the switch group (1..4) + * @param nChannelCode Number of the switch itself (1..4) + * @param bStatus Wether to switch on (true) or off (false) + * + * @return char[13] + */ +char* RCSwitch::getCodeWordB(int nAddressCode, int nChannelCode, bool bStatus) { + int nReturnPos = 0; + static char sReturn[13]; + + char* code[5] = { "FFFF", "0FFF", "F0FF", "FF0F", "FFF0" }; + if (nAddressCode < 1 || nAddressCode > 4 || nChannelCode < 1 || nChannelCode > 4) { + return '\0'; + } + for (int i = 0; i<4; i++) { + sReturn[nReturnPos++] = code[nAddressCode][i]; + } + + for (int i = 0; i<4; i++) { + sReturn[nReturnPos++] = code[nChannelCode][i]; + } + + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = 'F'; + + if (bStatus) { + sReturn[nReturnPos++] = 'F'; + } else { + sReturn[nReturnPos++] = '0'; + } + + sReturn[nReturnPos] = '\0'; + + return sReturn; +} + +/** + * Returns a char[13], representing the Code Word to be send. + * + * getCodeWordA(char*, char*) + * + */ +char* RCSwitch::getCodeWordA(char* sGroup, char* sDevice, bool bOn) { + static char sDipSwitches[13]; + int i = 0; + int j = 0; + + for (i=0; i < 5; i++) { + if (sGroup[i] == '0') { + sDipSwitches[j++] = 'F'; + } else { + sDipSwitches[j++] = '0'; + } + } + + for (i=0; i < 5; i++) { + if (sDevice[i] == '0') { + sDipSwitches[j++] = 'F'; + } else { + sDipSwitches[j++] = '0'; + } + } + + if ( bOn ) { + sDipSwitches[j++] = '0'; + sDipSwitches[j++] = 'F'; + } else { + sDipSwitches[j++] = 'F'; + sDipSwitches[j++] = '0'; + } + + sDipSwitches[j] = '\0'; + + return sDipSwitches; +} + +/** + * Like getCodeWord (Type C = Intertechno) + */ +char* RCSwitch::getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus) { + static char sReturn[13]; + int nReturnPos = 0; + + if ( (char)sFamily < 97 || (char)sFamily > 112 || nGroup < 1 || nGroup > 4 || nDevice < 1 || nDevice > 4) { + return '\0'; + } + + char* sDeviceGroupCode = dec2binWzerofill( (nDevice-1) + (nGroup-1)*4, 4 ); + char familycode[16][5] = { "0000", "F000", "0F00", "FF00", "00F0", "F0F0", "0FF0", "FFF0", "000F", "F00F", "0F0F", "FF0F", "00FF", "F0FF", "0FFF", "FFFF" }; + for (int i = 0; i<4; i++) { + sReturn[nReturnPos++] = familycode[ (int)sFamily - 97 ][i]; + } + for (int i = 0; i<4; i++) { + sReturn[nReturnPos++] = (sDeviceGroupCode[3-i] == '1' ? 'F' : '0'); + } + sReturn[nReturnPos++] = '0'; + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = 'F'; + if (bStatus) { + sReturn[nReturnPos++] = 'F'; + } else { + sReturn[nReturnPos++] = '0'; + } + sReturn[nReturnPos] = '\0'; + return sReturn; +} + +/** + * Decoding for the REV Switch Type + * + * Returns a char[13], representing the Tristate to be send. + * A Code Word consists of 7 address bits and 5 command data bits. + * A Code Bit can have 3 different states: "F" (floating), "0" (low), "1" (high) + * + * +-------------------------------+--------------------------------+-----------------------+ + * | 4 bits address (switch group) | 3 bits address (device number) | 5 bits (command data) | + * | A=1FFF B=F1FF C=FF1F D=FFF1 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | on=00010 off=00001 | + * +-------------------------------+--------------------------------+-----------------------+ + * + * 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 Wether to switch on (true) or off (false) + * + * @return char[13] + */ + +char* RCSwitch::getCodeWordD(char sGroup, int nDevice, bool bStatus){ + static char sReturn[13]; + int nReturnPos = 0; + + // Building 4 bits address + // (Potential problem if dec2binWcharfill not returning correct string) + char *sGroupCode; + switch(sGroup){ + case 'a': + case 'A': + sGroupCode = dec2binWcharfill(8, 4, 'F'); break; + case 'b': + case 'B': + sGroupCode = dec2binWcharfill(4, 4, 'F'); break; + case 'c': + case 'C': + sGroupCode = dec2binWcharfill(2, 4, 'F'); break; + case 'd': + case 'D': + sGroupCode = dec2binWcharfill(1, 4, 'F'); break; + default: + return '\0'; + } + + for (int i = 0; i<4; i++) + { + sReturn[nReturnPos++] = sGroupCode[i]; + } + + + // Building 3 bits address + // (Potential problem if dec2binWcharfill not returning correct string) + char *sDevice; + switch(nDevice) { + case 1: + sDevice = dec2binWcharfill(4, 3, 'F'); break; + case 2: + sDevice = dec2binWcharfill(2, 3, 'F'); break; + case 3: + sDevice = dec2binWcharfill(1, 3, 'F'); break; + default: + return '\0'; + } + + for (int i = 0; i<3; i++) + sReturn[nReturnPos++] = sDevice[i]; + + // fill up rest with zeros + for (int i = 0; i<5; i++) + sReturn[nReturnPos++] = '0'; + + // encode on or off + if (bStatus) + sReturn[10] = '1'; + else + sReturn[11] = '1'; + + // last position terminate string + sReturn[12] = '\0'; + return sReturn; + +} + +/** + * Sends a codeword + * @param sCodeWord Codeword to be sent + */ +void RCSwitch::sendTriState(char* sCodeWord) { + for (int nRepeat=0; nRepeat<nRepeatTransmit; nRepeat++) { + int i = 0; + while (sCodeWord[i] != '\0') { + switch(sCodeWord[i]) { + case '0': + this->sendT0(); + break; + case 'F': + this->sendTF(); + break; + case '1': + this->sendT1(); + break; + } + i++; + } + this->sendSync(); + } +} + +void RCSwitch::send(unsigned long Code, unsigned int length) { + this->send( this->dec2binWzerofill(Code, length) ); +} + +void RCSwitch::send(char* sCodeWord) { + for (int nRepeat=0; nRepeat<nRepeatTransmit; nRepeat++) { + int i = 0; + while (sCodeWord[i] != '\0') { + switch(sCodeWord[i]) { + case '0': + this->send0(); + break; + case '1': + this->send1(); + break; + } + i++; + } + this->sendSync(); + } +} + +void RCSwitch::transmit(int nHighPulses, int nLowPulses) { + bool disabled_Receive = false; + + if (TransmitEnable) { + if (ReceiveEnabled) { + this->disableReceive(); + disabled_Receive = true; + } + _tx = 1; + wait_us(this->nPulseLength * nHighPulses); + _tx = 0; + wait_us(this->nPulseLength *nLowPulses); + if(disabled_Receive){ + this->enableReceive(); + } + } +} +/** + * Sends a "0" Bit + * _ + * Waveform Protocol 1: | |___ + * _ + * Waveform Protocol 2: | |__ + */ +void RCSwitch::send0() { + if (this->nProtocol == 1){ + this->transmit(1,3); + } + else if (this->nProtocol == 2) { + this->transmit(1,2); + } + else if (this->nProtocol == 3) { + this->transmit(4,11); + } +} + +/** + * Sends a "1" Bit + * ___ + * Waveform Protocol 1: | |_ + * __ + * Waveform Protocol 2: | |_ + */ +void RCSwitch::send1() { + if (this->nProtocol == 1){ + this->transmit(3,1); + } + else if (this->nProtocol == 2) { + this->transmit(2,1); + } + else if (this->nProtocol == 3) { + this->transmit(9,6); + } +} + + +/** + * Sends a Tri-State "0" Bit + * _ _ + * Waveform: | |___| |___ + */ +void RCSwitch::sendT0() { + this->transmit(1,3); + this->transmit(1,3); +} + +/** + * Sends a Tri-State "1" Bit + * ___ ___ + * Waveform: | |_| |_ + */ +void RCSwitch::sendT1() { + this->transmit(3,1); + this->transmit(3,1); +} + +/** + * Sends a Tri-State "F" Bit + * _ ___ + * Waveform: | |___| |_ + */ +void RCSwitch::sendTF() { + this->transmit(1,3); + this->transmit(3,1); +} + +/** + * Sends a "Sync" Bit + * _ + * Waveform Protocol 1: | |_______________________________ + * _ + * Waveform Protocol 2: | |__________ + */ +void RCSwitch::sendSync() { + + if (this->nProtocol == 1){ + this->transmit(1,31); + } + else if (this->nProtocol == 2) { + this->transmit(1,10); + } + else if (this->nProtocol == 3) { + this->transmit(1,71); + } +} + +/** + * Enable receiving data + */ +void RCSwitch::enableReceive() { + RCSwitch::nReceivedValue = NULL; + RCSwitch::nReceivedBitlength = NULL; + _rx.enable_irq(); + ReceiveEnabled = true; +} + +/** + * Disable receiving data This disables the interrupt + * which may disable the port + */ +void RCSwitch::disableReceive() { + _rx.disable_irq(); + ReceiveEnabled = false; +} + +bool RCSwitch::available() { + return RCSwitch::nReceivedValue != NULL; +} + +void RCSwitch::resetAvailable() { + RCSwitch::nReceivedValue = NULL; +} + +unsigned long RCSwitch::getReceivedValue() { + return RCSwitch::nReceivedValue; +} + +unsigned int RCSwitch::getReceivedBitlength() { + return RCSwitch::nReceivedBitlength; +} + +unsigned int RCSwitch::getReceivedDelay() { + return nReceivedDelay; +} + +unsigned int RCSwitch::getReceivedProtocol() { + return RCSwitch::nReceivedProtocol; +} + +unsigned int* RCSwitch::getReceivedRawdata() { + return RCSwitch::timings; +} + +/** + * + */ +bool RCSwitch::receiveProtocol1(unsigned int changeCount){ + + unsigned long code = 0; + unsigned long delay = RCSwitch::timings[0] / 31; + unsigned long delayTolerance = delay * RCSwitch::nReceiveTolerance * 0.01; + + for (int i = 1; i<changeCount ; i=i+2) { + + if (RCSwitch::timings[i] > delay-delayTolerance && RCSwitch::timings[i] < delay+delayTolerance && RCSwitch::timings[i+1] > delay*3-delayTolerance && RCSwitch::timings[i+1] < delay*3+delayTolerance) { + code = code << 1; + } else if (RCSwitch::timings[i] > delay*3-delayTolerance && RCSwitch::timings[i] < delay*3+delayTolerance && RCSwitch::timings[i+1] > delay-delayTolerance && RCSwitch::timings[i+1] < delay+delayTolerance) { + code+=1; + code = code << 1; + } else { + // Failed + i = changeCount; + code = 0; + } + } + code = code >> 1; + if (changeCount > 6) { // ignore < 4bit values as there are no devices sending 4bit values => noise + RCSwitch::nReceivedValue = code; + RCSwitch::nReceivedBitlength = changeCount / 2; + nReceivedDelay = delay; + RCSwitch::nReceivedProtocol = 1; + } + + if (code == 0){ + return false; + } + return true; +} + +bool RCSwitch::receiveProtocol2(unsigned int changeCount){ + + unsigned long code = 0; + unsigned long delay = RCSwitch::timings[0] / 10; + unsigned long delayTolerance = delay * RCSwitch::nReceiveTolerance * 0.01; + + for (int i = 1; i<changeCount ; i=i+2) { + + if (RCSwitch::timings[i] > delay-delayTolerance && RCSwitch::timings[i] < delay+delayTolerance && RCSwitch::timings[i+1] > delay*2-delayTolerance && RCSwitch::timings[i+1] < delay*2+delayTolerance) { + code = code << 1; + } else if (RCSwitch::timings[i] > delay*2-delayTolerance && RCSwitch::timings[i] < delay*2+delayTolerance && RCSwitch::timings[i+1] > delay-delayTolerance && RCSwitch::timings[i+1] < delay+delayTolerance) { + code+=1; + code = code << 1; + } else { + // Failed + i = changeCount; + code = 0; + } + } + code = code >> 1; + if (changeCount > 6) { // ignore < 4bit values as there are no devices sending 4bit values => noise + RCSwitch::nReceivedValue = code; + RCSwitch::nReceivedBitlength = changeCount / 2; + nReceivedDelay = delay; + RCSwitch::nReceivedProtocol = 2; + } + + if (code == 0){ + return false; + } + return true; +} + +/** Protocol 3 is used by BL35P02. + * + */ +bool RCSwitch::receiveProtocol3(unsigned int changeCount){ + + unsigned long code = 0; + unsigned long delay = RCSwitch::timings[0] / PROTOCOL3_SYNC_FACTOR; + unsigned long delayTolerance = delay * RCSwitch::nReceiveTolerance * 0.01; + + for (int i = 1; i<changeCount ; i=i+2) { + + if (RCSwitch::timings[i] > delay*PROTOCOL3_0_HIGH_CYCLES - delayTolerance + && RCSwitch::timings[i] < delay*PROTOCOL3_0_HIGH_CYCLES + delayTolerance + && RCSwitch::timings[i+1] > delay*PROTOCOL3_0_LOW_CYCLES - delayTolerance + && RCSwitch::timings[i+1] < delay*PROTOCOL3_0_LOW_CYCLES + delayTolerance) { + code = code << 1; + } else if (RCSwitch::timings[i] > delay*PROTOCOL3_1_HIGH_CYCLES - delayTolerance + && RCSwitch::timings[i] < delay*PROTOCOL3_1_HIGH_CYCLES + delayTolerance + && RCSwitch::timings[i+1] > delay*PROTOCOL3_1_LOW_CYCLES - delayTolerance + && RCSwitch::timings[i+1] < delay*PROTOCOL3_1_LOW_CYCLES + delayTolerance) { + code+=1; + code = code << 1; + } else { + // Failed + i = changeCount; + code = 0; + } + } + code = code >> 1; + if (changeCount > 6) { // ignore < 4bit values as there are no devices sending 4bit values => noise + RCSwitch::nReceivedValue = code; + RCSwitch::nReceivedBitlength = changeCount / 2; + nReceivedDelay = delay; + RCSwitch::nReceivedProtocol = 3; + } + + if (code == 0){ + return false; + } + return true; +} + +void RCSwitch::RCSwitchRxPinChange() { + + static unsigned int duration; + static unsigned int changeCount; + static unsigned int repeatCount; + timer.stop(); + duration = timer.read_us(); + timer.reset(); + timer.start(); + + + if (duration > 5000 && duration > RCSwitch::timings[0] - 200 && duration < RCSwitch::timings[0] + 200) { + repeatCount++; + changeCount--; + + if (repeatCount == 2) { + if (receiveProtocol1(changeCount) == false){ + if (receiveProtocol2(changeCount) == false){ + if (receiveProtocol3(changeCount) == false){ + //failed + } + } + } + repeatCount = 0; + } + changeCount = 0; + } else if (duration > 5000) { + + changeCount = 0; + } + + if (changeCount >= RCSWITCH_MAX_CHANGES) { + changeCount = 0; + repeatCount = 0; + } + RCSwitch::timings[changeCount++] = duration; +} + +/** + * Turns a decimal value to its binary representation + */ +char* RCSwitch::dec2binWzerofill(unsigned long Dec, unsigned int bitLength){ + return dec2binWcharfill(Dec, bitLength, '0'); +} + +char* RCSwitch::dec2binWcharfill(unsigned long Dec, unsigned int bitLength, char fill){ + static char bin[64]; + unsigned int i=0; + + while (Dec > 0) { + bin[32+i++] = ((Dec & 1) > 0) ? '1' : fill; + Dec = Dec >> 1; + } + + for (unsigned int j = 0; j< bitLength; j++) { + if (j >= bitLength - i) { + bin[j] = bin[ 31 + i - (j - (bitLength - i)) ]; + }else { + bin[j] = fill; + } + } + bin[bitLength] = '\0'; + + return bin; +} + + +
diff -r 000000000000 -r 6f4be1a7962c RCSwitch.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/RCSwitch.h Sun Oct 12 09:57:12 2014 +0000 @@ -0,0 +1,364 @@ +/** + *@section DESCRIPTION + * RCSwitch - Ported from the Arduino libary for remote control outlet switches + * 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 + * - Chris Dick / Porting to mbed + * + * Project home: http://code.google.com/p/rc-switch/ + * @section LICENSE + * Copyright (c) 2011 Suat Özgür. All right reserved. + * + * 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 + * Permission is hereby granted, free of charge, to any person obtaining a copy + * @file "RCSwitch.h" + */ +#ifndef _RCSwitch_h +#define _RCSwitch_h +#include "mbed.h" + +// might need to change this... +// We can handle up to (unsigned long) => 32 bit * 2 H/L changes per bit + 2 for sync +#define RCSWITCH_MAX_CHANGES 67 /**< Number of maximum High/Low changes per packet. */ + +#define PROTOCOL3_SYNC_FACTOR 71 /**< Protocol 3 Sync Factor */ +#define PROTOCOL3_0_HIGH_CYCLES 4 /**< Protocol 3 number of high cycles in a 0 */ +#define PROTOCOL3_0_LOW_CYCLES 11 /**< Protocol 3 number of low cycles in a 0*/ +#define PROTOCOL3_1_HIGH_CYCLES 9 /**< Protocol 3 number of high cycles in a 1*/ +#define PROTOCOL3_1_LOW_CYCLES 6 /**< Protocol 3 number of low cycles in a 1*/ +/** RCSwitch Class + * + * Example: + * @code + * #include "mbed.h" + * #include "RCSwitch.h" + * + * // This Example should only do one of either transmit or receive + * //#define TRANSMIT + * #define RECEIVE + * + * Serial pc(USBTX, USBRX); // tx, rx + * RCSwitch mySwitch = RCSwitch( p11, p21 ); //tx, rx + * + * int main() + * { + * pc.printf("Setup"); + * while(1) { + * #ifdef RECEIVE + * if (mySwitch.available()) { + * + * int value = mySwitch.getReceivedValue(); + * + * if (value == 0) { + * pc.printf("Unknown encoding"); + * } else { + * pc.printf("Received %d \n\r", mySwitch.getReceivedValue()); + * pc.printf(" bit %d \n\r", mySwitch.getReceivedBitlength()); + * pc.printf(" Protocol: %d \n\r", mySwitch.getReceivedProtocol()); + * } + * mySwitch.resetAvailable(); + * } + * #endif + * #ifdef TRANSMIT + * // Example: TypeA_WithDIPSwitches + * mySwitch.switchOn("11111", "00010"); + * wait(1); + * mySwitch.switchOn("11111", "00010"); + * wait(1); + * + * // Same switch as above, but using decimal code + * mySwitch.send(5393, 24); + * wait(1); + * mySwitch.send(5396, 24); + * wait(1); + * + * // Same switch as above, but using binary code + * mySwitch.send("000000000001010100010001"); + * wait(1); + * mySwitch.send("000000000001010100010100"); + * wait(1); + * + * // Same switch as above, but tri-state code + * mySwitch.sendTriState("00000FFF0F0F"); + * wait(1); + * mySwitch.sendTriState("00000FFF0FF0"); + * wait(1); + * #endif + * } + * } + * + * @endcode + */ + + /** + * + * + */ +class RCSwitch { + + public: + /** Class constructor. + * The constructor assigns the specified pinout, attatches + * an Interrupt to the receive pin. for the LPC1768 this must not + * be pins 19 and 20. For the KL25Z, the pin must be on ports A or C + * @param tx Transmitter pin of the RF module. + * @param rx Receiver pin of the RF module. + */ + RCSwitch(PinName tx, PinName rx); + /** Class constructor. + * The constructor assigns the specified pinout, attatches + * an Interrupt to the receive pin. for the LPC1768 this must not + * be pins 19 and 20. For the KL25Z, the pin must be on ports A or C + * @param tx Transmitter pin of the RF module. + * @param rx Receiver pin of the RF module. + * @param tx_en Enable pin of the transmitter + */ + RCSwitch(PinName tx, PinName rx, PinName rx_en); +/** + * Set protocol to be used in transmission + * @param nProtocol Protocol type ot transmit + */ + void setProtocol(int nProtocol); +/** + * Set protocol to be used in transmission + * @param nProtocol Protocol type ot transmit + * @param nPulseLength Length of each pulse + */ + void setProtocol(int nProtocol, int nPulseLength); +/** + * 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 switchOn(char* sGroup, char* sDevice); +/** + * 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 switchOff(char* sGroup, char* sDevice); +/** + * Deprecated, use switchOn(char* sGroup, 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 switchOn(char* sGroup, int nChannelCode); +/** + * Deprecated, use switchOff(char* sGroup, 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 switchOff(char* sGroup, int nChannelCode); +/** + * 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 switchOn(int nAddressCode, int nChannelCode); +/** + * 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 switchOff(int nAddressCode, int nChannelCode); +/** + * 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 switchOn(char sFamily, int nGroup, int nDevice); +/** + * 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 switchOff(char sFamily, int nGroup, int nDevice); + +/** + * 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 switchOn(char sGroup, int nDevice); +/** + * 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 switchOff(char sGroup, int nDevice); +/** + * Sends a codeword + * @param sCodeWord Codeword to be sent + */ + void sendTriState(char* Code); +/** + * Converts a CodeWord to a set Length and sends it + * @param Code CodeWord to be sent + * @param length Length of CodeWord to send + */ + void send(unsigned long Code, unsigned int length); +/** + * Sends a CodeWord + * @param Code CodeWord to send + */ + void send(char* Code); +/** + * Enable receiving data This clear message storage + * and enables the interrupt, which may enable the port + */ + void enableReceive(); +/** + * Disable receiving data This disables the interrupt + * which may disable the port + */ + void disableReceive(); +/** + * Message availiable + * @return bool Message availiability + */ + bool available(); +/** + * Clear Messages + */ + void resetAvailable(); +/** + * Get Message Value + * @return unsigned long The value of the message received + */ + unsigned long getReceivedValue(); +/** + * Get bit length + * @return unsigned int Number of bits received + */ + unsigned int getReceivedBitlength(); +/** + * Get the delay + * @Return unsigned int The delay + */ + unsigned int getReceivedDelay(); +/** + * Get Protocol + * @return unsigned int The protocol used in the message + */ + unsigned int getReceivedProtocol(); +/** + * Get Raw data + * @return unsinged int The raw data of the message recieved + */ + unsigned int* getReceivedRawdata(); +/** + * Enable the transmitter + */ + void enableTransmit(); +/** + * Disable the transmitter + */ + void disableTransmit(); +/** + * Set pulse length in micro seconds + * @param nPulseLength the Length of the pulse + */ + void setPulseLength(int nPulseLength); +/** + * Set number of times to repeat transmission + * @param nRepeat Number of repeats + */ + void setRepeatTransmit(int nRepeatTransmit); +/** + * Set receive tolerance + * @param nPercent Percentage tolerance of the receiver + */ + void setReceiveTolerance(int nPercent); + + static int nReceiveTolerance; /**< Tolerance of the receiver */ + static unsigned long nReceivedValue; /**< Value Recieved */ + static unsigned int nReceivedBitlength; /**< Length in bits of value reveived */ + static unsigned int nReceivedDelay; /**< Delay in receive */ + static unsigned int nReceivedProtocol; /**< Protocol of message recieved */ + static bool ReceiveEnabled; /**< Receive enabled */ + static bool TransmitEnable; /**< Transmit enabled */ + static bool TransmitEnablePin; /**< Pin of transmitter enable pin */ + static unsigned int timings[RCSWITCH_MAX_CHANGES]; /**< timings[0] contains sync timing, followed by a number of bits */ + + private: + DigitalOut _tx; + InterruptIn _rx; + DigitalOut _tx_en; + + char* getCodeWordB(int nGroupNumber, int nSwitchNumber, bool bStatus); + + char* getCodeWordA(char* sGroup, int nSwitchNumber, bool bStatus); + + char* getCodeWordA(char* sGroup, char* sDevice, bool bStatus); + + char* getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus); + + char* getCodeWordD(char group, int nDevice, bool bStatus); + + void sendT0(); + + void sendT1(); + + void sendTF(); + + void send0(); + + void send1(); + + void sendSync(); + + void transmit(int nHighPulses, int nLowPulses); + + void RCSwitchRxPinChange(); + + static char* dec2binWzerofill(unsigned long dec, unsigned int length); + + static char* dec2binWcharfill(unsigned long dec, unsigned int length, char fill); + + static void handleInterrupt(); + + static bool receiveProtocol1(unsigned int changeCount); + + static bool receiveProtocol2(unsigned int changeCount); + + static bool receiveProtocol3(unsigned int changeCount); + + int nReceiverInterrupt; + int nTransmitterPin; + int nPulseLength; + int nRepeatTransmit; + char nProtocol; + Timer timer; +}; + +#endif