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
diff options
context:
space:
mode:
Diffstat (limited to 'lib/subghz/protocols/marantec.c')
-rw-r--r--lib/subghz/protocols/marantec.c393
1 files changed, 393 insertions, 0 deletions
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);
+}