rflink_old/Plugins/Plugin_006.c

288 lines
13 KiB
C

//#######################################################################################################
//## This Plugin is only for use with the RFLink software package ##
//## Plugin-006 Blyss & Avidsen ##
//#######################################################################################################
/*********************************************************************************************\
* This Plugin takes care of receiving of the Blyss protocol
*
* Author : StuntTeam
* Support : http://sourceforge.net/projects/rflink/
* License : This code is free for use in any open source project when this header is included.
* Usage of any parts of this code in a commercial application is prohibited!
*********************************************************************************************
* Changelog: v1.0 initial release
*********************************************************************************************
* Technical information:
* RF packets contain 106 pulses, 52 bits
*
* BLYSS Message Format:
* AAAAAAAA BBBBCCCC CCCCCCCC CCCCDDDD | EEEEFFFF FFFFGGGG GGGG
*
* A = Preamble, always 0xFE (0x32 in case of Avidsen)
* B = Global Channel (A=0,B=1,C=2,D=3)
* C = Address
* D = sub channel (channel 1=8, 2=4, 3=2, 4=1, 5=3) all channels = 0
* E = Light Status
* F = Rolling Code (0x98 -> 0xDA -> 0x1E -> 0xE6 -> 0x67)
* G = Time Stamp (random value?)
*
* Details https://skyduino.wordpress.com/2012/07/19/hack-partie-2-reverse-engineering-des-interrupteurs-domotique-blyss/
* https://barbudor.wiki.zoho.com/Système-domotique-Blyss-de-Castorama.html
*
* BlyssSend address,switch,cmd; => (16 bits,8 bits,on/off/allon/alloff)
* 20;0B;DEBUG;Pulses=106;Pulses(uSec)=2160,450,570,420,600,420,600,450,570,420,600,420,600,450,570,810,210,870,150,840,180,840,180,840,180,420,600,420,600,420,600,450,570,420,600,420,600,420,600,420,600,420,600,840,180,840,210,450,570,450,600,810,180,840,180,840,180,420,600,810,210,840,180,810,210,810,210,870,180,810,210,450,570,450,570,840,180,840,210,450,570,420,600,840,180,810,210,840,180,840,210,840,180,840,180,810,210,840,210,420,600,810,210,420,600,6990;
* 20;0C;Blyss;ID=ff98;SWITCH=A1;CMD=OFF;
\*********************************************************************************************/
#define BLYSS_PULSECOUNT 106
#define BLYSS_PULSEMID 500/RAWSIGNAL_SAMPLE_RATE
#ifdef PLUGIN_006
boolean Plugin_006(byte function, char *string) {
if (RawSignal.Number != BLYSS_PULSECOUNT) return false;
unsigned long bitstream=0L;
unsigned long bitstream1=0L;
byte bitcounter=0;
byte checksum=0;
int type=0;
//==================================================================================
// get bits
for(byte x=2;x < BLYSS_PULSECOUNT;x=x+2) {
if (RawSignal.Pulses[x] > BLYSS_PULSEMID) {
if (bitcounter < 32) {
bitstream = (bitstream << 1);
} else {
bitstream1 = (bitstream1 << 1);
}
bitcounter++;
} else {
if (bitcounter < 32) {
bitstream = (bitstream << 1) | 0x1;
} else {
bitstream1 = (bitstream1 << 1) | 0x1;
}
bitcounter++;
}
}
//==================================================================================
// all bits received, make sure checksum is okay
//==================================================================================
checksum=((bitstream) >> 24); // test preamble
if ((checksum != 0xFE) && (checksum != 0x32) ) return false; // must be 0xFE/32
if (checksum == 0x32) type=1;
//==================================================================================
// Prevent repeating signals from showing up
//==================================================================================
if(SignalHash!=SignalHashPrevious || RepeatingTimer<millis()) {
// not seen the RF packet recently
} else {
// already seen the RF packet recently
return true;
}
//==================================================================================
byte status=((bitstream1) >> 16) &0x0f;
if (status > 3) return false;
byte channel=((bitstream) >> 20) &0x0f;
unsigned int address=((bitstream) >> 4) &0xffff;
byte subchan=(bitstream) &0xf;
channel=channel+0x41;
if (subchan==8) {
subchan=1;
} else
if (subchan==4) {
subchan=2;
} else
if (subchan==2) {
subchan=3;
} else
if (subchan==1) {
subchan=4;
} else
if (subchan==3) {
subchan=5;
}
//==================================================================================
// Output
// ----------------------------------
sprintf(pbuffer, "20;%02X;", PKSequenceNumber++);// Node and packet number
Serial.print( pbuffer );
// ----------------------------------
if (type == 0) {
Serial.print(F("Blyss;")); // Label
} else {
Serial.print(F("Avidsen;")); // Label
}
sprintf(pbuffer, "ID=%04x;", address); // ID
Serial.print( pbuffer );
sprintf(pbuffer, "SWITCH=%c%d;", channel,subchan);
Serial.print( pbuffer );
Serial.print(F("CMD=")); // command
if (status==0) Serial.print(F("ON;"));
if (status==1) Serial.print(F("OFF;"));
if (status==2) Serial.print(F("ALLON;"));
if (status==3) Serial.print(F("ALLOFF;"));
Serial.println();
//==================================================================================
RawSignal.Repeats=true; // suppress repeats of the same RF packet
RawSignal.Number=0;
return true;
}
#endif // PLUGIN_006
#ifdef PLUGIN_TX_006
void Blyss_Send(unsigned long address, byte devtype);
boolean PluginTX_006(byte function, char *string) {
boolean success=false;
//10;Avidsen;00ff98;A1;OFF;
//012345678901234567890123456
//10;Blyss;00ff98;A1;OFF;
//012345678901234567890123456
int offset=0;
if (strncasecmp(InputBuffer_Serial+3,"AVIDSEN;",8) == 0) { // Blyss Command eg.
offset=2;
}
if ((strncasecmp(InputBuffer_Serial+3,"BLYSS;",6) == 0) || (offset==2)) { // Blyss Command eg.
unsigned long Bitstream = 0L;
if (InputBuffer_Serial[15+offset] != ';') return success; // check
if (InputBuffer_Serial[18+offset] != ';') return success; // check
unsigned long Home=0; // Blyss channel A..P
byte Address=0; // Blyss subchannel 1..5
byte c;
byte subchan=0; // subchannel
InputBuffer_Serial[7+offset]=0x30;
InputBuffer_Serial[8+offset]=0x78;
InputBuffer_Serial[15+offset]=0;
Bitstream=str2int(InputBuffer_Serial+7+offset); // get address
c=tolower(InputBuffer_Serial[16+offset]); // A..P
if(c>='a' && c<='p'){Home=c-'a';}
c=tolower(InputBuffer_Serial[17+offset]); // 1..5
if(c>='1' && c<='5'){Address=Address+c-'0';}
if (Address==1) subchan=0x80;
if (Address==2) subchan=0x40;
if (Address==3) subchan=0x20;
if (Address==4) subchan=0x10;
if (Address==5) subchan=0x30;
Home = Home << 24;
Bitstream=(Bitstream) << 8;
Bitstream=Bitstream+subchan;
Bitstream=Bitstream+Home;
c = str2cmd(InputBuffer_Serial+19+offset); // ALL ON/OFF command
if (c == VALUE_OFF) {
Bitstream=Bitstream|1;
} else {
if (c == VALUE_ALLOFF) {
Bitstream=Bitstream|3;
} else
if (c == VALUE_ALLON) {
Bitstream=Bitstream|2;
}
}
Blyss_Send(Bitstream, offset); // Bitstream contains the middle part of the bitstream to send
success=true;
}
return success;
}
void Blyss_Send(unsigned long address, byte devtype) {
int fpulse = 400; // Pulse witdh in microseconds
int fretrans = 8; // Number of code retransmissions
uint32_t fdatabit;
uint32_t fdatamask = 0x800000;
uint32_t fsendbuff;
unsigned char RollingCode[] = { 0x98, 0xDA, 0x1E, 0xE6, 0x67, 0x98};
digitalWrite(PIN_RF_RX_VCC,LOW); // Power off the RF receiver
digitalWrite(PIN_RF_TX_VCC,HIGH); // Turn on the RF transmitter
delayMicroseconds(TRANSMITTER_STABLE_DELAY); // short delay to let the transmitter become stable (Note: Aurel RTX MID needs 500µS/0,5ms)
byte temp=(millis() &0xff); // used for the timestamp at the end of the RF packet
for (int nRepeat = 0; nRepeat <= fretrans; nRepeat++) {
// send SYNC 1P low, 6P high
digitalWrite(PIN_RF_TX_DATA, LOW);
delayMicroseconds(fpulse);
digitalWrite(PIN_RF_TX_DATA, HIGH);
delayMicroseconds(fpulse * 6);
// end send SYNC
// --------------
// Send preamble (0xfe) - 8 bits
if (devtype == 0) {
fsendbuff=0x32;
} else {
fsendbuff=0xfe;
}
fdatamask=0x80;
for (int i = 0; i < 8; i++) { // Preamble
// read data bit
fdatabit = fsendbuff & fdatamask; // Get most left bit
fsendbuff = (fsendbuff << 1); // Shift left
if (fdatabit != fdatamask) { // Write 0
digitalWrite(PIN_RF_TX_DATA, LOW);
delayMicroseconds(fpulse * 2);
digitalWrite(PIN_RF_TX_DATA, HIGH);
delayMicroseconds(fpulse * 1);
} else { // Write 1
digitalWrite(PIN_RF_TX_DATA, LOW);
delayMicroseconds(fpulse * 1);
digitalWrite(PIN_RF_TX_DATA, HIGH);
delayMicroseconds(fpulse * 2);
}
}
// --------------
fsendbuff=address;
fdatamask=0x8000000;
// Send command (channel/address/status) - 28 bits
for (int i = 0; i < 28; i++) {
// read data bit
fdatabit = fsendbuff & fdatamask; // Get most left bit
fsendbuff = (fsendbuff << 1); // Shift left
if (fdatabit != fdatamask) { // Write 0
digitalWrite(PIN_RF_TX_DATA, LOW);
delayMicroseconds(fpulse * 2);
digitalWrite(PIN_RF_TX_DATA, HIGH);
delayMicroseconds(fpulse * 1);
} else { // Write 1
digitalWrite(PIN_RF_TX_DATA, LOW);
delayMicroseconds(fpulse * 1);
digitalWrite(PIN_RF_TX_DATA, HIGH);
delayMicroseconds(fpulse * 2);
}
}
// --------------
// Send rolling code & timestamp - 16 bits
fsendbuff=RollingCode[nRepeat];
fsendbuff=(fsendbuff<<8)+temp;
//fsendbuff=0x9800 + temp;
fdatamask=0x8000;
for (int i = 0; i < 16; i++) {
// read data bit
fdatabit = fsendbuff & fdatamask; // Get most left bit
fsendbuff = (fsendbuff << 1); // Shift left
if (fdatabit != fdatamask) { // Write 0
digitalWrite(PIN_RF_TX_DATA, LOW);
delayMicroseconds(fpulse * 2);
digitalWrite(PIN_RF_TX_DATA, HIGH);
delayMicroseconds(fpulse * 1);
} else { // Write 1
digitalWrite(PIN_RF_TX_DATA, LOW);
delayMicroseconds(fpulse * 1);
digitalWrite(PIN_RF_TX_DATA, HIGH);
delayMicroseconds(fpulse * 2);
}
}
// --------------
digitalWrite(PIN_RF_TX_DATA, LOW);
//delayMicroseconds(fpulse * 18); // delay between RF retransmits
delay(24); // delay 23.8 ms
}
delayMicroseconds(TRANSMITTER_STABLE_DELAY); // short delay to let the transmitter become stable (Note: Aurel RTX MID needs 500µS/0,5ms)
digitalWrite(PIN_RF_TX_VCC,LOW); // turn off the RF transmitter
digitalWrite(PIN_RF_RX_VCC,HIGH); // power on the RF receiver
RFLinkHW();
}
#endif // PLUGIN_TX_006