Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ClusterM/flipperzero-firmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorSkorpionm <85568270+Skorpionm@users.noreply.github.com>2022-08-07 18:56:45 +0300
committerGitHub <noreply@github.com>2022-08-07 18:56:45 +0300
commit416cce9ffc9819422940978cbc66476150aec900 (patch)
tree96ae67f85b9dc0789ac8e5d31ae552ce860e4ed9 /lib
parent81b404aafa3ead93c1496de696bef5c99b21d6fa (diff)
[FL-2718, FL-2719] SubGhz: add protocol BERNER / ELKA / TEDSEN / TELETASTER / Doitrand / Marantec / Phoenix V2 (static mode) / Phox (static mode), fix Princeton (#1516)
* SubGhz: add protocol marantec * SubGhz: add protocol BERNER / ELKA / TEDSEN / TELETASTER * SubGhz: add protocol Doitrand * SubGhz: delete debug * SubGhz: add protocol Phoenix V2 (static mode) * SubGhz: fix serial decode Phoenix V2 * SubGhz: fix Princeton, display serial number and button on boot * SubGhz: fix Bett decoder and fix unit_test * SubGhz: update test_random_raw for unit_test Co-authored-by: あく <alleteam@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/subghz/protocols/bett.c357
-rw-r--r--lib/subghz/protocols/bett.h107
-rw-r--r--lib/subghz/protocols/doitrand.c356
-rw-r--r--lib/subghz/protocols/doitrand.h107
-rw-r--r--lib/subghz/protocols/holtek.c2
-rw-r--r--lib/subghz/protocols/marantec.c393
-rw-r--r--lib/subghz/protocols/marantec.h107
-rw-r--r--lib/subghz/protocols/phoenix_v2.c339
-rw-r--r--lib/subghz/protocols/phoenix_v2.h107
-rw-r--r--lib/subghz/protocols/princeton.c25
-rw-r--r--lib/subghz/protocols/registry.c3
-rw-r--r--lib/subghz/protocols/registry.h4
12 files changed, 1894 insertions, 13 deletions
diff --git a/lib/subghz/protocols/bett.c b/lib/subghz/protocols/bett.c
new file mode 100644
index 00000000..e32679d2
--- /dev/null
+++ b/lib/subghz/protocols/bett.c
@@ -0,0 +1,357 @@
+#include "bett.h"
+
+#include "../blocks/const.h"
+#include "../blocks/decoder.h"
+#include "../blocks/encoder.h"
+#include "../blocks/generic.h"
+#include "../blocks/math.h"
+
+// protocol BERNER / ELKA / TEDSEN / TELETASTER
+#define TAG "SubGhzProtocolBETT"
+
+#define DIP_P 0b11 //(+)
+#define DIP_O 0b10 //(0)
+#define DIP_N 0b00 //(-)
+
+#define DIP_PATTERN "%c%c%c%c%c%c%c%c%c"
+#define SHOW_DIP_P(dip, check_dip) \
+ ((((dip >> 0x8) >> 0x8) == check_dip) ? '*' : '_'), \
+ ((((dip >> 0xE) & 0x3) == check_dip) ? '*' : '_'), \
+ ((((dip >> 0xC) & 0x3) == check_dip) ? '*' : '_'), \
+ ((((dip >> 0xA) & 0x3) == check_dip) ? '*' : '_'), \
+ ((((dip >> 0x8) & 0x3) == check_dip) ? '*' : '_'), \
+ ((((dip >> 0x6) & 0x3) == check_dip) ? '*' : '_'), \
+ ((((dip >> 0x4) & 0x3) == check_dip) ? '*' : '_'), \
+ ((((dip >> 0x2) & 0x3) == check_dip) ? '*' : '_'), \
+ ((((dip >> 0x0) & 0x3) == check_dip) ? '*' : '_')
+
+static const SubGhzBlockConst subghz_protocol_bett_const = {
+ .te_short = 340,
+ .te_long = 2000,
+ .te_delta = 150,
+ .min_count_bit_for_found = 18,
+};
+
+struct SubGhzProtocolDecoderBETT {
+ SubGhzProtocolDecoderBase base;
+
+ SubGhzBlockDecoder decoder;
+ SubGhzBlockGeneric generic;
+};
+
+struct SubGhzProtocolEncoderBETT {
+ SubGhzProtocolEncoderBase base;
+
+ SubGhzProtocolBlockEncoder encoder;
+ SubGhzBlockGeneric generic;
+};
+
+typedef enum {
+ BETTDecoderStepReset = 0,
+ BETTDecoderStepSaveDuration,
+ BETTDecoderStepCheckDuration,
+} BETTDecoderStep;
+
+const SubGhzProtocolDecoder subghz_protocol_bett_decoder = {
+ .alloc = subghz_protocol_decoder_bett_alloc,
+ .free = subghz_protocol_decoder_bett_free,
+
+ .feed = subghz_protocol_decoder_bett_feed,
+ .reset = subghz_protocol_decoder_bett_reset,
+
+ .get_hash_data = subghz_protocol_decoder_bett_get_hash_data,
+ .serialize = subghz_protocol_decoder_bett_serialize,
+ .deserialize = subghz_protocol_decoder_bett_deserialize,
+ .get_string = subghz_protocol_decoder_bett_get_string,
+};
+
+const SubGhzProtocolEncoder subghz_protocol_bett_encoder = {
+ .alloc = subghz_protocol_encoder_bett_alloc,
+ .free = subghz_protocol_encoder_bett_free,
+
+ .deserialize = subghz_protocol_encoder_bett_deserialize,
+ .stop = subghz_protocol_encoder_bett_stop,
+ .yield = subghz_protocol_encoder_bett_yield,
+};
+
+const SubGhzProtocol subghz_protocol_bett = {
+ .name = SUBGHZ_PROTOCOL_BETT_NAME,
+ .type = SubGhzProtocolTypeStatic,
+ .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
+ SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
+
+ .decoder = &subghz_protocol_bett_decoder,
+ .encoder = &subghz_protocol_bett_encoder,
+};
+
+void* subghz_protocol_encoder_bett_alloc(SubGhzEnvironment* environment) {
+ UNUSED(environment);
+ SubGhzProtocolEncoderBETT* instance = malloc(sizeof(SubGhzProtocolEncoderBETT));
+
+ instance->base.protocol = &subghz_protocol_bett;
+ instance->generic.protocol_name = instance->base.protocol->name;
+
+ instance->encoder.repeat = 10;
+ instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop)
+ instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
+ instance->encoder.is_runing = false;
+ return instance;
+}
+
+void subghz_protocol_encoder_bett_free(void* context) {
+ furi_assert(context);
+ SubGhzProtocolEncoderBETT* instance = context;
+ free(instance->encoder.upload);
+ free(instance);
+}
+
+/**
+ * Generating an upload from data.
+ * @param instance Pointer to a SubGhzProtocolEncoderBETT instance
+ * @return true On success
+ */
+static bool subghz_protocol_encoder_bett_get_upload(SubGhzProtocolEncoderBETT* instance) {
+ furi_assert(instance);
+ size_t index = 0;
+ size_t size_upload = (instance->generic.data_count_bit * 2);
+ if(size_upload > instance->encoder.size_upload) {
+ FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
+ return false;
+ } else {
+ instance->encoder.size_upload = size_upload;
+ }
+
+ for(uint8_t i = instance->generic.data_count_bit; i > 1; i--) {
+ if(bit_read(instance->generic.data, i - 1)) {
+ //send bit 1
+ instance->encoder.upload[index++] =
+ level_duration_make(true, (uint32_t)subghz_protocol_bett_const.te_long);
+ instance->encoder.upload[index++] =
+ level_duration_make(false, (uint32_t)subghz_protocol_bett_const.te_short);
+ } else {
+ //send bit 0
+ instance->encoder.upload[index++] =
+ level_duration_make(true, (uint32_t)subghz_protocol_bett_const.te_short);
+ instance->encoder.upload[index++] =
+ level_duration_make(false, (uint32_t)subghz_protocol_bett_const.te_long);
+ }
+ }
+ if(bit_read(instance->generic.data, 0)) {
+ //send bit 1
+ instance->encoder.upload[index++] =
+ level_duration_make(true, (uint32_t)subghz_protocol_bett_const.te_long);
+ instance->encoder.upload[index++] = level_duration_make(
+ false,
+ (uint32_t)subghz_protocol_bett_const.te_short +
+ subghz_protocol_bett_const.te_long * 7);
+ } else {
+ //send bit 0
+ instance->encoder.upload[index++] =
+ level_duration_make(true, (uint32_t)subghz_protocol_bett_const.te_short);
+ instance->encoder.upload[index++] = level_duration_make(
+ false,
+ (uint32_t)subghz_protocol_bett_const.te_long + subghz_protocol_bett_const.te_long * 7);
+ }
+ return true;
+}
+
+bool subghz_protocol_encoder_bett_deserialize(void* context, FlipperFormat* flipper_format) {
+ furi_assert(context);
+ SubGhzProtocolEncoderBETT* instance = context;
+ bool res = false;
+ do {
+ if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
+ FURI_LOG_E(TAG, "Deserialize error");
+ break;
+ }
+ if(instance->generic.data_count_bit !=
+ subghz_protocol_bett_const.min_count_bit_for_found) {
+ FURI_LOG_E(TAG, "Wrong number of bits in key");
+ break;
+ }
+ //optional parameter parameter
+ flipper_format_read_uint32(
+ flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
+
+ subghz_protocol_encoder_bett_get_upload(instance);
+ instance->encoder.is_runing = true;
+
+ res = true;
+ } while(false);
+
+ return res;
+}
+
+void subghz_protocol_encoder_bett_stop(void* context) {
+ SubGhzProtocolEncoderBETT* instance = context;
+ instance->encoder.is_runing = false;
+}
+
+LevelDuration subghz_protocol_encoder_bett_yield(void* context) {
+ SubGhzProtocolEncoderBETT* instance = context;
+
+ if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) {
+ instance->encoder.is_runing = false;
+ return level_duration_reset();
+ }
+
+ LevelDuration ret = instance->encoder.upload[instance->encoder.front];
+
+ if(++instance->encoder.front == instance->encoder.size_upload) {
+ instance->encoder.repeat--;
+ instance->encoder.front = 0;
+ }
+
+ return ret;
+}
+
+void* subghz_protocol_decoder_bett_alloc(SubGhzEnvironment* environment) {
+ UNUSED(environment);
+ SubGhzProtocolDecoderBETT* instance = malloc(sizeof(SubGhzProtocolDecoderBETT));
+ instance->base.protocol = &subghz_protocol_bett;
+ instance->generic.protocol_name = instance->base.protocol->name;
+ return instance;
+}
+
+void subghz_protocol_decoder_bett_free(void* context) {
+ furi_assert(context);
+ SubGhzProtocolDecoderBETT* instance = context;
+ free(instance);
+}
+
+void subghz_protocol_decoder_bett_reset(void* context) {
+ furi_assert(context);
+ SubGhzProtocolDecoderBETT* instance = context;
+ instance->decoder.parser_step = BETTDecoderStepReset;
+}
+
+void subghz_protocol_decoder_bett_feed(void* context, bool level, uint32_t duration) {
+ furi_assert(context);
+ SubGhzProtocolDecoderBETT* instance = context;
+
+ switch(instance->decoder.parser_step) {
+ case BETTDecoderStepReset:
+ if((!level) && (DURATION_DIFF(duration, subghz_protocol_bett_const.te_short * 42) <
+ subghz_protocol_bett_const.te_delta * 21)) {
+ //Found Preambula
+ instance->decoder.parser_step = BETTDecoderStepCheckDuration;
+ }
+ break;
+ case BETTDecoderStepSaveDuration:
+ if(!level) {
+ if(duration >= ((uint32_t)subghz_protocol_bett_const.te_short * 10 +
+ subghz_protocol_bett_const.te_delta)) {
+ instance->decoder.parser_step = BETTDecoderStepSaveDuration;
+ if(instance->decoder.decode_count_bit ==
+ subghz_protocol_bett_const.min_count_bit_for_found) {
+ instance->generic.data = instance->decoder.decode_data;
+ instance->generic.data_count_bit = instance->decoder.decode_count_bit;
+
+ if(instance->base.callback)
+ instance->base.callback(&instance->base, instance->base.context);
+ } else {
+ instance->decoder.parser_step = BETTDecoderStepReset;
+ }
+ instance->decoder.decode_data = 0;
+ instance->decoder.decode_count_bit = 0;
+ break;
+ } else {
+ if((DURATION_DIFF(duration, subghz_protocol_bett_const.te_short) <
+ subghz_protocol_bett_const.te_delta) ||
+ (DURATION_DIFF(duration, subghz_protocol_bett_const.te_long) <
+ subghz_protocol_bett_const.te_delta * 3)) {
+ instance->decoder.parser_step = BETTDecoderStepCheckDuration;
+ } else {
+ instance->decoder.parser_step = BETTDecoderStepReset;
+ }
+ }
+ }
+ break;
+ case BETTDecoderStepCheckDuration:
+ if(level) {
+ if(DURATION_DIFF(duration, subghz_protocol_bett_const.te_long) <
+ subghz_protocol_bett_const.te_delta * 3) {
+ subghz_protocol_blocks_add_bit(&instance->decoder, 1);
+ instance->decoder.parser_step = BETTDecoderStepSaveDuration;
+ } else if(
+ DURATION_DIFF(duration, subghz_protocol_bett_const.te_short) <
+ subghz_protocol_bett_const.te_delta) {
+ subghz_protocol_blocks_add_bit(&instance->decoder, 0);
+ instance->decoder.parser_step = BETTDecoderStepSaveDuration;
+ } else {
+ instance->decoder.parser_step = BETTDecoderStepReset;
+ }
+ } else {
+ instance->decoder.parser_step = BETTDecoderStepReset;
+ }
+ break;
+ }
+}
+
+/**
+ * Analysis of received data
+ * @param instance Pointer to a SubGhzBlockGeneric* instance
+ */
+static void subghz_protocol_bett_check_remote_controller(SubGhzBlockGeneric* instance) {
+ uint32_t code_found_reverse =
+ subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit);
+
+ instance->serial = (code_found_reverse & 0xFF) << 12 |
+ ((code_found_reverse >> 8) & 0xFF) << 4 |
+ ((code_found_reverse >> 20) & 0x0F);
+ instance->btn = ((code_found_reverse >> 16) & 0x0F);
+}
+
+uint8_t subghz_protocol_decoder_bett_get_hash_data(void* context) {
+ furi_assert(context);
+ SubGhzProtocolDecoderBETT* instance = context;
+ return subghz_protocol_blocks_get_hash_data(
+ &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
+}
+
+bool subghz_protocol_decoder_bett_serialize(
+ void* context,
+ FlipperFormat* flipper_format,
+ SubGhzPresetDefinition* preset) {
+ furi_assert(context);
+ SubGhzProtocolDecoderBETT* instance = context;
+ return subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
+}
+
+bool subghz_protocol_decoder_bett_deserialize(void* context, FlipperFormat* flipper_format) {
+ furi_assert(context);
+ SubGhzProtocolDecoderBETT* instance = context;
+ bool ret = false;
+ do {
+ if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
+ break;
+ }
+ if(instance->generic.data_count_bit !=
+ subghz_protocol_bett_const.min_count_bit_for_found) {
+ FURI_LOG_E(TAG, "Wrong number of bits in key");
+ break;
+ }
+ ret = true;
+ } while(false);
+ return ret;
+}
+
+void subghz_protocol_decoder_bett_get_string(void* context, string_t output) {
+ furi_assert(context);
+ SubGhzProtocolDecoderBETT* instance = context;
+ subghz_protocol_bett_check_remote_controller(&instance->generic);
+ uint32_t data = (uint32_t)(instance->generic.data & 0xFFFFFF);
+ string_cat_printf(
+ output,
+ "%s %dbit\r\n"
+ "Key:%05lX\r\n"
+ " +: " DIP_PATTERN "\r\n"
+ " o: " DIP_PATTERN "\r\n"
+ " -: " DIP_PATTERN "\r\n",
+ instance->generic.protocol_name,
+ instance->generic.data_count_bit,
+ (uint32_t)(instance->generic.data & 0xFFFFFF),
+ SHOW_DIP_P(data, DIP_P),
+ SHOW_DIP_P(data, DIP_O),
+ SHOW_DIP_P(data, DIP_N));
+}
diff --git a/lib/subghz/protocols/bett.h b/lib/subghz/protocols/bett.h
new file mode 100644
index 00000000..48f32b3e
--- /dev/null
+++ b/lib/subghz/protocols/bett.h
@@ -0,0 +1,107 @@
+#pragma once
+
+#include "base.h"
+
+#define SUBGHZ_PROTOCOL_BETT_NAME "BETT"
+
+typedef struct SubGhzProtocolDecoderBETT SubGhzProtocolDecoderBETT;
+typedef struct SubGhzProtocolEncoderBETT SubGhzProtocolEncoderBETT;
+
+extern const SubGhzProtocolDecoder subghz_protocol_bett_decoder;
+extern const SubGhzProtocolEncoder subghz_protocol_bett_encoder;
+extern const SubGhzProtocol subghz_protocol_bett;
+
+/**
+ * Allocate SubGhzProtocolEncoderBETT.
+ * @param environment Pointer to a SubGhzEnvironment instance
+ * @return SubGhzProtocolEncoderBETT* pointer to a SubGhzProtocolEncoderBETT instance
+ */
+void* subghz_protocol_encoder_bett_alloc(SubGhzEnvironment* environment);
+
+/**
+ * Free SubGhzProtocolEncoderBETT.
+ * @param context Pointer to a SubGhzProtocolEncoderBETT instance
+ */
+void subghz_protocol_encoder_bett_free(void* context);
+
+/**
+ * Deserialize and generating an upload to send.
+ * @param context Pointer to a SubGhzProtocolEncoderBETT instance
+ * @param flipper_format Pointer to a FlipperFormat instance
+ * @return true On success
+ */
+bool subghz_protocol_encoder_bett_deserialize(void* context, FlipperFormat* flipper_format);
+
+/**
+ * Forced transmission stop.
+ * @param context Pointer to a SubGhzProtocolEncoderBETT instance
+ */
+void subghz_protocol_encoder_bett_stop(void* context);
+
+/**
+ * Getting the level and duration of the upload to be loaded into DMA.
+ * @param context Pointer to a SubGhzProtocolEncoderBETT instance
+ * @return LevelDuration
+ */
+LevelDuration subghz_protocol_encoder_bett_yield(void* context);
+
+/**
+ * Allocate SubGhzProtocolDecoderBETT.
+ * @param environment Pointer to a SubGhzEnvironment instance
+ * @return SubGhzProtocolDecoderBETT* pointer to a SubGhzProtocolDecoderBETT instance
+ */
+void* subghz_protocol_decoder_bett_alloc(SubGhzEnvironment* environment);
+
+/**
+ * Free SubGhzProtocolDecoderBETT.
+ * @param context Pointer to a SubGhzProtocolDecoderBETT instance
+ */
+void subghz_protocol_decoder_bett_free(void* context);
+
+/**
+ * Reset decoder SubGhzProtocolDecoderBETT.
+ * @param context Pointer to a SubGhzProtocolDecoderBETT instance
+ */
+void subghz_protocol_decoder_bett_reset(void* context);
+
+/**
+ * Parse a raw sequence of levels and durations received from the air.
+ * @param context Pointer to a SubGhzProtocolDecoderBETT instance
+ * @param level Signal level true-high false-low
+ * @param duration Duration of this level in, us
+ */
+void subghz_protocol_decoder_bett_feed(void* context, bool level, uint32_t duration);
+
+/**
+ * Getting the hash sum of the last randomly received parcel.
+ * @param context Pointer to a SubGhzProtocolDecoderBETT instance
+ * @return hash Hash sum
+ */
+uint8_t subghz_protocol_decoder_bett_get_hash_data(void* context);
+
+/**
+ * Serialize data SubGhzProtocolDecoderBETT.
+ * @param context Pointer to a SubGhzProtocolDecoderBETT instance
+ * @param flipper_format Pointer to a FlipperFormat instance
+ * @param preset The modulation on which the signal was received, SubGhzPresetDefinition
+ * @return true On success
+ */
+bool subghz_protocol_decoder_bett_serialize(
+ void* context,
+ FlipperFormat* flipper_format,
+ SubGhzPresetDefinition* preset);
+
+/**
+ * Deserialize data SubGhzProtocolDecoderBETT.
+ * @param context Pointer to a SubGhzProtocolDecoderBETT instance
+ * @param flipper_format Pointer to a FlipperFormat instance
+ * @return true On success
+ */
+bool subghz_protocol_decoder_bett_deserialize(void* context, FlipperFormat* flipper_format);
+
+/**
+ * Getting a textual representation of the received data.
+ * @param context Pointer to a SubGhzProtocolDecoderBETT instance
+ * @param output Resulting text
+ */
+void subghz_protocol_decoder_bett_get_string(void* context, string_t output);
diff --git a/lib/subghz/protocols/doitrand.c b/lib/subghz/protocols/doitrand.c
new file mode 100644
index 00000000..c26cbc5b
--- /dev/null
+++ b/lib/subghz/protocols/doitrand.c
@@ -0,0 +1,356 @@
+#include "doitrand.h"
+
+#include "../blocks/const.h"
+#include "../blocks/decoder.h"
+#include "../blocks/encoder.h"
+#include "../blocks/generic.h"
+#include "../blocks/math.h"
+
+#define TAG "SubGhzProtocolDoitrand"
+
+#define DIP_PATTERN "%c%c%c%c%c%c%c%c%c%c"
+#define CNT_TO_DIP(dip) \
+ (dip & 0x0001 ? '1' : '0'), (dip & 0x0100 ? '1' : '0'), (dip & 0x0080 ? '1' : '0'), \
+ (dip & 0x0040 ? '1' : '0'), (dip & 0x0020 ? '1' : '0'), (dip & 0x1000 ? '1' : '0'), \
+ (dip & 0x0800 ? '1' : '0'), (dip & 0x0400 ? '1' : '0'), (dip & 0x0200 ? '1' : '0'), \
+ (dip & 0x0002 ? '1' : '0')
+
+static const SubGhzBlockConst subghz_protocol_doitrand_const = {
+ .te_short = 400,
+ .te_long = 1100,
+ .te_delta = 150,
+ .min_count_bit_for_found = 37,
+};
+
+struct SubGhzProtocolDecoderDoitrand {
+ SubGhzProtocolDecoderBase base;
+
+ SubGhzBlockDecoder decoder;
+ SubGhzBlockGeneric generic;
+};
+
+struct SubGhzProtocolEncoderDoitrand {
+ SubGhzProtocolEncoderBase base;
+
+ SubGhzProtocolBlockEncoder encoder;
+ SubGhzBlockGeneric generic;
+};
+
+typedef enum {
+ DoitrandDecoderStepReset = 0,
+ DoitrandDecoderStepFoundStartBit,
+ DoitrandDecoderStepSaveDuration,
+ DoitrandDecoderStepCheckDuration,
+} DoitrandDecoderStep;
+
+const SubGhzProtocolDecoder subghz_protocol_doitrand_decoder = {
+ .alloc = subghz_protocol_decoder_doitrand_alloc,
+ .free = subghz_protocol_decoder_doitrand_free,
+
+ .feed = subghz_protocol_decoder_doitrand_feed,
+ .reset = subghz_protocol_decoder_doitrand_reset,
+
+ .get_hash_data = subghz_protocol_decoder_doitrand_get_hash_data,
+ .serialize = subghz_protocol_decoder_doitrand_serialize,
+ .deserialize = subghz_protocol_decoder_doitrand_deserialize,
+ .get_string = subghz_protocol_decoder_doitrand_get_string,
+};
+
+const SubGhzProtocolEncoder subghz_protocol_doitrand_encoder = {
+ .alloc = subghz_protocol_encoder_doitrand_alloc,
+ .free = subghz_protocol_encoder_doitrand_free,
+
+ .deserialize = subghz_protocol_encoder_doitrand_deserialize,
+ .stop = subghz_protocol_encoder_doitrand_stop,
+ .yield = subghz_protocol_encoder_doitrand_yield,
+};
+
+const SubGhzProtocol subghz_protocol_doitrand = {
+ .name = SUBGHZ_PROTOCOL_DOITRAND_NAME,
+ .type = SubGhzProtocolTypeStatic,
+ .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
+ SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
+
+ .decoder = &subghz_protocol_doitrand_decoder,
+ .encoder = &subghz_protocol_doitrand_encoder,
+};
+
+void* subghz_protocol_encoder_doitrand_alloc(SubGhzEnvironment* environment) {
+ UNUSED(environment);
+ SubGhzProtocolEncoderDoitrand* instance = malloc(sizeof(SubGhzProtocolEncoderDoitrand));
+
+ instance->base.protocol = &subghz_protocol_doitrand;
+ instance->generic.protocol_name = instance->base.protocol->name;
+
+ instance->encoder.repeat = 10;
+ instance->encoder.size_upload = 128;
+ instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
+ instance->encoder.is_runing = false;
+ return instance;
+}
+
+void subghz_protocol_encoder_doitrand_free(void* context) {
+ furi_assert(context);
+ SubGhzProtocolEncoderDoitrand* instance = context;
+ free(instance->encoder.upload);
+ free(instance);
+}
+
+/**
+ * Generating an upload from data.
+ * @param instance Pointer to a SubGhzProtocolEncoderDoitrand instance
+ * @return true On success
+ */
+static bool subghz_protocol_encoder_doitrand_get_upload(SubGhzProtocolEncoderDoitrand* instance) {
+ furi_assert(instance);
+ size_t index = 0;
+ size_t size_upload = (instance->generic.data_count_bit * 2) + 2;
+ if(size_upload > instance->encoder.size_upload) {
+ FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
+ return false;
+ } else {
+ instance->encoder.size_upload = size_upload;
+ }
+ //Send header
+ instance->encoder.upload[index++] =
+ level_duration_make(false, (uint32_t)subghz_protocol_doitrand_const.te_short * 62);
+ //Send start bit
+ instance->encoder.upload[index++] =
+ level_duration_make(true, (uint32_t)subghz_protocol_doitrand_const.te_short * 2 - 100);
+ //Send key data
+ for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
+ if(bit_read(instance->generic.data, i - 1)) {
+ //send bit 1
+ instance->encoder.upload[index++] =
+ level_duration_make(false, (uint32_t)subghz_protocol_doitrand_const.te_long);
+ instance->encoder.upload[index++] =
+ level_duration_make(true, (uint32_t)subghz_protocol_doitrand_const.te_short);
+ } else {
+ //send bit 0
+ instance->encoder.upload[index++] =
+ level_duration_make(false, (uint32_t)subghz_protocol_doitrand_const.te_short);
+ instance->encoder.upload[index++] =
+ level_duration_make(true, (uint32_t)subghz_protocol_doitrand_const.te_long);
+ }
+ }
+ return true;
+}
+
+bool subghz_protocol_encoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format) {
+ furi_assert(context);
+ SubGhzProtocolEncoderDoitrand* instance = context;
+ bool res = false;
+ do {
+ if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
+ FURI_LOG_E(TAG, "Deserialize error");
+ break;
+ }
+ if(instance->generic.data_count_bit !=
+ subghz_protocol_doitrand_const.min_count_bit_for_found) {
+ FURI_LOG_E(TAG, "Wrong number of bits in key");
+ break;
+ }
+ //optional parameter parameter
+ flipper_format_read_uint32(
+ flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
+
+ subghz_protocol_encoder_doitrand_get_upload(instance);
+ instance->encoder.is_runing = true;
+
+ res = true;
+ } while(false);
+
+ return res;
+}
+
+void subghz_protocol_encoder_doitrand_stop(void* context) {
+ SubGhzProtocolEncoderDoitrand* instance = context;
+ instance->encoder.is_runing = false;
+}
+
+LevelDuration subghz_protocol_encoder_doitrand_yield(void* context) {
+ SubGhzProtocolEncoderDoitrand* instance = context;
+
+ if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) {
+ instance->encoder.is_runing = false;
+ return level_duration_reset();
+ }
+
+ LevelDuration ret = instance->encoder.upload[instance->encoder.front];
+
+ if(++instance->encoder.front == instance->encoder.size_upload) {
+ instance->encoder.repeat--;
+ instance->encoder.front = 0;
+ }
+
+ return ret;
+}
+
+void* subghz_protocol_decoder_doitrand_alloc(SubGhzEnvironment* environment) {
+ UNUSED(environment);
+ SubGhzProtocolDecoderDoitrand* instance = malloc(sizeof(SubGhzProtocolDecoderDoitrand));
+ instance->base.protocol = &subghz_protocol_doitrand;
+ instance->generic.protocol_name = instance->base.protocol->name;
+ return instance;
+}
+
+void subghz_protocol_decoder_doitrand_free(void* context) {
+ furi_assert(context);
+ SubGhzProtocolDecoderDoitrand* instance = context;
+ free(instance);
+}
+
+void subghz_protocol_decoder_doitrand_reset(void* context) {
+ furi_assert(context);
+ SubGhzProtocolDecoderDoitrand* instance = context;
+ instance->decoder.parser_step = DoitrandDecoderStepReset;
+}
+
+void subghz_protocol_decoder_doitrand_feed(void* context, bool level, uint32_t duration) {
+ furi_assert(context);
+ SubGhzProtocolDecoderDoitrand* instance = context;
+
+ switch(instance->decoder.parser_step) {
+ case DoitrandDecoderStepReset:
+ if((!level) && (DURATION_DIFF(duration, subghz_protocol_doitrand_const.te_short * 62) <
+ subghz_protocol_doitrand_const.te_delta * 30)) {
+ //Found Preambula
+ instance->decoder.parser_step = DoitrandDecoderStepFoundStartBit;
+ }
+ break;
+ case DoitrandDecoderStepFoundStartBit:
+ if(level && ((DURATION_DIFF(duration, (subghz_protocol_doitrand_const.te_short * 2)) <
+ subghz_protocol_doitrand_const.te_delta * 3))) {
+ //Found start bit
+ instance->decoder.parser_step = DoitrandDecoderStepSaveDuration;
+ instance->decoder.decode_data = 0;
+ instance->decoder.decode_count_bit = 0;
+ } else {
+ instance->decoder.parser_step = DoitrandDecoderStepReset;
+ }
+ break;
+ case DoitrandDecoderStepSaveDuration:
+ if(!level) {
+ if(duration >= ((uint32_t)subghz_protocol_doitrand_const.te_short * 10 +
+ subghz_protocol_doitrand_const.te_delta)) {
+ instance->decoder.parser_step = DoitrandDecoderStepFoundStartBit;
+ if(instance->decoder.decode_count_bit ==
+ subghz_protocol_doitrand_const.min_count_bit_for_found) {
+ instance->generic.data = instance->decoder.decode_data;
+ instance->generic.data_count_bit = instance->decoder.decode_count_bit;
+
+ if(instance->base.callback)
+ instance->base.callback(&instance->base, instance->base.context);
+ }
+ instance->decoder.decode_data = 0;
+ instance->decoder.decode_count_bit = 0;
+ break;
+ } else {
+ instance->decoder.te_last = duration;
+ instance->decoder.parser_step = DoitrandDecoderStepCheckDuration;
+ }
+ }
+ break;
+ case DoitrandDecoderStepCheckDuration:
+ if(level) {
+ if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_doitrand_const.te_short) <
+ subghz_protocol_doitrand_const.te_delta) &&
+ (DURATION_DIFF(duration, subghz_protocol_doitrand_const.te_long) <
+ subghz_protocol_doitrand_const.te_delta * 3)) {
+ subghz_protocol_blocks_add_bit(&instance->decoder, 0);
+ instance->decoder.parser_step = DoitrandDecoderStepSaveDuration;
+ } else if(
+ (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_doitrand_const.te_long) <
+ subghz_protocol_doitrand_const.te_delta * 3) &&
+ (DURATION_DIFF(duration, subghz_protocol_doitrand_const.te_short) <
+ subghz_protocol_doitrand_const.te_delta)) {
+ subghz_protocol_blocks_add_bit(&instance->decoder, 1);
+ instance->decoder.parser_step = DoitrandDecoderStepSaveDuration;
+ } else {
+ instance->decoder.parser_step = DoitrandDecoderStepReset;
+ }
+ } else {
+ instance->decoder.parser_step = DoitrandDecoderStepReset;
+ }
+ break;
+ }
+}
+
+/**
+ * Analysis of received data
+ * @param instance Pointer to a SubGhzBlockGeneric* instance
+ */
+static void subghz_protocol_doitrand_check_remote_controller(SubGhzBlockGeneric* instance) {
+ /*
+* 67892345 0 k 1
+* 0000082F5F => 00000000000000000 10 000010111101011111
+* 0002082F5F => 00000000000100000 10 000010111101011111
+* 0200082F5F => 00010000000000000 10 000010111101011111
+* 0400082F5F => 00100000000000000 10 000010111101011111
+* 0800082F5F => 01000000000000000 10 000010111101011111
+* 1000082F5F => 10000000000000000 10 000010111101011111
+* 0020082F5F => 00000001000000000 10 000010111101011111
+* 0040082F5F => 00000010000000000 10 000010111101011111
+* 0080082F5F => 00000100000000000 10 000010111101011111
+* 0100082F5F => 00001000000000000 10 000010111101011111
+* 000008AF5F => 00000000000000000 10 001010111101011111
+* 1FE208AF5F => 11111111000100000 10 001010111101011111
+*
+* 0...9 - DIP
+* k- KEY
+*/
+ instance->cnt = (instance->data >> 24) | ((instance->data >> 15) & 0x1);
+ instance->btn = ((instance->data >> 18) & 0x3);
+}
+
+uint8_t subghz_protocol_decoder_doitrand_get_hash_data(void* context) {
+ furi_assert(context);
+ SubGhzProtocolDecoderDoitrand* instance = context;
+ return subghz_protocol_blocks_get_hash_data(
+ &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
+}
+
+bool subghz_protocol_decoder_doitrand_serialize(
+ void* context,
+ FlipperFormat* flipper_format,
+ SubGhzPresetDefinition* preset) {
+ furi_assert(context);
+ SubGhzProtocolDecoderDoitrand* instance = context;
+ return subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
+}
+
+bool subghz_protocol_decoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format) {
+ furi_assert(context);
+ SubGhzProtocolDecoderDoitrand* instance = context;
+ bool ret = false;
+ do {
+ if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
+ break;
+ }
+ if(instance->generic.data_count_bit !=
+ subghz_protocol_doitrand_const.min_count_bit_for_found) {
+ FURI_LOG_E(TAG, "Wrong number of bits in key");
+ break;
+ }
+ ret = true;
+ } while(false);
+ return ret;
+}
+
+void subghz_protocol_decoder_doitrand_get_string(void* context, string_t output) {
+ furi_assert(context);
+ SubGhzProtocolDecoderDoitrand* instance = context;
+ subghz_protocol_doitrand_check_remote_controller(&instance->generic);
+ string_cat_printf(
+ output,
+ "%s %dbit\r\n"
+ "Key:%02lX%08lX\r\n"
+ "Btn:%lX\r\n"
+ "DIP:" DIP_PATTERN "\r\n",
+ instance->generic.protocol_name,
+ instance->generic.data_count_bit,
+ (uint32_t)(instance->generic.data >> 32) & 0xFFFFFFFF,
+ (uint32_t)(instance->generic.data & 0xFFFFFFFF),
+ instance->generic.btn,
+ CNT_TO_DIP(instance->generic.cnt));
+}
diff --git a/lib/subghz/protocols/doitrand.h b/lib/subghz/protocols/doitrand.h
new file mode 100644
index 00000000..f94d7389
--- /dev/null
+++ b/lib/subghz/protocols/doitrand.h
@@ -0,0 +1,107 @@
+#pragma once
+
+#include "base.h"
+
+#define SUBGHZ_PROTOCOL_DOITRAND_NAME "Doitrand"
+
+typedef struct SubGhzProtocolDecoderDoitrand SubGhzProtocolDecoderDoitrand;
+typedef struct SubGhzProtocolEncoderDoitrand SubGhzProtocolEncoderDoitrand;
+
+extern const SubGhzProtocolDecoder subghz_protocol_doitrand_decoder;
+extern const SubGhzProtocolEncoder subghz_protocol_doitrand_encoder;
+extern const SubGhzProtocol subghz_protocol_doitrand;
+
+/**
+ * Allocate SubGhzProtocolEncoderDoitrand.
+ * @param environment Pointer to a SubGhzEnvironment instance
+ * @return SubGhzProtocolEncoderDoitrand* pointer to a SubGhzProtocolEncoderDoitrand instance
+ */
+void* subghz_protocol_encoder_doitrand_alloc(SubGhzEnvironment* environment);
+
+/**
+ * Free SubGhzProtocolEncoderDoitrand.
+ * @param context Pointer to a SubGhzProtocolEncoderDoitrand instance
+ */
+void subghz_protocol_encoder_doitrand_free(void* context);
+
+/**
+ * Deserialize and generating an upload to send.
+ * @param context Pointer to a SubGhzProtocolEncoderDoitrand instance
+ * @param flipper_format Pointer to a FlipperFormat instance
+ * @return true On success
+ */
+bool subghz_protocol_encoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format);
+
+/**
+ * Forced transmission stop.
+ * @param context Pointer to a SubGhzProtocolEncoderDoitrand instance
+ */
+void subghz_protocol_encoder_doitrand_stop(void* context);
+
+/**
+ * Getting the level and duration of the upload to be loaded into DMA.
+ * @param context Pointer to a SubGhzProtocolEncoderDoitrand instance
+ * @return LevelDuration
+ */
+LevelDuration subghz_protocol_encoder_doitrand_yield(void* context);
+
+/**
+ * Allocate SubGhzProtocolDecoderDoitrand.
+ * @param environment Pointer to a SubGhzEnvironment instance
+ * @return SubGhzProtocolDecoderDoitrand* pointer to a SubGhzProtocolDecoderDoitrand instance
+ */
+void* subghz_protocol_decoder_doitrand_alloc(SubGhzEnvironment* environment);
+
+/**
+ * Free SubGhzProtocolDecoderDoitrand.
+ * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance
+ */
+void subghz_protocol_decoder_doitrand_free(void* context);
+
+/**
+ * Reset decoder SubGhzProtocolDecoderDoitrand.
+ * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance
+ */
+void subghz_protocol_decoder_doitrand_reset(void* context);
+
+/**
+ * Parse a raw sequence of levels and durations received from the air.
+ * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance
+ * @param level Signal level true-high false-low
+ * @param duration Duration of this level in, us
+ */
+void subghz_protocol_decoder_doitrand_feed(void* context, bool level, uint32_t duration);
+
+/**
+ * Getting the hash sum of the last randomly received parcel.
+ * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance
+ * @return hash Hash sum
+ */
+uint8_t subghz_protocol_decoder_doitrand_get_hash_data(void* context);
+
+/**
+ * Serialize data SubGhzProtocolDecoderDoitrand.
+ * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance
+ * @param flipper_format Pointer to a FlipperFormat instance
+ * @param preset The modulation on which the signal was received, SubGhzPresetDefinition
+ * @return true On success
+ */
+bool subghz_protocol_decoder_doitrand_serialize(
+ void* context,
+ FlipperFormat* flipper_format,
+ SubGhzPresetDefinition* preset);
+
+/**
+ * Deserialize data SubGhzProtocolDecoderDoitrand.
+ * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance
+ * @param flipper_format Pointer to a FlipperFormat instance
+ * @return true On success
+ */
+bool subghz_protocol_decoder_doitrand_deserialize(void* context, FlipperFormat* flipper_format);
+
+/**
+ * Getting a textual representation of the received data.
+ * @param context Pointer to a SubGhzProtocolDecoderDoitrand instance
+ * @param output Resulting text
+ */
+void subghz_protocol_decoder_doitrand_get_string(void* context, string_t output);
diff --git a/lib/subghz/protocols/holtek.c b/lib/subghz/protocols/holtek.c
index eeb24026..ed5e4fb5 100644
--- a/lib/subghz/protocols/holtek.c
+++ b/lib/subghz/protocols/holtek.c
@@ -359,7 +359,7 @@ void subghz_protocol_decoder_holtek_get_string(void* context, string_t output) {
output,
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
- "Sn:0x%05lX BTN:%X ",
+ "Sn:0x%05lX Btn:%X ",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)((instance->generic.data >> 32) & 0xFFFFFFFF),
diff --git a/lib/subghz/protocols/marantec.c b/lib/subghz/protocols/marantec.c
new file mode 100644
index 00000000..d4692724
--- /dev/null
+++ b/lib/subghz/protocols/marantec.c
@@ -0,0 +1,393 @@
+#include "marantec.h"
+#include <lib/toolbox/manchester_decoder.h>
+#include <lib/toolbox/manchester_encoder.h>
+#include "../blocks/const.h"
+#include "../blocks/decoder.h"
+#include "../blocks/encoder.h"
+#include "../blocks/generic.h"
+#include "../blocks/math.h"
+
+#define TAG "SubGhzProtocolMarantec"
+
+static const SubGhzBlockConst subghz_protocol_marantec_const = {
+ .te_short = 1000,
+ .te_long = 2000,
+ .te_delta = 200,
+ .min_count_bit_for_found = 49,
+};
+
+struct SubGhzProtocolDecoderMarantec {
+ SubGhzProtocolDecoderBase base;
+
+ SubGhzBlockDecoder decoder;
+ SubGhzBlockGeneric generic;
+ ManchesterState manchester_saved_state;
+ uint16_t header_count;
+};
+
+struct SubGhzProtocolEncoderMarantec {
+ SubGhzProtocolEncoderBase base;
+
+ SubGhzProtocolBlockEncoder encoder;
+ SubGhzBlockGeneric generic;
+};
+
+typedef enum {
+ MarantecDecoderStepReset = 0,
+ MarantecDecoderFoundHeader,
+ MarantecDecoderStepDecoderData,
+} MarantecDecoderStep;
+
+const SubGhzProtocolDecoder subghz_protocol_marantec_decoder = {
+ .alloc = subghz_protocol_decoder_marantec_alloc,
+ .free = subghz_protocol_decoder_marantec_free,
+
+ .feed = subghz_protocol_decoder_marantec_feed,
+ .reset = subghz_protocol_decoder_marantec_reset,
+
+ .get_hash_data = subghz_protocol_decoder_marantec_get_hash_data,
+ .serialize = subghz_protocol_decoder_marantec_serialize,
+ .deserialize = subghz_protocol_decoder_marantec_deserialize,
+ .get_string = subghz_protocol_decoder_marantec_get_string,
+};
+
+const SubGhzProtocolEncoder subghz_protocol_marantec_encoder = {
+ .alloc = subghz_protocol_encoder_marantec_alloc,
+ .free = subghz_protocol_encoder_marantec_free,
+
+ .deserialize = subghz_protocol_encoder_marantec_deserialize,
+ .stop = subghz_protocol_encoder_marantec_stop,
+ .yield = subghz_protocol_encoder_marantec_yield,
+};
+
+const SubGhzProtocol subghz_protocol_marantec = {
+ .name = SUBGHZ_PROTOCOL_MARANTEC_NAME,
+ .type = SubGhzProtocolTypeStatic,
+ .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
+ SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
+
+ .decoder = &subghz_protocol_marantec_decoder,
+ .encoder = &subghz_protocol_marantec_encoder,
+};
+
+void* subghz_protocol_encoder_marantec_alloc(SubGhzEnvironment* environment) {
+ UNUSED(environment);
+ SubGhzProtocolEncoderMarantec* instance = malloc(sizeof(SubGhzProtocolEncoderMarantec));
+
+ instance->base.protocol = &subghz_protocol_marantec;
+ instance->generic.protocol_name = instance->base.protocol->name;
+
+ instance->encoder.repeat = 10;
+ instance->encoder.size_upload = 256;
+ instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
+ instance->encoder.is_runing = false;
+ return instance;
+}
+
+void subghz_protocol_encoder_marantec_free(void* context) {
+ furi_assert(context);
+ SubGhzProtocolEncoderMarantec* instance = context;
+ free(instance->encoder.upload);
+ free(instance);
+}
+
+static LevelDuration
+ subghz_protocol_encoder_marantec_add_duration_to_upload(ManchesterEncoderResult result) {
+ LevelDuration data = {.duration = 0, .level = 0};
+ switch(result) {
+ case ManchesterEncoderResultShortLow:
+ data.duration = subghz_protocol_marantec_const.te_short;
+ data.level = false;
+ break;
+ case ManchesterEncoderResultLongLow:
+ data.duration = subghz_protocol_marantec_const.te_long;
+ data.level = false;
+ break;
+ case ManchesterEncoderResultLongHigh:
+ data.duration = subghz_protocol_marantec_const.te_long;
+ data.level = true;
+ break;
+ case ManchesterEncoderResultShortHigh:
+ data.duration = subghz_protocol_marantec_const.te_short;
+ data.level = true;
+ break;
+
+ default:
+ furi_crash("SubGhz: ManchesterEncoderResult is incorrect.");
+ break;
+ }
+ return level_duration_make(data.level, data.duration);
+}
+
+/**
+ * Generating an upload from data.
+ * @param instance Pointer to a SubGhzProtocolEncoderMarantec instance
+ */
+static void subghz_protocol_encoder_marantec_get_upload(SubGhzProtocolEncoderMarantec* instance) {
+ furi_assert(instance);
+ size_t index = 0;
+
+ ManchesterEncoderState enc_state;
+ manchester_encoder_reset(&enc_state);
+ ManchesterEncoderResult result;
+
+ if(!manchester_encoder_advance(
+ &enc_state,
+ bit_read(instance->generic.data, instance->generic.data_count_bit - 1),
+ &result)) {
+ instance->encoder.upload[index++] =
+ subghz_protocol_encoder_marantec_add_duration_to_upload(result);
+ manchester_encoder_advance(
+ &enc_state,
+ bit_read(instance->generic.data, instance->generic.data_count_bit - 1),
+ &result);
+ }
+ instance->encoder.upload[index++] =
+ level_duration_make(false, (uint32_t)subghz_protocol_marantec_const.te_long * 5);
+
+ for(uint8_t i = instance->generic.data_count_bit - 1; i > 0; i--) {
+ if(!manchester_encoder_advance(
+ &enc_state, bit_read(instance->generic.data, i - 1), &result)) {
+ instance->encoder.upload[index++] =
+ subghz_protocol_encoder_marantec_add_duration_to_upload(result);
+ manchester_encoder_advance(
+ &enc_state, bit_read(instance->generic.data, i - 1), &result);
+ }
+ instance->encoder.upload[index++] =
+ subghz_protocol_encoder_marantec_add_duration_to_upload(result);
+ }
+ instance->encoder.upload[index] = subghz_protocol_encoder_marantec_add_duration_to_upload(
+ manchester_encoder_finish(&enc_state));
+ if(level_duration_get_level(instance->encoder.upload[index])) {
+ index++;
+ }
+ instance->encoder.size_upload = index;
+}
+
+uint8_t subghz_protocol_marantec_crc8(uint8_t* data, size_t len) {
+ uint8_t crc = 0x08;
+ size_t i, j;
+ for(i = 0; i < len; i++) {
+ crc ^= data[i];
+ for(j = 0; j < 8; j++) {
+ if((crc & 0x80) != 0)
+ crc = (uint8_t)((crc << 1) ^ 0x1D);
+ else
+ crc <<= 1;
+ }
+ }
+ return crc;
+}
+
+/**
+ * Analysis of received data
+ * @param instance Pointer to a SubGhzBlockGeneric* instance
+ */
+static void subghz_protocol_marantec_remote_controller(SubGhzBlockGeneric* instance) {
+ instance->btn = (instance->data >> 16) & 0xF;
+ instance->serial = ((instance->data >> 12) & 0xFFFFFF00) | ((instance->data >> 8) & 0xFF);
+}
+
+bool subghz_protocol_encoder_marantec_deserialize(void* context, FlipperFormat* flipper_format) {
+ furi_assert(context);
+ SubGhzProtocolEncoderMarantec* instance = context;
+ bool res = false;
+ do {
+ if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
+ FURI_LOG_E(TAG, "Deserialize error");
+ break;
+ }
+ if(instance->generic.data_count_bit !=
+ subghz_protocol_marantec_const.min_count_bit_for_found) {
+ FURI_LOG_E(TAG, "Wrong number of bits in key");
+ break;
+ }
+ //optional parameter parameter
+ flipper_format_read_uint32(
+ flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
+
+ subghz_protocol_marantec_remote_controller(&instance->generic);
+ subghz_protocol_encoder_marantec_get_upload(instance);
+ instance->encoder.is_runing = true;
+
+ res = true;
+ } while(false);
+
+ return res;
+}
+
+void subghz_protocol_encoder_marantec_stop(void* context) {
+ SubGhzProtocolEncoderMarantec* instance = context;
+ instance->encoder.is_runing = false;
+}
+
+LevelDuration subghz_protocol_encoder_marantec_yield(void* context) {
+ SubGhzProtocolEncoderMarantec* instance = context;
+
+ if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) {
+ instance->encoder.is_runing = false;
+ return level_duration_reset();
+ }
+
+ LevelDuration ret = instance->encoder.upload[instance->encoder.front];
+
+ if(++instance->encoder.front == instance->encoder.size_upload) {
+ instance->encoder.repeat--;
+ instance->encoder.front = 0;
+ }
+
+ return ret;
+}
+
+void* subghz_protocol_decoder_marantec_alloc(SubGhzEnvironment* environment) {
+ UNUSED(environment);
+ SubGhzProtocolDecoderMarantec* instance = malloc(sizeof(SubGhzProtocolDecoderMarantec));
+ instance->base.protocol = &subghz_protocol_marantec;
+ instance->generic.protocol_name = instance->base.protocol->name;
+ return instance;
+}
+
+void subghz_protocol_decoder_marantec_free(void* context) {
+ furi_assert(context);
+ SubGhzProtocolDecoderMarantec* instance = context;
+ free(instance);
+}
+
+void subghz_protocol_decoder_marantec_reset(void* context) {
+ furi_assert(context);
+ SubGhzProtocolDecoderMarantec* instance = context;
+ manchester_advance(
+ instance->manchester_saved_state,
+ ManchesterEventReset,
+ &instance->manchester_saved_state,
+ NULL);
+}
+
+void subghz_protocol_decoder_marantec_feed(void* context, bool level, volatile uint32_t duration) {
+ furi_assert(context);
+ SubGhzProtocolDecoderMarantec* instance = context;
+ ManchesterEvent event = ManchesterEventReset;
+
+ switch(instance->decoder.parser_step) {
+ case MarantecDecoderStepReset:
+ if((!level) && (DURATION_DIFF(duration, subghz_protocol_marantec_const.te_long * 5) <
+ subghz_protocol_marantec_const.te_delta * 8)) {
+ //Found header marantec
+ instance->decoder.parser_step = MarantecDecoderStepDecoderData;
+ instance->decoder.decode_data = 1;
+ instance->decoder.decode_count_bit = 1;
+ manchester_advance(
+ instance->manchester_saved_state,
+ ManchesterEventReset,
+ &instance->manchester_saved_state,
+ NULL);
+ }
+ break;
+ case MarantecDecoderStepDecoderData:
+ if(!level) {
+ if(DURATION_DIFF(duration, subghz_protocol_marantec_const.te_short) <
+ subghz_protocol_marantec_const.te_delta) {
+ event = ManchesterEventShortLow;
+ } else if(
+ DURATION_DIFF(duration, subghz_protocol_marantec_const.te_long) <
+ subghz_protocol_marantec_const.te_delta) {
+ event = ManchesterEventLongLow;
+ } else if(
+ duration >= ((uint32_t)subghz_protocol_marantec_const.te_long * 2 +
+ subghz_protocol_marantec_const.te_delta)) {
+ if(instance->decoder.decode_count_bit ==
+ subghz_protocol_marantec_const.min_count_bit_for_found) {
+ instance->generic.data = instance->decoder.decode_data;
+ instance->generic.data_count_bit = instance->decoder.decode_count_bit;
+
+ if(instance->base.callback)
+ instance->base.callback(&instance->base, instance->base.context);
+ }
+ instance->decoder.decode_data = 1;
+ instance->decoder.decode_count_bit = 1;
+ manchester_advance(
+ instance->manchester_saved_state,
+ ManchesterEventReset,
+ &instance->manchester_saved_state,
+ NULL);
+ } else {
+ instance->decoder.parser_step = MarantecDecoderStepReset;
+ }
+ } else {
+ if(DURATION_DIFF(duration, subghz_protocol_marantec_const.te_short) <
+ subghz_protocol_marantec_const.te_delta) {
+ event = ManchesterEventShortHigh;
+ } else if(
+ DURATION_DIFF(duration, subghz_protocol_marantec_const.te_long) <
+ subghz_protocol_marantec_const.te_delta) {
+ event = ManchesterEventLongHigh;
+ } else {
+ instance->decoder.parser_step = MarantecDecoderStepReset;
+ }
+ }
+ if(event != ManchesterEventReset) {
+ bool data;
+ bool data_ok = manchester_advance(
+ instance->manchester_saved_state, event, &instance->manchester_saved_state, &data);
+
+ if(data_ok) {
+ instance->decoder.decode_data = (instance->decoder.decode_data << 1) | data;
+ instance->decoder.decode_count_bit++;
+ }
+ }
+ break;
+ }
+}
+
+uint8_t subghz_protocol_decoder_marantec_get_hash_data(void* context) {
+ furi_assert(context);
+ SubGhzProtocolDecoderMarantec* instance = context;
+ return subghz_protocol_blocks_get_hash_data(
+ &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
+}
+
+bool subghz_protocol_decoder_marantec_serialize(
+ void* context,
+ FlipperFormat* flipper_format,
+ SubGhzPresetDefinition* preset) {
+ furi_assert(context);
+ SubGhzProtocolDecoderMarantec* instance = context;
+ return subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
+}
+
+bool subghz_protocol_decoder_marantec_deserialize(void* context, FlipperFormat* flipper_format) {
+ furi_assert(context);
+ SubGhzProtocolDecoderMarantec* instance = context;
+ bool ret = false;
+ do {
+ if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
+ break;
+ }
+ if(instance->generic.data_count_bit !=
+ subghz_protocol_marantec_const.min_count_bit_for_found) {
+ FURI_LOG_E(TAG, "Wrong number of bits in key");
+ break;
+ }
+ ret = true;
+ } while(false);
+ return ret;
+}
+
+void subghz_protocol_decoder_marantec_get_string(void* context, string_t output) {
+ furi_assert(context);
+ SubGhzProtocolDecoderMarantec* instance = context;
+ subghz_protocol_marantec_remote_controller(&instance->generic);
+
+ string_cat_printf(
+ output,
+ "%s %db\r\n"
+ "Key:0x%lX%08lX\r\n"
+ "Sn:0x%07lX \r\n"
+ "Btn:%lX\r\n",
+ instance->generic.protocol_name,
+ instance->generic.data_count_bit,
+ (uint32_t)(instance->generic.data >> 32),
+ (uint32_t)(instance->generic.data & 0xFFFFFFFF),
+ instance->generic.serial,
+ instance->generic.btn);
+}
diff --git a/lib/subghz/protocols/marantec.h b/lib/subghz/protocols/marantec.h
new file mode 100644
index 00000000..2da3c88a
--- /dev/null
+++ b/lib/subghz/protocols/marantec.h
@@ -0,0 +1,107 @@
+#pragma once
+
+#include "base.h"
+
+#define SUBGHZ_PROTOCOL_MARANTEC_NAME "Marantec"
+
+typedef struct SubGhzProtocolDecoderMarantec SubGhzProtocolDecoderMarantec;
+typedef struct SubGhzProtocolEncoderMarantec SubGhzProtocolEncoderMarantec;
+
+extern const SubGhzProtocolDecoder subghz_protocol_marantec_decoder;
+extern const SubGhzProtocolEncoder subghz_protocol_marantec_encoder;
+extern const SubGhzProtocol subghz_protocol_marantec;
+
+/**
+ * Allocate SubGhzProtocolEncoderMarantec.
+ * @param environment Pointer to a SubGhzEnvironment instance
+ * @return SubGhzProtocolEncoderMarantec* pointer to a SubGhzProtocolEncoderMarantec instance
+ */
+void* subghz_protocol_encoder_marantec_alloc(SubGhzEnvironment* environment);
+
+/**
+ * Free SubGhzProtocolEncoderMarantec.
+ * @param context Pointer to a SubGhzProtocolEncoderMarantec instance
+ */
+void subghz_protocol_encoder_marantec_free(void* context);
+
+/**
+ * Deserialize and generating an upload to send.
+ * @param context Pointer to a SubGhzProtocolEncoderMarantec instance
+ * @param flipper_format Pointer to a FlipperFormat instance
+ * @return true On success
+ */
+bool subghz_protocol_encoder_marantec_deserialize(void* context, FlipperFormat* flipper_format);
+
+/**
+ * Forced transmission stop.
+ * @param context Pointer to a SubGhzProtocolEncoderMarantec instance
+ */
+void subghz_protocol_encoder_marantec_stop(void* context);
+
+/**
+ * Getting the level and duration of the upload to be loaded into DMA.
+ * @param context Pointer to a SubGhzProtocolEncoderMarantec instance
+ * @return LevelDuration
+ */
+LevelDuration subghz_protocol_encoder_marantec_yield(void* context);
+
+/**
+ * Allocate SubGhzProtocolDecoderMarantec.
+ * @param environment Pointer to a SubGhzEnvironment instance
+ * @return SubGhzProtocolDecoderMarantec* pointer to a SubGhzProtocolDecoderMarantec instance
+ */
+void* subghz_protocol_decoder_marantec_alloc(SubGhzEnvironment* environment);
+
+/**
+ * Free SubGhzProtocolDecoderMarantec.
+ * @param context Pointer to a SubGhzProtocolDecoderMarantec instance
+ */
+void subghz_protocol_decoder_marantec_free(void* context);
+
+/**
+ * Reset decoder SubGhzProtocolDecoderMarantec.
+ * @param context Pointer to a SubGhzProtocolDecoderMarantec instance
+ */
+void subghz_protocol_decoder_marantec_reset(void* context);
+
+/**
+ * Parse a raw sequence of levels and durations received from the air.
+ * @param context Pointer to a SubGhzProtocolDecoderMarantec instance
+ * @param level Signal level true-high false-low
+ * @param duration Duration of this level in, us
+ */
+void subghz_protocol_decoder_marantec_feed(void* context, bool level, uint32_t duration);
+
+/**
+ * Getting the hash sum of the last randomly received parcel.
+ * @param context Pointer to a SubGhzProtocolDecoderMarantec instance
+ * @return hash Hash sum
+ */
+uint8_t subghz_protocol_decoder_marantec_get_hash_data(void* context);
+
+/**
+ * Serialize data SubGhzProtocolDecoderMarantec.
+ * @param context Pointer to a SubGhzProtocolDecoderMarantec instance
+ * @param flipper_format Pointer to a FlipperFormat instance
+ * @param preset The modulation on which the signal was received, SubGhzPresetDefinition
+ * @return true On success
+ */
+bool subghz_protocol_decoder_marantec_serialize(
+ void* context,
+ FlipperFormat* flipper_format,
+ SubGhzPresetDefinition* preset);
+
+/**
+ * Deserialize data SubGhzProtocolDecoderMarantec.
+ * @param context Pointer to a SubGhzProtocolDecoderMarantec instance
+ * @param flipper_format Pointer to a FlipperFormat instance
+ * @return true On success
+ */
+bool subghz_protocol_decoder_marantec_deserialize(void* context, FlipperFormat* flipper_format);
+
+/**
+ * Getting a textual representation of the received data.
+ * @param context Pointer to a SubGhzProtocolDecoderMarantec instance
+ * @param output Resulting text
+ */
+void subghz_protocol_decoder_marantec_get_string(void* context, string_t output);
diff --git a/lib/subghz/protocols/phoenix_v2.c b/lib/subghz/protocols/phoenix_v2.c
new file mode 100644
index 00000000..e71e2834
--- /dev/null
+++ b/lib/subghz/protocols/phoenix_v2.c
@@ -0,0 +1,339 @@
+#include "phoenix_v2.h"
+
+#include "../blocks/const.h"
+#include "../blocks/decoder.h"
+#include "../blocks/encoder.h"
+#include "../blocks/generic.h"
+#include "../blocks/math.h"
+
+#define TAG "SubGhzProtocolPhoenix_V2"
+
+//transmission only static mode
+
+static const SubGhzBlockConst subghz_protocol_phoenix_v2_const = {
+ .te_short = 427,
+ .te_long = 853,
+ .te_delta = 100,
+ .min_count_bit_for_found = 52,
+};
+
+struct SubGhzProtocolDecoderPhoenix_V2 {
+ SubGhzProtocolDecoderBase base;
+
+ SubGhzBlockDecoder decoder;
+ SubGhzBlockGeneric generic;
+};
+
+struct SubGhzProtocolEncoderPhoenix_V2 {
+ SubGhzProtocolEncoderBase base;
+
+ SubGhzProtocolBlockEncoder encoder;
+ SubGhzBlockGeneric generic;
+};
+
+typedef enum {
+ Phoenix_V2DecoderStepReset = 0,
+ Phoenix_V2DecoderStepFoundStartBit,
+ Phoenix_V2DecoderStepSaveDuration,
+ Phoenix_V2DecoderStepCheckDuration,
+} Phoenix_V2DecoderStep;
+
+const SubGhzProtocolDecoder subghz_protocol_phoenix_v2_decoder = {
+ .alloc = subghz_protocol_decoder_phoenix_v2_alloc,
+ .free = subghz_protocol_decoder_phoenix_v2_free,
+
+ .feed = subghz_protocol_decoder_phoenix_v2_feed,
+ .reset = subghz_protocol_decoder_phoenix_v2_reset,
+
+ .get_hash_data = subghz_protocol_decoder_phoenix_v2_get_hash_data,
+ .serialize = subghz_protocol_decoder_phoenix_v2_serialize,
+ .deserialize = subghz_protocol_decoder_phoenix_v2_deserialize,
+ .get_string = subghz_protocol_decoder_phoenix_v2_get_string,
+};
+
+const SubGhzProtocolEncoder subghz_protocol_phoenix_v2_encoder = {
+ .alloc = subghz_protocol_encoder_phoenix_v2_alloc,
+ .free = subghz_protocol_encoder_phoenix_v2_free,
+
+ .deserialize = subghz_protocol_encoder_phoenix_v2_deserialize,
+ .stop = subghz_protocol_encoder_phoenix_v2_stop,
+ .yield = subghz_protocol_encoder_phoenix_v2_yield,
+};
+
+const SubGhzProtocol subghz_protocol_phoenix_v2 = {
+ .name = SUBGHZ_PROTOCOL_PHOENIX_V2_NAME,
+ .type = SubGhzProtocolTypeStatic,
+ .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
+ SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
+
+ .decoder = &subghz_protocol_phoenix_v2_decoder,
+ .encoder = &subghz_protocol_phoenix_v2_encoder,
+};
+
+void* subghz_protocol_encoder_phoenix_v2_alloc(SubGhzEnvironment* environment) {
+ UNUSED(environment);
+ SubGhzProtocolEncoderPhoenix_V2* instance = malloc(sizeof(SubGhzProtocolEncoderPhoenix_V2));
+
+ instance->base.protocol = &subghz_protocol_phoenix_v2;
+ instance->generic.protocol_name = instance->base.protocol->name;
+
+ instance->encoder.repeat = 10;
+ instance->encoder.size_upload = 128;
+ instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
+ instance->encoder.is_runing = false;
+ return instance;
+}
+
+void subghz_protocol_encoder_phoenix_v2_free(void* context) {
+ furi_assert(context);
+ SubGhzProtocolEncoderPhoenix_V2* instance = context;
+ free(instance->encoder.upload);
+ free(instance);
+}
+
+/**
+ * Generating an upload from data.
+ * @param instance Pointer to a SubGhzProtocolEncoderPhoenix_V2 instance
+ * @return true On success
+ */
+static bool
+ subghz_protocol_encoder_phoenix_v2_get_upload(SubGhzProtocolEncoderPhoenix_V2* instance) {
+ furi_assert(instance);
+ size_t index = 0;
+ size_t size_upload = (instance->generic.data_count_bit * 2) + 2;
+ if(size_upload > instance->encoder.size_upload) {
+ FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
+ return false;
+ } else {
+ instance->encoder.size_upload = size_upload;
+ }
+ //Send header
+ instance->encoder.upload[index++] =
+ level_duration_make(false, (uint32_t)subghz_protocol_phoenix_v2_const.te_short * 60);
+ //Send start bit
+ instance->encoder.upload[index++] =
+ level_duration_make(true, (uint32_t)subghz_protocol_phoenix_v2_const.te_short * 6);
+ //Send key data
+ for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
+ if(!bit_read(instance->generic.data, i - 1)) {
+ //send bit 1
+ instance->encoder.upload[index++] =
+ level_duration_make(false, (uint32_t)subghz_protocol_phoenix_v2_const.te_long);
+ instance->encoder.upload[index++] =
+ level_duration_make(true, (uint32_t)subghz_protocol_phoenix_v2_const.te_short);
+ } else {
+ //send bit 0
+ instance->encoder.upload[index++] =
+ level_duration_make(false, (uint32_t)subghz_protocol_phoenix_v2_const.te_short);
+ instance->encoder.upload[index++] =
+ level_duration_make(true, (uint32_t)subghz_protocol_phoenix_v2_const.te_long);
+ }
+ }
+ return true;
+}
+
+bool subghz_protocol_encoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format) {
+ furi_assert(context);
+ SubGhzProtocolEncoderPhoenix_V2* instance = context;
+ bool res = false;
+ do {
+ if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
+ FURI_LOG_E(TAG, "Deserialize error");
+ break;
+ }
+ if(instance->generic.data_count_bit !=
+ subghz_protocol_phoenix_v2_const.min_count_bit_for_found) {
+ FURI_LOG_E(TAG, "Wrong number of bits in key");
+ break;
+ }
+ //optional parameter parameter
+ flipper_format_read_uint32(
+ flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
+
+ subghz_protocol_encoder_phoenix_v2_get_upload(instance);
+ instance->encoder.is_runing = true;
+
+ res = true;
+ } while(false);
+
+ return res;
+}
+
+void subghz_protocol_encoder_phoenix_v2_stop(void* context) {
+ SubGhzProtocolEncoderPhoenix_V2* instance = context;
+ instance->encoder.is_runing = false;
+}
+
+LevelDuration subghz_protocol_encoder_phoenix_v2_yield(void* context) {
+ SubGhzProtocolEncoderPhoenix_V2* instance = context;
+
+ if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) {
+ instance->encoder.is_runing = false;
+ return level_duration_reset();
+ }
+
+ LevelDuration ret = instance->encoder.upload[instance->encoder.front];
+
+ if(++instance->encoder.front == instance->encoder.size_upload) {
+ instance->encoder.repeat--;
+ instance->encoder.front = 0;
+ }
+
+ return ret;
+}
+
+void* subghz_protocol_decoder_phoenix_v2_alloc(SubGhzEnvironment* environment) {
+ UNUSED(environment);
+ SubGhzProtocolDecoderPhoenix_V2* instance = malloc(sizeof(SubGhzProtocolDecoderPhoenix_V2));
+ instance->base.protocol = &subghz_protocol_phoenix_v2;
+ instance->generic.protocol_name = instance->base.protocol->name;
+ return instance;
+}
+
+void subghz_protocol_decoder_phoenix_v2_free(void* context) {
+ furi_assert(context);
+ SubGhzProtocolDecoderPhoenix_V2* instance = context;
+ free(instance);
+}
+
+void subghz_protocol_decoder_phoenix_v2_reset(void* context) {
+ furi_assert(context);
+ SubGhzProtocolDecoderPhoenix_V2* instance = context;
+ instance->decoder.parser_step = Phoenix_V2DecoderStepReset;
+}
+
+void subghz_protocol_decoder_phoenix_v2_feed(void* context, bool level, uint32_t duration) {
+ furi_assert(context);
+ SubGhzProtocolDecoderPhoenix_V2* instance = context;
+
+ switch(instance->decoder.parser_step) {
+ case Phoenix_V2DecoderStepReset:
+ if((!level) && (DURATION_DIFF(duration, subghz_protocol_phoenix_v2_const.te_short * 60) <
+ subghz_protocol_phoenix_v2_const.te_delta * 30)) {
+ //Found Preambula
+ instance->decoder.parser_step = Phoenix_V2DecoderStepFoundStartBit;
+ }
+ break;
+ case Phoenix_V2DecoderStepFoundStartBit:
+ if(level && ((DURATION_DIFF(duration, (subghz_protocol_phoenix_v2_const.te_short * 6)) <
+ subghz_protocol_phoenix_v2_const.te_delta * 4))) {
+ //Found start bit
+ instance->decoder.parser_step = Phoenix_V2DecoderStepSaveDuration;
+ instance->decoder.decode_data = 0;
+ instance->decoder.decode_count_bit = 0;
+ } else {
+ instance->decoder.parser_step = Phoenix_V2DecoderStepReset;
+ }
+ break;
+ case Phoenix_V2DecoderStepSaveDuration:
+ if(!level) {
+ if(duration >= ((uint32_t)subghz_protocol_phoenix_v2_const.te_short * 10 +
+ subghz_protocol_phoenix_v2_const.te_delta)) {
+ instance->decoder.parser_step = Phoenix_V2DecoderStepFoundStartBit;
+ if(instance->decoder.decode_count_bit ==
+ subghz_protocol_phoenix_v2_const.min_count_bit_for_found) {
+ instance->generic.data = instance->decoder.decode_data;
+ instance->generic.data_count_bit = instance->decoder.decode_count_bit;
+
+ if(instance->base.callback)
+ instance->base.callback(&instance->base, instance->base.context);
+ }
+ instance->decoder.decode_data = 0;
+ instance->decoder.decode_count_bit = 0;
+ break;
+ } else {
+ instance->decoder.te_last = duration;
+ instance->decoder.parser_step = Phoenix_V2DecoderStepCheckDuration;
+ }
+ }
+ break;
+ case Phoenix_V2DecoderStepCheckDuration:
+ if(level) {
+ if((DURATION_DIFF(
+ instance->decoder.te_last, subghz_protocol_phoenix_v2_const.te_short) <
+ subghz_protocol_phoenix_v2_const.te_delta) &&
+ (DURATION_DIFF(duration, subghz_protocol_phoenix_v2_const.te_long) <
+ subghz_protocol_phoenix_v2_const.te_delta * 3)) {
+ subghz_protocol_blocks_add_bit(&instance->decoder, 1);
+ instance->decoder.parser_step = Phoenix_V2DecoderStepSaveDuration;
+ } else if(
+ (DURATION_DIFF(
+ instance->decoder.te_last, subghz_protocol_phoenix_v2_const.te_long) <
+ subghz_protocol_phoenix_v2_const.te_delta * 3) &&
+ (DURATION_DIFF(duration, subghz_protocol_phoenix_v2_const.te_short) <
+ subghz_protocol_phoenix_v2_const.te_delta)) {
+ subghz_protocol_blocks_add_bit(&instance->decoder, 0);
+ instance->decoder.parser_step = Phoenix_V2DecoderStepSaveDuration;
+ } else {
+ instance->decoder.parser_step = Phoenix_V2DecoderStepReset;
+ }
+ } else {
+ instance->decoder.parser_step = Phoenix_V2DecoderStepReset;
+ }
+ break;
+ }
+}
+
+/**
+ * Analysis of received data
+ * @param instance Pointer to a SubGhzBlockGeneric* instance
+ */
+static void subghz_protocol_phoenix_v2_check_remote_controller(SubGhzBlockGeneric* instance) {
+ uint64_t data_rev =
+ subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit + 4);
+ instance->serial = data_rev & 0xFFFFFFFF;
+ instance->cnt = (data_rev >> 40) & 0xFFFF;
+ instance->btn = (data_rev >> 32) & 0xF;
+}
+
+uint8_t subghz_protocol_decoder_phoenix_v2_get_hash_data(void* context) {
+ furi_assert(context);
+ SubGhzProtocolDecoderPhoenix_V2* instance = context;
+ return subghz_protocol_blocks_get_hash_data(
+ &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
+}
+
+bool subghz_protocol_decoder_phoenix_v2_serialize(
+ void* context,
+ FlipperFormat* flipper_format,
+ SubGhzPresetDefinition* preset) {
+ furi_assert(context);
+ SubGhzProtocolDecoderPhoenix_V2* instance = context;
+ return subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
+}
+
+bool subghz_protocol_decoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format) {
+ furi_assert(context);
+ SubGhzProtocolDecoderPhoenix_V2* instance = context;
+ bool ret = false;
+ do {
+ if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
+ break;
+ }
+ if(instance->generic.data_count_bit !=
+ subghz_protocol_phoenix_v2_const.min_count_bit_for_found) {
+ FURI_LOG_E(TAG, "Wrong number of bits in key");
+ break;
+ }
+ ret = true;
+ } while(false);
+ return ret;
+}
+
+void subghz_protocol_decoder_phoenix_v2_get_string(void* context, string_t output) {
+ furi_assert(context);
+ SubGhzProtocolDecoderPhoenix_V2* instance = context;
+ subghz_protocol_phoenix_v2_check_remote_controller(&instance->generic);
+ string_cat_printf(
+ output,
+ "%s %dbit\r\n"
+ "Key:%02lX%08lX\r\n"
+ "Sn:0x%07lX \r\n"
+ "Btn:%lX\r\n",
+ instance->generic.protocol_name,
+ instance->generic.data_count_bit,
+ (uint32_t)(instance->generic.data >> 32) & 0xFFFFFFFF,
+ (uint32_t)(instance->generic.data & 0xFFFFFFFF),
+ instance->generic.serial,
+ instance->generic.btn);
+}
diff --git a/lib/subghz/protocols/phoenix_v2.h b/lib/subghz/protocols/phoenix_v2.h
new file mode 100644
index 00000000..38cadc1a
--- /dev/null
+++ b/lib/subghz/protocols/phoenix_v2.h
@@ -0,0 +1,107 @@
+#pragma once
+
+#include "base.h"
+
+#define SUBGHZ_PROTOCOL_PHOENIX_V2_NAME "Phoenix_V2"
+
+typedef struct SubGhzProtocolDecoderPhoenix_V2 SubGhzProtocolDecoderPhoenix_V2;
+typedef struct SubGhzProtocolEncoderPhoenix_V2 SubGhzProtocolEncoderPhoenix_V2;
+
+extern const SubGhzProtocolDecoder subghz_protocol_phoenix_v2_decoder;
+extern const SubGhzProtocolEncoder subghz_protocol_phoenix_v2_encoder;
+extern const SubGhzProtocol subghz_protocol_phoenix_v2;
+
+/**
+ * Allocate SubGhzProtocolEncoderPhoenix_V2.
+ * @param environment Pointer to a SubGhzEnvironment instance
+ * @return SubGhzProtocolEncoderPhoenix_V2* pointer to a SubGhzProtocolEncoderPhoenix_V2 instance
+ */
+void* subghz_protocol_encoder_phoenix_v2_alloc(SubGhzEnvironment* environment);
+
+/**
+ * Free SubGhzProtocolEncoderPhoenix_V2.
+ * @param context Pointer to a SubGhzProtocolEncoderPhoenix_V2 instance
+ */
+void subghz_protocol_encoder_phoenix_v2_free(void* context);
+
+/**
+ * Deserialize and generating an upload to send.
+ * @param context Pointer to a SubGhzProtocolEncoderPhoenix_V2 instance
+ * @param flipper_format Pointer to a FlipperFormat instance
+ * @return true On success
+ */
+bool subghz_protocol_encoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format);
+
+/**
+ * Forced transmission stop.
+ * @param context Pointer to a SubGhzProtocolEncoderPhoenix_V2 instance
+ */
+void subghz_protocol_encoder_phoenix_v2_stop(void* context);
+
+/**
+ * Getting the level and duration of the upload to be loaded into DMA.
+ * @param context Pointer to a SubGhzProtocolEncoderPhoenix_V2 instance
+ * @return LevelDuration
+ */
+LevelDuration subghz_protocol_encoder_phoenix_v2_yield(void* context);
+
+/**
+ * Allocate SubGhzProtocolDecoderPhoenix_V2.
+ * @param environment Pointer to a SubGhzEnvironment instance
+ * @return SubGhzProtocolDecoderPhoenix_V2* pointer to a SubGhzProtocolDecoderPhoenix_V2 instance
+ */
+void* subghz_protocol_decoder_phoenix_v2_alloc(SubGhzEnvironment* environment);
+
+/**
+ * Free SubGhzProtocolDecoderPhoenix_V2.
+ * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance
+ */
+void subghz_protocol_decoder_phoenix_v2_free(void* context);
+
+/**
+ * Reset decoder SubGhzProtocolDecoderPhoenix_V2.
+ * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance
+ */
+void subghz_protocol_decoder_phoenix_v2_reset(void* context);
+
+/**
+ * Parse a raw sequence of levels and durations received from the air.
+ * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance
+ * @param level Signal level true-high false-low
+ * @param duration Duration of this level in, us
+ */
+void subghz_protocol_decoder_phoenix_v2_feed(void* context, bool level, uint32_t duration);
+
+/**
+ * Getting the hash sum of the last randomly received parcel.
+ * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance
+ * @return hash Hash sum
+ */
+uint8_t subghz_protocol_decoder_phoenix_v2_get_hash_data(void* context);
+
+/**
+ * Serialize data SubGhzProtocolDecoderPhoenix_V2.
+ * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance
+ * @param flipper_format Pointer to a FlipperFormat instance
+ * @param preset The modulation on which the signal was received, SubGhzPresetDefinition
+ * @return true On success
+ */
+bool subghz_protocol_decoder_phoenix_v2_serialize(
+ void* context,
+ FlipperFormat* flipper_format,
+ SubGhzPresetDefinition* preset);
+
+/**
+ * Deserialize data SubGhzProtocolDecoderPhoenix_V2.
+ * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance
+ * @param flipper_format Pointer to a FlipperFormat instance
+ * @return true On success
+ */
+bool subghz_protocol_decoder_phoenix_v2_deserialize(void* context, FlipperFormat* flipper_format);
+
+/**
+ * Getting a textual representation of the received data.
+ * @param context Pointer to a SubGhzProtocolDecoderPhoenix_V2 instance
+ * @param output Resulting text
+ */
+void subghz_protocol_decoder_phoenix_v2_get_string(void* context, string_t output);
diff --git a/lib/subghz/protocols/princeton.c b/lib/subghz/protocols/princeton.c
index 0f100137..3fdeaae9 100644
--- a/lib/subghz/protocols/princeton.c
+++ b/lib/subghz/protocols/princeton.c
@@ -256,8 +256,6 @@ void subghz_protocol_decoder_princeton_feed(void* context, bool level, uint32_t
instance->generic.data = instance->decoder.decode_data;
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
- instance->generic.serial = instance->decoder.decode_data >> 4;
- instance->generic.btn = (uint8_t)instance->decoder.decode_data & 0x00000F;
if(instance->base.callback)
instance->base.callback(&instance->base, instance->base.context);
@@ -295,6 +293,15 @@ void subghz_protocol_decoder_princeton_feed(void* context, bool level, uint32_t
}
}
+/**
+ * Analysis of received data
+ * @param instance Pointer to a SubGhzBlockGeneric* instance
+ */
+static void subghz_protocol_princeton_check_remote_controller(SubGhzBlockGeneric* instance) {
+ instance->serial = instance->data >> 4;
+ instance->btn = instance->data & 0xF;
+}
+
uint8_t subghz_protocol_decoder_princeton_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderPrinceton* instance = context;
@@ -347,25 +354,21 @@ bool subghz_protocol_decoder_princeton_deserialize(void* context, FlipperFormat*
void subghz_protocol_decoder_princeton_get_string(void* context, string_t output) {
furi_assert(context);
SubGhzProtocolDecoderPrinceton* instance = context;
-
- uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
-
- uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key(
+ subghz_protocol_princeton_check_remote_controller(&instance->generic);
+ uint32_t data_rev = subghz_protocol_blocks_reverse_key(
instance->generic.data, instance->generic.data_count_bit);
- uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
-
string_cat_printf(
output,
"%s %dbit\r\n"
"Key:0x%08lX\r\n"
"Yek:0x%08lX\r\n"
- "Sn:0x%05lX BTN:%02X\r\n"
+ "Sn:0x%05lX Btn:%01X\r\n"
"Te:%dus\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
- code_found_lo,
- code_found_reverse_lo,
+ (uint32_t)(instance->generic.data & 0xFFFFFF),
+ data_rev,
instance->generic.serial,
instance->generic.btn,
instance->te);
diff --git a/lib/subghz/protocols/registry.c b/lib/subghz/protocols/registry.c
index 5a09ee8c..89394730 100644
--- a/lib/subghz/protocols/registry.c
+++ b/lib/subghz/protocols/registry.c
@@ -9,7 +9,8 @@ const SubGhzProtocol* subghz_protocol_registry[] = {
&subghz_protocol_somfy_keytis, &subghz_protocol_scher_khan, &subghz_protocol_princeton,
&subghz_protocol_raw, &subghz_protocol_linear, &subghz_protocol_secplus_v2,
&subghz_protocol_secplus_v1, &subghz_protocol_megacode, &subghz_protocol_holtek,
- &subghz_protocol_chamb_code, &subghz_protocol_power_smart,
+ &subghz_protocol_chamb_code, &subghz_protocol_power_smart, &subghz_protocol_marantec,
+ &subghz_protocol_bett, &subghz_protocol_doitrand, &subghz_protocol_phoenix_v2,
};
diff --git a/lib/subghz/protocols/registry.h b/lib/subghz/protocols/registry.h
index d64b0cdd..97a1376d 100644
--- a/lib/subghz/protocols/registry.h
+++ b/lib/subghz/protocols/registry.h
@@ -28,6 +28,10 @@
#include "holtek.h"
#include "chamberlain_code.h"
#include "power_smart.h"
+#include "marantec.h"
+#include "bett.h"
+#include "doitrand.h"
+#include "phoenix_v2.h"
/**
* Registration by name SubGhzProtocol.