thermferm/rc-switch.c

Wed, 12 May 2021 21:17:59 +0200

author
Michiel Broek
date
Wed, 12 May 2021 21:17:59 +0200
changeset 611
732d482f47c8
parent 213
2317b8d644fa
child 652
16d3d4b58b5b
permissions
-rw-r--r--

Improved logging if wiringpi failed.

/*****************************************************************************
 * 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 ThermFerm; 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"
#include "xutil.h"
#include "rc-switch.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 int 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*, int);
char *getCodeWordB(int, int, int);
char *getCodeWordC(char, int, int, int);

char *getCodeWordE(char, int, int);
void sendTriState(char*);
void transmit(int, int, int);
void send0(void);
void send1(void);
void sendT0(void);
void sendT1(void);
void sendTF(void);
void sendSync(void);
int  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, int 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, int 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, int 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, int 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, int 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, int 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, int 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, int 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, int 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 transmit(int nFirstPulses, int nSecondPulses, int bHighFirst)
{
    int		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 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]);
}



/*
 * 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]);
}



/*
 * 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]);
}



/*
 * 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;
}



int 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
 */
int 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