// Oregon V2 decoder modfied - Olivier Lebrun // Oregon V2 decoder added - Dominique Pierre // New code to decode OOK signals from weather sensors, etc. // 2010-04-11 http://opensource.org/licenses/mit-license.php // $Id: ookDecoder.pde 5331 2010-04-17 10:45:17Z jcw $ class DecodeOOK { protected: byte total_bits, bits, flip, state, pos, data[25]; virtual char decode (word width) =0; public: enum { UNKNOWN, T0, T1, T2, T3, OK, DONE }; DecodeOOK () { resetDecoder(); } bool nextPulse (word width) { if (state != DONE) switch (decode(width)) { case -1: resetDecoder(); break; case 1: done(); break; } return isDone(); } bool isDone () const { return state == DONE; } const byte* getData (byte& count) const { count = pos; return data; } void resetDecoder () { total_bits = bits = pos = flip = 0; state = UNKNOWN; } // add one bit to the packet data buffer virtual void gotBit (char value) { if(!(total_bits & 0x01)) { data[pos] = (data[pos] >> 1) | (value ? 0x80 : 00); } total_bits++; pos = total_bits >> 4; if(pos == 2) { // Taille de trame par défaut (utilisée dans la majorité des sondes) int max_bits = 160; // Exceptions : if(data[0] == 0xEA) { if(data[1] == 0x4C) max_bits = 136; // TH132N : 68 * 2 else if(data[1] == 0x7C) max_bits = 240; // UV138 : 120 * 2 } else if(data[0] == 0x5A) { if(data[1] == 0x5D) max_bits = 176; // THGR918 : 88 * 2 else if(data[1] == 0x6D)max_bits = 192; // BTHR918N : 96 * 2 } else if(data[0] == 0x1A && data[1] == 0x99) max_bits = 176; // WTGR800 : 88 * 2 else if(data[0] == 0xDA && data[1] == 0x78) max_bits = 144; // UVN800 : 72 * 2 else if((data[0] == 0x8A || data[0] == 0x9A) && data[1] == 0xEC) max_bits = 208; // RTGR328N 104 * 2 else if(data[0] == 0x2A) { if(data[1] == 0x19) max_bits = 184; // RCR800 : 92 * 2 else if(data[1] == 0x1d) max_bits = 168; // WGR918 : 84 * 2 } } if (pos >= sizeof data) { Serial.println("sizeof data"); resetDecoder(); return; } state = OK; } // store a bit using Manchester encoding void manchester (char value) { flip ^= value; // manchester code, long pulse flips the bit gotBit(flip); } // move bits to the front so that all the bits are aligned to the end void alignTail (byte max =0) { // align bits if (bits != 0) { data[pos] >>= 8 - bits; for (byte i = 0; i < pos; ++i) data[i] = (data[i] >> bits) | (data[i+1] << (8 - bits)); bits = 0; } // optionally shift bytes down if there are too many of 'em if (max > 0 && pos > max) { byte n = pos - max; pos = max; for (byte i = 0; i < pos; ++i) data[i] = data[i+n]; } } void reverseBits () { for (byte i = 0; i < pos; ++i) { byte b = data[i]; for (byte j = 0; j < 8; ++j) { data[i] = (data[i] << 1) | (b & 1); b >>= 1; } } } void reverseNibbles () { for (byte i = 0; i < pos; ++i) data[i] = (data[i] << 4) | (data[i] >> 4); } void done () { while (bits) gotBit(0); // padding state = DONE; } }; class OregonDecoderV2 : public DecodeOOK { public: OregonDecoderV2() {} // add one bit to the packet data buffer virtual void gotBit (char value) { if(!(total_bits & 0x01)) { data[pos] = (data[pos] >> 1) | (value ? 0x80 : 00); } total_bits++; pos = total_bits >> 4; if (pos >= sizeof data) { Serial.println("sizeof data"); resetDecoder(); return; } state = OK; } virtual char decode (word width) { if (200 <= width && width < 1200) { //Serial.println(width); byte w = width >= 700; switch (state) { case UNKNOWN: if (w != 0) { // Long pulse ++flip; } else if (w == 0 && 24 <= flip) { // Short pulse, start bit flip = 0; state = T0; } else { // Reset decoder return -1; } break; case OK: if (w == 0) { // Short pulse state = T0; } else { // Long pulse manchester(1); } break; case T0: if (w == 0) { // Second short pulse manchester(0); } else { // Reset decoder return -1; } break; } } else if (width >= 2500 && pos >= 8) { return 1; } else { return -1; } return 0; } }; OregonDecoderV2 orscV2; volatile word pulse; void ext_int_1(void) { static word last; // determine the pulse length in microseconds, for either polarity pulse = micros() - last; last += pulse; } void reportSerial (const char* s, class DecodeOOK& decoder) { byte pos; const byte* data = decoder.getData(pos); Serial.print(s); Serial.print(' '); for (byte i = 0; i < pos; ++i) { Serial.print(data[i] >> 4, HEX); Serial.print(data[i] & 0x0F, HEX); } Serial.println(); decoder.resetDecoder(); } void setup () { Serial.begin(115200); Serial.println("\n[ookDecoder]"); attachInterrupt(1, ext_int_1, CHANGE); //DDRE &= ~_BV(PE5); //input with pull-up //PORTE &= ~_BV(PE5); } void loop () { static int i = 0; cli(); word p = pulse; pulse = 0; sei(); if (p != 0) { if (orscV2.nextPulse(p)) reportSerial("OSV2", orscV2); } }