// 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 Mein Sensorprotokoll
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();
}
}*_