Просмотр исходного кода

SubGhz add protocol Firefly (#1183)

* SubGhz: add protocol "Firefly"
* SubGhz: refactoring "Add Manually" scene
* SubGhz: refactoring Firefly protocol

Co-authored-by: あく <alleteam@gmail.com>
Skorpionm 3 лет назад
Родитель
Сommit
73477cceed

+ 77 - 16
applications/subghz/scenes/subghz_scene_set_type.c

@@ -4,6 +4,7 @@
 #include <dolphin/dolphin.h>
 #include <dolphin/dolphin.h>
 #include <flipper_format/flipper_format_i.h>
 #include <flipper_format/flipper_format_i.h>
 #include <lib/toolbox/stream/stream.h>
 #include <lib/toolbox/stream/stream.h>
+#include <lib/subghz/protocols/registry.h>
 
 
 #define TAG "SubGhzSetType"
 #define TAG "SubGhzSetType"
 
 
@@ -19,13 +20,16 @@ enum SubmenuIndex {
     SubmenuIndexGateTX,
     SubmenuIndexGateTX,
     SubmenuIndexDoorHan_315_00,
     SubmenuIndexDoorHan_315_00,
     SubmenuIndexDoorHan_433_92,
     SubmenuIndexDoorHan_433_92,
+    SubmenuIndexFirefly_300_00,
 };
 };
 
 
 bool subghz_scene_set_type_submenu_gen_data_protocol(
 bool subghz_scene_set_type_submenu_gen_data_protocol(
     void* context,
     void* context,
     const char* protocol_name,
     const char* protocol_name,
     uint64_t key,
     uint64_t key,
-    uint32_t bit) {
+    uint32_t bit,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
     furi_assert(context);
     furi_assert(context);
     SubGhz* subghz = context;
     SubGhz* subghz = context;
 
 
@@ -44,10 +48,7 @@ bool subghz_scene_set_type_submenu_gen_data_protocol(
         Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data);
         Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data);
         stream_clean(fff_data_stream);
         stream_clean(fff_data_stream);
         if(!subghz_protocol_decoder_base_serialize(
         if(!subghz_protocol_decoder_base_serialize(
-               subghz->txrx->decoder_result,
-               subghz->txrx->fff_data,
-               subghz_setting_get_default_frequency(subghz->setting),
-               FuriHalSubGhzPresetOok650Async)) {
+               subghz->txrx->decoder_result, subghz->txrx->fff_data, frequency, preset)) {
             FURI_LOG_E(TAG, "Unable to serialize");
             FURI_LOG_E(TAG, "Unable to serialize");
             break;
             break;
         }
         }
@@ -107,6 +108,12 @@ void subghz_scene_set_type_on_enter(void* context) {
         SubmenuIndexCAME24bit,
         SubmenuIndexCAME24bit,
         subghz_scene_set_type_submenu_callback,
         subghz_scene_set_type_submenu_callback,
         subghz);
         subghz);
+    submenu_add_item(
+        subghz->submenu,
+        "Firefly_300",
+        SubmenuIndexFirefly_300_00,
+        subghz_scene_set_type_submenu_callback,
+        subghz);
     submenu_add_item(
     submenu_add_item(
         subghz->submenu,
         subghz->submenu,
         "CAME TWEE",
         "CAME TWEE",
@@ -152,7 +159,13 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
         switch(event.event) {
         switch(event.event) {
         case SubmenuIndexPricenton:
         case SubmenuIndexPricenton:
             key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
             key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
-            if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "Princeton", key, 24)) {
+            if(subghz_scene_set_type_submenu_gen_data_protocol(
+                   subghz,
+                   SUBGHZ_PROTOCOL_PRINCETON_NAME,
+                   key,
+                   24,
+                   433920000,
+                   FuriHalSubGhzPresetOok650Async)) {
                 uint32_t te = 400;
                 uint32_t te = 400;
                 flipper_format_update_uint32(subghz->txrx->fff_data, "TE", (uint32_t*)&te, 1);
                 flipper_format_update_uint32(subghz->txrx->fff_data, "TE", (uint32_t*)&te, 1);
                 generated_protocol = true;
                 generated_protocol = true;
@@ -160,32 +173,74 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
             break;
             break;
         case SubmenuIndexNiceFlo12bit:
         case SubmenuIndexNiceFlo12bit:
             key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
             key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
-            if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "Nice FLO", key, 12)) {
+            if(subghz_scene_set_type_submenu_gen_data_protocol(
+                   subghz,
+                   SUBGHZ_PROTOCOL_NICE_FLO_NAME,
+                   key,
+                   12,
+                   433920000,
+                   FuriHalSubGhzPresetOok650Async)) {
                 generated_protocol = true;
                 generated_protocol = true;
             }
             }
             break;
             break;
         case SubmenuIndexNiceFlo24bit:
         case SubmenuIndexNiceFlo24bit:
             key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
             key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
-            if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "Nice FLO", key, 24)) {
+            if(subghz_scene_set_type_submenu_gen_data_protocol(
+                   subghz,
+                   SUBGHZ_PROTOCOL_NICE_FLO_NAME,
+                   key,
+                   24,
+                   433920000,
+                   FuriHalSubGhzPresetOok650Async)) {
                 generated_protocol = true;
                 generated_protocol = true;
             }
             }
             break;
             break;
         case SubmenuIndexCAME12bit:
         case SubmenuIndexCAME12bit:
             key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
             key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
-            if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "CAME", key, 12)) {
+            if(subghz_scene_set_type_submenu_gen_data_protocol(
+                   subghz,
+                   SUBGHZ_PROTOCOL_CAME_NAME,
+                   key,
+                   12,
+                   433920000,
+                   FuriHalSubGhzPresetOok650Async)) {
                 generated_protocol = true;
                 generated_protocol = true;
             }
             }
             break;
             break;
         case SubmenuIndexCAME24bit:
         case SubmenuIndexCAME24bit:
             key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
             key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
-            if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "CAME", key, 24)) {
+            if(subghz_scene_set_type_submenu_gen_data_protocol(
+                   subghz,
+                   SUBGHZ_PROTOCOL_CAME_NAME,
+                   key,
+                   24,
+                   433920000,
+                   FuriHalSubGhzPresetOok650Async)) {
+                generated_protocol = true;
+            }
+            break;
+        case SubmenuIndexFirefly_300_00:
+            key = (key & 0x3FF);
+            if(subghz_scene_set_type_submenu_gen_data_protocol(
+                   subghz,
+                   SUBGHZ_PROTOCOL_FIREFLY_NAME,
+                   key,
+                   10,
+                   300000000,
+                   FuriHalSubGhzPresetOok650Async)) {
                 generated_protocol = true;
                 generated_protocol = true;
             }
             }
             break;
             break;
         case SubmenuIndexCAMETwee:
         case SubmenuIndexCAMETwee:
             key = (key & 0x0FFFFFF0);
             key = (key & 0x0FFFFFF0);
             key = 0x003FFF7200000000 | (key ^ 0xE0E0E0EE);
             key = 0x003FFF7200000000 | (key ^ 0xE0E0E0EE);
-            if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "CAME TWEE", key, 54)) {
+            if(subghz_scene_set_type_submenu_gen_data_protocol(
+                   subghz,
+                   SUBGHZ_PROTOCOL_CAME_TWEE_NAME,
+                   key,
+                   54,
+                   433920000,
+                   FuriHalSubGhzPresetOok650Async)) {
                 generated_protocol = true;
                 generated_protocol = true;
             }
             }
             break;
             break;
@@ -198,13 +253,19 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
         case SubmenuIndexGateTX:
         case SubmenuIndexGateTX:
             key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?)
             key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?)
             uint64_t rev_key = subghz_protocol_blocks_reverse_key(key, 24);
             uint64_t rev_key = subghz_protocol_blocks_reverse_key(key, 24);
-            if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "GateTX", rev_key, 24)) {
+            if(subghz_scene_set_type_submenu_gen_data_protocol(
+                   subghz,
+                   SUBGHZ_PROTOCOL_GATE_TX_NAME,
+                   rev_key,
+                   24,
+                   433920000,
+                   FuriHalSubGhzPresetOok650Async)) {
                 generated_protocol = true;
                 generated_protocol = true;
             }
             }
             break;
             break;
         case SubmenuIndexDoorHan_433_92:
         case SubmenuIndexDoorHan_433_92:
-            subghz->txrx->transmitter =
-                subghz_transmitter_alloc_init(subghz->txrx->environment, "KeeLoq");
+            subghz->txrx->transmitter = subghz_transmitter_alloc_init(
+                subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
             if(subghz->txrx->transmitter) {
             if(subghz->txrx->transmitter) {
                 subghz_protocol_keeloq_create_data(
                 subghz_protocol_keeloq_create_data(
                     subghz->txrx->transmitter->protocol_instance,
                     subghz->txrx->transmitter->protocol_instance,
@@ -227,8 +288,8 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
             }
             }
             break;
             break;
         case SubmenuIndexDoorHan_315_00:
         case SubmenuIndexDoorHan_315_00:
-            subghz->txrx->transmitter =
-                subghz_transmitter_alloc_init(subghz->txrx->environment, "KeeLoq");
+            subghz->txrx->transmitter = subghz_transmitter_alloc_init(
+                subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
             if(subghz->txrx->transmitter) {
             if(subghz->txrx->transmitter) {
                 subghz_protocol_keeloq_create_data(
                 subghz_protocol_keeloq_create_data(
                     subghz->txrx->transmitter->protocol_instance,
                     subghz->txrx->transmitter->protocol_instance,

+ 343 - 0
lib/subghz/protocols/firefly.c

@@ -0,0 +1,343 @@
+#include "firefly.h"
+
+#include "../blocks/const.h"
+#include "../blocks/decoder.h"
+#include "../blocks/encoder.h"
+#include "../blocks/generic.h"
+#include "../blocks/math.h"
+
+/*
+ * Help
+ * https://phreakerclub.com/447
+ *
+ */
+
+#define TAG "SubGhzProtocolFirefly"
+
+#define DIP_PATTERN "%c%c%c%c%c%c%c%c%c%c"
+#define DATA_TO_DIP(dip)                                                                    \
+    (dip & 0x0200 ? '1' : '0'), (dip & 0x0100 ? '1' : '0'), (dip & 0x0080 ? '1' : '0'),     \
+        (dip & 0x0040 ? '1' : '0'), (dip & 0x0020 ? '1' : '0'), (dip & 0x0010 ? '1' : '0'), \
+        (dip & 0x0008 ? '1' : '0'), (dip & 0x0004 ? '1' : '0'), (dip & 0x0002 ? '1' : '0'), \
+        (dip & 0x0001 ? '1' : '0')
+
+static const SubGhzBlockConst subghz_protocol_firefly_const = {
+    .te_short = 500,
+    .te_long = 1500,
+    .te_delta = 150,
+    .min_count_bit_for_found = 10,
+};
+
+struct SubGhzProtocolDecoderFirefly {
+    SubGhzProtocolDecoderBase base;
+
+    SubGhzBlockDecoder decoder;
+    SubGhzBlockGeneric generic;
+};
+
+struct SubGhzProtocolEncoderFirefly {
+    SubGhzProtocolEncoderBase base;
+
+    SubGhzProtocolBlockEncoder encoder;
+    SubGhzBlockGeneric generic;
+};
+
+typedef enum {
+    FireflyDecoderStepReset = 0,
+    FireflyDecoderStepSaveDuration,
+    FireflyDecoderStepCheckDuration,
+} FireflyDecoderStep;
+
+const SubGhzProtocolDecoder subghz_protocol_firefly_decoder = {
+    .alloc = subghz_protocol_decoder_firefly_alloc,
+    .free = subghz_protocol_decoder_firefly_free,
+
+    .feed = subghz_protocol_decoder_firefly_feed,
+    .reset = subghz_protocol_decoder_firefly_reset,
+
+    .get_hash_data = subghz_protocol_decoder_firefly_get_hash_data,
+    .serialize = subghz_protocol_decoder_firefly_serialize,
+    .deserialize = subghz_protocol_decoder_firefly_deserialize,
+    .get_string = subghz_protocol_decoder_firefly_get_string,
+};
+
+const SubGhzProtocolEncoder subghz_protocol_firefly_encoder = {
+    .alloc = subghz_protocol_encoder_firefly_alloc,
+    .free = subghz_protocol_encoder_firefly_free,
+
+    .deserialize = subghz_protocol_encoder_firefly_deserialize,
+    .stop = subghz_protocol_encoder_firefly_stop,
+    .yield = subghz_protocol_encoder_firefly_yield,
+};
+
+const SubGhzProtocol subghz_protocol_firefly = {
+    .name = SUBGHZ_PROTOCOL_FIREFLY_NAME,
+    .type = SubGhzProtocolTypeStatic,
+    .flag = SubGhzProtocolFlag_315 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
+            SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
+
+    .decoder = &subghz_protocol_firefly_decoder,
+    .encoder = &subghz_protocol_firefly_encoder,
+};
+
+void* subghz_protocol_encoder_firefly_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolEncoderFirefly* instance = malloc(sizeof(SubGhzProtocolEncoderFirefly));
+
+    instance->base.protocol = &subghz_protocol_firefly;
+    instance->generic.protocol_name = instance->base.protocol->name;
+
+    instance->encoder.repeat = 10;
+    instance->encoder.size_upload = 28; //max 10bit*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_firefly_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolEncoderFirefly* instance = context;
+    free(instance->encoder.upload);
+    free(instance);
+}
+
+/**
+ * Generating an upload from data.
+ * @param instance Pointer to a SubGhzProtocolEncoderFirefly instance
+ * @return true On success
+ */
+static bool subghz_protocol_encoder_firefly_get_upload(SubGhzProtocolEncoderFirefly* 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;
+    }
+
+    //Send key data
+    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_firefly_const.te_short * 3);
+            instance->encoder.upload[index++] =
+                level_duration_make(false, (uint32_t)subghz_protocol_firefly_const.te_short);
+        } else {
+            //send bit 0
+            instance->encoder.upload[index++] =
+                level_duration_make(true, (uint32_t)subghz_protocol_firefly_const.te_short);
+            instance->encoder.upload[index++] =
+                level_duration_make(false, (uint32_t)subghz_protocol_firefly_const.te_short * 3);
+        }
+    }
+    //Send end bit
+    if(bit_read(instance->generic.data, 0)) {
+        //send bit 1
+        instance->encoder.upload[index++] =
+            level_duration_make(true, (uint32_t)subghz_protocol_firefly_const.te_short * 3);
+        //Send PT_GUARD
+        instance->encoder.upload[index++] =
+            level_duration_make(false, (uint32_t)subghz_protocol_firefly_const.te_short * 42);
+    } else {
+        //send bit 0
+        instance->encoder.upload[index++] =
+            level_duration_make(true, (uint32_t)subghz_protocol_firefly_const.te_short);
+        //Send PT_GUARD
+        instance->encoder.upload[index++] =
+            level_duration_make(false, (uint32_t)subghz_protocol_firefly_const.te_short * 44);
+    }
+
+    return true;
+}
+
+bool subghz_protocol_encoder_firefly_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolEncoderFirefly* instance = context;
+    bool res = false;
+    do {
+        if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
+            FURI_LOG_E(TAG, "Deserialize error");
+            break;
+        }
+
+        //optional parameter parameter
+        flipper_format_read_uint32(
+            flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
+
+        subghz_protocol_encoder_firefly_get_upload(instance);
+        instance->encoder.is_runing = true;
+
+        res = true;
+    } while(false);
+
+    return res;
+}
+
+void subghz_protocol_encoder_firefly_stop(void* context) {
+    SubGhzProtocolEncoderFirefly* instance = context;
+    instance->encoder.is_runing = false;
+}
+
+LevelDuration subghz_protocol_encoder_firefly_yield(void* context) {
+    SubGhzProtocolEncoderFirefly* 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_firefly_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolDecoderFirefly* instance = malloc(sizeof(SubGhzProtocolDecoderFirefly));
+    instance->base.protocol = &subghz_protocol_firefly;
+    instance->generic.protocol_name = instance->base.protocol->name;
+    return instance;
+}
+
+void subghz_protocol_decoder_firefly_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderFirefly* instance = context;
+    free(instance);
+}
+
+void subghz_protocol_decoder_firefly_reset(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderFirefly* instance = context;
+    instance->decoder.parser_step = FireflyDecoderStepReset;
+}
+
+void subghz_protocol_decoder_firefly_feed(void* context, bool level, uint32_t duration) {
+    furi_assert(context);
+    SubGhzProtocolDecoderFirefly* instance = context;
+    switch(instance->decoder.parser_step) {
+    case FireflyDecoderStepReset:
+        if((!level) && (DURATION_DIFF(duration, subghz_protocol_firefly_const.te_short * 42) <
+                        subghz_protocol_firefly_const.te_delta * 20)) {
+            //Found header Firefly
+            instance->decoder.decode_data = 0;
+            instance->decoder.decode_count_bit = 0;
+            instance->decoder.parser_step = FireflyDecoderStepSaveDuration;
+        }
+        break;
+    case FireflyDecoderStepSaveDuration:
+        if(level) {
+            instance->decoder.te_last = duration;
+            instance->decoder.parser_step = FireflyDecoderStepCheckDuration;
+        } else {
+            instance->decoder.parser_step = FireflyDecoderStepReset;
+        }
+        break;
+    case FireflyDecoderStepCheckDuration:
+        if(!level) { //save interval
+            if(duration >= (subghz_protocol_firefly_const.te_short * 5)) {
+                instance->decoder.parser_step = FireflyDecoderStepReset;
+                //checking that the duration matches the guardtime
+                if((DURATION_DIFF(duration, subghz_protocol_firefly_const.te_short * 42) >
+                    subghz_protocol_firefly_const.te_delta * 20)) {
+                    break;
+                }
+                if(DURATION_DIFF(
+                       instance->decoder.te_last, subghz_protocol_firefly_const.te_short) <
+                   subghz_protocol_firefly_const.te_delta) {
+                    subghz_protocol_blocks_add_bit(&instance->decoder, 0);
+                } else if(
+                    DURATION_DIFF(
+                        instance->decoder.te_last, subghz_protocol_firefly_const.te_long) <
+                    subghz_protocol_firefly_const.te_delta) {
+                    subghz_protocol_blocks_add_bit(&instance->decoder, 1);
+                }
+                if(instance->decoder.decode_count_bit ==
+                   subghz_protocol_firefly_const.min_count_bit_for_found) {
+                    instance->generic.serial = 0x0;
+                    instance->generic.btn = 0x0;
+
+                    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);
+                }
+                break;
+            }
+
+            if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_firefly_const.te_short) <
+                subghz_protocol_firefly_const.te_delta) &&
+               (DURATION_DIFF(duration, subghz_protocol_firefly_const.te_long) <
+                subghz_protocol_firefly_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 0);
+                instance->decoder.parser_step = FireflyDecoderStepSaveDuration;
+            } else if(
+                (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_firefly_const.te_long) <
+                 subghz_protocol_firefly_const.te_delta) &&
+                (DURATION_DIFF(duration, subghz_protocol_firefly_const.te_short) <
+                 subghz_protocol_firefly_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 1);
+                instance->decoder.parser_step = FireflyDecoderStepSaveDuration;
+            } else {
+                instance->decoder.parser_step = FireflyDecoderStepReset;
+            }
+
+        } else {
+            instance->decoder.parser_step = FireflyDecoderStepReset;
+        }
+        break;
+    }
+}
+
+uint8_t subghz_protocol_decoder_firefly_get_hash_data(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderFirefly* instance = context;
+    return subghz_protocol_blocks_get_hash_data(
+        &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
+}
+
+bool subghz_protocol_decoder_firefly_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    furi_assert(context);
+    SubGhzProtocolDecoderFirefly* instance = context;
+    return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
+}
+
+bool subghz_protocol_decoder_firefly_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolDecoderFirefly* instance = context;
+    return subghz_block_generic_deserialize(&instance->generic, flipper_format);
+}
+
+void subghz_protocol_decoder_firefly_get_string(void* context, string_t output) {
+    furi_assert(context);
+    SubGhzProtocolDecoderFirefly* instance = context;
+
+    uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
+
+    uint64_t code_found_reverse = 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"
+        "DIP:" DIP_PATTERN "\r\n",
+        instance->generic.protocol_name,
+        instance->generic.data_count_bit,
+        code_found_lo,
+        code_found_reverse_lo,
+        DATA_TO_DIP(code_found_lo));
+}

+ 109 - 0
lib/subghz/protocols/firefly.h

@@ -0,0 +1,109 @@
+#pragma once
+
+#include "base.h"
+
+#define SUBGHZ_PROTOCOL_FIREFLY_NAME "Firefly"
+
+typedef struct SubGhzProtocolDecoderFirefly SubGhzProtocolDecoderFirefly;
+typedef struct SubGhzProtocolEncoderFirefly SubGhzProtocolEncoderFirefly;
+
+extern const SubGhzProtocolDecoder subghz_protocol_firefly_decoder;
+extern const SubGhzProtocolEncoder subghz_protocol_firefly_encoder;
+extern const SubGhzProtocol subghz_protocol_firefly;
+
+/**
+ * Allocate SubGhzProtocolEncoderFirefly.
+ * @param environment Pointer to a SubGhzEnvironment instance
+ * @return SubGhzProtocolEncoderFirefly* pointer to a SubGhzProtocolEncoderFirefly instance
+ */
+void* subghz_protocol_encoder_firefly_alloc(SubGhzEnvironment* environment);
+
+/**
+ * Free SubGhzProtocolEncoderFirefly.
+ * @param context Pointer to a SubGhzProtocolEncoderFirefly instance
+ */
+void subghz_protocol_encoder_firefly_free(void* context);
+
+/**
+ * Deserialize and generating an upload to send.
+ * @param context Pointer to a SubGhzProtocolEncoderFirefly instance
+ * @param flipper_format Pointer to a FlipperFormat instance
+ * @return true On success
+ */
+bool subghz_protocol_encoder_firefly_deserialize(void* context, FlipperFormat* flipper_format);
+
+/**
+ * Forced transmission stop.
+ * @param context Pointer to a SubGhzProtocolEncoderFirefly instance
+ */
+void subghz_protocol_encoder_firefly_stop(void* context);
+
+/**
+ * Getting the level and duration of the upload to be loaded into DMA.
+ * @param context Pointer to a SubGhzProtocolEncoderFirefly instance
+ * @return LevelDuration 
+ */
+LevelDuration subghz_protocol_encoder_firefly_yield(void* context);
+
+/**
+ * Allocate SubGhzProtocolDecoderFirefly.
+ * @param environment Pointer to a SubGhzEnvironment instance
+ * @return SubGhzProtocolDecoderFirefly* pointer to a SubGhzProtocolDecoderFirefly instance
+ */
+void* subghz_protocol_decoder_firefly_alloc(SubGhzEnvironment* environment);
+
+/**
+ * Free SubGhzProtocolDecoderFirefly.
+ * @param context Pointer to a SubGhzProtocolDecoderFirefly instance
+ */
+void subghz_protocol_decoder_firefly_free(void* context);
+
+/**
+ * Reset decoder SubGhzProtocolDecoderFirefly.
+ * @param context Pointer to a SubGhzProtocolDecoderFirefly instance
+ */
+void subghz_protocol_decoder_firefly_reset(void* context);
+
+/**
+ * Parse a raw sequence of levels and durations received from the air.
+ * @param context Pointer to a SubGhzProtocolDecoderFirefly instance
+ * @param level Signal level true-high false-low
+ * @param duration Duration of this level in, us
+ */
+void subghz_protocol_decoder_firefly_feed(void* context, bool level, uint32_t duration);
+
+/**
+ * Getting the hash sum of the last randomly received parcel.
+ * @param context Pointer to a SubGhzProtocolDecoderFirefly instance
+ * @return hash Hash sum
+ */
+uint8_t subghz_protocol_decoder_firefly_get_hash_data(void* context);
+
+/**
+ * Serialize data SubGhzProtocolDecoderFirefly.
+ * @param context Pointer to a SubGhzProtocolDecoderFirefly instance
+ * @param flipper_format Pointer to a FlipperFormat instance
+ * @param frequency The frequency at which the signal was received, Hz
+ * @param preset The modulation on which the signal was received, FuriHalSubGhzPreset
+ * @return true On success
+ */
+bool subghz_protocol_decoder_firefly_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset);
+
+/**
+ * Deserialize data SubGhzProtocolDecoderFirefly.
+ * @param context Pointer to a SubGhzProtocolDecoderFirefly instance
+ * @param flipper_format Pointer to a FlipperFormat instance
+ * @return true On success
+ */
+bool subghz_protocol_decoder_firefly_deserialize(void* context, FlipperFormat* flipper_format);
+
+/**
+ * Getting a textual representation of the received data.
+ * @param context Pointer to a SubGhzProtocolDecoderFirefly instance
+ * @param output Resulting text
+ */
+void subghz_protocol_decoder_firefly_get_string(void* context, string_t output);

+ 1 - 1
lib/subghz/protocols/registry.c

@@ -7,7 +7,7 @@ const SubGhzProtocol* subghz_protocol_registry[] = {
     &subghz_protocol_nero_sketch,  &subghz_protocol_ido,        &subghz_protocol_kia,
     &subghz_protocol_nero_sketch,  &subghz_protocol_ido,        &subghz_protocol_kia,
     &subghz_protocol_hormann,      &subghz_protocol_nero_radio, &subghz_protocol_somfy_telis,
     &subghz_protocol_hormann,      &subghz_protocol_nero_radio, &subghz_protocol_somfy_telis,
     &subghz_protocol_somfy_keytis, &subghz_protocol_scher_khan, &subghz_protocol_gate_tx,
     &subghz_protocol_somfy_keytis, &subghz_protocol_scher_khan, &subghz_protocol_gate_tx,
-    &subghz_protocol_raw,
+    &subghz_protocol_raw,          &subghz_protocol_firefly,
 
 
 };
 };
 
 

+ 1 - 0
lib/subghz/protocols/registry.h

@@ -21,6 +21,7 @@
 #include "scher_khan.h"
 #include "scher_khan.h"
 #include "gate_tx.h"
 #include "gate_tx.h"
 #include "raw.h"
 #include "raw.h"
+#include "firefly.h"
 
 
 /**
 /**
  * Registration by name SubGhzProtocol.
  * Registration by name SubGhzProtocol.