portapack-mayhem/firmware/baseband/fprotos/w-oregon2.hpp

249 lines
8.6 KiB
C++

#ifndef __FPROTO_OREGON2_H__
#define __FPROTO_OREGON2_H__
#include "weatherbase.hpp"
#define OREGON2_PREAMBLE_BITS 19
#define OREGON2_PREAMBLE_MASK 0b1111111111111111111
#define OREGON2_SENSOR_ID(d) (((d) >> 16) & 0xFFFF)
#define OREGON2_CHECKSUM_BITS 8
// 15 ones + 0101 (inverted A)
#define OREGON2_PREAMBLE 0b1111111111111110101
// bit indicating the low battery
#define OREGON2_FLAG_BAT_LOW 0x4
/// Documentation for Oregon Scientific protocols can be found here:
/// http://wmrx00.sourceforge.net/Arduino/OregonScientific-RF-Protocols.pdf
// Sensors ID
#define ID_THGR122N 0x1d20
#define ID_THGR968 0x1d30
#define ID_BTHR918 0x5d50
#define ID_BHTR968 0x5d60
#define ID_RGR968 0x2d10
#define ID_THR228N 0xec40
#define ID_THN132N 0xec40 // same as THR228N but different packet size
#define ID_RTGN318 0x0cc3 // warning: id is from 0x0cc3 and 0xfcc3
#define ID_RTGN129 0x0cc3 // same as RTGN318 but different packet size
#define ID_THGR810 0xf824 // This might be ID_THGR81, but what's true is lost in (git) history
#define ID_THGR810a 0xf8b4 // unconfirmed version
#define ID_THN802 0xc844
#define ID_PCR800 0x2914
#define ID_PCR800a 0x2d14 // Different PCR800 ID - AU version I think
#define ID_WGR800 0x1984
#define ID_WGR800a 0x1994 // unconfirmed version
#define ID_WGR968 0x3d00
#define ID_UV800 0xd874
#define ID_THN129 0xcc43 // THN129 Temp only
#define ID_RTHN129 0x0cd3 // RTHN129 Temp, clock sensors
#define ID_RTHN129_1 0x9cd3
#define ID_RTHN129_2 0xacd3
#define ID_RTHN129_3 0xbcd3
#define ID_RTHN129_4 0xccd3
#define ID_RTHN129_5 0xdcd3
#define ID_BTHGN129 0x5d53 // Baro, Temp, Hygro sensor
#define ID_UVR128 0xec70
#define ID_THGR328N 0xcc23 // Temp & Hygro sensor similar to THR228N with 5 channel instead of 3
#define ID_RTGR328N_1 0xdcc3 // RTGR328N_[1-5] RFclock(date &time)&Temp&Hygro sensor
#define ID_RTGR328N_2 0xccc3
#define ID_RTGR328N_3 0xbcc3
#define ID_RTGR328N_4 0xacc3
#define ID_RTGR328N_5 0x9cc3
#define ID_RTGR328N_6 0x8ce3 // RTGR328N_6&7 RFclock(date &time)&Temp&Hygro sensor like THGR328N
#define ID_RTGR328N_7 0x8ae3
typedef enum {
Oregon2DecoderStepReset = 0,
Oregon2DecoderStepFoundPreamble,
Oregon2DecoderStepVarData,
} Oregon2DecoderStep;
class FProtoWeatherOregon2 : public FProtoWeatherBase {
public:
FProtoWeatherOregon2() {
sensorType = FPW_OREGON2;
}
void feed(bool level, uint32_t duration) override {
// oregon v2.1 signal is inverted
ManchesterEvent event = level_and_duration_to_event(!level, duration);
bool data;
// low-level bit sequence decoding
if (event == ManchesterEventReset) {
parser_step = Oregon2DecoderStepReset;
have_bit = false;
decode_data = 0UL;
decode_count_bit = 0;
}
if (FProtoGeneral::manchester_advance(manchester_saved_state, event, &manchester_saved_state, &data)) {
if (have_bit) {
if (!prev_bit && data) {
subghz_protocol_blocks_add_bit(1);
} else if (prev_bit && !data) {
subghz_protocol_blocks_add_bit(0);
} else {
ws_protocol_decoder_oregon2_reset();
}
have_bit = false;
} else {
prev_bit = data;
have_bit = true;
}
}
switch (parser_step) {
case Oregon2DecoderStepReset:
// waiting for fixed oregon2 preamble
if (decode_count_bit >= OREGON2_PREAMBLE_BITS &&
((decode_data & OREGON2_PREAMBLE_MASK) == OREGON2_PREAMBLE)) {
parser_step = Oregon2DecoderStepFoundPreamble;
decode_count_bit = 0;
decode_data = 0UL;
}
break;
case Oregon2DecoderStepFoundPreamble:
// waiting for fixed oregon2 data
if (decode_count_bit == 32) {
data = decode_data;
data_count_bit = decode_count_bit;
decode_data = 0UL;
decode_count_bit = 0;
// reverse nibbles in decoded data
data = (data & 0x55555555) << 1 |
(data & 0xAAAAAAAA) >> 1;
data = (data & 0x33333333) << 2 |
(data & 0xCCCCCCCC) >> 2;
ws_oregon2_decode_const_data();
var_bits =
oregon2_sensor_id_var_bits(OREGON2_SENSOR_ID(data));
if (!var_bits) {
// sensor is not supported, stop decoding, but showing the decoded fixed part
parser_step = Oregon2DecoderStepReset;
if (callback) callback(this);
} else {
parser_step = Oregon2DecoderStepVarData;
}
}
break;
case Oregon2DecoderStepVarData:
// waiting for variable (sensor-specific data)
if (decode_count_bit == (uint32_t)var_bits + OREGON2_CHECKSUM_BITS) {
var_data = decode_data & 0xFFFFFFFF;
// reverse nibbles in var data
var_data = (var_data & 0x55555555) << 1 |
(var_data & 0xAAAAAAAA) >> 1;
var_data = (var_data & 0x33333333) << 2 |
(var_data & 0xCCCCCCCC) >> 2;
ws_oregon2_decode_var_data(OREGON2_SENSOR_ID(data), var_data >> OREGON2_CHECKSUM_BITS);
parser_step = Oregon2DecoderStepReset;
if (callback) callback(this);
}
break;
}
}
protected:
// timing values
uint32_t te_short = 500;
uint32_t te_long = 1000;
uint32_t te_delta = 200;
uint32_t min_count_bit_for_found = 32;
bool have_bit = false;
bool prev_bit = 0;
uint8_t var_bits{0};
uint32_t var_data{0};
void ws_protocol_decoder_oregon2_reset() {
parser_step = Oregon2DecoderStepReset;
decode_data = 0UL;
decode_count_bit = 0;
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
have_bit = false;
var_data = 0;
var_bits = 0;
}
ManchesterEvent level_and_duration_to_event(bool level, uint32_t duration) {
bool is_long = false;
if (DURATION_DIFF(duration, te_long) < te_delta) {
is_long = true;
} else if (DURATION_DIFF(duration, te_short) < te_delta) {
is_long = false;
} else {
return ManchesterEventReset;
}
if (level)
return is_long ? ManchesterEventLongHigh : ManchesterEventShortHigh;
else
return is_long ? ManchesterEventLongLow : ManchesterEventShortLow;
}
uint8_t oregon2_sensor_id_var_bits(uint16_t sensor_id) {
switch (sensor_id) {
case ID_THR228N:
case ID_RTHN129_1:
case ID_RTHN129_2:
case ID_RTHN129_3:
case ID_RTHN129_4:
case ID_RTHN129_5:
return 16;
case ID_THGR122N:
return 24;
default:
return 0;
}
}
void ws_oregon2_decode_const_data() {
id = OREGON2_SENSOR_ID(data);
uint8_t ch_bits = (data >> 12) & 0xF;
channel = 1;
while (ch_bits > 1) {
channel++;
ch_bits >>= 1;
}
battery_low = (data & OREGON2_FLAG_BAT_LOW) ? 1 : 0;
}
uint16_t bcd_decode_short(uint32_t data) {
return (data & 0xF) * 10 + ((data >> 4) & 0xF);
}
float ws_oregon2_decode_temp(uint32_t data) {
int32_t temp_val;
temp_val = bcd_decode_short(data >> 4);
temp_val *= 10;
temp_val += (data >> 12) & 0xF;
if (data & 0xF) temp_val = -temp_val;
return (float)temp_val / 10.0;
}
void ws_oregon2_decode_var_data(uint16_t sensor_id, uint32_t data) {
switch (sensor_id) {
case ID_THR228N:
case ID_RTHN129_1:
case ID_RTHN129_2:
case ID_RTHN129_3:
case ID_RTHN129_4:
case ID_RTHN129_5:
temp = ws_oregon2_decode_temp(data);
humidity = WS_NO_HUMIDITY;
return;
case ID_THGR122N:
humidity = bcd_decode_short(data);
temp = ws_oregon2_decode_temp(data >> 8);
return;
default:
break;
}
}
};
#endif