Half part of the transition of baseband processor.

This commit is contained in:
HTotoo 2023-12-08 13:12:48 +01:00
parent a5705e1d6c
commit b45638f9ed
23 changed files with 502 additions and 216 deletions

View File

@ -320,7 +320,7 @@ void set_spectrum_painter_config(const uint16_t width, const uint16_t height, bo
}
void set_weather() {
const WeatherRxConfigureMessage message{};
const SubGhzFPRxConfigureMessage message{0, 0};
send_message(&message);
}

View File

@ -0,0 +1,176 @@
#ifndef __FPROTO_GENERAL_H__
#define __FPROTO_GENERAL_H__
#include <stdint.h>
#include <stddef.h>
#define bit_read(value, bit) (((value) >> (bit)) & 0x01)
#define DURATION_DIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y)))
typedef enum {
ManchesterStateStart1 = 0,
ManchesterStateMid1 = 1,
ManchesterStateMid0 = 2,
ManchesterStateStart0 = 3
} ManchesterState;
typedef enum {
ManchesterEventShortLow = 0,
ManchesterEventShortHigh = 2,
ManchesterEventLongLow = 4,
ManchesterEventLongHigh = 6,
ManchesterEventReset = 8
} ManchesterEvent;
class FProtoGeneral {
public:
static bool manchester_advance(
ManchesterState state,
ManchesterEvent event,
ManchesterState* next_state,
bool* data) {
bool result = false;
ManchesterState new_state;
if (event == ManchesterEventReset) {
new_state = ManchesterStateMid1;
} else {
new_state = (ManchesterState)(transitions[state] >> event & 0x3);
if (new_state == state) {
new_state = ManchesterStateMid1;
} else {
if (new_state == ManchesterStateMid0) {
if (data) *data = false;
result = true;
} else if (new_state == ManchesterStateMid1) {
if (data) *data = true;
result = true;
}
}
}
*next_state = new_state;
return result;
}
static uint8_t subghz_protocol_blocks_add_bytes(uint8_t const message[], size_t size) {
uint32_t result = 0;
for (size_t i = 0; i < size; ++i) {
result += message[i];
}
return (uint8_t)result;
}
static uint8_t subghz_protocol_blocks_parity8(uint8_t byte) {
byte ^= byte >> 4;
byte &= 0xf;
return (0x6996 >> byte) & 1;
}
static uint8_t subghz_protocol_blocks_parity_bytes(uint8_t const message[], size_t size) {
uint8_t result = 0;
for (size_t i = 0; i < size; ++i) {
result ^= subghz_protocol_blocks_parity8(message[i]);
}
return result;
}
static uint8_t subghz_protocol_blocks_lfsr_digest8(
uint8_t const message[],
size_t size,
uint8_t gen,
uint8_t key) {
uint8_t sum = 0;
for (size_t byte = 0; byte < size; ++byte) {
uint8_t data = message[byte];
for (int i = 7; i >= 0; --i) {
// XOR key into sum if data bit is set
if ((data >> i) & 1) sum ^= key;
// roll the key right (actually the LSB is dropped here)
// and apply the gen (needs to include the dropped LSB as MSB)
if (key & 1)
key = (key >> 1) ^ gen;
else
key = (key >> 1);
}
}
return sum;
}
static float locale_fahrenheit_to_celsius(float temp_f) {
return (temp_f - 32.f) / 1.8f;
}
static uint8_t subghz_protocol_blocks_crc4(
uint8_t const message[],
size_t size,
uint8_t polynomial,
uint8_t init) {
uint8_t remainder = init << 4; // LSBs are unused
uint8_t poly = polynomial << 4;
uint8_t bit;
while (size--) {
remainder ^= *message++;
for (bit = 0; bit < 8; bit++) {
if (remainder & 0x80) {
remainder = (remainder << 1) ^ poly;
} else {
remainder = (remainder << 1);
}
}
}
return remainder >> 4 & 0x0f; // discard the LSBs
}
static uint8_t subghz_protocol_blocks_lfsr_digest8_reflect(
uint8_t const message[],
size_t size,
uint8_t gen,
uint8_t key) {
uint8_t sum = 0;
// Process message from last byte to first byte (reflected)
for (int byte = size - 1; byte >= 0; --byte) {
uint8_t data = message[byte];
// Process individual bits of each byte (reflected)
for (uint8_t i = 0; i < 8; ++i) {
// XOR key into sum if data bit is set
if ((data >> i) & 1) {
sum ^= key;
}
// roll the key left (actually the LSB is dropped here)
// and apply the gen (needs to include the dropped lsb as MSB)
if (key & 0x80)
key = (key << 1) ^ gen;
else
key = (key << 1);
}
}
return sum;
}
static uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t bit_count) {
uint64_t reverse_key = 0;
for (uint8_t i = 0; i < bit_count; i++) {
reverse_key = reverse_key << 1 | bit_read(key, i);
}
return reverse_key;
}
static uint8_t subghz_protocol_blocks_crc8(
uint8_t const message[],
size_t size,
uint8_t polynomial,
uint8_t init) {
uint8_t remainder = init;
for (size_t byte = 0; byte < size; ++byte) {
remainder ^= message[byte];
for (uint8_t bit = 0; bit < 8; ++bit) {
if (remainder & 0x80) {
remainder = (remainder << 1) ^ polynomial;
} else {
remainder = (remainder << 1);
}
}
}
return remainder;
}
private:
static inline const uint8_t transitions[] = {0b00000001, 0b10010001, 0b10011011, 0b11111011};
};
#endif

View File

@ -0,0 +1,12 @@
#ifndef __FPROTO_PROTOLISTGENERAL_H__
#define __FPROTO_PROTOLISTGENERAL_H__
#include <stdint.h>
class FProtoListGeneral {
public:
FProtoListGeneral() {}
virtual ~FProtoListGeneral() {}
virtual void feed(bool level, uint32_t duration) = 0;
};
#endif

View File

@ -0,0 +1,126 @@
#ifndef __FPROTO_ANSONIC_H__
#define __FPROTO_ANSONIC_H__
#include "subghzdbase.hpp"
#define ANSONICDIP_PATTERN "%c%c%c%c%c%c%c%c%c%c"
#define ANSONICCNT_TO_DIP(dip) \
(dip & 0x0800 ? '1' : '0'), (dip & 0x0400 ? '1' : '0'), (dip & 0x0200 ? '1' : '0'), \
(dip & 0x0100 ? '1' : '0'), (dip & 0x0080 ? '1' : '0'), (dip & 0x0040 ? '1' : '0'), \
(dip & 0x0020 ? '1' : '0'), (dip & 0x0010 ? '1' : '0'), (dip & 0x0001 ? '1' : '0'), \
(dip & 0x0008 ? '1' : '0')
typedef enum {
AnsonicDecoderStepReset = 0,
AnsonicDecoderStepFoundStartBit,
AnsonicDecoderStepSaveDuration,
AnsonicDecoderStepCheckDuration,
} AnsonicDecoderStep;
class FProtoSubGhzDAnsonic : public FProtoSubGhzDBase {
public:
FProtoSubGhzDAnsonic() {
sensorType = FPS_ANSONIC;
modulation = FPM_FM;
}
void feed(bool level, uint32_t duration) {
switch (parser_step) {
case AnsonicDecoderStepReset:
if ((!level) && (DURATION_DIFF(duration, te_short * 35) < te_delta * 35)) {
// Found header Ansonic
parser_step = AnsonicDecoderStepFoundStartBit;
}
break;
case AnsonicDecoderStepFoundStartBit:
if (!level) {
break;
} else if (
DURATION_DIFF(duration, te_short) < te_delta) {
// Found start bit Ansonic
parser_step = AnsonicDecoderStepSaveDuration;
decode_data = 0;
decode_count_bit = 0;
} else {
parser_step = AnsonicDecoderStepReset;
}
break;
case AnsonicDecoderStepSaveDuration:
if (!level) { // save interval
if (duration >= (te_short * 4)) {
parser_step = AnsonicDecoderStepFoundStartBit;
if (decode_count_bit >=
min_count_bit_for_found) {
serial = 0x0;
btn = 0x0;
data = decode_data;
data_count_bit = decode_count_bit;
if (callback) callback(this);
}
break;
}
te_last = duration;
parser_step = AnsonicDecoderStepCheckDuration;
} else {
parser_step = AnsonicDecoderStepReset;
}
break;
case AnsonicDecoderStepCheckDuration:
if (level) {
if ((DURATION_DIFF(te_last, te_short) <
te_delta) &&
(DURATION_DIFF(duration, te_long) <
te_delta)) {
subghz_protocol_blocks_add_bit(1);
parser_step = AnsonicDecoderStepSaveDuration;
} else if (
(DURATION_DIFF(te_last, te_long) <
te_delta) &&
(DURATION_DIFF(duration, te_short) <
te_delta)) {
subghz_protocol_blocks_add_bit(0);
parser_step = AnsonicDecoderStepSaveDuration;
} else
parser_step = AnsonicDecoderStepReset;
} else {
parser_step = AnsonicDecoderStepReset;
}
break;
}
}
void subghz_protocol_ansonic_check_remote_controller() {
/*
* 12345678(10) k 9
* AAA => 10101010 1 01 0
*
* 1...10 - DIP
* k- KEY
*/
cnt = data & 0xFFF;
btn = ((data >> 1) & 0x3);
}
void get_string(char* output, size_t outSize) {
subghz_protocol_ansonic_check_remote_controller();
snprintf(
output, outSize,
"%dbit\r\n"
"Key:%03lX\r\n"
"Btn:%X\r\n"
"DIP:" ANSONICDIP_PATTERN "\r\n",
data_count_bit,
(uint32_t)(data & 0xFFFFFFFF),
btn,
ANSONICCNT_TO_DIP(cnt));
}
protected:
uint32_t te_short = 555;
uint32_t te_long = 1111;
uint32_t te_delta = 120;
uint32_t min_count_bit_for_found = 12;
uint32_t crc = 0;
};
#endif

View File

@ -0,0 +1,61 @@
/*
Base class for all weather protocols.
This and most of the weather protocols uses code from Flipper XTreme codebase ( https://github.com/Flipper-XFW/Xtreme-Firmware/tree/dev/lib/subghz ). Thanks for their work!
For comments in a protocol implementation check w-nexus-th.hpp
*/
#ifndef __FPROTO_SBASE_H__
#define __FPROTO_SBASE_H__
#include "fprotogeneral.hpp"
#include "subghztypes.hpp"
#include <string>
// default walues to indicate 'no value'
#define SD_NO_ID 0xFFFFFFFF
class FProtoSubGhzDBase;
typedef void (*SubGhzDProtocolDecoderBaseRxCallback)(FProtoSubGhzDBase* instance);
class FProtoSubGhzDBase {
public:
FProtoSubGhzDBase() {}
virtual ~FProtoSubGhzDBase() {}
virtual void feed(bool level, uint32_t duration) = 0; // need to be implemented on each protocol handler.
void setCallback(SubGhzDProtocolDecoderBaseRxCallback cb) { callback = cb; } // this is called when there is a hit.
uint8_t getSensorType() { return sensorType; }
uint32_t getSensorId() { return id; }
protected:
// Helper functions to keep it as compatible with flipper as we can, so adding new protos will be easy.
void subghz_protocol_blocks_add_bit(uint8_t bit) {
decode_data = decode_data << 1 | bit;
decode_count_bit++;
}
// General weather data holder
uint8_t sensorType = FPS_Invalid;
uint32_t id = SD_NO_ID;
FPROTO_SUBGHZD_MODULATION modulation = FPM_AM; // override this, if FM
// inner logic stuff, also for flipper compatibility.
SubGhzDProtocolDecoderBaseRxCallback callback = NULL;
uint16_t header_count = 0;
uint8_t parser_step = 0;
uint32_t te_last = 0;
uint64_t data = 0;
uint64_t data_2 = 0;
uint32_t serial = 0;
uint16_t data_count_bit = 0;
uint64_t decode_data = 0;
uint32_t decode_count_bit = 0;
uint8_t btn = 0;
uint32_t cnt = 0;
uint8_t cnt_2 = 0;
uint32_t seed = 0;
ManchesterState manchester_saved_state = ManchesterStateMid1;
};
#endif

View File

@ -0,0 +1,45 @@
/*
This is the protocol list handler. It holds an instance of all known protocols.
So include here the .hpp, and add a new element to the protos vector in the constructor. That's all you need to do here if you wanna add a new proto.
@htotoo
*/
#include <vector>
#include <memory>
#include "portapack_shared_memory.hpp"
#include "fprotolistgeneral.hpp"
#include "subghzdbase.hpp"
#include "s-ansonic.hpp"
#ifndef __FPROTO_PROTOLISTSGZ_H__
#define __FPROTO_PROTOLISTSGZ_H__
class SubGhzDProtos : public FProtoListGeneral {
public:
SubGhzDProtos() {
// add protos
protos.push_back(std::make_unique<FProtoSubGhzDAnsonic>()); // 1
// set callback for them
for (const auto& obj : protos) {
obj->setCallback(callbackTarget);
}
}
static void callbackTarget(FProtoSubGhzDBase* instance) {
SubGhzDDataMessage packet_message{instance->getSensorType(), instance->getSensorId()}; // TODO add get_string data too
shared_memory.application_queue.push(packet_message);
}
void feed(bool level, uint32_t duration) {
for (const auto& obj : protos) {
obj->feed(level, duration);
}
}
protected:
std::vector<std::unique_ptr<FProtoSubGhzDBase>> protos{};
};
#endif

View File

@ -8,8 +8,14 @@ These values must be present on the protocol's constructor, like FProtoWeatherAc
Also it must have a switch-case element in the getSubGhzDSensorTypeName() function, to display it's name.
*/
enum FPROTO_SUBGHZD_MODULATION {
FPM_AM = 0,
FPM_FM = 1,
};
enum FPROTO_SUBGHZD_SENSOR {
FPS_Invalid = 0,
FPS_ANSONIC = 1,
};

View File

@ -130,9 +130,9 @@ class FProtoWeatherAcurite592TXR : public FProtoWeatherBase {
static_cast<uint8_t>(decode_data >> 16),
static_cast<uint8_t>(decode_data >> 8)};
if ((subghz_protocol_blocks_add_bytes(msg, 6) ==
if ((FProtoGeneral::subghz_protocol_blocks_add_bytes(msg, 6) ==
(uint8_t)(decode_data & 0xFF)) &&
(!subghz_protocol_blocks_parity_bytes(&msg[2], 4))) {
(!FProtoGeneral::subghz_protocol_blocks_parity_bytes(&msg[2], 4))) {
return true;
} else {
return false;

View File

@ -102,7 +102,7 @@ class FProtoWeatherAcurite606TX : public FProtoWeatherBase {
static_cast<uint8_t>(decode_data >> 16),
static_cast<uint8_t>(decode_data >> 8)};
uint8_t crc = subghz_protocol_blocks_lfsr_digest8(msg, 3, 0x98, 0xF1);
uint8_t crc = FProtoGeneral::subghz_protocol_blocks_lfsr_digest8(msg, 3, 0x98, 0xF1);
return (crc == (decode_data & 0xFF));
}
};

View File

@ -108,16 +108,16 @@ class FProtoWeatherAcurite986 : public FProtoWeatherBase {
void ws_protocol_acurite_986_remote_controller() {
int temp;
id = subghz_protocol_blocks_reverse_key(data >> 24, 8);
id = (id << 8) | subghz_protocol_blocks_reverse_key(data >> 16, 8);
id = FProtoGeneral::subghz_protocol_blocks_reverse_key(data >> 24, 8);
id = (id << 8) | FProtoGeneral::subghz_protocol_blocks_reverse_key(data >> 16, 8);
battery_low = (data >> 14) & 1;
channel = ((data >> 15) & 1) + 1;
temp = subghz_protocol_blocks_reverse_key(data >> 32, 8);
temp = FProtoGeneral::subghz_protocol_blocks_reverse_key(data >> 32, 8);
if (temp & 0x80) {
temp = -(temp & 0x7F);
}
temp = locale_fahrenheit_to_celsius((float)temp);
temp = FProtoGeneral::locale_fahrenheit_to_celsius((float)temp);
btn = WS_NO_BTN;
humidity = WS_NO_HUMIDITY;
}
@ -130,7 +130,7 @@ class FProtoWeatherAcurite986 : public FProtoWeatherBase {
(uint8_t)(decode_data >> 16),
(uint8_t)(decode_data >> 8)};
uint8_t crc = subghz_protocol_blocks_crc8(msg, 4, 0x07, 0x00);
uint8_t crc = FProtoGeneral::subghz_protocol_blocks_crc8(msg, 4, 0x07, 0x00);
return (crc == (decode_data & 0xFF));
}
};

View File

@ -33,7 +33,7 @@ class FProtoWeatherAmbient : public FProtoWeatherBase {
}
if (event != ManchesterEventReset) {
bool data;
bool data_ok = manchester_advance(manchester_saved_state, event, &manchester_saved_state, &data);
bool data_ok = FProtoGeneral::manchester_advance(manchester_saved_state, event, &manchester_saved_state, &data);
if (data_ok) {
decode_data = (decode_data << 1) | !data;
@ -53,7 +53,7 @@ class FProtoWeatherAmbient : public FProtoWeatherBase {
} else {
decode_data = 0;
decode_count_bit = 0;
manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
}
}
@ -71,7 +71,7 @@ class FProtoWeatherAmbient : public FProtoWeatherBase {
static_cast<uint8_t>(decode_data >> 16),
static_cast<uint8_t>(decode_data >> 8)};
uint8_t crc = subghz_protocol_blocks_lfsr_digest8(msg, 5, 0x98, 0x3e) ^ 0x64;
uint8_t crc = FProtoGeneral::subghz_protocol_blocks_lfsr_digest8(msg, 5, 0x98, 0x3e) ^ 0x64;
return (crc == (uint8_t)(decode_data & 0xFF));
}
@ -79,7 +79,7 @@ class FProtoWeatherAmbient : public FProtoWeatherBase {
id = (data >> 32) & 0xFF;
battery_low = (data >> 31) & 1;
channel = ((data >> 28) & 0x07) + 1;
temp = locale_fahrenheit_to_celsius(((float)((data >> 16) & 0x0FFF) - 400.0f) / 10.0f);
temp = FProtoGeneral::locale_fahrenheit_to_celsius(((float)((data >> 16) & 0x0FFF) - 400.0f) / 10.0f);
humidity = (data >> 8) & 0xFF;
btn = WS_NO_BTN;
}

View File

@ -118,8 +118,7 @@ class FProtoWeatherInfactory : public FProtoWeatherBase {
static_cast<uint8_t>(decode_data >> 8),
static_cast<uint8_t>(decode_data)};
uint8_t crc =
subghz_protocol_blocks_crc4(msg, 4, 0x13, 0); // Koopmann 0x9, CCITT-4; FP-4; ITU-T G.704
uint8_t crc = FProtoGeneral::subghz_protocol_blocks_crc4(msg, 4, 0x13, 0); // Koopmann 0x9, CCITT-4; FP-4; ITU-T G.704
crc ^= msg[4] >> 4; // last nibble is only XORed
return (crc == ((decode_data >> 28) & 0x0F));
}
@ -127,10 +126,8 @@ class FProtoWeatherInfactory : public FProtoWeatherBase {
id = data >> 32;
battery_low = (data >> 26) & 1;
btn = WS_NO_BTN;
temp =
locale_fahrenheit_to_celsius(((float)((data >> 12) & 0x0FFF) - 900.0f) / 10.0f);
humidity =
(((data >> 8) & 0x0F) * 10) + ((data >> 4) & 0x0F); // BCD, 'A0'=100%rH
temp = FProtoGeneral::locale_fahrenheit_to_celsius(((float)((data >> 12) & 0x0FFF) - 900.0f) / 10.0f);
humidity = (((data >> 8) & 0x0F) * 10) + ((data >> 4) & 0x0F); // BCD, 'A0'=100%rH
channel = data & 0x03;
}
};

View File

@ -155,7 +155,7 @@ class FProtoWeatherLaCrosseTx : public FProtoWeatherBase {
static_cast<uint8_t>((decode_data >> 8) & 0x0F),
static_cast<uint8_t>((decode_data >> 4) & 0x0F)};
uint8_t crc = subghz_protocol_blocks_add_bytes(msg, 9);
uint8_t crc = FProtoGeneral::subghz_protocol_blocks_add_bytes(msg, 9);
return ((crc & 0x0F) == (decode_data & 0x0F));
}
};

View File

@ -104,7 +104,7 @@ class FProtoWeatherLaCrosseTx141thbv2 : public FProtoWeatherBase {
}
uint8_t msg[] = {static_cast<uint8_t>(data >> 32), static_cast<uint8_t>(data >> 24), static_cast<uint8_t>(data >> 16), static_cast<uint8_t>(data >> 8)};
uint8_t crc = subghz_protocol_blocks_lfsr_digest8_reflect(msg, 4, 0x31, 0xF4);
uint8_t crc = FProtoGeneral::subghz_protocol_blocks_lfsr_digest8_reflect(msg, 4, 0x31, 0xF4);
return (crc == (data & 0xFF));
}
void ws_protocol_lacrosse_tx141thbv2_remote_controller() {

View File

@ -77,7 +77,7 @@ class FProtoWeatherOregon2 : public FProtoWeatherBase {
decode_data = 0UL;
decode_count_bit = 0;
}
if (manchester_advance(manchester_saved_state, event, &manchester_saved_state, &data)) {
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);
@ -166,7 +166,7 @@ class FProtoWeatherOregon2 : public FProtoWeatherBase {
parser_step = Oregon2DecoderStepReset;
decode_data = 0UL;
decode_count_bit = 0;
manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
have_bit = false;
var_data = 0;
var_bits = 0;

View File

@ -47,7 +47,7 @@ class FProtoWeatherOregon3 : public FProtoWeatherBase {
decode_data = 0UL;
decode_count_bit = 0;
}
if (manchester_advance(
if (FProtoGeneral::manchester_advance(
manchester_saved_state, event, &manchester_saved_state, &prev_bit)) {
subghz_protocol_blocks_add_bit(prev_bit);
}

View File

@ -64,11 +64,7 @@ class FProtoWeatherOregonV1 : public FProtoWeatherBase {
// found all the necessary patterns
decode_data = 0;
decode_count_bit = 1;
manchester_advance(
manchester_saved_state,
ManchesterEventReset,
&manchester_saved_state,
NULL);
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
parser_step = Oregon_V1DecoderStepParse;
if (duration < te_short * 4) {
first_bit = 1;
@ -114,19 +110,14 @@ class FProtoWeatherOregonV1 : public FProtoWeatherBase {
}
decode_data = 0;
decode_count_bit = 0;
manchester_advance(
manchester_saved_state,
ManchesterEventReset,
&manchester_saved_state,
NULL);
FProtoGeneral::manchester_advance(manchester_saved_state, ManchesterEventReset, &manchester_saved_state, NULL);
} else {
parser_step = Oregon_V1DecoderStepReset;
}
}
if (event != ManchesterEventReset) {
bool data;
bool data_ok = manchester_advance(
manchester_saved_state, event, &manchester_saved_state, &data);
bool data_ok = FProtoGeneral::manchester_advance(manchester_saved_state, event, &manchester_saved_state, &data);
if (data_ok) {
decode_data = (decode_data << 1) | !data;
@ -149,13 +140,13 @@ class FProtoWeatherOregonV1 : public FProtoWeatherBase {
bool ws_protocol_oregon_v1_check() {
if (!decode_data) return false;
uint64_t data = subghz_protocol_blocks_reverse_key(decode_data, 32);
uint64_t data = FProtoGeneral::subghz_protocol_blocks_reverse_key(decode_data, 32);
uint16_t crc = (data & 0xff) + ((data >> 8) & 0xff) + ((data >> 16) & 0xff);
crc = (crc & 0xff) + ((crc >> 8) & 0xff);
return (crc == ((data >> 24) & 0xFF));
}
void ws_protocol_oregon_v1_remote_controller() {
uint64_t data2 = subghz_protocol_blocks_reverse_key(data, 32);
uint64_t data2 = FProtoGeneral::subghz_protocol_blocks_reverse_key(data, 32);
id = data2 & 0xFF;
channel = ((data2 >> 6) & 0x03) + 1;

View File

@ -128,7 +128,7 @@ class FProtoWeatherWendoxW6726 : public FProtoWeatherBase {
static_cast<uint8_t>(decode_data >> 12),
static_cast<uint8_t>(decode_data >> 4)};
uint8_t crc = subghz_protocol_blocks_crc4(msg, 4, 0x9, 0xD);
uint8_t crc = FProtoGeneral::subghz_protocol_blocks_crc4(msg, 4, 0x9, 0xD);
return (crc == (decode_data & 0x0F));
}
void ws_protocol_wendox_w6726_remote_controller() {

View File

@ -7,8 +7,7 @@ For comments in a protocol implementation check w-nexus-th.hpp
#ifndef __FPROTO_BASE_H__
#define __FPROTO_BASE_H__
#define bit_read(value, bit) (((value) >> (bit)) & 0x01)
#include "fprotogeneral.hpp"
#include "weathertypes.hpp"
#include <string>
@ -20,20 +19,6 @@ For comments in a protocol implementation check w-nexus-th.hpp
#define WS_NO_BTN 0xFF
#define WS_NO_TEMPERATURE -273.0f
#define DURATION_DIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y)))
typedef enum {
ManchesterStateStart1 = 0,
ManchesterStateMid1 = 1,
ManchesterStateMid0 = 2,
ManchesterStateStart0 = 3
} ManchesterState;
typedef enum {
ManchesterEventShortLow = 0,
ManchesterEventShortHigh = 2,
ManchesterEventLongLow = 4,
ManchesterEventLongHigh = 6,
ManchesterEventReset = 8
} ManchesterEvent;
class FProtoWeatherBase;
typedef void (*SubGhzProtocolDecoderBaseRxCallback)(FProtoWeatherBase* instance);
@ -49,7 +34,6 @@ class FProtoWeatherBase {
float getTemp() { return temp; }
uint8_t getHumidity() { return humidity; }
uint8_t getBattLow() { return battery_low; }
uint32_t getTimestamp() { return timestamp; }
uint8_t getChannel() { return channel; }
uint8_t getButton() { return btn; }
@ -59,149 +43,6 @@ class FProtoWeatherBase {
decode_data = decode_data << 1 | bit;
decode_count_bit++;
}
uint8_t subghz_protocol_blocks_add_bytes(uint8_t const message[], size_t size) {
uint32_t result = 0;
for (size_t i = 0; i < size; ++i) {
result += message[i];
}
return (uint8_t)result;
}
uint8_t subghz_protocol_blocks_parity8(uint8_t byte) {
byte ^= byte >> 4;
byte &= 0xf;
return (0x6996 >> byte) & 1;
}
uint8_t subghz_protocol_blocks_parity_bytes(uint8_t const message[], size_t size) {
uint8_t result = 0;
for (size_t i = 0; i < size; ++i) {
result ^= subghz_protocol_blocks_parity8(message[i]);
}
return result;
}
uint8_t subghz_protocol_blocks_lfsr_digest8(
uint8_t const message[],
size_t size,
uint8_t gen,
uint8_t key) {
uint8_t sum = 0;
for (size_t byte = 0; byte < size; ++byte) {
uint8_t data = message[byte];
for (int i = 7; i >= 0; --i) {
// XOR key into sum if data bit is set
if ((data >> i) & 1) sum ^= key;
// roll the key right (actually the LSB is dropped here)
// and apply the gen (needs to include the dropped LSB as MSB)
if (key & 1)
key = (key >> 1) ^ gen;
else
key = (key >> 1);
}
}
return sum;
}
float locale_fahrenheit_to_celsius(float temp_f) {
return (temp_f - 32.f) / 1.8f;
}
bool manchester_advance(
ManchesterState state,
ManchesterEvent event,
ManchesterState* next_state,
bool* data) {
bool result = false;
ManchesterState new_state;
if (event == ManchesterEventReset) {
new_state = manchester_reset_state;
} else {
new_state = (ManchesterState)(transitions[state] >> event & 0x3);
if (new_state == state) {
new_state = manchester_reset_state;
} else {
if (new_state == ManchesterStateMid0) {
if (data) *data = false;
result = true;
} else if (new_state == ManchesterStateMid1) {
if (data) *data = true;
result = true;
}
}
}
*next_state = new_state;
return result;
}
uint8_t subghz_protocol_blocks_crc4(
uint8_t const message[],
size_t size,
uint8_t polynomial,
uint8_t init) {
uint8_t remainder = init << 4; // LSBs are unused
uint8_t poly = polynomial << 4;
uint8_t bit;
while (size--) {
remainder ^= *message++;
for (bit = 0; bit < 8; bit++) {
if (remainder & 0x80) {
remainder = (remainder << 1) ^ poly;
} else {
remainder = (remainder << 1);
}
}
}
return remainder >> 4 & 0x0f; // discard the LSBs
}
uint8_t subghz_protocol_blocks_lfsr_digest8_reflect(
uint8_t const message[],
size_t size,
uint8_t gen,
uint8_t key) {
uint8_t sum = 0;
// Process message from last byte to first byte (reflected)
for (int byte = size - 1; byte >= 0; --byte) {
uint8_t data = message[byte];
// Process individual bits of each byte (reflected)
for (uint8_t i = 0; i < 8; ++i) {
// XOR key into sum if data bit is set
if ((data >> i) & 1) {
sum ^= key;
}
// roll the key left (actually the LSB is dropped here)
// and apply the gen (needs to include the dropped lsb as MSB)
if (key & 0x80)
key = (key << 1) ^ gen;
else
key = (key << 1);
}
}
return sum;
}
uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t bit_count) {
uint64_t reverse_key = 0;
for (uint8_t i = 0; i < bit_count; i++) {
reverse_key = reverse_key << 1 | bit_read(key, i);
}
return reverse_key;
}
uint8_t subghz_protocol_blocks_crc8(
uint8_t const message[],
size_t size,
uint8_t polynomial,
uint8_t init) {
uint8_t remainder = init;
for (size_t byte = 0; byte < size; ++byte) {
remainder ^= message[byte];
for (uint8_t bit = 0; bit < 8; ++bit) {
if (remainder & 0x80) {
remainder = (remainder << 1) ^ polynomial;
} else {
remainder = (remainder << 1);
}
}
}
return remainder;
}
// General weather data holder
uint8_t sensorType = FPW_Invalid;
@ -209,11 +50,10 @@ class FProtoWeatherBase {
float temp = WS_NO_TEMPERATURE;
uint8_t humidity = WS_NO_HUMIDITY;
uint8_t battery_low = WS_NO_BATT;
uint32_t timestamp = 0;
uint8_t channel = WS_NO_CHANNEL;
uint8_t btn = WS_NO_BTN;
// inner logic stuff, also for flipper compatibility. //todo revork a bit, so won't have dupes (decode_data + data, ..), but check if any of the protos uses it in the same time or not. (shouldn't)
// inner logic stuff, also for flipper compatibility.
SubGhzProtocolDecoderBaseRxCallback callback = NULL;
uint16_t header_count = 0;
uint8_t parser_step = 0;
@ -223,8 +63,6 @@ class FProtoWeatherBase {
uint64_t decode_data = 0;
uint32_t decode_count_bit = 0;
ManchesterState manchester_saved_state = ManchesterStateMid1;
static const ManchesterState manchester_reset_state = ManchesterStateMid1;
static inline const uint8_t transitions[] = {0b00000001, 0b10010001, 0b10011011, 0b11111011};
};
#endif

View File

@ -3,6 +3,9 @@ This is the protocol list handler. It holds an instance of all known protocols.
So include here the .hpp, and add a new element to the protos vector in the constructor. That's all you need to do here if you wanna add a new proto.
@htotoo
*/
#include "fprotolistgeneral.hpp"
#include "w-nexus-th.hpp"
#include "w-acurite592txr.hpp"
#include "w-acurite606tx.hpp"
@ -26,10 +29,10 @@ So include here the .hpp, and add a new element to the protos vector in the cons
#include <memory>
#include "portapack_shared_memory.hpp"
#ifndef __FPROTO_PROTOLIST_H__
#define __FPROTO_PROTOLIST_H__
#ifndef __FPROTO_PROTOLISTWTH_H__
#define __FPROTO_PROTOLISTWTH_H__
class WeatherProtos {
class WeatherProtos : public FProtoListGeneral {
public:
WeatherProtos() {
// add protos

View File

@ -37,7 +37,7 @@ void WeatherProcessor::execute(const buffer_c8_t& buffer) {
{
if (currentDuration < UINT32_MAX) currentDuration += usperTick;
} else { // called on change, so send the last duration and dir.
protoList.feed(currentHiLow, currentDuration / 1000);
if (protoList) protoList->feed(currentHiLow, currentDuration / 1000);
currentDuration = usperTick;
currentHiLow = meashl;
}
@ -54,11 +54,23 @@ void WeatherProcessor::execute(const buffer_c8_t& buffer) {
void WeatherProcessor::on_message(const Message* const message) {
if (message->id == Message::ID::WeatherRxConfigure)
configure(*reinterpret_cast<const WeatherRxConfigureMessage*>(message));
configure(*reinterpret_cast<const SubGhzFPRxConfigureMessage*>(message));
}
void WeatherProcessor::configure(const WeatherRxConfigureMessage& message) {
void WeatherProcessor::configure(const SubGhzFPRxConfigureMessage& message) {
(void)message;
modulation = message.modulation; // NIY
if (protoMode != message.protoMode) {
// change it.
FProtoListGeneral* tmp = protoList;
protoList = NULL;
protoMode = message.protoMode;
if (tmp) free(tmp); // takes some time
if (protoMode == 0) protoList = new WeatherProtos();
if (protoMode == 1) protoList = new SubGhzDProtos();
}
configured = true;
}

View File

@ -32,6 +32,7 @@
#include "message.hpp"
#include "fprotos/weatherprotos.hpp"
#include "fprotos/subghzdprotos.hpp"
class WeatherProcessor : public BasebandProcessor {
public:
@ -46,12 +47,14 @@ class WeatherProcessor : public BasebandProcessor {
bool currentHiLow = false;
bool configured{false};
// for debug
uint8_t modulation = 255; // 0 AM, 1 FM 255 = Not set
uint8_t protoMode = 255; // 0 weather, 1 subghzd, 255 = Not set
// for threshold
uint32_t cnt = 0;
uint32_t tm = 0;
WeatherProtos protoList{}; // holds all the protocols we can parse
void configure(const WeatherRxConfigureMessage& message);
FProtoListGeneral* protoList = NULL; // holds all the protocols we can parse
void configure(const SubGhzFPRxConfigureMessage& message);
/* NB: Threads should be the last members in the class definition. */
BasebandThread baseband_thread{baseband_fs, this, baseband::Direction::Receive};

View File

@ -117,6 +117,7 @@ class Message {
BTLETxConfigure = 59,
WeatherRxConfigure = 60,
WeatherData = 61,
SubGhzDData = 62,
MAX
};
@ -1238,12 +1239,14 @@ class SpectrumPainterBufferConfigureResponseMessage : public Message {
SpectrumPainterFIFO* fifo{nullptr};
};
class WeatherRxConfigureMessage : public Message {
class SubGhzFPRxConfigureMessage : public Message {
public:
constexpr WeatherRxConfigureMessage()
: Message{ID::WeatherRxConfigure} {
constexpr SubGhzFPRxConfigureMessage(uint8_t protoMode = 0, uint8_t modulation = 0)
: Message{ID::WeatherRxConfigure}, protoMode{protoMode}, modulation{modulation} {
// todoh give some more info
}
uint8_t protoMode = 0; // 0 weather, 1 subhgzd
uint8_t modulation = 0; // 0 am, 1 fm
};
class WeatherDataMessage : public Message {
@ -1274,4 +1277,17 @@ class WeatherDataMessage : public Message {
uint8_t btn = 0xFF;
};
class SubGhzDDataMessage : public Message {
public:
constexpr SubGhzDDataMessage(
uint8_t sensorType = 0,
uint32_t id = 0xFFFFFFFF)
: Message{ID::SubGhzDData},
sensorType{sensorType},
id{id} {
}
uint8_t sensorType = 0;
uint32_t id = 0xFFFFFFFF; // todo add results too!
};
#endif /*__MESSAGE_H__*/