From 25786026ac08b2e215e067610d20967393ed3c57 Mon Sep 17 00:00:00 2001 From: HTotoo Date: Sat, 9 Dec 2023 22:40:13 +0100 Subject: [PATCH] More protos --- firmware/application/apps/ui_subghzd.cpp | 6 + firmware/baseband/fprotos/fprotogeneral.hpp | 11 ++ firmware/baseband/fprotos/s-came_twee.hpp | 4 +- firmware/baseband/fprotos/s-chambcode.hpp | 165 ++++++++++++++++++++ firmware/baseband/fprotos/s-clemsa.hpp | 92 +++++++++++ firmware/baseband/fprotos/s-doitrand.hpp | 88 +++++++++++ firmware/baseband/fprotos/subghzdprotos.hpp | 6 + firmware/baseband/fprotos/subghztypes.hpp | 3 + 8 files changed, 373 insertions(+), 2 deletions(-) create mode 100644 firmware/baseband/fprotos/s-chambcode.hpp create mode 100644 firmware/baseband/fprotos/s-clemsa.hpp create mode 100644 firmware/baseband/fprotos/s-doitrand.hpp diff --git a/firmware/application/apps/ui_subghzd.cpp b/firmware/application/apps/ui_subghzd.cpp index 1e03f061..7c2e13ea 100644 --- a/firmware/application/apps/ui_subghzd.cpp +++ b/firmware/application/apps/ui_subghzd.cpp @@ -142,6 +142,12 @@ const char* SubGhzDView::getSensorTypeName(FPROTO_SUBGHZD_SENSOR type) { return "Came Atomo"; case FPS_CAMETWEE: return "Came Twee"; + case FPS_CHAMBCODE: + return "Chamb Code"; + case FPS_CLEMSA: + return "Clemsa"; + case FPS_DOITRAND: + return "Doitrand"; case FPS_Invalid: default: return "Unknown"; diff --git a/firmware/baseband/fprotos/fprotogeneral.hpp b/firmware/baseband/fprotos/fprotogeneral.hpp index d23ac95a..25c03cdc 100644 --- a/firmware/baseband/fprotos/fprotogeneral.hpp +++ b/firmware/baseband/fprotos/fprotogeneral.hpp @@ -7,6 +7,17 @@ #include #define bit_read(value, bit) (((value) >> (bit)) & 0x01) +#define bit_set(value, bit) \ + ({ \ + __typeof__(value) _one = (1); \ + (value) |= (_one << (bit)); \ + }) +#define bit_clear(value, bit) \ + ({ \ + __typeof__(value) _one = (1); \ + (value) &= ~(_one << (bit)); \ + }) +#define bit_write(value, bit, bitvalue) (bitvalue ? bit_set(value, bit) : bit_clear(value, bit)) #define DURATION_DIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y))) diff --git a/firmware/baseband/fprotos/s-came_twee.hpp b/firmware/baseband/fprotos/s-came_twee.hpp index 6a3aaab0..91dfde2a 100644 --- a/firmware/baseband/fprotos/s-came_twee.hpp +++ b/firmware/baseband/fprotos/s-came_twee.hpp @@ -119,10 +119,10 @@ class FProtoSubGhzDCameTwee : public FProtoSubGhzDBase { */ uint8_t cnt_parcel = (uint8_t)(data & 0xF); - uint32_t data = (uint32_t)(data & 0x0FFFFFFFF); + uint32_t dataa = (uint32_t)(data & 0x0FFFFFFFF); data = (data ^ came_twee_magic_numbers_xor[cnt_parcel]); - serial = data; + serial = dataa; data /= 4; btn = (data >> 4) & 0x0F; data >>= 16; diff --git a/firmware/baseband/fprotos/s-chambcode.hpp b/firmware/baseband/fprotos/s-chambcode.hpp new file mode 100644 index 00000000..24e2a96d --- /dev/null +++ b/firmware/baseband/fprotos/s-chambcode.hpp @@ -0,0 +1,165 @@ + +#ifndef __FPROTO_CHAMBCODE_H__ +#define __FPROTO_CHAMBCODE_H__ + +#include "subghzdbase.hpp" + +#define CHAMBERLAIN_CODE_BIT_STOP 0b0001 +#define CHAMBERLAIN_CODE_BIT_1 0b0011 +#define CHAMBERLAIN_CODE_BIT_0 0b0111 + +#define CHAMBERLAIN_7_CODE_MASK 0xF000000FF0F +#define CHAMBERLAIN_8_CODE_MASK 0xF00000F00F +#define CHAMBERLAIN_9_CODE_MASK 0xF000000000F + +#define CHAMBERLAIN_7_CODE_MASK_CHECK 0x10000001101 +#define CHAMBERLAIN_8_CODE_MASK_CHECK 0x1000001001 +#define CHAMBERLAIN_9_CODE_MASK_CHECK 0x10000000001 + +typedef enum { + Chamb_CodeDecoderStepReset = 0, + Chamb_CodeDecoderStepFoundStartBit, + Chamb_CodeDecoderStepSaveDuration, + Chamb_CodeDecoderStepCheckDuration, +} Chamb_CodeDecoderStep; + +class FProtoSubGhzDChambCode : public FProtoSubGhzDBase { + public: + FProtoSubGhzDChambCode() { + sensorType = FPS_CHAMBCODE; + } + + void feed(bool level, uint32_t duration) { + switch (parser_step) { + case Chamb_CodeDecoderStepReset: + if ((!level) && (DURATION_DIFF(duration, te_short * 39) < te_delta * 20)) { + // Found header Chamb_Code + parser_step = Chamb_CodeDecoderStepFoundStartBit; + } + break; + case Chamb_CodeDecoderStepFoundStartBit: + if ((level) && (DURATION_DIFF(duration, te_short) < te_delta)) { + // Found start bit Chamb_Code + decode_data = 0; + decode_count_bit = 0; + decode_data = decode_data << 4 | CHAMBERLAIN_CODE_BIT_STOP; + decode_count_bit++; + parser_step = Chamb_CodeDecoderStepSaveDuration; + } else { + parser_step = Chamb_CodeDecoderStepReset; + } + break; + case Chamb_CodeDecoderStepSaveDuration: + if (!level) { // save interval + if (duration > te_short * 5) { + if (decode_count_bit >= + min_count_bit_for_found) { + serial = SD_NO_SERIAL; + btn = SD_NO_BTN; + if (subghz_protocol_decoder_chamb_code_check_mask_and_parse()) { + data = decode_data; + data_count_bit = decode_count_bit; + if (callback) callback(this); + } + } + parser_step = Chamb_CodeDecoderStepReset; + } else { + te_last = duration; + parser_step = Chamb_CodeDecoderStepCheckDuration; + } + } else { + parser_step = Chamb_CodeDecoderStepReset; + } + break; + case Chamb_CodeDecoderStepCheckDuration: + if (level) { + if ((DURATION_DIFF( // Found stop bit Chamb_Code + te_last, + te_short * 3) < + te_delta) && + (DURATION_DIFF(duration, te_short) < + te_delta)) { + decode_data = decode_data << 4 | + CHAMBERLAIN_CODE_BIT_STOP; + decode_count_bit++; + parser_step = Chamb_CodeDecoderStepSaveDuration; + } else if ( + (DURATION_DIFF( + te_last, te_short * 2) < + te_delta) && + (DURATION_DIFF(duration, te_short * 2) < + te_delta)) { + decode_data = decode_data << 4 | + CHAMBERLAIN_CODE_BIT_1; + decode_count_bit++; + parser_step = Chamb_CodeDecoderStepSaveDuration; + } else if ( + (DURATION_DIFF( + te_last, te_short) < + te_delta) && + (DURATION_DIFF(duration, te_short * 3) < + te_delta)) { + decode_data = decode_data << 4 | + CHAMBERLAIN_CODE_BIT_0; + decode_count_bit++; + parser_step = Chamb_CodeDecoderStepSaveDuration; + } else { + parser_step = Chamb_CodeDecoderStepReset; + } + + } else { + parser_step = Chamb_CodeDecoderStepReset; + } + break; + } + } + + protected: + uint32_t te_short = 1000; + uint32_t te_long = 3000; + uint32_t te_delta = 200; + uint32_t min_count_bit_for_found = 10; + + bool subghz_protocol_decoder_chamb_code_check_mask_and_parse() { + if (decode_count_bit > min_count_bit_for_found + 1) + return false; + + if ((decode_data & CHAMBERLAIN_7_CODE_MASK) == CHAMBERLAIN_7_CODE_MASK_CHECK) { + decode_count_bit = 7; + decode_data &= ~CHAMBERLAIN_7_CODE_MASK; + decode_data = (decode_data >> 12) | ((decode_data >> 4) & 0xF); + } else if ( + (decode_data & CHAMBERLAIN_8_CODE_MASK) == CHAMBERLAIN_8_CODE_MASK_CHECK) { + decode_count_bit = 8; + decode_data &= ~CHAMBERLAIN_8_CODE_MASK; + decode_data = decode_data >> 4 | CHAMBERLAIN_CODE_BIT_0 << 8; // DIP 6 no use + } else if ( + (decode_data & CHAMBERLAIN_9_CODE_MASK) == CHAMBERLAIN_9_CODE_MASK_CHECK) { + decode_count_bit = 9; + decode_data &= ~CHAMBERLAIN_9_CODE_MASK; + decode_data >>= 4; + } else { + return false; + } + return subghz_protocol_chamb_code_to_bit(&decode_data, decode_count_bit); + } + + bool subghz_protocol_chamb_code_to_bit(uint64_t* data, uint8_t size) { + uint64_t data_tmp = data[0]; + uint64_t data_res = 0; + for (uint8_t i = 0; i < size; i++) { + if ((data_tmp & 0xFll) == CHAMBERLAIN_CODE_BIT_0) { + bit_write(data_res, i, 0); + } else if ((data_tmp & 0xFll) == CHAMBERLAIN_CODE_BIT_1) { + bit_write(data_res, i, 1); + } else { + return false; + } + data_tmp >>= 4; + } + data[0] = data_res; + return true; + } +}; + +#endif diff --git a/firmware/baseband/fprotos/s-clemsa.hpp b/firmware/baseband/fprotos/s-clemsa.hpp new file mode 100644 index 00000000..4d7b1d61 --- /dev/null +++ b/firmware/baseband/fprotos/s-clemsa.hpp @@ -0,0 +1,92 @@ + +#ifndef __FPROTO_CLEMSA_H__ +#define __FPROTO_CLEMSA_H__ + +#include "subghzdbase.hpp" + +typedef enum { + ClemsaDecoderStepReset = 0, + ClemsaDecoderStepSaveDuration, + ClemsaDecoderStepCheckDuration, +} ClemsaDecoderStep; + +class FProtoSubGhzDClemsa : public FProtoSubGhzDBase { + public: + FProtoSubGhzDClemsa() { + sensorType = FPS_CLEMSA; + } + + void feed(bool level, uint32_t duration) { + switch (parser_step) { + case ClemsaDecoderStepReset: + if ((!level) && (DURATION_DIFF(duration, te_short * 51) < te_delta * 25)) { + parser_step = ClemsaDecoderStepSaveDuration; + decode_data = 0; + decode_count_bit = 0; + } + break; + + case ClemsaDecoderStepSaveDuration: + if (level) { + te_last = duration; + parser_step = ClemsaDecoderStepCheckDuration; + } else { + parser_step = ClemsaDecoderStepReset; + } + break; + + case ClemsaDecoderStepCheckDuration: + if (!level) { + if ((DURATION_DIFF(te_last, te_short) < te_delta) && + (DURATION_DIFF(duration, te_long) < te_delta * 3)) { + subghz_protocol_blocks_add_bit(0); + parser_step = ClemsaDecoderStepSaveDuration; + } else if ( + (DURATION_DIFF(te_last, te_long) < te_delta * 3) && + (DURATION_DIFF(duration, te_short) < te_delta)) { + subghz_protocol_blocks_add_bit(1); + parser_step = ClemsaDecoderStepSaveDuration; + } else if ( + DURATION_DIFF(duration, te_short * 51) < te_delta * 25) { + if ((DURATION_DIFF(te_last, te_short) < te_delta)) { + subghz_protocol_blocks_add_bit(0); + } else if ((DURATION_DIFF(te_last, te_long) < te_delta * 3)) { + subghz_protocol_blocks_add_bit(1); + } else { + parser_step = ClemsaDecoderStepReset; + } + + if (decode_count_bit == + min_count_bit_for_found) { + data = decode_data; + data_count_bit = decode_count_bit; + subghz_protocol_clemsa_check_remote_controller(); + if (callback) callback(this); + } + parser_step = ClemsaDecoderStepSaveDuration; + decode_data = 0; + decode_count_bit = 0; + + } else { + parser_step = ClemsaDecoderStepReset; + } + } else { + parser_step = ClemsaDecoderStepReset; + } + break; + } + } + + protected: + uint32_t te_short = 385; + uint32_t te_long = 2695; + uint32_t te_delta = 150; + uint32_t min_count_bit_for_found = 18; + + void subghz_protocol_clemsa_check_remote_controller() { + serial = (data >> 2) & 0xFFFF; + btn = (data & 0x03); + } +}; + +#endif diff --git a/firmware/baseband/fprotos/s-doitrand.hpp b/firmware/baseband/fprotos/s-doitrand.hpp new file mode 100644 index 00000000..780329d9 --- /dev/null +++ b/firmware/baseband/fprotos/s-doitrand.hpp @@ -0,0 +1,88 @@ + +#ifndef __FPROTO_DOITRAND_H__ +#define __FPROTO_DOITRAND_H__ + +#include "subghzdbase.hpp" + +typedef enum { + DoitrandDecoderStepReset = 0, + DoitrandDecoderStepFoundStartBit, + DoitrandDecoderStepSaveDuration, + DoitrandDecoderStepCheckDuration, +} DoitrandDecoderStep; + +class FProtoSubGhzDDoitrand : public FProtoSubGhzDBase { + public: + FProtoSubGhzDDoitrand() { + sensorType = FPS_DOITRAND; + } + + void feed(bool level, uint32_t duration) { + switch (parser_step) { + case DoitrandDecoderStepReset: + if ((!level) && (DURATION_DIFF(duration, te_short * 62) < te_delta * 30)) { + // Found Preambula + parser_step = DoitrandDecoderStepFoundStartBit; + } + break; + case DoitrandDecoderStepFoundStartBit: + if (level && ((DURATION_DIFF(duration, (te_short * 2)) < te_delta * 3))) { + // Found start bit + parser_step = DoitrandDecoderStepSaveDuration; + decode_data = 0; + decode_count_bit = 0; + } else { + parser_step = DoitrandDecoderStepReset; + } + break; + case DoitrandDecoderStepSaveDuration: + if (!level) { + if (duration >= ((uint32_t)te_short * 10 + te_delta)) { + parser_step = DoitrandDecoderStepFoundStartBit; + if (decode_count_bit == min_count_bit_for_found) { + data = decode_data; + data_count_bit = decode_count_bit; + + // controller + cnt = (data >> 24) | ((data >> 15) & 0x1); + btn = ((data >> 18) & 0x3); + if (callback) callback(this); + } + decode_data = 0; + decode_count_bit = 0; + break; + } else { + te_last = duration; + parser_step = DoitrandDecoderStepCheckDuration; + } + } + break; + case DoitrandDecoderStepCheckDuration: + if (level) { + if ((DURATION_DIFF(te_last, te_short) < te_delta) && + (DURATION_DIFF(duration, te_long) < te_delta * 3)) { + subghz_protocol_blocks_add_bit(0); + parser_step = DoitrandDecoderStepSaveDuration; + } else if ( + (DURATION_DIFF(te_last, te_long) < te_delta * 3) && + (DURATION_DIFF(duration, te_short) < te_delta)) { + subghz_protocol_blocks_add_bit(1); + parser_step = DoitrandDecoderStepSaveDuration; + } else { + parser_step = DoitrandDecoderStepReset; + } + } else { + parser_step = DoitrandDecoderStepReset; + } + break; + } + } + + protected: + uint32_t te_short = 400; + uint32_t te_long = 1100; + uint32_t te_delta = 150; + uint32_t min_count_bit_for_found = 37; +}; + +#endif diff --git a/firmware/baseband/fprotos/subghzdprotos.hpp b/firmware/baseband/fprotos/subghzdprotos.hpp index 2b172e1e..033fdb31 100644 --- a/firmware/baseband/fprotos/subghzdprotos.hpp +++ b/firmware/baseband/fprotos/subghzdprotos.hpp @@ -16,6 +16,9 @@ So include here the .hpp, and add a new element to the protos vector in the cons #include "s-came.hpp" #include "s-came_atomo.hpp" #include "s-came_twee.hpp" +#include "s-chambcode.hpp" +#include "s-clemsa.hpp" +#include "s-doitrand.hpp" #ifndef __FPROTO_PROTOLISTSGZ_H__ #define __FPROTO_PROTOLISTSGZ_H__ @@ -30,6 +33,9 @@ class SubGhzDProtos : public FProtoListGeneral { protos.push_back(std::make_unique()); // 4, 5, 6 protos.push_back(std::make_unique()); // 7 protos.push_back(std::make_unique()); // 8 + protos.push_back(std::make_unique()); // 9 + protos.push_back(std::make_unique()); // 10 + protos.push_back(std::make_unique()); // 11 // set callback for them for (const auto& obj : protos) { diff --git a/firmware/baseband/fprotos/subghztypes.hpp b/firmware/baseband/fprotos/subghztypes.hpp index fb035d57..36c2a108 100644 --- a/firmware/baseband/fprotos/subghztypes.hpp +++ b/firmware/baseband/fprotos/subghztypes.hpp @@ -27,6 +27,9 @@ enum FPROTO_SUBGHZD_SENSOR { FPS_AIRFORCE = 6, FPS_CAMEATOMO = 7, FPS_CAMETWEE = 8, + FPS_CHAMBCODE = 9, + FPS_CLEMSA = 10, + FPS_DOITRAND = 11, }; #endif \ No newline at end of file