thermferm/rc-switch.c

changeset 51
a03b6dac5398
--- /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 <mbroek at mbse dot eu>
+ *
+ * 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; 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 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<changeCount ; i=i+2) {
+      
+	if (timings[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
+

mercurial