mirror of
https://github.com/eried/portapack-mayhem.git
synced 2025-01-13 00:09:43 -05:00
Half part of the transition of baseband processor.
This commit is contained in:
parent
a5705e1d6c
commit
b45638f9ed
@ -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);
|
||||
}
|
||||
|
||||
|
176
firmware/baseband/fprotos/fprotogeneral.hpp
Normal file
176
firmware/baseband/fprotos/fprotogeneral.hpp
Normal 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
|
12
firmware/baseband/fprotos/fprotolistgeneral.hpp
Normal file
12
firmware/baseband/fprotos/fprotolistgeneral.hpp
Normal 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
|
126
firmware/baseband/fprotos/s-ansonic.hpp
Normal file
126
firmware/baseband/fprotos/s-ansonic.hpp
Normal 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
|
61
firmware/baseband/fprotos/subghzdbase.hpp
Normal file
61
firmware/baseband/fprotos/subghzdbase.hpp
Normal 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
|
45
firmware/baseband/fprotos/subghzdprotos.hpp
Normal file
45
firmware/baseband/fprotos/subghzdprotos.hpp
Normal 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
|
@ -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,
|
||||
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -118,19 +118,16 @@ 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
|
||||
crc ^= msg[4] >> 4; // last nibble is only XORed
|
||||
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));
|
||||
}
|
||||
void ws_protocol_infactory_remote_controller() {
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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};
|
||||
|
@ -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__*/
|
||||
|
Loading…
Reference in New Issue
Block a user