Program for decoding radio-signals sent by a ETH-Window-Shutter-Contact, received with a RFM12B-module. The messages are sent to KNX via a freebus rs-interface. Details see http://mbed.org/users/charly/notebook/connecting-a-radio-window-shutter-contact-to-knx/
Dependencies: TextLCD mbed ConfigFile
Diff: eth_comfort.cpp
- Revision:
- 0:b79cb3278583
diff -r 000000000000 -r b79cb3278583 eth_comfort.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eth_comfort.cpp Wed Apr 27 19:02:00 2011 +0000 @@ -0,0 +1,294 @@ +/** module for receiving data from eth comfort window sensor by ELV(R) with a RFM12 transceiver module by Hope + + Details see discussion on http://www.mikrocontroller.net/topic/172034 + Frequenz 868,3 + Modulation FSK + Hub +/- 15kHz + Datenrate 10kbit Manchester + + das Protokoll ist Machester codiert + 0x7e zz ll aa aa aa cmd crc crc + + zz ist ein fortlaufender Zaehler + ll die Blocklaenge 10,20,30 (20 = 9 Byte, 10= 10Byte ,30= ?) + aa 3 Byte Adresse + cmd der Befehl + crc 16 bit checksumme + + die Reihenfolge der Bits im Byte ist verdreht. + +*/ +/*! + * \file eth_comfort.cpp + * \brief Read the messages from the ETH-Radio-Shutter + * \author Karl Zweimüller based on code from WED 6.9.2009 + */ + + +#include "eth_comfort.h" + +/* orig AVR-values +#define BIT_MAX 0x90 +#define BIT_MIN 0x10 +#define LEN_2T 0x44 +*/ + +//working: 300-80-200 +// nominal values are: 208-104-208 for 9600 bits/sec +#define BIT_MAX 300 // maximum allowed time for one or two bits high or low +#define BIT_MIN 80 // minimum allowed time for one or two bits high or low +#define LEN_2T 200 // time-value to differentiate one or two bit length + + +// Timer for bit-length-measurement +Timer BitTime; + + +eth_comfort::eth_comfort(PinName mosi, PinName miso, PinName sclk, PinName nsel, PinName rxdata, PinName rxled) { + + rfm12b_spi = new rfm12b(mosi,miso,sclk,nsel,rxdata); + + // the ReceiveLED + rxLED = new DigitalOut(rxled); + + // init the eth_receiver + init(); + + // Interrupt on every bit-change + rfm12b_spi->attachISR(this, ð_comfort::ISR); + + // Init the RFM12B + rfm12b_spi->RFM_init(); + +}; +//------------------------------------------------------------------------- +// calcCRC16r() +//------------------------------------------------------------------------- +/** + * @brief calculate reverse CRC + * @param c 16bit value for crc + * @param crc old crc value + * @param mask crc polynom + * @return crc value + */ +uint16_t eth_comfort::calcCRC16r( uint16_t c,uint16_t crc, uint16_t mask) { // reverse crc!!!!!! + uint8_t i; + for (i=0;i<8;i++) { + if ((crc ^ c) & 1) { + crc=(crc>>1)^mask; + } else crc>>=1; + c>>=1; + }; + return(crc); +} + +// initialize eth_receiver +void eth_comfort::init() { + + rbyte=0; + bit_cnt=0; + buffer_cnt=0; + decode=0; + pack_ok=0; + + // start timer for bit-length-measurement + BitTime.start(); + message_received = false; + // init the buffer + last_message.cnt = 0; + last_message.len = 0; + last_message.adr = 0; + last_message.cmd = 0; + last_message.data = 0; + last_message.xdata = 0; + last_message.crc = 0; + + new_message = last_message; +} + + +// is a new message readable +bool eth_comfort::readable() { + return(message_received); +} + +// read a eth-messsage +eth_message eth_comfort::getMessage() { + if (readable()) { + last_message = new_message; + message_received = false; + return(new_message); + } else + // we should return nothing here! + return(last_message); +} + +/** ISR Interrupt routine for received data + * triggers on every pin change high/low and low/high + * does all the encoding of the signal including manchester decoding! + * as the eth doesn't send a good signal, which the rfm12 could decode for himself + * didn't test for myself - just got the code from someone else and ported to mbed! +*/ +void eth_comfort::ISR() { // pin change on rxin ->interrupt + //led2=!led2; + b=BitTime.read_us(); // time since last change + BitTime.reset(); + + if ((b>BIT_MAX)||(b<BIT_MIN)) { // is bit time in range? + state=0; + } else { + + + if (state==0) { // wait for first bitchange 2T + if (b>LEN_2T)state=1; + //if((rxin)!=0)state=0; // level should be low + } else if (state<=10) { // wait for 5 fullbit without bitchange 10 shortbits + if (b<LEN_2T)state++; + else state=1; // bitchange found back to state 1 + } else if (state==11) { // now expecting bitchange (last bit in 7e is 0) + if (b<LEN_2T) { + state=0; // no bitchange -> back to search + }; + state=20; // now we found 7e sync finished + rbyte=0x7e; // set shift value to 0 + bit_cnt=8; // clear bitcounter + buffer_cnt=0; // clear buffercounter + bcnt=0; + lastbit=0; + + } else if (state==20) { + if (b>LEN_2T) { // check for bitchange + if (lastbit!=0) { + rbyte=(rbyte>>1); // last bit was 1 new is 0 + bcnt=0; + lastbit=0; + } else { + rbyte=(rbyte>>1)|0x80; // last bit was 0 new is 1 + bcnt++; + lastbit=1; + } + state=20; // fullbit compleate + bit_cnt++; // increase bit counter + } else { + state=21; // bit is halfbit, wait for next halfbit + }; + } else if (state==21) { // no bitchange + if (b<LEN_2T) { // next bit must be a halfbit + if (lastbit==0) { + rbyte=(rbyte>>1); // last bit was 0 new is 0 + lastbit=0; + bcnt=0; + } else { + rbyte=(rbyte>>1)|0x80; // last bit was 1 new is 1 + lastbit=1; + bcnt++; + } + state=20; + bit_cnt++; + } else { + state=0; // bit is no halfbit -> Manchester violation + // state=20; + }; + } else if (state==22) { // after 5 bit 1 skip one bit 0 + if (b>LEN_2T) { // check for bitchange (next bit 0) + lastbit=0; + state=20; + } else { + + lastbit=1; + //state=11; + state=21; + } + bcnt=0; + + + } + if (bcnt==5)state=22; + + if (bit_cnt>7) { // wait for 8 bits + buf[buffer_cnt]=rbyte; // save value into buffer + if (buffer_cnt<1020) { + buffer_cnt++; + }; + pack_ok=1; // set receiveflag + bit_cnt=0; // clear bitcounter + *rxLED = ! *rxLED; //show received byte + ////////////////////////////////////////////////////////////////////////////////////////////////////////// + //here we received another byte + + // we have to check if we are ready with the message + if (buffer_cnt>8) { + if (buf[2]==0x10) blocklength=10; + else if (buf[2]==0x20) blocklength=9; + else blocklength=99; + j=0; + crc_ok = false; + for (i=0;i<=buffer_cnt;i++) { + //pc.printf("%02X ",buf[i]); + j++; + if (j==blocklength) { + //check crc + if (blocklength==9) { + crc=0xbdb7; + for (k=0;k<7;k++) { // crc over first 7 byte + crc=calcCRC16r(buf[k],crc,0x8408); + } + //swap the two crc-bytes + swapped = ((crc >> 8) & 0xff) | ((crc << 8) & 0xff00); + //pc.printf("CRC: %04X ",swapped); + if (((buf[7]<<8) | buf[8]) == swapped) crc_ok = true; + else crc_ok = false; + //pc.printf("%s", (crc_ok==true) ? "OK" : "Not OK"); + if (crc_ok) { + /* + pc.printf("\n\rCounter: %02X\n\r",buf[1]); + pc.printf( " Dev-ID: %02X %02X %02X\n\r",buf[3],buf[4],buf[5]); + //pc.printf( "Battery: %s\n\r", (buf[6]&0x80 != 0x00) ? "WEAK" : "GOOD"); + pc.printf( "Window : %s\n\r\n\r", (buf[6]&0x01 != 0x00) ? "OPEN" : "CLOSE"); + lcd.cls(); + lcd.printf("#:%02X ID: %02X%02X%02X\n",buf[1],buf[3],buf[4],buf[5]); + lcd.printf("Window : %s\n", (buf[6]&0x01 != 0x00) ? "OPEN" : "CLOSE"); + */ + + // insert buf into message + new_message.cnt = buf[1]; + new_message.len = buf[2]; + new_message.adr = buf[3]<<16 | buf[4]<<8 | buf[5]; + new_message.cmd = buf[6]; + new_message.data = buf[7]; + new_message.xdata = 0; + new_message.crc = swapped; + + //is the new message different from the old message? + // or is another sender on air? + if ((new_message.cnt != last_message.cnt) || (new_message.adr != last_message.adr)) { + last_message = new_message; + message_received = true; + } + + } //crc_ok + } //block_length = 9 + } //j==blocklength + } //for + + + //start receive from beginning + buffer_cnt=0; + bit_cnt=0; + startbit=0; + state=0; + //pc.printf("\n\r-----------------------------\n\r"); + //clear the buffer + for (i=0;i<1023;i++)buf[i]=0; + *rxLED = 0; //turn off receive led + } //buffer_cnt >8 + ////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + } + } + +} + + + +