255 lines
6.5 KiB
C++
Executable File
255 lines
6.5 KiB
C++
Executable File
// 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 <jcw@equi4.com> 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);
|
|
}
|
|
}
|