diff -r 8b5e8f1e172d -r a03b6dac5398 thermferm/rc-switch.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thermferm/rc-switch.c Sun May 25 22:06:56 2014 +0200 @@ -0,0 +1,955 @@ +/***************************************************************************** + * Copyright (C) 2014 + * + * Michiel Broek + * + * This file is part of the mbsePi-apps + * + * Based on the Arduino libary for remote control outlet switches. + * Project home: http://code.google.com/p/rc-switch/ + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * mbsePi-apps 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EC-65K; see the file COPYING. If not, write to the Free + * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + *****************************************************************************/ + +#include "thermferm.h" + +#ifdef HAVE_WIRINGPI_H + + +#define TYPE_UNDEF 0 +#define TYPE_MINIMUM 0 +#define TYPE_A 1 +#define TYPE_B 2 +#define TYPE_C 3 +#define TYPE_D 4 +#define TYPE_E 3 // TODO: Which Protocol does REV use? +#define TYPE_MAXIMUM 4 + +// 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 + +// i.e. ProtocolCount + 1 (for TYPE_UNDEF) +#define MAX_PROTOCOLS 5 + +#define PROTOCOL_A_SYNC_FACTOR 31 +#define PROTOCOL_A_ZERO_FIRST_CYCLES 1 +#define PROTOCOL_A_ZERO_SECOND_CYCLES 3 +#define PROTOCOL_A_ONE_FIRST_CYCLES 3 +#define PROTOCOL_A_ONE_SECOND_CYCLES 1 +#define PROTOCOL_A_HIGH_FIRST true + +#define PROTOCOL_B_SYNC_FACTOR 10 +#define PROTOCOL_B_ZERO_FIRST_CYCLES 1 +#define PROTOCOL_B_ZERO_SECOND_CYCLES 2 +#define PROTOCOL_B_ONE_FIRST_CYCLES 2 +#define PROTOCOL_B_ONE_SECOND_CYCLES 1 +#define PROTOCOL_B_HIGH_FIRST true + +#define PROTOCOL_C_SYNC_FACTOR 71 +#define PROTOCOL_C_ZERO_FIRST_CYCLES 4 +#define PROTOCOL_C_ZERO_SECOND_CYCLES 11 +#define PROTOCOL_C_ONE_FIRST_CYCLES 9 +#define PROTOCOL_C_ONE_SECOND_CYCLES 6 +#define PROTOCOL_C_HIGH_FIRST true + +// I think, this will work for receive, however, I haven't tested, as I don't own a receiver... +// As Type D doesn't sync acc. to https://github.com/d-a-n/433-codes/blob/master/database.md#quigg +// the sync factor is totally undetermined. +// Malte Diers, 22.11.2013 +#define PROTOCOL_D_SYNC_FACTOR 1 +#define PROTOCOL_D_ZERO_FIRST_CYCLES 1 +#define PROTOCOL_D_ZERO_SECOND_CYCLES 2 +#define PROTOCOL_D_ONE_FIRST_CYCLES 2 +#define PROTOCOL_D_ONE_SECOND_CYCLES 1 +#define PROTOCOL_D_HIGH_FIRST false + + +#define PROTOCOL3_SYNC_FACTOR 71 +#define PROTOCOL3_0_HIGH_CYCLES 4 +#define PROTOCOL3_0_LOW_CYCLES 11 +#define PROTOCOL3_1_HIGH_CYCLES 9 +#define PROTOCOL3_1_LOW_CYCLES 6 + + + +unsigned long rcReceivedValue = 0; +unsigned int rcReceivedBitlength = 0; +unsigned int rcReceivedDelay = 0; +unsigned int rcReceivedProtocol = 0; +int rcReceiveTolerance = 60; +int rcReceiverInterruptPin = -1; + +unsigned int timings[RCSWITCH_MAX_CHANGES]; +int rcTransmitterPin = -1; +int rcPulseLength = 350; // thermometers 2.4 msec = 2400 +int rcRepeatTransmit = 10; +int rcProtocol = 1; + +int backupProtocol; +int backupPulseLength; +int backupRepeatTransmit; + + +//const char TYPE_A_CODE[ 6][6] = { "00000", "10000", "01000", "00100", "00010", "00001"}; +const char TYPE_B_CODE[ 5][5] = { "FFFF", "0FFF", "F0FF", "FF0F", "FFF0" }; +const char TYPE_C_CODE[16][5] = { "0000", "F000", "0F00", "FF00", "00F0", "F0F0", "0FF0", "FFF0", + "000F", "F00F", "0F0F", "FF0F", "00FF", "F0FF", "0FFF", "FFFF" }; +const char TYPE_D_CODE[5][2][9] = { { "11100001", "11110000" }, { "00000000", "00010001" }, { "10000010", "10010011" }, + { "11000011", "11010010" }, { "01000001", "01010000" } }; + /* Type A Type D */ +const int PULSE_LENGTH[MAX_PROTOCOLS] = { 0, 350, 650, 100, 666, }; +const int REPEAT_TRANSMIT[MAX_PROTOCOLS] = { 0, 10, 10, 10, 4, }; +const int SYNC_FACTOR[MAX_PROTOCOLS] = { 0, PROTOCOL_A_SYNC_FACTOR, PROTOCOL_B_SYNC_FACTOR, PROTOCOL_C_SYNC_FACTOR, PROTOCOL_D_SYNC_FACTOR, }; +const int ZERO_FIRST_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ZERO_FIRST_CYCLES, PROTOCOL_B_ZERO_FIRST_CYCLES, PROTOCOL_C_ZERO_FIRST_CYCLES, PROTOCOL_D_ZERO_FIRST_CYCLES, }; +const int ZERO_SECOND_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ZERO_SECOND_CYCLES, PROTOCOL_B_ZERO_SECOND_CYCLES, PROTOCOL_C_ZERO_SECOND_CYCLES, PROTOCOL_D_ZERO_SECOND_CYCLES, }; +const int ONE_FIRST_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ONE_FIRST_CYCLES, PROTOCOL_B_ONE_FIRST_CYCLES, PROTOCOL_C_ONE_FIRST_CYCLES, PROTOCOL_D_ONE_FIRST_CYCLES, }; +const int ONE_SECOND_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ONE_SECOND_CYCLES, PROTOCOL_B_ONE_SECOND_CYCLES, PROTOCOL_C_ONE_SECOND_CYCLES, PROTOCOL_D_ONE_SECOND_CYCLES, }; +const bool HIGH_FIRST[MAX_PROTOCOLS] = { 0, PROTOCOL_A_HIGH_FIRST, PROTOCOL_B_HIGH_FIRST, PROTOCOL_C_HIGH_FIRST, PROTOCOL_D_HIGH_FIRST, }; + + +char *getCodeWordA(char*, char*, bool); +char *getCodeWordB(int, int, bool); +char *getCodeWordC(char, int, int, bool); + +char *getCodeWordE(char, int, bool); +void sendTriState(char*); +void transmit(int, int, bool); +void send0(void); +void send1(void); +void sendT0(void); +void sendT1(void); +void sendTF(void); +void sendSync(void); +bool receiveProtocol(int, unsigned int); +void handleInterrupt(void); +char *dec2binWcharfill(unsigned long, unsigned int, char); + +void setReceiveTolerance(int); +void setProtocol(int); + +void saveProtocol(int); +void loadProtocol(void); + + + +/* + * Sets the protocol to send. + */ +void setProtocol(int nProtocol) { + + if ((nProtocol < TYPE_MINIMUM) || (nProtocol > TYPE_MAXIMUM)) { + return; + } + + rcProtocol = nProtocol; + rcPulseLength = PULSE_LENGTH[nProtocol]; + rcRepeatTransmit = REPEAT_TRANSMIT[nProtocol]; +} + + + +/* + * Set Receiving Tolerance + */ +void setReceiveTolerance(int nPercent) { + rcReceiveTolerance = nPercent; +} + + + +/* + * Enable transmissions + * + * @param nTransmitterPin Pin to which the sender is connected to + */ +void enableTransmit(int nTransmitterPin) { + rcTransmitterPin = nTransmitterPin; + pinMode(rcTransmitterPin, OUTPUT); +} + + + +/* + * Disable transmissions + */ +void disableTransmit(void) { + rcTransmitterPin = -1; +} + + + +/* + * Toggle switch, a command looks like B,3,2,1 which means switch type B, + * group 3, device 2, status on. + */ +int toggleSwitch(char *command) +{ + static char *cmd = NULL; + char *s, cType; + int rc, iGroup, iDevice, iState; + + cmd = xstrcpy(command); + s = strtok(cmd, ",\0"); + cType = s[0]; + + if (cType == 'A') { + + } else if (cType == 'B') { + s = strtok(NULL, ",\0"); + rc = sscanf(s, "%d", &iGroup); + if (rc != 1) + return 1; + s = strtok(NULL, ",\0"); + rc = sscanf(s, "%d", &iDevice); + if (rc != 1) + return 1; + s = strtok(NULL, ",\0"); + rc = sscanf(s, "%d", &iState); + if (rc != 1) + return 1; + free(cmd); + return toggleTypeB(iGroup, iDevice, iState); + } + + free(cmd); + return 1; +} + + + +/* + * Switch a remote switch on (Type E REV) + * + * @param sGroup Code of the switch group (A,B,C,D) + * @param nDevice Number of the switch itself (1..3) + * @param bStatus Status to toggle to + */ +int toggleTypeE(char sGroup, int nDevice, bool bStatus) { + sendTriState( getCodeWordE(sGroup, nDevice, bStatus) ); + return 0; +} + + + +/* + * 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) + * @param bStatus Status to toggle to + */ +int toggleTypeC(char sFamily, int nGroup, int nDevice, bool bStatus) { + char *str = xstrcpy(getCodeWordC(sFamily, nGroup, nDevice, bStatus)); + + if (strlen(str) == 0) + return 1; + + saveProtocol(TYPE_A); // ??? + sendTriState( str ); + loadProtocol(); + free(str); + return 0; +} + + + +/* + * Switch a remote switch on/off (Type B with two rotary/sliding switches) + * + * @param iGroup Number of the switch group (1..4) + * @param iDevice Number of the switch itself (1..4) + * @param bStatus Status to toggle to + */ +int toggleTypeB(int iGroup, int iDevice, bool bStatus) +{ + char *str = xstrcpy(getCodeWordB(iGroup, iDevice, bStatus)); + + if (strlen(str) == 0) + return 1; + + saveProtocol(TYPE_A); // They do better with protocol A timings. + sendTriState( str ); + loadProtocol(); + free(str); + return 0; +} + + + +/* + * 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") + * @param bStatus Status to toggle to + */ +int toggleTypeA(char* sGroup, char* sDevice, bool bStatus) { + char *str = xstrcpy(getCodeWordA(sGroup, sDevice, bStatus)); + + if (strlen(str) == 0) + return 1; + + saveProtocol(TYPE_A); + sendTriState( str ); + loadProtocol(); + free(str); + return 0; +} + + + +/* + * 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 *getCodeWordB(int nAddressCode, int nChannelCode, bool bStatus) +{ + int i, nReturnPos = 0; + static char sReturn[13]; + + if (nAddressCode < 1 || nAddressCode > 4 || nChannelCode < 1 || nChannelCode > 4) { + return '\0'; + } + for (i = 0; i<4; i++) { + sReturn[nReturnPos++] = TYPE_B_CODE[nAddressCode][i]; + } + + for (i = 0; i<4; i++) { + sReturn[nReturnPos++] = TYPE_B_CODE[nChannelCode][i]; + } + + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = bStatus ? 'F' : '0'; + sReturn[nReturnPos] = '\0'; + + return sReturn; +} + + + +/* + * Returns a char[13], representing the Code Word to be send. + * + * getCodeWordA(char*, char*) + * + */ +char *getCodeWordA(char* sGroup, char* sDevice, bool bOn) +{ + static char sDipSwitches[13]; + int i, j = 0; + + for (i=0; i < 5; i++) { + sDipSwitches[j++] = (sGroup[i] == '0') ? 'F' : '0'; + } + + for (i=0; i < 5; i++) { + sDipSwitches[j++] = (sDevice[i] == '0') ? 'F' : '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 *getCodeWordC(char sFamily, int nGroup, int nDevice, bool bStatus) +{ + static char sReturn[13]; + int i, nReturnPos = 0; + + if (sFamily < 'a') { + // To also enable capital 'A' to 'F' + sFamily += 32; + } + + if ( sFamily < 'a' || sFamily > 'f' || nGroup < 1 || nGroup > 4 || nDevice < 1 || nDevice > 4) { + return '\0'; + } + + for (i = 0; i<4; i++) { + sReturn[nReturnPos++] = TYPE_C_CODE[ sFamily - 'a' ][i]; + } + + char *sDeviceGroupCode = dec2binWzerofill( (nDevice-1) + (nGroup-1)*4, 4 ); + for (i = 0; i<4; i++) { + sReturn[nReturnPos++] = (sDeviceGroupCode[3-i] == '1' ? 'F' : '0'); + } + + sReturn[nReturnPos++] = '0'; + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = bStatus ? 'F' : '0'; + sReturn[nReturnPos] = '\0'; + + return sReturn; +} + + + +/* + * Decoding for the Quigg Switch Type + * + * Returns a char[22], representing the States to be send. + * A Code Word consists of 1 start bit, 12 address bits and 8 command data bits. + * A Code Bit can have 2 different states: "0" (low), "1" (high) + * + * +--------------+--------------------------------+------------------------------+ + * | 1 bits start | 12 bits address (device group) | 8 bits (command/switch data) | + * | 1 | 110011001100 | 00010001 | + * +--------------+--------------------------------+------------------------------+ + * + * Source: https://github.com/d-a-n/433-codes/blob/master/database.md#quigg + * + * @param sGroup 12-bit Binary ID of the Device Group + * @param nDevice Number of the switch itself (1..4, or 0 to switch the entire Group) + * @param bStatus Wether to switch on (true) or off (false) + * + * @return char[22] + */ +char *getCodeWordD(char *sGroup, int nDevice, bool bStatus) +{ + static char sReturn[22]; + int i, nReturnPos = 0; + + /* Startbit */ + sReturn[nReturnPos++] = '1'; + + /* 12 bit Group */ + for (i = 0; i < 12; ++i) { + sReturn[nReturnPos++] = sGroup[i]; + } + + /* 8 Bit Device Identifier + Status (undividable!) */ + for (i = 0; i < 8; ++i) { + sReturn[nReturnPos++] = TYPE_D_CODE[nDevice][bStatus][i]; + } + 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 *getCodeWordE(char sGroup, int nDevice, bool bStatus){ + static char sReturn[13]; + int i, 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 (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 (i = 0; i<3; i++) + sReturn[nReturnPos++] = sDevice[i]; + + // fill up rest with zeros + for (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; + +} + + + +/* + * @param sCodeWord /^[10FS]*$/ -> see getCodeWord + */ +void sendTriState(char* sCodeWord) { + int nRepeat; + + for (nRepeat = 0; nRepeat < rcRepeatTransmit; nRepeat++) { + int i = 0; + while (sCodeWord[i] != '\0') { + switch(sCodeWord[i]) { + case '0': + sendT0(); + break; + case 'F': + sendTF(); + break; + case '1': + sendT1(); + break; + } + i++; + } + 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; nRepeatsend0(); + break; + case '1': + this->send1(); + break; + } + i++; + } + this->sendSync(); + } +} +*/ + + +void transmit(int nFirstPulses, int nSecondPulses, bool bHighFirst) +{ + bool disabled_Receive = false; + int nReceiverInterrupt_backup = rcReceiverInterruptPin; + + if (rcTransmitterPin != -1) { + if (rcReceiverInterruptPin != -1) { + disableReceive(); + disabled_Receive = true; + } + digitalWrite(rcTransmitterPin, bHighFirst ? HIGH : LOW); + delayMicroseconds( rcPulseLength * nFirstPulses); + digitalWrite(rcTransmitterPin, bHighFirst ? LOW : HIGH); + delayMicroseconds( rcPulseLength * nSecondPulses); + + if (disabled_Receive) { + enableReceiveIRQ(nReceiverInterrupt_backup); + } + } +} + + + +/* + * Sends a "0" Bit + * _ + * Waveform Protocol 1: | |___ + * _ + * Waveform Protocol 2: | |__ + * ____ + * Waveform Protocol 3: | |___________ + */ +//void send0(void) { +// if (rcProtocol == 1){ +// transmit(1,3); +// } +// else if (rcProtocol == 2) { +// transmit(1,2); +// } +// else if (rcProtocol == 3) { +// transmit(4,11); +// } +//} + + + +/* + * Sends a "1" Bit + * ___ + * Waveform Protocol 1: | |_ + * __ + * Waveform Protocol 2: | |_ + * _________ + * Waveform Protocol 3: | |______ + */ +//void send1(void) { +// if (rcProtocol == 1){ +// transmit(3,1); +// } +// else if (rcProtocol == 2) { +// transmit(2,1); +// } +// else if (rcProtocol == 3) { +// transmit(9,6); +// } +//} + + + +/* + * Sends a Tri-State "0" Bit + * _ _ + * Waveform: | |___| |___ + */ +void sendT0(void) { + transmit(ZERO_FIRST_CYCLES[rcProtocol], ZERO_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); + transmit(ZERO_FIRST_CYCLES[rcProtocol], ZERO_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); +// transmit(1,3,true); +// transmit(1,3,true); +} + + + +/* + * Sends a Tri-State "1" Bit + * ___ ___ + * Waveform: | |_| |_ + */ +void sendT1(void) { + transmit(ONE_FIRST_CYCLES[rcProtocol], ONE_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); + transmit(ONE_FIRST_CYCLES[rcProtocol], ONE_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); +// transmit(3,1,true); +// transmit(3,1,true); +} + + + +/* + * Sends a Tri-State "F" Bit + * _ ___ + * Waveform: | |___| |_ + */ +void sendTF(void) { + transmit(ZERO_FIRST_CYCLES[rcProtocol], ZERO_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); + transmit(ONE_FIRST_CYCLES[rcProtocol], ONE_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); +// transmit(1,3,true); +// transmit(3,1,true); +} + + + +/* + * Sends a "Sync" Bit + * _ + * Waveform Protocol 1: | |_______________________________ + * _ + * Waveform Protocol 2: | |__________ + * ____ + * Waveform Protocol 3: | |_______________________________________________________________________ + * + * Waveform Protocol D: (none, just pause 80 msecs) + */ +void sendSync(void) { + + if (rcProtocol == TYPE_A) { + transmit(1,31,true); + } else if (rcProtocol == TYPE_B) { + transmit(1,10,true); + } else if (rcProtocol == TYPE_C) { + transmit(4,71,true); + } else if (rcProtocol == TYPE_D) { + transmit(0,1,false); + delayMicroseconds(80000); + } +} + + + +/* + * Enable receiving data + */ +void enableReceiveIRQ(int Pin) { + rcReceiverInterruptPin = Pin; + enableReceive(); +} + +void enableReceive(void) { + if (rcReceiverInterruptPin != -1) { + rcReceivedValue = 0; + rcReceivedBitlength = 0; + wiringPiISR(rcReceiverInterruptPin, INT_EDGE_BOTH, &handleInterrupt); + } +} + + + +/* + * Disable receiving data + */ +void disableReceive() { + // wiringPi disable interrupts ??? + rcReceiverInterruptPin = -1; +} + + + +bool available(void) { + return rcReceivedValue != 0; +} + + + +void resetAvailable(void) { + rcReceivedValue = 0; +} + + + +unsigned long getReceivedValue(void) { + return rcReceivedValue; +} + + + +unsigned int getReceivedBitlength(void) { + return rcReceivedBitlength; +} + + + +unsigned int getReceivedDelay(void) { + return rcReceivedDelay; +} + + + +unsigned int getReceivedProtocol(void) { + return rcReceivedProtocol; +} + + + +unsigned int* getReceivedRawdata(void) { + return timings; +} + + + +/* + * ASK protool 1 + */ +bool receiveProtocol(int prot, unsigned int changeCount) +{ + unsigned long code = 0; + unsigned long ldelay = timings[0] / SYNC_FACTOR[prot]; + unsigned long delayTolerance = ldelay * rcReceiveTolerance * 0.01; + int i; + + if (prot < TYPE_MINIMUM || prot > TYPE_MAXIMUM) { + return false; + } + + for (i = 1; i ldelay * ZERO_FIRST_CYCLES[prot] - delayTolerance && + timings[i] < ldelay * ZERO_FIRST_CYCLES[prot] + delayTolerance && + timings[i+1] > ldelay * ZERO_SECOND_CYCLES[prot] - delayTolerance && + timings[i+1] < ldelay * ZERO_SECOND_CYCLES[prot] + delayTolerance) { + code = code << 1; + } else if (timings[i] > ldelay * ONE_FIRST_CYCLES[prot] - delayTolerance && + timings[i] < ldelay * ONE_FIRST_CYCLES[prot] + delayTolerance && + timings[i+1] > ldelay * ONE_SECOND_CYCLES[prot] - delayTolerance && + timings[i+1] < ldelay * ONE_SECOND_CYCLES[prot] + 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 + rcReceivedValue = code; + rcReceivedBitlength = changeCount / 2; + rcReceivedDelay = ldelay; + rcReceivedProtocol = prot; + } + + return (code != 0); +} + + + +void handleInterrupt() { + + static unsigned int duration; + static unsigned int changeCount; + static unsigned long lastTime; + static unsigned int repeatCount; + + + long thistime = micros(); + duration = thistime - lastTime; + + if (duration > 5000 && duration > timings[0] - 200 && duration < timings[0] + 200) { + repeatCount++; + changeCount--; + if (repeatCount == 2) { + if (receiveProtocol(TYPE_A, changeCount) == false) { + if (receiveProtocol(TYPE_B, changeCount) == false) { + if (receiveProtocol(TYPE_C, changeCount) == false) { + if (receiveProtocol(TYPE_D, changeCount) == false) { + //failed + } + } + } + } + repeatCount = 0; + } + changeCount = 0; + } else if (duration > 5000) { + changeCount = 0; + } + + if (changeCount >= RCSWITCH_MAX_CHANGES) { + changeCount = 0; + repeatCount = 0; + } + timings[changeCount++] = duration; + lastTime = thistime; +} + + + +/* + * Turns a decimal value to its binary representation + */ +char *dec2binWzerofill(unsigned long Dec, unsigned int bitLength) +{ + return dec2binWcharfill(Dec, bitLength, '0'); +} + +char *dec2binWcharfill(unsigned long Dec, unsigned int bitLength, char fill) +{ + static char bin[64]; + unsigned int i = 0, j; + + while (Dec > 0) { + bin[32+i++] = ((Dec & 1) > 0) ? '1' : fill; + Dec = Dec >> 1; + } + + for (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; +} + + +void saveProtocol(int prot) +{ + backupProtocol = rcProtocol; + backupPulseLength = rcPulseLength; + backupRepeatTransmit = rcRepeatTransmit; + + setProtocol(prot); +} + + + +void loadProtocol(void) +{ + rcProtocol = backupProtocol; + rcPulseLength = backupPulseLength; + rcRepeatTransmit = backupRepeatTransmit; +} + + +#endif +