Go Down

Topic: Wireless doorbell (Read 4 times) previous topic - next topic

Lectere

// The basic idea is to measure pulse widths between 0/1 and 1/0 transitions,
// and to keep track of pulse width sequences in a state machine.

// can't just change these pin definitions, PIN_868 uses interrupts
#define PIN_868 14  // the 868 MHz receiver is connected to AIO1

enum { UNKNOWN, T0, T1, T2, T3, OK, DONE };

// track bit-by-bit reception using multiple independent state machines
struct { char bits; byte state; uint32_t prev; uint64_t data; } FS20;
struct { char bits; byte state, pos, data[16]; } S300;
struct { char bits; byte state, pos, seq; word data[10]; } EM10;
struct { byte state; char bits; uint32_t prev; word data; } KAKU;

static byte FS20_bit (char value) {
   FS20.data = (FS20.data << 1) | value;
   if (FS20.bits < 0 && (byte) FS20.data != 0x01)
       return OK;
   if (++FS20.bits == 45 && ((FS20.data >> 15) & 1) == 0 ||
         FS20.bits == 54 && ((FS20.data >> 24) & 1))
       return DONE;
   return OK;
}

static byte S300_bit (char value) {
   byte *ptr = S300.data + S300.pos;
   *ptr = (*ptr >> 1) | (value << 4);
   
   if (S300.bits < 0 && *ptr != 0x10)
       return OK; // not yet synchronized

   if (++S300.bits == 4) {
       if (S300.pos >= 9 && S300.data[0] == 0x11 || S300.pos >= 15) {
           *ptr >>= 1;
           return DONE;
       }
   } else if (S300.bits >= 5) {
       ++S300.pos;
       S300.bits = 0;
   }

   return OK;
}

static byte EM10_bit (char value) {
   word *ptr = EM10.data + EM10.pos;
   *ptr = (*ptr >> 1) | (value << 8);
   
   if (EM10.bits < 0 && *ptr != 0x100)
       return OK; // not yet synchronized

   if (++EM10.bits == 8) {
       if (EM10.pos >= 9) {
           *ptr >>= 1;
           return DONE;
       }
   } else if (EM10.bits >= 9) {
       ++EM10.pos;
       EM10.bits = 0;
   }

   return OK;
}

static void ook868interrupt () {
   // count is the pulse length in units of 4 usecs
   byte count = TCNT2;
   TCNT2 = 0;

   // FS20 pulse widths are 400 and 600 usec (split on 300, 500, and 700)
   // see http://fhz4linux.info/tiki-index.php?page=FS20%20Protocol
   if (FS20.state != DONE)
       switch ((count - 25) / 50) {
           case 1:  FS20.state = FS20.state == T0 ? FS20_bit(0) : T0; break;
           case 2:  FS20.state = FS20.state == T1 ? FS20_bit(1) : T1; break;
           default: FS20.state = UNKNOWN;
       }

   // (K)S300 pulse widths are 400 and 800 usec (split on 200, 600, and 1000)
   // see http://www.dc3yc.homepage.t-online.de/protocol.htm
   if (S300.state != DONE)
       switch ((count + 50) / 100) {
           case 1:  S300.state = S300.state == T1 ? S300_bit(0) : T0; break;
           case 2:  S300.state = S300.state == T0 ? S300_bit(1) : T1; break;
           default: S300.state = UNKNOWN;
       }

   // EM10 pulse widths are 400 and 800 usec (split on 200, 600, and 1000)
   // see http://fhz4linux.info/tiki-index.php?page=EM+Protocol
   if (EM10.state != DONE) {
       switch ((count + 50) / 100) {
           case 1:  EM10.state = EM10.state == T0 ? EM10_bit(0) : T0; break;
           case 2:  if (EM10.state == T0) {
                       EM10.state = EM10_bit(1);
                       break;
                    } // else fall through
           default: EM10.state = UNKNOWN;
       }
   }
}

static void reset_FS20 () {
   FS20.bits = -1;
   FS20.data = 0xFF;
   FS20.state = UNKNOWN;
}

static void reset_S300 () {
   S300.bits = -1;
   S300.pos = 0;
   S300.data[0] = 0x1F;
   S300.state = UNKNOWN;
}

static void reset_EM10 () {
   EM10.bits = -1;
   EM10.pos = 0;
   EM10.data[0] = 0x1FF;
   EM10.state = UNKNOWN;
}

static void ook868timeout () {
   if (FS20.state != DONE)
       reset_FS20();
   if (S300.state != DONE)
       reset_S300();
   if (EM10.state != DONE)
       reset_EM10();
}

static void ook868setup () {
   pinMode(PIN_868, INPUT);
   digitalWrite(PIN_868, 1); // pull-up

   // enable pin change interrupts on PC0
   PCMSK1 = bit(0);
   PCICR |= bit(PCIE1);

   /* prescaler 64 -> 250 KHz = 4 usec/count, max 1.024 msec (16 MHz clock) */
   TCNT2 = 0;
   TCCR2A = 0;
   TCCR2B = _BV(CS22);
   TIMSK2 = _BV(TOIE2);
   
   reset_FS20();
   reset_S300();
   reset_EM10();
}

// Poll and return a count > 0 when a valid packet has been received:
//  4 = S300
//  5 = FS20
//  6 = FS20 extended
//  7 = KS300
//  9 = EM10*

static byte ook868poll (byte* buf) {
   if (FS20.state == DONE) {  
       byte len = FS20.bits / 9;
       byte sum = 6;
       for (byte i = 0; i < len; ++i) {
           byte b = FS20.data >> (1 + 9 * i);
           buf[len-i-1] = b;
           if (i > 0)
               sum += b;
       }
       if (sum == buf[len-1]) {
           uint32_t since = millis() - FS20.prev;
           FS20.prev = millis();
           reset_FS20();
           if (since > 150)
               return len;
       }
       
       reset_FS20();
   }
 
   if (S300.state == DONE) {    
       byte n = S300.pos, ones = 0, sum = 37 - S300.data[n], chk = 0;
       for (byte i = 0; i < n; ++i) {
           byte b = S300.data;
           ones += b >> 4;
           sum += b;
           chk ^= b;
           
           if (i & 1)
               buf[i>>1] |= b << 4;
           else
               buf[i>>1] = b & 0x0F;
       }
       
       reset_S300();
       
       if (ones == n && (chk & 0x0F) == 0 && (sum & 0x0F) == 0)
           return n >> 1;
   }
 
   if (EM10.state == DONE) {    
       if ((byte) EM10.data[2] != EM10.seq) {
           byte ones = 0, chk = 0;
           for (byte i = 0; i < 10; ++i) {
               word v = EM10.data;
               ones += v >> 8;
               chk ^= v;
               buf = v;
           }
           
           if (ones == 9 && chk == 0) {
               EM10.seq = EM10.data[2];
               reset_EM10();
               return 9;
           }
       }
       
       reset_EM10();
   }
   
   return 0;
}

ISR(TIMER2_OVF_vect)    { ook868timeout(); }
ISR(PCINT1_vect)        { ook868interrupt(); }

void setup () {
   Serial.begin(57600);
   Serial.println("[TempHumid]\n");
   ook868setup();
}

void loop () {
   byte buf[10];
   byte len = ook868poll(buf);
       
       Serial.print("Packet:");
       for (byte i = 0; i < len; ++i) {
           Serial.print(' ');
           Serial.print(buf, DEC);
       }
       Serial.println();

   }
}

Lectere


Ive done a similar project a while back, and I had to take the doorbell apart and make an antenna....You might want to try that. If its too delicate, then don't bother... :D


You also had the FS20 TK?

Zack_Johnston

#7
Nov 12, 2012, 12:39 am Last Edit: Nov 12, 2012, 12:41 am by Zack_Johnston Reason: 1
I can't find anything wrong with the code. :(

You might want to secure all of your connections. You have probably already done this...

Try looking into the doorbell to see if anything is wrong with it.

No I haven't had the FS20 TK but I tried making a wireless doorbell.

Lectere


I can't find anything wrong with the code. :(

You might want to secure all of your connections. You have probably already done this...

Try looking into the doorbell to see if anything is wrong with it.


Secure connections? what do you mean?

I'm going for new batteries tomorrow...

But still, for a protocol which should be able to do 400 meters, strange that it won't do more than 30 cm...

Zack_Johnston

#9
Nov 12, 2012, 12:48 am Last Edit: Nov 12, 2012, 12:54 am by Zack_Johnston Reason: 1
Secure connections? what do you mean?

I'm going for new batteries tomorrow...

But still, for a protocol which should be able to do 400 meters, strange that it won't do more than 30 cm...
[/quote]

By secure connections, I mean check the wires in the Arduino and make sure they are connected and working. :)

Good idea for the batteries. A while ago you said that you were wondering if you should go for 3v or 5v. I think you should try five because the reception might strengthen and improve.

I agree. It should be able to reach farther than 30 cm....:(

Go Up