2 RCSwitch - Arduino libary for remote control outlet switches
\r
3 Copyright (c) 2011 Suat Özgür. All right reserved.
\r
6 - Andre Koehler / info(at)tomate-online(dot)de
\r
7 - Gordeev Andrey Vladimirovich / gordeev(at)openpyro(dot)com
\r
8 - Skineffect / http://forum.ardumote.com/viewtopic.php?f=2&t=46
\r
9 - Dominik Fischer / dom_fischer(at)web(dot)de
\r
11 Project home: http://code.google.com/p/rc-switch/
\r
13 This library is free software; you can redistribute it and/or
\r
14 modify it under the terms of the GNU Lesser General Public
\r
15 License as published by the Free Software Foundation; either
\r
16 version 2.1 of the License, or (at your option) any later version.
\r
18 This library is distributed in the hope that it will be useful,
\r
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
21 Lesser General Public License for more details.
\r
23 You should have received a copy of the GNU Lesser General Public
\r
24 License along with this library; if not, write to the Free Software
\r
25 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\r
28 #include "RCSwitch.h"
\r
30 unsigned long RCSwitch::nReceivedValue = NULL;
\r
31 unsigned int RCSwitch::nReceivedBitlength = 0;
\r
32 unsigned int RCSwitch::nReceivedDelay = 0;
\r
33 unsigned int RCSwitch::nReceivedProtocol = 0;
\r
34 unsigned int RCSwitch::timings[RCSWITCH_MAX_CHANGES];
\r
35 int RCSwitch::nReceiveTolerance = 60;
\r
37 RCSwitch::RCSwitch() {
\r
38 this->nReceiverInterrupt = -1;
\r
39 this->nTransmitterPin = -1;
\r
40 RCSwitch::nReceivedValue = NULL;
\r
41 this->setPulseLength(350);
\r
42 this->setRepeatTransmit(10);
\r
43 this->setReceiveTolerance(60);
\r
44 this->setProtocol(1);
\r
48 * Sets the protocol to send.
\r
50 void RCSwitch::setProtocol(int nProtocol) {
\r
51 this->nProtocol = nProtocol;
\r
52 if (nProtocol == 1){
\r
53 this->setPulseLength(350);
\r
55 else if (nProtocol == 2) {
\r
56 this->setPulseLength(650);
\r
61 * Sets the protocol to send with pulse length in microseconds.
\r
63 void RCSwitch::setProtocol(int nProtocol, int nPulseLength) {
\r
64 this->nProtocol = nProtocol;
\r
65 if (nProtocol == 1){
\r
66 this->setPulseLength(nPulseLength);
\r
68 else if (nProtocol == 2) {
\r
69 this->setPulseLength(nPulseLength);
\r
75 * Sets pulse length in microseconds
\r
77 void RCSwitch::setPulseLength(int nPulseLength) {
\r
78 this->nPulseLength = nPulseLength;
\r
82 * Sets Repeat Transmits
\r
84 void RCSwitch::setRepeatTransmit(int nRepeatTransmit) {
\r
85 this->nRepeatTransmit = nRepeatTransmit;
\r
89 * Set Receiving Tolerance
\r
91 void RCSwitch::setReceiveTolerance(int nPercent) {
\r
92 RCSwitch::nReceiveTolerance = nPercent;
\r
97 * Enable transmissions
\r
99 * @param nTransmitterPin Arduino Pin to which the sender is connected to
\r
101 void RCSwitch::enableTransmit(int nTransmitterPin) {
\r
102 this->nTransmitterPin = nTransmitterPin;
\r
103 pinMode(this->nTransmitterPin, OUTPUT);
\r
107 * Disable transmissions
\r
109 void RCSwitch::disableTransmit() {
\r
110 this->nTransmitterPin = -1;
\r
114 * Switch a remote switch on (Type C Intertechno)
\r
116 * @param sFamily Familycode (a..f)
\r
117 * @param nGroup Number of group (1..4)
\r
118 * @param nDevice Number of device (1..4)
\r
120 void RCSwitch::switchOn(char sFamily, int nGroup, int nDevice) {
\r
121 this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, true) );
\r
125 * Switch a remote switch off (Type C Intertechno)
\r
127 * @param sFamily Familycode (a..f)
\r
128 * @param nGroup Number of group (1..4)
\r
129 * @param nDevice Number of device (1..4)
\r
131 void RCSwitch::switchOff(char sFamily, int nGroup, int nDevice) {
\r
132 this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, false) );
\r
136 * Switch a remote switch on (Type B with two rotary/sliding switches)
\r
138 * @param nAddressCode Number of the switch group (1..4)
\r
139 * @param nChannelCode Number of the switch itself (1..4)
\r
141 void RCSwitch::switchOn(int nAddressCode, int nChannelCode) {
\r
142 this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, true) );
\r
146 * Switch a remote switch off (Type B with two rotary/sliding switches)
\r
148 * @param nAddressCode Number of the switch group (1..4)
\r
149 * @param nChannelCode Number of the switch itself (1..4)
\r
151 void RCSwitch::switchOff(int nAddressCode, int nChannelCode) {
\r
152 this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, false) );
\r
156 * Deprecated, use switchOn(char* sGroup, char* sDevice) instead!
\r
157 * Switch a remote switch on (Type A with 10 pole DIP switches)
\r
159 * @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")
\r
160 * @param nChannelCode Number of the switch itself (1..5)
\r
162 void RCSwitch::switchOn(char* sGroup, int nChannel) {
\r
163 char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" };
\r
164 this->switchOn(sGroup, code[nChannel]);
\r
168 * Deprecated, use switchOff(char* sGroup, char* sDevice) instead!
\r
169 * Switch a remote switch off (Type A with 10 pole DIP switches)
\r
171 * @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")
\r
172 * @param nChannelCode Number of the switch itself (1..5)
\r
174 void RCSwitch::switchOff(char* sGroup, int nChannel) {
\r
175 char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" };
\r
176 this->switchOff(sGroup, code[nChannel]);
\r
180 * Switch a remote switch on (Type A with 10 pole DIP switches)
\r
182 * @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")
\r
183 * @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")
\r
185 void RCSwitch::switchOn(char* sGroup, char* sDevice) {
\r
186 this->sendTriState( this->getCodeWordA(sGroup, sDevice, true) );
\r
190 * Switch a remote switch off (Type A with 10 pole DIP switches)
\r
192 * @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")
\r
193 * @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")
\r
195 void RCSwitch::switchOff(char* sGroup, char* sDevice) {
\r
196 this->sendTriState( this->getCodeWordA(sGroup, sDevice, false) );
\r
200 * Returns a char[13], representing the Code Word to be send.
\r
201 * 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.
\r
202 * A Code Bit can have 4 different states: "F" (floating), "0" (low), "1" (high), "S" (synchronous bit)
\r
204 * +-------------------------------+--------------------------------+-----------------------------------------+-----------------------------------------+----------------------+------------+
\r
205 * | 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 |
\r
206 * | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | F | F | on=FF off=F0 | S |
\r
207 * +-------------------------------+--------------------------------+-----------------------------------------+-----------------------------------------+----------------------+------------+
\r
209 * @param nAddressCode Number of the switch group (1..4)
\r
210 * @param nChannelCode Number of the switch itself (1..4)
\r
211 * @param bStatus Wether to switch on (true) or off (false)
\r
215 char* RCSwitch::getCodeWordB(int nAddressCode, int nChannelCode, boolean bStatus) {
\r
216 int nReturnPos = 0;
\r
217 static char sReturn[13];
\r
219 char* code[5] = { "FFFF", "0FFF", "F0FF", "FF0F", "FFF0" };
\r
220 if (nAddressCode < 1 || nAddressCode > 4 || nChannelCode < 1 || nChannelCode > 4) {
\r
223 for (int i = 0; i<4; i++) {
\r
224 sReturn[nReturnPos++] = code[nAddressCode][i];
\r
227 for (int i = 0; i<4; i++) {
\r
228 sReturn[nReturnPos++] = code[nChannelCode][i];
\r
231 sReturn[nReturnPos++] = 'F';
\r
232 sReturn[nReturnPos++] = 'F';
\r
233 sReturn[nReturnPos++] = 'F';
\r
236 sReturn[nReturnPos++] = 'F';
\r
238 sReturn[nReturnPos++] = '0';
\r
241 sReturn[nReturnPos] = '\0';
\r
247 * Returns a char[13], representing the Code Word to be send.
\r
249 * getCodeWordA(char*, char*)
\r
252 char* RCSwitch::getCodeWordA(char* sGroup, char* sDevice, boolean bOn) {
\r
253 static char sDipSwitches[13];
\r
257 for (i=0; i < 5; i++) {
\r
258 if (sGroup[i] == '0') {
\r
259 sDipSwitches[j++] = 'F';
\r
261 sDipSwitches[j++] = '0';
\r
265 for (i=0; i < 5; i++) {
\r
266 if (sDevice[i] == '0') {
\r
267 sDipSwitches[j++] = 'F';
\r
269 sDipSwitches[j++] = '0';
\r
274 sDipSwitches[j++] = '0';
\r
275 sDipSwitches[j++] = 'F';
\r
277 sDipSwitches[j++] = 'F';
\r
278 sDipSwitches[j++] = '0';
\r
281 sDipSwitches[j] = '\0';
\r
283 return sDipSwitches;
\r
287 * Like getCodeWord (Type C = Intertechno)
\r
289 char* RCSwitch::getCodeWordC(char sFamily, int nGroup, int nDevice, boolean bStatus) {
\r
290 static char sReturn[13];
\r
291 int nReturnPos = 0;
\r
293 if ( (byte)sFamily < 97 || (byte)sFamily > 112 || nGroup < 1 || nGroup > 4 || nDevice < 1 || nDevice > 4) {
\r
297 char* sDeviceGroupCode = dec2binWzerofill( (nDevice-1) + (nGroup-1)*4, 4 );
\r
298 char familycode[16][5] = { "0000", "F000", "0F00", "FF00", "00F0", "F0F0", "0FF0", "FFF0", "000F", "F00F", "0F0F", "FF0F", "00FF", "F0FF", "0FFF", "FFFF" };
\r
299 for (int i = 0; i<4; i++) {
\r
300 sReturn[nReturnPos++] = familycode[ (int)sFamily - 97 ][i];
\r
302 for (int i = 0; i<4; i++) {
\r
303 sReturn[nReturnPos++] = (sDeviceGroupCode[3-i] == '1' ? 'F' : '0');
\r
305 sReturn[nReturnPos++] = '0';
\r
306 sReturn[nReturnPos++] = 'F';
\r
307 sReturn[nReturnPos++] = 'F';
\r
309 sReturn[nReturnPos++] = 'F';
\r
311 sReturn[nReturnPos++] = '0';
\r
313 sReturn[nReturnPos] = '\0';
\r
318 * Sends a Code Word
\r
319 * @param sCodeWord /^[10FS]*$/ -> see getCodeWord
\r
321 void RCSwitch::sendTriState(char* sCodeWord) {
\r
322 for (int nRepeat=0; nRepeat<nRepeatTransmit; nRepeat++) {
\r
324 while (sCodeWord[i] != '\0') {
\r
325 switch(sCodeWord[i]) {
\r
342 void RCSwitch::send(unsigned long Code, unsigned int length) {
\r
343 this->send( this->dec2binWzerofill(Code, length) );
\r
346 void RCSwitch::send(char* sCodeWord) {
\r
347 for (int nRepeat=0; nRepeat<nRepeatTransmit; nRepeat++) {
\r
349 while (sCodeWord[i] != '\0') {
\r
350 switch(sCodeWord[i]) {
\r
364 void RCSwitch::transmit(int nHighPulses, int nLowPulses) {
\r
365 boolean disabled_Receive = false;
\r
366 int nReceiverInterrupt_backup = nReceiverInterrupt;
\r
367 if (this->nTransmitterPin != -1) {
\r
368 if (this->nReceiverInterrupt != -1) {
\r
369 this->disableReceive();
\r
370 disabled_Receive = true;
\r
372 digitalWrite(this->nTransmitterPin, HIGH);
\r
373 delayMicroseconds( this->nPulseLength * nHighPulses);
\r
374 digitalWrite(this->nTransmitterPin, LOW);
\r
375 delayMicroseconds( this->nPulseLength * nLowPulses);
\r
376 if(disabled_Receive){
\r
377 this->enableReceive(nReceiverInterrupt_backup);
\r
384 * Waveform Protocol 1: | |___
\r
386 * Waveform Protocol 2: | |__
\r
388 void RCSwitch::send0() {
\r
389 if (this->nProtocol == 1){
\r
390 this->transmit(1,3);
\r
392 else if (this->nProtocol == 2) {
\r
393 this->transmit(1,2);
\r
400 * Waveform Protocol 1: | |_
\r
402 * Waveform Protocol 2: | |_
\r
404 void RCSwitch::send1() {
\r
405 if (this->nProtocol == 1){
\r
406 this->transmit(3,1);
\r
408 else if (this->nProtocol == 2) {
\r
409 this->transmit(2,1);
\r
415 * Sends a Tri-State "0" Bit
\r
417 * Waveform: | |___| |___
\r
419 void RCSwitch::sendT0() {
\r
420 this->transmit(1,3);
\r
421 this->transmit(1,3);
\r
425 * Sends a Tri-State "1" Bit
\r
427 * Waveform: | |_| |_
\r
429 void RCSwitch::sendT1() {
\r
430 this->transmit(3,1);
\r
431 this->transmit(3,1);
\r
435 * Sends a Tri-State "F" Bit
\r
437 * Waveform: | |___| |_
\r
439 void RCSwitch::sendTF() {
\r
440 this->transmit(1,3);
\r
441 this->transmit(3,1);
\r
445 * Sends a "Sync" Bit
\r
447 * Waveform Protocol 1: | |_______________________________
\r
449 * Waveform Protocol 2: | |__________
\r
451 void RCSwitch::sendSync() {
\r
453 if (this->nProtocol == 1){
\r
454 this->transmit(1,31);
\r
456 else if (this->nProtocol == 2) {
\r
457 this->transmit(1,10);
\r
462 * Enable receiving data
\r
464 void RCSwitch::enableReceive(int interrupt) {
\r
465 this->nReceiverInterrupt = interrupt;
\r
466 this->enableReceive();
\r
469 void RCSwitch::enableReceive() {
\r
470 if (this->nReceiverInterrupt != -1) {
\r
471 RCSwitch::nReceivedValue = NULL;
\r
472 RCSwitch::nReceivedBitlength = NULL;
\r
473 attachInterrupt(this->nReceiverInterrupt, handleInterrupt, CHANGE);
\r
478 * Disable receiving data
\r
480 void RCSwitch::disableReceive() {
\r
481 detachInterrupt(this->nReceiverInterrupt);
\r
482 this->nReceiverInterrupt = -1;
\r
485 bool RCSwitch::available() {
\r
486 return RCSwitch::nReceivedValue != NULL;
\r
489 void RCSwitch::resetAvailable() {
\r
490 RCSwitch::nReceivedValue = NULL;
\r
493 unsigned long RCSwitch::getReceivedValue() {
\r
494 return RCSwitch::nReceivedValue;
\r
497 unsigned int RCSwitch::getReceivedBitlength() {
\r
498 return RCSwitch::nReceivedBitlength;
\r
501 unsigned int RCSwitch::getReceivedDelay() {
\r
502 return RCSwitch::nReceivedDelay;
\r
505 unsigned int RCSwitch::getReceivedProtocol() {
\r
506 return RCSwitch::nReceivedProtocol;
\r
509 unsigned int* RCSwitch::getReceivedRawdata() {
\r
510 return RCSwitch::timings;
\r
516 bool RCSwitch::receiveProtocol1(unsigned int changeCount){
\r
518 unsigned long code = 0;
\r
519 unsigned long delay = RCSwitch::timings[0] / 31;
\r
520 unsigned long delayTolerance = delay * RCSwitch::nReceiveTolerance * 0.01;
\r
522 for (int i = 1; i<changeCount ; i=i+2) {
\r
524 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) {
\r
526 } 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) {
\r
536 if (changeCount > 6) { // ignore < 4bit values as there are no devices sending 4bit values => noise
\r
537 RCSwitch::nReceivedValue = code;
\r
538 RCSwitch::nReceivedBitlength = changeCount / 2;
\r
539 RCSwitch::nReceivedDelay = delay;
\r
540 RCSwitch::nReceivedProtocol = 1;
\r
545 }else if (code != 0){
\r
552 bool RCSwitch::receiveProtocol2(unsigned int changeCount){
\r
554 unsigned long code = 0;
\r
555 unsigned long delay = RCSwitch::timings[0] / 10;
\r
556 unsigned long delayTolerance = delay * RCSwitch::nReceiveTolerance * 0.01;
\r
558 for (int i = 1; i<changeCount ; i=i+2) {
\r
560 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) {
\r
562 } 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) {
\r
572 if (changeCount > 6) { // ignore < 4bit values as there are no devices sending 4bit values => noise
\r
573 RCSwitch::nReceivedValue = code;
\r
574 RCSwitch::nReceivedBitlength = changeCount / 2;
\r
575 RCSwitch::nReceivedDelay = delay;
\r
576 RCSwitch::nReceivedProtocol = 2;
\r
581 }else if (code != 0){
\r
586 void RCSwitch::handleInterrupt() {
\r
588 static unsigned int duration;
\r
589 static unsigned int changeCount;
\r
590 static unsigned long lastTime;
\r
591 static unsigned int repeatCount;
\r
594 long time = micros();
\r
595 duration = time - lastTime;
\r
597 if (duration > 5000 && duration > RCSwitch::timings[0] - 200 && duration < RCSwitch::timings[0] + 200) {
\r
600 if (repeatCount == 2) {
\r
601 if (receiveProtocol1(changeCount) == false){
\r
602 if (receiveProtocol2(changeCount) == false){
\r
609 } else if (duration > 5000) {
\r
613 if (changeCount >= RCSWITCH_MAX_CHANGES) {
\r
617 RCSwitch::timings[changeCount++] = duration;
\r
622 * Turns a decimal value to its binary representation
\r
624 char* RCSwitch::dec2binWzerofill(unsigned long Dec, unsigned int bitLength){
\r
625 static char bin[64];
\r
629 bin[32+i++] = ((Dec & 1) > 0) ? '1' : '0';
\r
633 for (unsigned int j = 0; j< bitLength; j++) {
\r
634 if (j >= bitLength - i) {
\r
635 bin[j] = bin[ 31 + i - (j - (bitLength - i)) ];
\r
640 bin[bitLength] = '\0';
\r