mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2024-12-04 23:45:26 +00:00
Increase sensitivity (#2309)
Increase sensitivity of Weather and SubghzD apps.
This commit is contained in:
parent
cc7123b28d
commit
cb3774ad81
@ -213,6 +213,11 @@ const char* WeatherView::getWeatherSensorTypeName(FPROTO_WEATHER_SENSOR type) {
|
||||
return "EmosE601x";
|
||||
case FPW_SolightTE44:
|
||||
return "SolightTE44";
|
||||
case FPW_Bresser3CH:
|
||||
case FPW_Bresser3CH_V1:
|
||||
return "Bresser3CH";
|
||||
case FPW_Vauno_EN8822:
|
||||
return "Vauno EN8822";
|
||||
case FPW_Invalid:
|
||||
default:
|
||||
return "Unknown";
|
||||
@ -532,6 +537,42 @@ WeatherRecentEntry WeatherView::process_data(const WeatherDataMessage* data) {
|
||||
i16 |= 0xf000;
|
||||
}
|
||||
ret.temp = (float)i16 / 10.0;
|
||||
break;
|
||||
case FPW_Bresser3CH:
|
||||
ret.id = (data->decode_data >> 28) & 0xff;
|
||||
ret.channel = ((data->decode_data >> 27) & 0x01) | (((data->decode_data >> 26) & 0x01) << 1);
|
||||
// ret.btn = ((data->decode_data >> 25) & 0x1);
|
||||
ret.battery_low = ((data->decode_data >> 24) & 0x1);
|
||||
i16 = (data->decode_data >> 12) & 0x0fff;
|
||||
/* Handle signed data */
|
||||
if (i16 & 0x0800) {
|
||||
i16 |= 0xf000;
|
||||
}
|
||||
ret.temp = (float)i16 / 10.0;
|
||||
ret.humidity = data->decode_data & 0xff;
|
||||
break;
|
||||
case FPW_Bresser3CH_V1:
|
||||
ret.id = (data->decode_data >> 32) & 0xff;
|
||||
ret.battery_low = ((data->decode_data >> 31) & 0x1);
|
||||
// ret.btn = (data->decode_data >> 30) & 0x1;
|
||||
ret.channel = (data->decode_data >> 28) & 0x3;
|
||||
ret.temp = (data->decode_data >> 16) & 0xfff;
|
||||
ret.temp = FProtoGeneral::locale_fahrenheit_to_celsius((float)(ret.temp - 900) / 10.0);
|
||||
ret.humidity = (data->decode_data >> 8) & 0xff;
|
||||
break;
|
||||
|
||||
case FPW_Vauno_EN8822:
|
||||
ret.id = (data->decode_data >> 34) & 0xff;
|
||||
ret.battery_low = (data->decode_data >> 33) & 0x01;
|
||||
ret.channel = ((data->decode_data >> 30) & 0x03);
|
||||
i16 = (data->decode_data >> 18) & 0x0fff;
|
||||
/* Handle signed data */
|
||||
if (i16 & 0x0800) {
|
||||
i16 |= 0xf000;
|
||||
}
|
||||
ret.temp = (float)i16 / 10.0;
|
||||
ret.humidity = (data->decode_data >> 11) & 0x7f;
|
||||
|
||||
break;
|
||||
case FPW_Invalid:
|
||||
default:
|
||||
|
197
firmware/baseband/fprotos/w-bresser_3ch.hpp
Normal file
197
firmware/baseband/fprotos/w-bresser_3ch.hpp
Normal file
@ -0,0 +1,197 @@
|
||||
|
||||
#ifndef __FPROTO_Bresser3ch_H__
|
||||
#define __FPROTO_Bresser3ch_H__
|
||||
|
||||
#include "weatherbase.hpp"
|
||||
|
||||
#define BRESSER_V0_DATA 36
|
||||
#define BRESSER_V0_DATA_AND_TAIL 52
|
||||
#define BRESSER_V1_DATA 40
|
||||
|
||||
typedef enum {
|
||||
Bresser3chDecoderStepReset = 0,
|
||||
Bresser3chDecoderStepV0SaveDuration,
|
||||
Bresser3chDecoderStepV0CheckDuration,
|
||||
Bresser3chDecoderStepV0TailCheckDuration,
|
||||
Bresser3chDecoderStepV1PreambleDn,
|
||||
Bresser3chDecoderStepV1PreambleUp,
|
||||
Bresser3chDecoderStepV1SaveDuration,
|
||||
Bresser3chDecoderStepV1CheckDuration,
|
||||
} Bresser3chDecoderStepV1;
|
||||
|
||||
class FProtoWeatheBresser3CH : public FProtoWeatherBase {
|
||||
public:
|
||||
FProtoWeatheBresser3CH() {
|
||||
sensorType = FPW_Bresser3CH;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) {
|
||||
switch (parser_step) {
|
||||
case Bresser3chDecoderStepReset:
|
||||
if (level && DURATION_DIFF(duration, te_short * 3) < te_delta) {
|
||||
te_last = duration;
|
||||
parser_step = Bresser3chDecoderStepV1PreambleDn;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else if ((!level) && duration >= te_long) {
|
||||
parser_step = Bresser3chDecoderStepV0SaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case Bresser3chDecoderStepV0SaveDuration:
|
||||
if (level) {
|
||||
te_last = duration;
|
||||
if (decode_count_bit < BRESSER_V0_DATA) {
|
||||
parser_step = Bresser3chDecoderStepV0CheckDuration;
|
||||
} else {
|
||||
parser_step = Bresser3chDecoderStepV0TailCheckDuration;
|
||||
}
|
||||
} else {
|
||||
parser_step = Bresser3chDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
|
||||
case Bresser3chDecoderStepV0CheckDuration:
|
||||
if (!level) {
|
||||
if (DURATION_DIFF(te_last, te_short) < te_delta) {
|
||||
if (DURATION_DIFF(duration, te_short * 2) < te_delta) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = Bresser3chDecoderStepV0SaveDuration;
|
||||
} else if (
|
||||
DURATION_DIFF(duration, te_short * 4) < te_delta) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = Bresser3chDecoderStepV0SaveDuration;
|
||||
} else
|
||||
parser_step = Bresser3chDecoderStepReset;
|
||||
} else
|
||||
parser_step = Bresser3chDecoderStepReset;
|
||||
} else
|
||||
parser_step = Bresser3chDecoderStepReset;
|
||||
break;
|
||||
|
||||
case Bresser3chDecoderStepV0TailCheckDuration:
|
||||
if (!level) {
|
||||
if (duration >= te_long) {
|
||||
if (decode_count_bit == BRESSER_V0_DATA_AND_TAIL &&
|
||||
ws_protocol_bresser_3ch_check_v0()) {
|
||||
decode_count_bit = BRESSER_V0_DATA;
|
||||
sensorType = FPW_Bresser3CH;
|
||||
// ws_protocol_bresser_3ch_extract_data_v0();
|
||||
if (callback) {
|
||||
callback(this);
|
||||
}
|
||||
}
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
parser_step = Bresser3chDecoderStepReset;
|
||||
} else if (
|
||||
decode_count_bit < BRESSER_V0_DATA_AND_TAIL &&
|
||||
DURATION_DIFF(te_last, te_short) < te_delta &&
|
||||
DURATION_DIFF(duration, te_short * 2) < te_delta) {
|
||||
decode_count_bit++;
|
||||
parser_step = Bresser3chDecoderStepV0SaveDuration;
|
||||
} else
|
||||
parser_step = Bresser3chDecoderStepReset;
|
||||
} else
|
||||
parser_step = Bresser3chDecoderStepReset;
|
||||
break;
|
||||
|
||||
case Bresser3chDecoderStepV1PreambleDn:
|
||||
if ((!level) && DURATION_DIFF(duration, te_short_v1 * 3) < te_delta) {
|
||||
if (DURATION_DIFF(te_last, te_short_v1 * 12) < te_delta * 2) {
|
||||
// End of sync after 4*750 (12*250) high values, start reading the message
|
||||
parser_step = Bresser3chDecoderStepV1SaveDuration;
|
||||
} else {
|
||||
parser_step = Bresser3chDecoderStepV1PreambleUp;
|
||||
}
|
||||
} else {
|
||||
parser_step = Bresser3chDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
|
||||
case Bresser3chDecoderStepV1PreambleUp:
|
||||
if (level && DURATION_DIFF(duration, te_short_v1 * 3) < te_delta) {
|
||||
te_last = te_last + duration;
|
||||
parser_step = Bresser3chDecoderStepV1PreambleDn;
|
||||
} else {
|
||||
parser_step = Bresser3chDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
|
||||
case Bresser3chDecoderStepV1SaveDuration:
|
||||
if (decode_count_bit == BRESSER_V1_DATA) {
|
||||
if (ws_protocol_bresser_3ch_check_v1()) {
|
||||
// ws_protocol_bresser_3ch_extract_data_v1(&instance->generic);
|
||||
sensorType = FPW_Bresser3CH_V1;
|
||||
if (callback) {
|
||||
callback(this);
|
||||
}
|
||||
}
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
parser_step = Bresser3chDecoderStepReset;
|
||||
} else if (level) {
|
||||
te_last = duration;
|
||||
parser_step = Bresser3chDecoderStepV1CheckDuration;
|
||||
} else {
|
||||
parser_step = Bresser3chDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
|
||||
case Bresser3chDecoderStepV1CheckDuration:
|
||||
if (!level) {
|
||||
if (DURATION_DIFF(te_last, te_short_v1) < te_delta && DURATION_DIFF(duration, te_long_v1) < te_delta) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = Bresser3chDecoderStepV1SaveDuration;
|
||||
} else if (
|
||||
DURATION_DIFF(te_last, te_long_v1) < te_delta && DURATION_DIFF(duration, te_short_v1) < te_delta) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = Bresser3chDecoderStepV1SaveDuration;
|
||||
} else
|
||||
parser_step = Bresser3chDecoderStepReset;
|
||||
} else
|
||||
parser_step = Bresser3chDecoderStepReset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
uint32_t te_short = 475;
|
||||
uint32_t te_long = 3900;
|
||||
uint32_t te_delta = 150;
|
||||
|
||||
uint32_t te_short_v1 = 250;
|
||||
uint32_t te_long_v1 = 500;
|
||||
|
||||
bool ws_protocol_bresser_3ch_check_v0() {
|
||||
if (!decode_data) return false;
|
||||
// No CRC, so better sanity checks here
|
||||
if (((decode_data >> 8) & 0x0f) != 0x0f) return false; // separator not 0xf
|
||||
if (((decode_data >> 28) & 0xff) == 0xff) return false; // ID only ones?
|
||||
if (((decode_data >> 28) & 0xff) == 0x00) return false; // ID only zeroes?
|
||||
if (((decode_data >> 25) & 0x0f) == 0x0f) return false; // flags only ones?
|
||||
if (((decode_data >> 25) & 0x0f) == 0x00) return false; // flags only zeroes?
|
||||
if (((decode_data >> 12) & 0x0fff) == 0x0fff)
|
||||
return false; // temperature maxed out?
|
||||
if ((decode_data & 0xff) < 20)
|
||||
return false; // humidity percentage less than 20?
|
||||
if ((decode_data & 0xff) > 95)
|
||||
return false; // humidity percentage more than 95?
|
||||
return true;
|
||||
}
|
||||
bool ws_protocol_bresser_3ch_check_v1() {
|
||||
if (!decode_data) return false;
|
||||
|
||||
uint8_t sum = (((decode_data >> 32) & 0xff) +
|
||||
((decode_data >> 24) & 0xff) +
|
||||
((decode_data >> 16) & 0xff) +
|
||||
((decode_data >> 8) & 0xff)) &
|
||||
0xff;
|
||||
|
||||
return (decode_data & 0xff) == sum;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
88
firmware/baseband/fprotos/w-vauno_en8822.hpp
Normal file
88
firmware/baseband/fprotos/w-vauno_en8822.hpp
Normal file
@ -0,0 +1,88 @@
|
||||
|
||||
#ifndef __FPROTO_VAUNO_EN8822_H__
|
||||
#define __FPROTO_VAUNO_EN8822_H__
|
||||
|
||||
#include "weatherbase.hpp"
|
||||
|
||||
typedef enum {
|
||||
VaunoEN8822CDecoderStepReset = 0,
|
||||
VaunoEN8822CDecoderStepSaveDuration,
|
||||
VaunoEN8822CDecoderStepCheckDuration,
|
||||
} VaunoEN8822CDecoderStep;
|
||||
|
||||
class FProtoWeatherVaunoEN8822 : public FProtoWeatherBase {
|
||||
public:
|
||||
FProtoWeatherVaunoEN8822() {
|
||||
sensorType = FPW_Vauno_EN8822;
|
||||
}
|
||||
|
||||
void feed(bool level, uint32_t duration) override {
|
||||
switch (parser_step) {
|
||||
case VaunoEN8822CDecoderStepReset:
|
||||
if ((!level) && DURATION_DIFF(duration, te_long * 4) < te_delta) {
|
||||
parser_step = VaunoEN8822CDecoderStepSaveDuration;
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case VaunoEN8822CDecoderStepSaveDuration:
|
||||
if (level) {
|
||||
te_last = duration;
|
||||
parser_step = VaunoEN8822CDecoderStepCheckDuration;
|
||||
} else {
|
||||
parser_step = VaunoEN8822CDecoderStepReset;
|
||||
}
|
||||
break;
|
||||
|
||||
case VaunoEN8822CDecoderStepCheckDuration:
|
||||
if (!level) {
|
||||
if (DURATION_DIFF(te_last, te_short) < te_delta) {
|
||||
if (DURATION_DIFF(duration, te_long * 2) < te_delta) {
|
||||
subghz_protocol_blocks_add_bit(1);
|
||||
parser_step = VaunoEN8822CDecoderStepSaveDuration;
|
||||
} else if (DURATION_DIFF(duration, te_long) < te_delta) {
|
||||
subghz_protocol_blocks_add_bit(0);
|
||||
parser_step = VaunoEN8822CDecoderStepSaveDuration;
|
||||
} else if (DURATION_DIFF(duration, te_long * 4) < te_delta) {
|
||||
parser_step = VaunoEN8822CDecoderStepReset;
|
||||
if (decode_count_bit == min_count_bit_for_found && ws_protocol_vauno_en8822c_check()) {
|
||||
// ws_protocol_vauno_en8822c_extract_data(&instance->generic);
|
||||
|
||||
if (callback) {
|
||||
callback(this);
|
||||
}
|
||||
} else if (decode_count_bit == 1) {
|
||||
parser_step = VaunoEN8822CDecoderStepSaveDuration;
|
||||
}
|
||||
decode_data = 0;
|
||||
decode_count_bit = 0;
|
||||
} else
|
||||
parser_step = VaunoEN8822CDecoderStepReset;
|
||||
} else
|
||||
parser_step = VaunoEN8822CDecoderStepReset;
|
||||
} else
|
||||
parser_step = VaunoEN8822CDecoderStepReset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
// timing values
|
||||
uint32_t te_short = 500;
|
||||
uint32_t te_long = 1940;
|
||||
uint32_t te_delta = 150;
|
||||
uint32_t min_count_bit_for_found = 42;
|
||||
|
||||
bool ws_protocol_vauno_en8822c_check() {
|
||||
if (!decode_data) return false;
|
||||
// The sum of all nibbles should match the last 6 bits
|
||||
uint8_t sum = 0;
|
||||
for (uint8_t i = 6; i <= 38; i += 4) {
|
||||
sum += ((decode_data >> i) & 0x0f);
|
||||
}
|
||||
return sum != 0 && (sum & 0x3f) == (decode_data & 0x3f);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
@ -29,6 +29,8 @@ So include here the .hpp, and add a new element to the protos vector in the cons
|
||||
#include "w-acurite5in1.hpp"
|
||||
#include "w-emose601x.hpp"
|
||||
#include "w-solight_te44.hpp"
|
||||
#include "w-bresser_3ch.hpp"
|
||||
#include "w-vauno_en8822.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
@ -66,10 +68,13 @@ class WeatherProtos : public FProtoListGeneral {
|
||||
protos[FPW_Acurite5in1] = new FProtoWeatherAcurite5in1();
|
||||
protos[FPW_EmosE601x] = new FProtoWeatherEmosE601x();
|
||||
protos[FPW_SolightTE44] = new FProtoWeatherSolightTE44();
|
||||
protos[FPW_Bresser3CH] = new FProtoWeatheBresser3CH();
|
||||
protos[FPW_Bresser3CH_V1] = nullptr; // done by FProtoWeatheBresser3CH
|
||||
protos[FPW_Vauno_EN8822] = new FProtoWeatherVaunoEN8822();
|
||||
|
||||
// set callback for them
|
||||
for (uint8_t i = 0; i < FPW_COUNT; ++i) {
|
||||
protos[i]->setCallback(callbackTarget);
|
||||
if (protos[i] != NULL) protos[i]->setCallback(callbackTarget);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,6 +39,9 @@ enum FPROTO_WEATHER_SENSOR {
|
||||
FPW_Acurite5in1 = 21,
|
||||
FPW_EmosE601x = 22,
|
||||
FPW_SolightTE44 = 23,
|
||||
FPW_Bresser3CH = 24,
|
||||
FPW_Bresser3CH_V1 = 25,
|
||||
FPW_Vauno_EN8822 = 26,
|
||||
FPW_COUNT // this must be the last
|
||||
};
|
||||
|
||||
|
@ -38,32 +38,79 @@ void SubGhzDProcessor::execute(const buffer_c8_t& buffer) {
|
||||
feed_channel_stats(decim_1_out);
|
||||
|
||||
for (size_t i = 0; i < decim_1_out.count; i++) {
|
||||
threshold = (low_estimate + high_estimate) / 2;
|
||||
int32_t const hysteresis = threshold / 8; // +-12%
|
||||
int16_t re = decim_1_out.p[i].real();
|
||||
int16_t im = decim_1_out.p[i].imag();
|
||||
uint32_t mag = ((uint32_t)re * (uint32_t)re) + ((uint32_t)im * (uint32_t)im);
|
||||
|
||||
mag = (mag >> 12); // Decim samples are calculated with saturated gain . (we could also reduce that sat. param at configure time)
|
||||
mag = (mag >> 10);
|
||||
int32_t const ook_low_delta = mag - low_estimate;
|
||||
bool meashl = currentHiLow;
|
||||
if (sig_state == STATE_IDLE) {
|
||||
if (mag > (threshold + hysteresis)) { // just become high
|
||||
meashl = true;
|
||||
sig_state = STATE_PULSE;
|
||||
numg = 0;
|
||||
} else {
|
||||
meashl = false; // still low
|
||||
low_estimate += ook_low_delta / OOK_EST_LOW_RATIO;
|
||||
low_estimate += ((ook_low_delta > 0) ? 1 : -1); // Hack to compensate for lack of fixed-point scaling
|
||||
// Calculate default OOK high level estimate
|
||||
high_estimate = 1.35 * low_estimate; // Default is a ratio of low level
|
||||
high_estimate = std::max(high_estimate, min_high_level);
|
||||
high_estimate = std::min(high_estimate, (uint32_t)OOK_MAX_HIGH_LEVEL);
|
||||
}
|
||||
|
||||
} else if (sig_state == STATE_PULSE) {
|
||||
++numg;
|
||||
if (numg > 100) numg = 100;
|
||||
if (mag < (threshold - hysteresis)) {
|
||||
// check if really a bad value
|
||||
if (numg < 3) {
|
||||
// susp
|
||||
sig_state = STATE_GAP;
|
||||
} else {
|
||||
numg = 0;
|
||||
sig_state = STATE_GAP_START;
|
||||
}
|
||||
meashl = false; // low
|
||||
} else {
|
||||
high_estimate += mag / OOK_EST_HIGH_RATIO - high_estimate / OOK_EST_HIGH_RATIO;
|
||||
high_estimate = std::max(high_estimate, min_high_level);
|
||||
high_estimate = std::min(high_estimate, (uint32_t)OOK_MAX_HIGH_LEVEL);
|
||||
meashl = true; // still high
|
||||
}
|
||||
} else if (sig_state == STATE_GAP_START) {
|
||||
++numg;
|
||||
if (mag > (threshold + hysteresis)) { // New pulse?
|
||||
sig_state = STATE_PULSE;
|
||||
meashl = true;
|
||||
} else if (numg >= 3) {
|
||||
sig_state = STATE_GAP;
|
||||
meashl = false; // gap
|
||||
}
|
||||
} else if (sig_state == STATE_GAP) {
|
||||
++numg;
|
||||
if (mag > (threshold + hysteresis)) { // New pulse?
|
||||
numg = 0;
|
||||
sig_state = STATE_PULSE;
|
||||
meashl = true;
|
||||
} else {
|
||||
meashl = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool meashl = (mag > threshold);
|
||||
tm += mag;
|
||||
if (meashl == currentHiLow && currentDuration < 30'000'000) // allow pass 'end' signal
|
||||
{
|
||||
currentDuration += nsPerDecSamp;
|
||||
} else { // called on change, so send the last duration and dir.
|
||||
if (currentDuration >= 30'000'000) sig_state = STATE_IDLE;
|
||||
if (protoList) protoList->feed(currentHiLow, currentDuration / 1000);
|
||||
currentDuration = nsPerDecSamp;
|
||||
currentHiLow = meashl;
|
||||
}
|
||||
}
|
||||
|
||||
cnt += decim_1_out.count; // TODO , check if it is necessary that xdecim factor.
|
||||
if (cnt > 90'000) {
|
||||
threshold = (tm / cnt) / 2;
|
||||
cnt = 0;
|
||||
tm = 0;
|
||||
if (threshold < 50) threshold = 50;
|
||||
if (threshold > 1700) threshold = 1700;
|
||||
}
|
||||
}
|
||||
|
||||
void SubGhzDProcessor::on_message(const Message* const message) {
|
||||
@ -75,8 +122,6 @@ void SubGhzDProcessor::configure(const SubGhzFPRxConfigureMessage& message) {
|
||||
// constexpr size_t decim_0_output_fs = baseband_fs / decim_0.decimation_factor; //unused
|
||||
// constexpr size_t decim_1_output_fs = decim_0_output_fs / decim_1.decimation_factor; //unused
|
||||
|
||||
modulation = message.modulation; // TODO: add support for FM (currently AM only)
|
||||
|
||||
baseband_fs = message.sampling_rate;
|
||||
baseband_thread.set_sampling_rate(baseband_fs);
|
||||
nsPerDecSamp = 1'000'000'000 / baseband_fs * 8; // Scaled it due to less array buffer sampes due to /8 decimation. 250 nseg (4Mhz) * 8
|
||||
|
@ -32,7 +32,14 @@
|
||||
#include "message.hpp"
|
||||
#include "dsp_decimate.hpp"
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize("Os")
|
||||
#include "fprotos/subghzdprotos.hpp"
|
||||
#pragma GCC pop_options
|
||||
|
||||
#define OOK_EST_HIGH_RATIO 3 // Constant for slowness of OOK high level estimator
|
||||
#define OOK_EST_LOW_RATIO 5 // Constant for slowness of OOK low level (noise) estimator (very slow)
|
||||
#define OOK_MAX_HIGH_LEVEL 450000
|
||||
|
||||
class SubGhzDProcessor : public BasebandProcessor {
|
||||
public:
|
||||
@ -40,9 +47,18 @@ class SubGhzDProcessor : public BasebandProcessor {
|
||||
void on_message(const Message* const message) override;
|
||||
|
||||
private:
|
||||
enum {
|
||||
STATE_IDLE = 0,
|
||||
STATE_PULSE = 1,
|
||||
STATE_GAP_START = 2,
|
||||
STATE_GAP = 3,
|
||||
} sig_state = STATE_IDLE;
|
||||
uint32_t low_estimate = 100;
|
||||
uint32_t high_estimate = 12000;
|
||||
uint32_t min_high_level = 10;
|
||||
uint8_t numg = 0; // count of matched signals to filter spikes
|
||||
size_t baseband_fs = 0; // will be set later by configure message
|
||||
uint32_t nsPerDecSamp = 0;
|
||||
uint8_t modulation = 0;
|
||||
|
||||
/* Array Buffer aux. used in decim0 and decim1 IQ c16 signed data ; (decim0 defines the max length of the array) */
|
||||
std::array<complex16_t, 512> dst{}; // decim0 /4 , 2048/4 = 512 complex I,Q
|
||||
@ -55,14 +71,10 @@ class SubGhzDProcessor : public BasebandProcessor {
|
||||
dsp::decimate::FIRC16xR16x16Decim2 decim_1{};
|
||||
|
||||
uint32_t currentDuration = 0;
|
||||
uint32_t threshold = 0x0630; // will overwrite after the first iteration
|
||||
uint32_t threshold = 0x0630;
|
||||
bool currentHiLow = false;
|
||||
bool configured{false};
|
||||
|
||||
// for threshold
|
||||
uint32_t cnt = 0;
|
||||
uint32_t tm = 0;
|
||||
|
||||
FProtoListGeneral* protoList = new SubGhzDProtos(); // holds all the protocols we can parse
|
||||
void configure(const SubGhzFPRxConfigureMessage& message);
|
||||
|
||||
|
@ -39,32 +39,79 @@ void WeatherProcessor::execute(const buffer_c8_t& buffer) {
|
||||
feed_channel_stats(decim_1_out);
|
||||
|
||||
for (size_t i = 0; i < decim_1_out.count; i++) {
|
||||
threshold = (low_estimate + high_estimate) / 2;
|
||||
int32_t const hysteresis = threshold / 8; // +-12%
|
||||
int16_t re = decim_1_out.p[i].real();
|
||||
int16_t im = decim_1_out.p[i].imag();
|
||||
uint32_t mag = ((uint32_t)re * (uint32_t)re) + ((uint32_t)im * (uint32_t)im);
|
||||
|
||||
mag = (mag >> 12); // Decim samples are calculated with saturated gain . (we could also reduce that sat. param at configure time)
|
||||
mag = (mag >> 10);
|
||||
int32_t const ook_low_delta = mag - low_estimate;
|
||||
bool meashl = currentHiLow;
|
||||
if (sig_state == STATE_IDLE) {
|
||||
if (mag > (threshold + hysteresis)) { // just become high
|
||||
meashl = true;
|
||||
sig_state = STATE_PULSE;
|
||||
numg = 0;
|
||||
} else {
|
||||
meashl = false; // still low
|
||||
low_estimate += ook_low_delta / OOK_EST_LOW_RATIO;
|
||||
low_estimate += ((ook_low_delta > 0) ? 1 : -1); // Hack to compensate for lack of fixed-point scaling
|
||||
// Calculate default OOK high level estimate
|
||||
high_estimate = 1.35 * low_estimate; // Default is a ratio of low level
|
||||
high_estimate = std::max(high_estimate, min_high_level);
|
||||
high_estimate = std::min(high_estimate, (uint32_t)OOK_MAX_HIGH_LEVEL);
|
||||
}
|
||||
|
||||
} else if (sig_state == STATE_PULSE) {
|
||||
++numg;
|
||||
if (numg > 100) numg = 100;
|
||||
if (mag < (threshold - hysteresis)) {
|
||||
// check if really a bad value
|
||||
if (numg < 3) {
|
||||
// susp
|
||||
sig_state = STATE_GAP;
|
||||
} else {
|
||||
numg = 0;
|
||||
sig_state = STATE_GAP_START;
|
||||
}
|
||||
meashl = false; // low
|
||||
} else {
|
||||
high_estimate += mag / OOK_EST_HIGH_RATIO - high_estimate / OOK_EST_HIGH_RATIO;
|
||||
high_estimate = std::max(high_estimate, min_high_level);
|
||||
high_estimate = std::min(high_estimate, (uint32_t)OOK_MAX_HIGH_LEVEL);
|
||||
meashl = true; // still high
|
||||
}
|
||||
} else if (sig_state == STATE_GAP_START) {
|
||||
++numg;
|
||||
if (mag > (threshold + hysteresis)) { // New pulse?
|
||||
sig_state = STATE_PULSE;
|
||||
meashl = true;
|
||||
} else if (numg >= 3) {
|
||||
sig_state = STATE_GAP;
|
||||
meashl = false; // gap
|
||||
}
|
||||
} else if (sig_state == STATE_GAP) {
|
||||
++numg;
|
||||
if (mag > (threshold + hysteresis)) { // New pulse?
|
||||
numg = 0;
|
||||
sig_state = STATE_PULSE;
|
||||
meashl = true;
|
||||
} else {
|
||||
meashl = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool meashl = (mag > threshold);
|
||||
tm += mag;
|
||||
if (meashl == currentHiLow && currentDuration < 30'000'000) // allow pass 'end' signal
|
||||
{
|
||||
currentDuration += nsPerDecSamp;
|
||||
} else { // called on change, so send the last duration and dir.
|
||||
if (currentDuration >= 30'000'000) sig_state = STATE_IDLE;
|
||||
if (protoList) protoList->feed(currentHiLow, currentDuration / 1000);
|
||||
currentDuration = nsPerDecSamp;
|
||||
currentHiLow = meashl;
|
||||
}
|
||||
}
|
||||
|
||||
cnt += decim_1_out.count; // TODO , check if it is necessary that xdecim factor.
|
||||
if (cnt > 90'000) {
|
||||
threshold = (tm / cnt) / 2;
|
||||
cnt = 0;
|
||||
tm = 0;
|
||||
if (threshold < 50) threshold = 50;
|
||||
if (threshold > 1700) threshold = 1700;
|
||||
}
|
||||
}
|
||||
|
||||
void WeatherProcessor::on_message(const Message* const message) {
|
||||
|
@ -26,6 +26,7 @@
|
||||
#ifndef __PROC_WEATHER_H__
|
||||
#define __PROC_WEATHER_H__
|
||||
|
||||
#include <algorithm>
|
||||
#include "baseband_processor.hpp"
|
||||
#include "baseband_thread.hpp"
|
||||
#include "rssi_thread.hpp"
|
||||
@ -34,15 +35,28 @@
|
||||
|
||||
#include "fprotos/weatherprotos.hpp"
|
||||
|
||||
#define OOK_EST_HIGH_RATIO 3 // Constant for slowness of OOK high level estimator
|
||||
#define OOK_EST_LOW_RATIO 5 // Constant for slowness of OOK low level (noise) estimator (very slow)
|
||||
#define OOK_MAX_HIGH_LEVEL 450000
|
||||
|
||||
class WeatherProcessor : public BasebandProcessor {
|
||||
public:
|
||||
void execute(const buffer_c8_t& buffer) override;
|
||||
void on_message(const Message* const message) override;
|
||||
|
||||
private:
|
||||
enum {
|
||||
STATE_IDLE = 0,
|
||||
STATE_PULSE = 1,
|
||||
STATE_GAP_START = 2,
|
||||
STATE_GAP = 3,
|
||||
} sig_state = STATE_IDLE;
|
||||
uint32_t low_estimate = 100;
|
||||
uint32_t high_estimate = 12000;
|
||||
uint32_t min_high_level = 10;
|
||||
size_t baseband_fs = 0; // will be set later by configure message.
|
||||
uint32_t nsPerDecSamp = 0;
|
||||
|
||||
uint8_t numg = 0; // count of matched signals to filter spikes
|
||||
/* Array Buffer aux. used in decim0 and decim1 IQ c16 signed data ; (decim0 defines the max length of the array) */
|
||||
std::array<complex16_t, 512> dst{}; // decim0 /4 , 2048/4 = 512 complex I,Q
|
||||
const buffer_c16_t dst_buffer{
|
||||
@ -58,10 +72,6 @@ class WeatherProcessor : public BasebandProcessor {
|
||||
bool currentHiLow = false;
|
||||
bool configured{false};
|
||||
|
||||
// for threshold
|
||||
uint32_t cnt = 0;
|
||||
uint32_t tm = 0;
|
||||
|
||||
FProtoListGeneral* protoList = new WeatherProtos(); // holds all the protocols we can parse
|
||||
void configure(const SubGhzFPRxConfigureMessage& message);
|
||||
void on_beep_message(const AudioBeepMessage& message);
|
||||
|
Loading…
Reference in New Issue
Block a user