portapack-mayhem/firmware/baseband/fprotos/w-oregon3.hpp
Totoo 5d9428e568
Weather station update (#2209)
* Acurite609txc fix

* Added Kedsum

* Add auriol 5in1

* prev was: FPW_Acurite5in1, this is EmosE601x

* Remove BTN from weather
Saved flash space by creating chaos.
Fix EmosE601
2024-07-24 11:53:09 +02:00

174 lines
6.0 KiB
C++

#ifndef __FPROTO_OREGON3_H__
#define __FPROTO_OREGON3_H__
#include "weatherbase.hpp"
#define OREGON3_PREAMBLE_BITS 28
#define OREGON3_PREAMBLE_MASK 0b1111111111111111111111111111
// 24 ones + 0101 (inverted A)
#define OREGON3_PREAMBLE 0b1111111111111111111111110101
// Fixed part contains:
// - Sensor type: 16 bits
// - Channel: 4 bits
// - ID (changes when batteries are changed): 8 bits
// - Battery status: 4 bits
#define OREGON3_FIXED_PART_BITS (16 + 4 + 8 + 4)
#define OREGON3_SENSOR_ID(d) (((d) >> 16) & 0xFFFF)
#define OREGON3_CHECKSUM_BITS 8
// bit indicating the low battery
#define OREGON3_FLAG_BAT_LOW 0x4
/// Documentation for Oregon Scientific protocols can be found here:
/// https://www.osengr.org/Articles/OS-RF-Protocols-IV.pdf
// Sensors ID
#define ID_THGR221 0xf824
typedef enum {
Oregon3DecoderStepReset = 0,
Oregon3DecoderStepFoundPreamble,
Oregon3DecoderStepVarData,
} Oregon3DecoderStep;
class FProtoWeatherOregon3 : public FProtoWeatherBase {
public:
FProtoWeatherOregon3() {
sensorType = FPW_OREGON3;
}
void feed(bool level, uint32_t duration) override {
ManchesterEvent event = level_and_duration_to_event(!level, duration);
// low-level bit sequence decoding
if (event == ManchesterEventReset) {
parser_step = Oregon3DecoderStepReset;
prev_bit = false;
decode_data = 0UL;
decode_count_bit = 0;
}
if (FProtoGeneral::manchester_advance(
manchester_saved_state, event, &manchester_saved_state, &prev_bit)) {
subghz_protocol_blocks_add_bit(prev_bit);
}
switch (parser_step) {
case Oregon3DecoderStepReset:
// waiting for fixed oregon3 preamble
if (decode_count_bit >= OREGON3_PREAMBLE_BITS &&
((decode_data & OREGON3_PREAMBLE_MASK) == OREGON3_PREAMBLE)) {
parser_step = Oregon3DecoderStepFoundPreamble;
decode_count_bit = 0;
decode_data = 0UL;
}
break;
case Oregon3DecoderStepFoundPreamble:
// waiting for fixed oregon3 data
if (decode_count_bit == OREGON3_FIXED_PART_BITS) {
data = decode_data;
data_count_bit = decode_count_bit;
decode_data = 0UL;
decode_count_bit = 0;
// reverse nibbles in decoded data as oregon v3.0 is LSB first
data = (data & 0x55555555) << 1 |
(data & 0xAAAAAAAA) >> 1;
data = (data & 0x33333333) << 2 |
(data & 0xCCCCCCCC) >> 2;
ws_oregon3_decode_const_data();
var_bits =
oregon3_sensor_id_var_bits(OREGON3_SENSOR_ID(data));
if (!var_bits) {
// sensor is not supported, stop decoding
parser_step = Oregon3DecoderStepReset;
} else {
parser_step = Oregon3DecoderStepVarData;
}
}
break;
case Oregon3DecoderStepVarData:
// waiting for variable (sensor-specific data)
if (decode_count_bit == (uint32_t)var_bits + OREGON3_CHECKSUM_BITS) {
var_data = decode_data & 0xFFFFFFFFFFFFFFFF;
// reverse nibbles in var data
var_data = (var_data & 0x5555555555555555) << 1 |
(var_data & 0xAAAAAAAAAAAAAAAA) >> 1;
var_data = (var_data & 0x3333333333333333) << 2 |
(var_data & 0xCCCCCCCCCCCCCCCC) >> 2;
ws_oregon3_decode_var_data(OREGON3_SENSOR_ID(data), var_data >> OREGON3_CHECKSUM_BITS);
parser_step = Oregon3DecoderStepReset;
if (callback) callback(this);
}
break;
}
}
protected:
// timing values
uint32_t te_short = 500;
uint32_t te_long = 1100;
uint32_t te_delta = 300;
uint32_t min_count_bit_for_found = 32;
bool prev_bit = false;
uint8_t var_bits{0};
uint64_t var_data{0};
ManchesterState manchester_saved_state = ManchesterStateMid1;
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 oregon3_sensor_id_var_bits(uint16_t sensor_id) {
switch (sensor_id) {
case ID_THGR221:
// nibbles: temp + hum + '0'
return (4 + 2 + 1) * 4;
default:
return 0;
}
}
void ws_oregon3_decode_const_data() {
id = OREGON3_SENSOR_ID(data);
channel = (data >> 12) & 0xF;
battery_low = (data & OREGON3_FLAG_BAT_LOW) ? 1 : 0;
}
uint16_t ws_oregon3_bcd_decode_short(uint32_t data) {
return (data & 0xF) * 10 + ((data >> 4) & 0xF);
}
float ws_oregon3_decode_temp(uint32_t data) {
int32_t temp_val;
temp_val = ws_oregon3_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_oregon3_decode_var_data(uint16_t sensor_id, uint32_t data) {
switch (sensor_id) {
case ID_THGR221:
default:
humidity = ws_oregon3_bcd_decode_short(data >> 4);
temp = ws_oregon3_decode_temp(data >> 12);
break;
}
}
};
#endif