Programm for decoding radio-signals sent by a ETH-Window-Shutter-Contact, received with a RFM12B-module

Dependencies:   TextLCD mbed

eth_comfort.cpp

Committer:
charly
Date:
2011-04-07
Revision:
1:fc72e0bdb693
Parent:
0:96794c9fc5a3

File content as of revision 1:fc72e0bdb693:

/** 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, &eth_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?
                                if (new_message.cnt != last_message.cnt) {
                                    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
            //////////////////////////////////////////////////////////////////////////////////////////////////////////
            //
        }
    }

}