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
--- /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
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ }
+ }
+
+}
+
+
+
+