thermferm/rc-switch.c

Sat, 25 Apr 2020 20:31:31 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Sat, 25 Apr 2020 20:31:31 +0200
changeset 605
e00f8ff4de9a
parent 213
2317b8d644fa
child 652
16d3d4b58b5b
permissions
-rw-r--r--

Version 0.9.8. Added extra path to the fonts for Debian buster. Changed the PID to work on Proportional on Measurement. Added loops so that it looks like the PID is running at 100 mSec intervals.

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