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

[FL-3242] SubGhz: refactoring app (#2554)

* SubGhz: add SubGhzThresholdRssi
* SubGhz: remove direct reading of subghz-txrx-txrx_state
* SubGhz: remove direct reading subghz->txrx->hopper_state
* SubGhz: remove direct reading subghz->lock
* SubGhz: check load type file
* SubGhz: remove direct reading subghz->txrx->rx_key_state
* SubGhz: remove direct reading subghz->txrx->speaker_state
* SubGhz: refactoring subghz_scene_set_type.c
* SubGhz: moving "txrx" entity to a separate file
* SubGhz: show error tx start
* SubGhz: refactoring RPC
* SubGhz: value get optimizations
* SubGhz: fix name file
* SubGhz: add function description
* SubGhz: fix double back with a blocked transmission in this region and speacker, when a transmission is blocked in this region
* SubGhz: correct spelling
* SubGhz: better naming
* SubGhz: simplify includes

Co-authored-by: SG <who.just.the.doctor@gmail.com>
Co-authored-by: あく <alleteam@gmail.com>
Skorpionm 2 лет назад
Родитель
Сommit
d2ca67d261
37 измененных файлов с 1704 добавлено и 1117 удалено
  1. 3 3
      applications/external/weather_station/views/weather_station_receiver.c
  2. 2 3
      applications/main/subghz/helpers/subghz_custom_event.h
  3. 1 1
      applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c
  4. 60 0
      applications/main/subghz/helpers/subghz_threshold_rssi.c
  5. 43 0
      applications/main/subghz/helpers/subghz_threshold_rssi.h
  6. 521 0
      applications/main/subghz/helpers/subghz_txrx.c
  7. 290 0
      applications/main/subghz/helpers/subghz_txrx.h
  8. 164 0
      applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c
  9. 96 0
      applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h
  10. 27 0
      applications/main/subghz/helpers/subghz_txrx_i.h
  11. 7 0
      applications/main/subghz/helpers/subghz_types.h
  12. 2 2
      applications/main/subghz/scenes/subghz_scene_delete.c
  13. 1 1
      applications/main/subghz/scenes/subghz_scene_delete_raw.c
  14. 7 11
      applications/main/subghz/scenes/subghz_scene_need_saving.c
  15. 69 160
      applications/main/subghz/scenes/subghz_scene_read_raw.c
  16. 48 74
      applications/main/subghz/scenes/subghz_scene_receiver.c
  17. 78 55
      applications/main/subghz/scenes/subghz_scene_receiver_config.c
  18. 35 77
      applications/main/subghz/scenes/subghz_scene_receiver_info.c
  19. 1 2
      applications/main/subghz/scenes/subghz_scene_region_info.c
  20. 10 10
      applications/main/subghz/scenes/subghz_scene_rpc.c
  21. 7 9
      applications/main/subghz/scenes/subghz_scene_save_name.c
  22. 2 2
      applications/main/subghz/scenes/subghz_scene_save_success.c
  23. 2 2
      applications/main/subghz/scenes/subghz_scene_saved.c
  24. 46 209
      applications/main/subghz/scenes/subghz_scene_set_type.c
  25. 5 6
      applications/main/subghz/scenes/subghz_scene_show_error.c
  26. 1 1
      applications/main/subghz/scenes/subghz_scene_start.c
  27. 15 31
      applications/main/subghz/scenes/subghz_scene_transmitter.c
  28. 24 71
      applications/main/subghz/subghz.c
  29. 90 313
      applications/main/subghz/subghz_i.c
  30. 23 53
      applications/main/subghz/subghz_i.h
  31. 12 11
      applications/main/subghz/views/receiver.c
  32. 1 1
      applications/main/subghz/views/receiver.h
  33. 4 4
      applications/main/subghz/views/subghz_read_raw.c
  34. 1 1
      applications/main/subghz/views/subghz_read_raw.h
  35. 3 3
      applications/main/subghz/views/transmitter.c
  36. 1 1
      applications/main/subghz/views/transmitter.h
  37. 2 0
      lib/subghz/environment.c

+ 3 - 3
applications/external/weather_station/views/weather_station_receiver.c

@@ -12,7 +12,7 @@
 #define MENU_ITEMS 4u
 #define UNLOCK_CNT 3
 
-#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f
+#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f
 typedef struct {
     FuriString* item_str;
     uint8_t type;
@@ -69,10 +69,10 @@ void ws_view_receiver_set_rssi(WSReceiver* instance, float rssi) {
         instance->view,
         WSReceiverModel * model,
         {
-            if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) {
+            if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) {
                 model->u_rssi = 0;
             } else {
-                model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN);
+                model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN);
             }
         },
         true);

+ 2 - 3
applications/main/subghz/helpers/subghz_custom_event.h

@@ -6,14 +6,13 @@ typedef enum {
     SubGhzCustomEventManagerSetRAW,
 
     //SubmenuIndex
-    SubmenuIndexPricenton,
+    SubmenuIndexPricenton_433,
+    SubmenuIndexPricenton_315,
     SubmenuIndexNiceFlo12bit,
     SubmenuIndexNiceFlo24bit,
     SubmenuIndexCAME12bit,
     SubmenuIndexCAME24bit,
     SubmenuIndexCAMETwee,
-    SubmenuIndexNeroSketch,
-    SubmenuIndexNeroRadio,
     SubmenuIndexGateTX,
     SubmenuIndexDoorHan_315_00,
     SubmenuIndexDoorHan_433_92,

+ 1 - 1
applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c

@@ -261,7 +261,7 @@ SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc(void* cont
     instance->thread = furi_thread_alloc_ex(
         "SubGhzFAWorker", 2048, subghz_frequency_analyzer_worker_thread, instance);
     SubGhz* subghz = context;
-    instance->setting = subghz->setting;
+    instance->setting = subghz_txrx_get_setting(subghz->txrx);
     return instance;
 }
 

+ 60 - 0
applications/main/subghz/helpers/subghz_threshold_rssi.c

@@ -0,0 +1,60 @@
+#include "subghz_threshold_rssi.h"
+#include <float_tools.h>
+#include "../subghz_i.h"
+
+#define TAG "SubGhzThresholdRssi"
+#define THRESHOLD_RSSI_LOW_COUNT 10
+
+struct SubGhzThresholdRssi {
+    float threshold_rssi;
+    uint8_t threshold_rssi_low_count;
+};
+
+SubGhzThresholdRssi* subghz_threshold_rssi_alloc(void) {
+    SubGhzThresholdRssi* instance = malloc(sizeof(SubGhzThresholdRssi));
+    instance->threshold_rssi = SUBGHZ_RAW_THRESHOLD_MIN;
+    instance->threshold_rssi_low_count = THRESHOLD_RSSI_LOW_COUNT;
+    return instance;
+}
+
+void subghz_threshold_rssi_free(SubGhzThresholdRssi* instance) {
+    furi_assert(instance);
+    free(instance);
+}
+
+void subghz_threshold_rssi_set(SubGhzThresholdRssi* instance, float rssi) {
+    furi_assert(instance);
+    instance->threshold_rssi = rssi;
+}
+
+float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance) {
+    furi_assert(instance);
+    return instance->threshold_rssi;
+}
+
+SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance) {
+    furi_assert(instance);
+    float rssi = furi_hal_subghz_get_rssi();
+    SubGhzThresholdRssiData ret = {.rssi = rssi, .is_above = false};
+
+    if(float_is_equal(instance->threshold_rssi, SUBGHZ_RAW_THRESHOLD_MIN)) {
+        ret.is_above = true;
+    } else {
+        if(rssi < instance->threshold_rssi) {
+            instance->threshold_rssi_low_count++;
+            if(instance->threshold_rssi_low_count > THRESHOLD_RSSI_LOW_COUNT) {
+                instance->threshold_rssi_low_count = THRESHOLD_RSSI_LOW_COUNT;
+            }
+            ret.is_above = false;
+        } else {
+            instance->threshold_rssi_low_count = 0;
+        }
+
+        if(instance->threshold_rssi_low_count == THRESHOLD_RSSI_LOW_COUNT) {
+            ret.is_above = false;
+        } else {
+            ret.is_above = true;
+        }
+    }
+    return ret;
+}

+ 43 - 0
applications/main/subghz/helpers/subghz_threshold_rssi.h

@@ -0,0 +1,43 @@
+#pragma once
+
+#include <furi.h>
+
+typedef struct {
+    float rssi; /**< Current RSSI */
+    bool is_above; /**< Exceeded threshold level */
+} SubGhzThresholdRssiData;
+
+typedef struct SubGhzThresholdRssi SubGhzThresholdRssi;
+
+/** Allocate SubGhzThresholdRssi
+ * 
+ * @return SubGhzThresholdRssi* 
+ */
+SubGhzThresholdRssi* subghz_threshold_rssi_alloc(void);
+
+/** Free SubGhzThresholdRssi
+ * 
+ * @param instance Pointer to a SubGhzThresholdRssi
+ */
+void subghz_threshold_rssi_free(SubGhzThresholdRssi* instance);
+
+/** Set threshold
+ * 
+ * @param instance Pointer to a SubGhzThresholdRssi
+ * @param rssi RSSI threshold
+ */
+void subghz_threshold_rssi_set(SubGhzThresholdRssi* instance, float rssi);
+
+/** Get threshold
+ * 
+ * @param instance Pointer to a SubGhzThresholdRssi
+ * @return float RSSI threshold
+ */
+float subghz_threshold_rssi_get(SubGhzThresholdRssi* instance);
+
+/** Check threshold
+ * 
+ * @param instance Pointer to a SubGhzThresholdRssi
+ * @return SubGhzThresholdRssiData 
+ */
+SubGhzThresholdRssiData subghz_threshold_get_rssi_data(SubGhzThresholdRssi* instance);

+ 521 - 0
applications/main/subghz/helpers/subghz_txrx.c

@@ -0,0 +1,521 @@
+#include "subghz_txrx_i.h"
+
+#include <lib/subghz/protocols/protocol_items.h>
+
+#define TAG "SubGhz"
+
+SubGhzTxRx* subghz_txrx_alloc() {
+    SubGhzTxRx* instance = malloc(sizeof(SubGhzTxRx));
+    instance->setting = subghz_setting_alloc();
+    subghz_setting_load(instance->setting, EXT_PATH("subghz/assets/setting_user"));
+
+    instance->preset = malloc(sizeof(SubGhzRadioPreset));
+    instance->preset->name = furi_string_alloc();
+    subghz_txrx_set_preset(
+        instance, "AM650", subghz_setting_get_default_frequency(instance->setting), NULL, 0);
+
+    instance->txrx_state = SubGhzTxRxStateSleep;
+
+    subghz_txrx_hopper_set_state(instance, SubGhzHopperStateOFF);
+    subghz_txrx_speaker_set_state(instance, SubGhzSpeakerStateDisable);
+
+    instance->worker = subghz_worker_alloc();
+    instance->fff_data = flipper_format_string_alloc();
+
+    instance->environment = subghz_environment_alloc();
+    instance->is_database_loaded = subghz_environment_load_keystore(
+        instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes"));
+    subghz_environment_load_keystore(
+        instance->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user"));
+    subghz_environment_set_came_atomo_rainbow_table_file_name(
+        instance->environment, EXT_PATH("subghz/assets/came_atomo"));
+    subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
+        instance->environment, EXT_PATH("subghz/assets/alutech_at_4n"));
+    subghz_environment_set_nice_flor_s_rainbow_table_file_name(
+        instance->environment, EXT_PATH("subghz/assets/nice_flor_s"));
+    subghz_environment_set_protocol_registry(
+        instance->environment, (void*)&subghz_protocol_registry);
+    instance->receiver = subghz_receiver_alloc_init(instance->environment);
+
+    subghz_worker_set_overrun_callback(
+        instance->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset);
+    subghz_worker_set_pair_callback(
+        instance->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode);
+    subghz_worker_set_context(instance->worker, instance->receiver);
+
+    return instance;
+}
+
+void subghz_txrx_free(SubGhzTxRx* instance) {
+    furi_assert(instance);
+
+    subghz_worker_free(instance->worker);
+    subghz_receiver_free(instance->receiver);
+    subghz_environment_free(instance->environment);
+    flipper_format_free(instance->fff_data);
+    furi_string_free(instance->preset->name);
+    subghz_setting_free(instance->setting);
+    free(instance->preset);
+    free(instance);
+}
+
+bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    return instance->is_database_loaded;
+}
+
+void subghz_txrx_set_preset(
+    SubGhzTxRx* instance,
+    const char* preset_name,
+    uint32_t frequency,
+    uint8_t* preset_data,
+    size_t preset_data_size) {
+    furi_assert(instance);
+    furi_string_set(instance->preset->name, preset_name);
+    SubGhzRadioPreset* preset = instance->preset;
+    preset->frequency = frequency;
+    preset->data = preset_data;
+    preset->data_size = preset_data_size;
+}
+
+const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset) {
+    UNUSED(instance);
+    const char* preset_name = "";
+    if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) {
+        preset_name = "AM270";
+    } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) {
+        preset_name = "AM650";
+    } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) {
+        preset_name = "FM238";
+    } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) {
+        preset_name = "FM476";
+    } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) {
+        preset_name = "CUSTOM";
+    } else {
+        FURI_LOG_E(TAG, "Unknown preset");
+    }
+    return preset_name;
+}
+
+SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    return *instance->preset;
+}
+
+void subghz_txrx_get_frequency_and_modulation(
+    SubGhzTxRx* instance,
+    FuriString* frequency,
+    FuriString* modulation) {
+    furi_assert(instance);
+    SubGhzRadioPreset* preset = instance->preset;
+    if(frequency != NULL) {
+        furi_string_printf(
+            frequency,
+            "%03ld.%02ld",
+            preset->frequency / 1000000 % 1000,
+            preset->frequency / 10000 % 100);
+    }
+    if(modulation != NULL) {
+        furi_string_printf(modulation, "%.2s", furi_string_get_cstr(preset->name));
+    }
+}
+
+static void subghz_txrx_begin(SubGhzTxRx* instance, uint8_t* preset_data) {
+    furi_assert(instance);
+    furi_hal_subghz_reset();
+    furi_hal_subghz_idle();
+    furi_hal_subghz_load_custom_preset(preset_data);
+    furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
+    instance->txrx_state = SubGhzTxRxStateIDLE;
+}
+
+static uint32_t subghz_txrx_rx(SubGhzTxRx* instance, uint32_t frequency) {
+    furi_assert(instance);
+    if(!furi_hal_subghz_is_frequency_valid(frequency)) {
+        furi_crash("SubGhz: Incorrect RX frequency.");
+    }
+    furi_assert(
+        instance->txrx_state != SubGhzTxRxStateRx && instance->txrx_state != SubGhzTxRxStateSleep);
+
+    furi_hal_subghz_idle();
+    uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency);
+    furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
+    furi_hal_subghz_flush_rx();
+    subghz_txrx_speaker_on(instance);
+    furi_hal_subghz_rx();
+
+    furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, instance->worker);
+    subghz_worker_start(instance->worker);
+    instance->txrx_state = SubGhzTxRxStateRx;
+    return value;
+}
+
+static void subghz_txrx_idle(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    furi_assert(instance->txrx_state != SubGhzTxRxStateSleep);
+    furi_hal_subghz_idle();
+    subghz_txrx_speaker_off(instance);
+    instance->txrx_state = SubGhzTxRxStateIDLE;
+}
+
+static void subghz_txrx_rx_end(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    furi_assert(instance->txrx_state == SubGhzTxRxStateRx);
+
+    if(subghz_worker_is_running(instance->worker)) {
+        subghz_worker_stop(instance->worker);
+        furi_hal_subghz_stop_async_rx();
+    }
+    furi_hal_subghz_idle();
+    subghz_txrx_speaker_off(instance);
+    instance->txrx_state = SubGhzTxRxStateIDLE;
+}
+
+void subghz_txrx_sleep(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    furi_hal_subghz_sleep();
+    instance->txrx_state = SubGhzTxRxStateSleep;
+}
+
+static bool subghz_txrx_tx(SubGhzTxRx* instance, uint32_t frequency) {
+    furi_assert(instance);
+    if(!furi_hal_subghz_is_frequency_valid(frequency)) {
+        furi_crash("SubGhz: Incorrect TX frequency.");
+    }
+    furi_assert(instance->txrx_state != SubGhzTxRxStateSleep);
+    furi_hal_subghz_idle();
+    furi_hal_subghz_set_frequency_and_path(frequency);
+    furi_hal_gpio_write(&gpio_cc1101_g0, false);
+    furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
+    bool ret = furi_hal_subghz_tx();
+    if(ret) {
+        subghz_txrx_speaker_on(instance);
+        instance->txrx_state = SubGhzTxRxStateTx;
+    }
+
+    return ret;
+}
+
+SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format) {
+    furi_assert(instance);
+    furi_assert(flipper_format);
+
+    subghz_txrx_stop(instance);
+
+    SubGhzTxRxStartTxState ret = SubGhzTxRxStartTxStateErrorParserOthers;
+    FuriString* temp_str = furi_string_alloc();
+    uint32_t repeat = 200;
+    do {
+        if(!flipper_format_rewind(flipper_format)) {
+            FURI_LOG_E(TAG, "Rewind error");
+            break;
+        }
+        if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) {
+            FURI_LOG_E(TAG, "Missing Protocol");
+            break;
+        }
+        if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) {
+            FURI_LOG_E(TAG, "Unable Repeat");
+            break;
+        }
+        ret = SubGhzTxRxStartTxStateOk;
+
+        SubGhzRadioPreset* preset = instance->preset;
+        instance->transmitter =
+            subghz_transmitter_alloc_init(instance->environment, furi_string_get_cstr(temp_str));
+
+        if(instance->transmitter) {
+            if(subghz_transmitter_deserialize(instance->transmitter, flipper_format) ==
+               SubGhzProtocolStatusOk) {
+                if(strcmp(furi_string_get_cstr(preset->name), "") != 0) {
+                    subghz_txrx_begin(
+                        instance,
+                        subghz_setting_get_preset_data_by_name(
+                            instance->setting, furi_string_get_cstr(preset->name)));
+                    if(preset->frequency) {
+                        if(!subghz_txrx_tx(instance, preset->frequency)) {
+                            FURI_LOG_E(TAG, "Only Rx");
+                            ret = SubGhzTxRxStartTxStateErrorOnlyRx;
+                        }
+                    } else {
+                        ret = SubGhzTxRxStartTxStateErrorParserOthers;
+                    }
+
+                } else {
+                    FURI_LOG_E(
+                        TAG, "Unknown name preset \" %s \"", furi_string_get_cstr(preset->name));
+                    ret = SubGhzTxRxStartTxStateErrorParserOthers;
+                }
+
+                if(ret == SubGhzTxRxStartTxStateOk) {
+                    //Start TX
+                    furi_hal_subghz_start_async_tx(
+                        subghz_transmitter_yield, instance->transmitter);
+                }
+            } else {
+                ret = SubGhzTxRxStartTxStateErrorParserOthers;
+            }
+        } else {
+            ret = SubGhzTxRxStartTxStateErrorParserOthers;
+        }
+        if(ret != SubGhzTxRxStartTxStateOk) {
+            subghz_transmitter_free(instance->transmitter);
+            if(instance->txrx_state != SubGhzTxRxStateIDLE) {
+                subghz_txrx_idle(instance);
+            }
+        }
+
+    } while(false);
+    furi_string_free(temp_str);
+    return ret;
+}
+
+void subghz_txrx_rx_start(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    subghz_txrx_stop(instance);
+    subghz_txrx_begin(
+        instance,
+        subghz_setting_get_preset_data_by_name(
+            subghz_txrx_get_setting(instance), furi_string_get_cstr(instance->preset->name)));
+    subghz_txrx_rx(instance, instance->preset->frequency);
+}
+
+void subghz_txrx_set_need_save_callback(
+    SubGhzTxRx* instance,
+    SubGhzTxRxNeedSaveCallback callback,
+    void* context) {
+    furi_assert(instance);
+    instance->need_save_callback = callback;
+    instance->need_save_context = context;
+}
+
+static void subghz_txrx_tx_stop(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    furi_assert(instance->txrx_state == SubGhzTxRxStateTx);
+    //Stop TX
+    furi_hal_subghz_stop_async_tx();
+    subghz_transmitter_stop(instance->transmitter);
+    subghz_transmitter_free(instance->transmitter);
+
+    //if protocol dynamic then we save the last upload
+    if(instance->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) {
+        if(instance->need_save_callback) {
+            instance->need_save_callback(instance->need_save_context);
+        }
+    }
+    subghz_txrx_idle(instance);
+    subghz_txrx_speaker_off(instance);
+    //Todo: Show message
+    // notification_message(notifications, &sequence_reset_red);
+}
+
+FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    return instance->fff_data;
+}
+
+SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    return instance->setting;
+}
+
+void subghz_txrx_stop(SubGhzTxRx* instance) {
+    furi_assert(instance);
+
+    switch(instance->txrx_state) {
+    case SubGhzTxRxStateTx:
+        subghz_txrx_tx_stop(instance);
+        subghz_txrx_speaker_unmute(instance);
+        break;
+    case SubGhzTxRxStateRx:
+        subghz_txrx_rx_end(instance);
+        subghz_txrx_speaker_mute(instance);
+        break;
+
+    default:
+        break;
+    }
+}
+
+void subghz_txrx_hopper_update(SubGhzTxRx* instance) {
+    furi_assert(instance);
+
+    switch(instance->hopper_state) {
+    case SubGhzHopperStateOFF:
+    case SubGhzHopperStatePause:
+        return;
+    case SubGhzHopperStateRSSITimeOut:
+        if(instance->hopper_timeout != 0) {
+            instance->hopper_timeout--;
+            return;
+        }
+        break;
+    default:
+        break;
+    }
+    float rssi = -127.0f;
+    if(instance->hopper_state != SubGhzHopperStateRSSITimeOut) {
+        // See RSSI Calculation timings in CC1101 17.3 RSSI
+        rssi = furi_hal_subghz_get_rssi();
+
+        // Stay if RSSI is high enough
+        if(rssi > -90.0f) {
+            instance->hopper_timeout = 10;
+            instance->hopper_state = SubGhzHopperStateRSSITimeOut;
+            return;
+        }
+    } else {
+        instance->hopper_state = SubGhzHopperStateRunnig;
+    }
+    // Select next frequency
+    if(instance->hopper_idx_frequency <
+       subghz_setting_get_hopper_frequency_count(instance->setting) - 1) {
+        instance->hopper_idx_frequency++;
+    } else {
+        instance->hopper_idx_frequency = 0;
+    }
+
+    if(instance->txrx_state == SubGhzTxRxStateRx) {
+        subghz_txrx_rx_end(instance);
+    };
+    if(instance->txrx_state == SubGhzTxRxStateIDLE) {
+        subghz_receiver_reset(instance->receiver);
+        instance->preset->frequency =
+            subghz_setting_get_hopper_frequency(instance->setting, instance->hopper_idx_frequency);
+        subghz_txrx_rx(instance, instance->preset->frequency);
+    }
+}
+
+SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    return instance->hopper_state;
+}
+
+void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state) {
+    furi_assert(instance);
+    instance->hopper_state = state;
+}
+
+void subghz_txrx_hopper_unpause(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    if(instance->hopper_state == SubGhzHopperStatePause) {
+        instance->hopper_state = SubGhzHopperStateRunnig;
+    }
+}
+
+void subghz_txrx_hopper_pause(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    if(instance->hopper_state == SubGhzHopperStateRunnig) {
+        instance->hopper_state = SubGhzHopperStatePause;
+    }
+}
+
+void subghz_txrx_speaker_on(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    if(instance->speaker_state == SubGhzSpeakerStateEnable) {
+        if(furi_hal_speaker_acquire(30)) {
+            furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
+        } else {
+            instance->speaker_state = SubGhzSpeakerStateDisable;
+        }
+    }
+}
+
+void subghz_txrx_speaker_off(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    if(instance->speaker_state != SubGhzSpeakerStateDisable) {
+        if(furi_hal_speaker_is_mine()) {
+            furi_hal_subghz_set_async_mirror_pin(NULL);
+            furi_hal_speaker_release();
+            if(instance->speaker_state == SubGhzSpeakerStateShutdown)
+                instance->speaker_state = SubGhzSpeakerStateDisable;
+        }
+    }
+}
+
+void subghz_txrx_speaker_mute(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    if(instance->speaker_state == SubGhzSpeakerStateEnable) {
+        if(furi_hal_speaker_is_mine()) {
+            furi_hal_subghz_set_async_mirror_pin(NULL);
+        }
+    }
+}
+
+void subghz_txrx_speaker_unmute(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    if(instance->speaker_state == SubGhzSpeakerStateEnable) {
+        if(furi_hal_speaker_is_mine()) {
+            furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
+        }
+    }
+}
+
+void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state) {
+    furi_assert(instance);
+    instance->speaker_state = state;
+}
+
+SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    return instance->speaker_state;
+}
+
+bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol) {
+    furi_assert(instance);
+    furi_assert(name_protocol);
+    bool res = false;
+    instance->decoder_result =
+        subghz_receiver_search_decoder_base_by_name(instance->receiver, name_protocol);
+    if(instance->decoder_result) {
+        res = true;
+    }
+    return res;
+}
+
+SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    return instance->decoder_result;
+}
+
+bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance) {
+    furi_assert(instance);
+    return (
+        (instance->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) ==
+        SubGhzProtocolFlag_Save);
+}
+
+bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type) {
+    furi_assert(instance);
+    const SubGhzProtocol* protocol = instance->decoder_result->protocol;
+    if(check_type) {
+        return (
+            ((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) &&
+            protocol->encoder->deserialize && protocol->type == SubGhzProtocolTypeStatic);
+    }
+    return (
+        ((protocol->flag & SubGhzProtocolFlag_Send) == SubGhzProtocolFlag_Send) &&
+        protocol->encoder->deserialize);
+}
+
+void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter) {
+    furi_assert(instance);
+    subghz_receiver_set_filter(instance->receiver, filter);
+}
+
+void subghz_txrx_set_rx_calback(
+    SubGhzTxRx* instance,
+    SubGhzReceiverCallback callback,
+    void* context) {
+    subghz_receiver_set_rx_callback(instance->receiver, callback, context);
+}
+
+void subghz_txrx_set_raw_file_encoder_worker_callback_end(
+    SubGhzTxRx* instance,
+    SubGhzProtocolEncoderRAWCallbackEnd callback,
+    void* context) {
+    subghz_protocol_raw_file_encoder_worker_set_callback_end(
+        (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance(instance->transmitter),
+        callback,
+        context);
+}

+ 290 - 0
applications/main/subghz/helpers/subghz_txrx.h

@@ -0,0 +1,290 @@
+#pragma once
+
+#include "subghz_types.h"
+
+#include <lib/subghz/subghz_worker.h>
+#include <lib/subghz/subghz_setting.h>
+#include <lib/subghz/receiver.h>
+#include <lib/subghz/transmitter.h>
+#include <lib/subghz/protocols/raw.h>
+
+typedef struct SubGhzTxRx SubGhzTxRx;
+
+typedef void (*SubGhzTxRxNeedSaveCallback)(void* context);
+
+typedef enum {
+    SubGhzTxRxStartTxStateOk,
+    SubGhzTxRxStartTxStateErrorOnlyRx,
+    SubGhzTxRxStartTxStateErrorParserOthers,
+} SubGhzTxRxStartTxState;
+
+/**
+ * Allocate SubGhzTxRx
+ * 
+ * @return SubGhzTxRx* pointer to SubGhzTxRx
+ */
+SubGhzTxRx* subghz_txrx_alloc();
+
+/**
+ * Free SubGhzTxRx
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ */
+void subghz_txrx_free(SubGhzTxRx* instance);
+
+/**
+ * Check if the database is loaded
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @return bool True if the database is loaded
+ */
+bool subghz_txrx_is_database_loaded(SubGhzTxRx* instance);
+
+/**
+ * Set preset 
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @param preset_name Name of preset
+ * @param frequency Frequency in Hz
+ * @param preset_data Data of preset
+ * @param preset_data_size Size of preset data
+ */
+void subghz_txrx_set_preset(
+    SubGhzTxRx* instance,
+    const char* preset_name,
+    uint32_t frequency,
+    uint8_t* preset_data,
+    size_t preset_data_size);
+
+/**
+ * Get name of preset
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @param preset String of preset 
+ * @return const char*  Name of preset
+ */
+const char* subghz_txrx_get_preset_name(SubGhzTxRx* instance, const char* preset);
+
+/**
+ * Get of preset
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @return SubGhzRadioPreset Preset
+ */
+SubGhzRadioPreset subghz_txrx_get_preset(SubGhzTxRx* instance);
+
+/**
+ * Get string frequency and modulation
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @param frequency Pointer to a string frequency
+ * @param modulation Pointer to a string modulation
+ */
+void subghz_txrx_get_frequency_and_modulation(
+    SubGhzTxRx* instance,
+    FuriString* frequency,
+    FuriString* modulation);
+
+/**
+ * Start TX CC1101
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @param flipper_format Pointer to a FlipperFormat
+ * @return SubGhzTxRxStartTxState 
+ */
+SubGhzTxRxStartTxState subghz_txrx_tx_start(SubGhzTxRx* instance, FlipperFormat* flipper_format);
+
+/**
+ * Start RX CC1101
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ */
+void subghz_txrx_rx_start(SubGhzTxRx* instance);
+
+/**
+ * Stop TX/RX CC1101
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ */
+void subghz_txrx_stop(SubGhzTxRx* instance);
+
+/**
+ * Set sleep mode CC1101
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ */
+void subghz_txrx_sleep(SubGhzTxRx* instance);
+
+/**
+ * Update frequency CC1101 in automatic mode (hopper)
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ */
+void subghz_txrx_hopper_update(SubGhzTxRx* instance);
+
+/**
+ * Get state hopper
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @return SubGhzHopperState 
+ */
+SubGhzHopperState subghz_txrx_hopper_get_state(SubGhzTxRx* instance);
+
+/**
+ * Set state hopper
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @param state State hopper
+ */
+void subghz_txrx_hopper_set_state(SubGhzTxRx* instance, SubGhzHopperState state);
+
+/**
+ * Unpause hopper
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ */
+void subghz_txrx_hopper_unpause(SubGhzTxRx* instance);
+
+/**
+ * Set pause hopper
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ */
+void subghz_txrx_hopper_pause(SubGhzTxRx* instance);
+
+/**
+ * Speaker on
+ * 
+ * @param instance Pointer to a SubGhzTxRx 
+ */
+void subghz_txrx_speaker_on(SubGhzTxRx* instance);
+
+/**
+ * Speaker off
+ * 
+ * @param instance Pointer to a SubGhzTxRx 
+ */
+void subghz_txrx_speaker_off(SubGhzTxRx* instance);
+
+/**
+ * Speaker mute
+ * 
+ * @param instance Pointer to a SubGhzTxRx 
+ */
+void subghz_txrx_speaker_mute(SubGhzTxRx* instance);
+
+/**
+ * Speaker unmute
+ * 
+ * @param instance Pointer to a SubGhzTxRx 
+ */
+void subghz_txrx_speaker_unmute(SubGhzTxRx* instance);
+
+/**
+ * Set state speaker
+ * 
+ * @param instance Pointer to a SubGhzTxRx 
+ * @param state State speaker
+ */
+void subghz_txrx_speaker_set_state(SubGhzTxRx* instance, SubGhzSpeakerState state);
+
+/**
+ * Get state speaker
+ * 
+ * @param instance Pointer to a SubGhzTxRx 
+ * @return SubGhzSpeakerState 
+ */
+SubGhzSpeakerState subghz_txrx_speaker_get_state(SubGhzTxRx* instance);
+
+/**
+ * load decoder by name protocol
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @param name_protocol Name protocol
+ * @return bool True if the decoder is loaded 
+ */
+bool subghz_txrx_load_decoder_by_name_protocol(SubGhzTxRx* instance, const char* name_protocol);
+
+/**
+ * Get decoder
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @return SubGhzProtocolDecoderBase* Pointer to a SubGhzProtocolDecoderBase
+ */
+SubGhzProtocolDecoderBase* subghz_txrx_get_decoder(SubGhzTxRx* instance);
+
+/**
+ * Set callback for save data
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @param callback Callback for save data
+ * @param context Context for callback
+ */
+void subghz_txrx_set_need_save_callback(
+    SubGhzTxRx* instance,
+    SubGhzTxRxNeedSaveCallback callback,
+    void* context);
+
+/**
+ * Get pointer to a load data key
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @return FlipperFormat* 
+ */
+FlipperFormat* subghz_txrx_get_fff_data(SubGhzTxRx* instance);
+
+/**
+ * Get pointer to a SugGhzSetting
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @return SubGhzSetting* 
+ */
+SubGhzSetting* subghz_txrx_get_setting(SubGhzTxRx* instance);
+
+/**
+ * Is it possible to save this protocol
+ * 
+ * @param instance Pointer to a SubGhzTxRx 
+ * @return bool True if it is possible to save this protocol
+ */
+bool subghz_txrx_protocol_is_serializable(SubGhzTxRx* instance);
+
+/**
+ * Is it possible to send this protocol
+ * 
+ * @param instance Pointer to a SubGhzTxRx 
+ * @return bool True if it is possible to send this protocol
+ */
+bool subghz_txrx_protocol_is_transmittable(SubGhzTxRx* instance, bool check_type);
+
+/**
+ * Set filter, what types of decoder to use 
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @param filter Filter
+ */
+void subghz_txrx_receiver_set_filter(SubGhzTxRx* instance, SubGhzProtocolFlag filter);
+
+/**
+ * Set callback for receive data
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @param callback Callback for receive data
+ * @param context Context for callback
+ */
+void subghz_txrx_set_rx_calback(
+    SubGhzTxRx* instance,
+    SubGhzReceiverCallback callback,
+    void* context);
+
+/**
+ * Set callback for Raw decoder, end of data transfer  
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @param callback Callback for Raw decoder, end of data transfer 
+ * @param context Context for callback
+ */
+void subghz_txrx_set_raw_file_encoder_worker_callback_end(
+    SubGhzTxRx* instance,
+    SubGhzProtocolEncoderRAWCallbackEnd callback,
+    void* context);

+ 164 - 0
applications/main/subghz/helpers/subghz_txrx_create_potocol_key.c

@@ -0,0 +1,164 @@
+#include "subghz_txrx_i.h"
+#include "subghz_txrx_create_potocol_key.h"
+#include <lib/subghz/transmitter.h>
+#include <lib/subghz/protocols/protocol_items.h>
+#include <lib/subghz/protocols/protocol_items.h>
+#include <lib/subghz/protocols/keeloq.h>
+#include <lib/subghz/protocols/secplus_v1.h>
+#include <lib/subghz/protocols/secplus_v2.h>
+
+#include <flipper_format/flipper_format_i.h>
+#include <lib/toolbox/stream/stream.h>
+#include <lib/subghz/protocols/raw.h>
+
+#define TAG "SubGhzCreateProtocolKey"
+
+bool subghz_txrx_gen_data_protocol(
+    void* context,
+    const char* preset_name,
+    uint32_t frequency,
+    const char* protocol_name,
+    uint64_t key,
+    uint32_t bit) {
+    furi_assert(context);
+    SubGhzTxRx* instance = context;
+
+    bool res = false;
+
+    subghz_txrx_set_preset(instance, preset_name, frequency, NULL, 0);
+    instance->decoder_result =
+        subghz_receiver_search_decoder_base_by_name(instance->receiver, protocol_name);
+
+    if(instance->decoder_result == NULL) {
+        //TODO: Error
+        // furi_string_set(error_str, "Protocol not\nfound!");
+        // scene_manager_next_scene(scene_manager, SubGhzSceneShowErrorSub);
+        FURI_LOG_E(TAG, "Protocol not found!");
+        return false;
+    }
+
+    do {
+        Stream* fff_data_stream = flipper_format_get_raw_stream(instance->fff_data);
+        stream_clean(fff_data_stream);
+        if(subghz_protocol_decoder_base_serialize(
+               instance->decoder_result, instance->fff_data, instance->preset) !=
+           SubGhzProtocolStatusOk) {
+            FURI_LOG_E(TAG, "Unable to serialize");
+            break;
+        }
+        if(!flipper_format_update_uint32(instance->fff_data, "Bit", &bit, 1)) {
+            FURI_LOG_E(TAG, "Unable to update Bit");
+            break;
+        }
+
+        uint8_t key_data[sizeof(uint64_t)] = {0};
+        for(size_t i = 0; i < sizeof(uint64_t); i++) {
+            key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF;
+        }
+        if(!flipper_format_update_hex(instance->fff_data, "Key", key_data, sizeof(uint64_t))) {
+            FURI_LOG_E(TAG, "Unable to update Key");
+            break;
+        }
+        res = true;
+    } while(false);
+    return res;
+}
+
+bool subghz_txrx_gen_data_protocol_and_te(
+    SubGhzTxRx* instance,
+    const char* preset_name,
+    uint32_t frequency,
+    const char* protocol_name,
+    uint64_t key,
+    uint32_t bit,
+    uint32_t te) {
+    furi_assert(instance);
+    bool ret = false;
+    if(subghz_txrx_gen_data_protocol(instance, preset_name, frequency, protocol_name, key, bit)) {
+        if(!flipper_format_update_uint32(instance->fff_data, "TE", (uint32_t*)&te, 1)) {
+            FURI_LOG_E(TAG, "Unable to update Te");
+        } else {
+            ret = true;
+        }
+    }
+    return ret;
+}
+
+bool subghz_txrx_gen_keelog_protocol(
+    SubGhzTxRx* instance,
+    const char* name_preset,
+    uint32_t frequency,
+    const char* name_sysmem,
+    uint32_t serial,
+    uint8_t btn,
+    uint16_t cnt) {
+    furi_assert(instance);
+
+    bool ret = false;
+    serial &= 0x0FFFFFFF;
+    instance->transmitter =
+        subghz_transmitter_alloc_init(instance->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
+    subghz_txrx_set_preset(instance, name_preset, frequency, NULL, 0);
+    if(instance->transmitter) {
+        subghz_protocol_keeloq_create_data(
+            subghz_transmitter_get_protocol_instance(instance->transmitter),
+            instance->fff_data,
+            serial,
+            btn,
+            cnt,
+            name_sysmem,
+            instance->preset);
+        ret = true;
+    }
+    subghz_transmitter_free(instance->transmitter);
+    return ret;
+}
+
+bool subghz_txrx_gen_secplus_v2_protocol(
+    SubGhzTxRx* instance,
+    const char* name_preset,
+    uint32_t frequency,
+    uint32_t serial,
+    uint8_t btn,
+    uint32_t cnt) {
+    furi_assert(instance);
+
+    bool ret = false;
+    instance->transmitter =
+        subghz_transmitter_alloc_init(instance->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
+    subghz_txrx_set_preset(instance, name_preset, frequency, NULL, 0);
+    if(instance->transmitter) {
+        subghz_protocol_secplus_v2_create_data(
+            subghz_transmitter_get_protocol_instance(instance->transmitter),
+            instance->fff_data,
+            serial,
+            btn,
+            cnt,
+            instance->preset);
+        ret = true;
+    }
+    return ret;
+}
+
+bool subghz_txrx_gen_secplus_v1_protocol(
+    SubGhzTxRx* instance,
+    const char* name_preset,
+    uint32_t frequency) {
+    furi_assert(instance);
+
+    bool ret = false;
+    uint32_t serial = (uint32_t)rand();
+    while(!subghz_protocol_secplus_v1_check_fixed(serial)) {
+        serial = (uint32_t)rand();
+    }
+    if(subghz_txrx_gen_data_protocol(
+           instance,
+           name_preset,
+           frequency,
+           SUBGHZ_PROTOCOL_SECPLUS_V1_NAME,
+           (uint64_t)serial << 32 | 0xE6000000,
+           42)) {
+        ret = true;
+    }
+    return ret;
+}

+ 96 - 0
applications/main/subghz/helpers/subghz_txrx_create_potocol_key.h

@@ -0,0 +1,96 @@
+#pragma once
+#include "subghz_types.h"
+#include "subghz_txrx.h"
+
+/**
+ * Generate data for protocol
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @param preset_name Name of preset
+ * @param frequency Frequency in Hz
+ * @param protocol_name Name of protocol
+ * @param key Key
+ * @param bit Bit
+ * @return bool True if success
+ */
+bool subghz_txrx_gen_data_protocol(
+    void* context,
+    const char* preset_name,
+    uint32_t frequency,
+    const char* protocol_name,
+    uint64_t key,
+    uint32_t bit);
+
+/**
+ * Generate data for protocol and te
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @param preset_name Name of preset
+ * @param frequency Frequency in Hz
+ * @param protocol_name Name of protocol
+ * @param key Key
+ * @param bit Bit
+ * @param te Te
+ * @return bool True if success
+ */
+bool subghz_txrx_gen_data_protocol_and_te(
+    SubGhzTxRx* instance,
+    const char* preset_name,
+    uint32_t frequency,
+    const char* protocol_name,
+    uint64_t key,
+    uint32_t bit,
+    uint32_t te);
+
+/**
+ * Generate data Keeloq protocol
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @param name_preset Name of preset
+ * @param frequency Frequency in Hz
+ * @param name_sysmem Name of Keeloq sysmem
+ * @param serial Serial number
+ * @param btn Button
+ * @param cnt Counter
+ * @return bool True if success
+ */
+bool subghz_txrx_gen_keelog_protocol(
+    SubGhzTxRx* instance,
+    const char* name_preset,
+    uint32_t frequency,
+    const char* name_sysmem,
+    uint32_t serial,
+    uint8_t btn,
+    uint16_t cnt);
+
+/**
+ * Generate data SecPlus v2 protocol
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @param name_preset Name of preset
+ * @param frequency Frequency in Hz
+ * @param serial Serial number
+ * @param btn Button
+ * @param cnt Counter
+ * @return bool True if success
+ */
+bool subghz_txrx_gen_secplus_v2_protocol(
+    SubGhzTxRx* instance,
+    const char* name_preset,
+    uint32_t frequency,
+    uint32_t serial,
+    uint8_t btn,
+    uint32_t cnt);
+
+/**
+ * Generate data SecPlus v1 protocol
+ * 
+ * @param instance Pointer to a SubGhzTxRx
+ * @param name_preset Name of preset
+ * @param frequency Frequency in Hz
+ * @return bool True if success
+ */
+bool subghz_txrx_gen_secplus_v1_protocol(
+    SubGhzTxRx* instance,
+    const char* name_preset,
+    uint32_t frequency);

+ 27 - 0
applications/main/subghz/helpers/subghz_txrx_i.h

@@ -0,0 +1,27 @@
+#pragma once
+
+#include "subghz_txrx.h"
+
+struct SubGhzTxRx {
+    SubGhzWorker* worker;
+
+    SubGhzEnvironment* environment;
+    SubGhzReceiver* receiver;
+    SubGhzTransmitter* transmitter;
+    SubGhzProtocolDecoderBase* decoder_result;
+    FlipperFormat* fff_data;
+
+    SubGhzRadioPreset* preset;
+    SubGhzSetting* setting;
+
+    uint8_t hopper_timeout;
+    uint8_t hopper_idx_frequency;
+    bool is_database_loaded;
+    SubGhzHopperState hopper_state;
+
+    SubGhzTxRxState txrx_state;
+    SubGhzSpeakerState speaker_state;
+
+    SubGhzTxRxNeedSaveCallback need_save_callback;
+    void* need_save_context;
+};

+ 7 - 0
applications/main/subghz/helpers/subghz_types.h

@@ -77,3 +77,10 @@ typedef enum {
     SubGhzViewIdTestCarrier,
     SubGhzViewIdTestPacket,
 } SubGhzViewId;
+
+/** SubGhz load type file */
+typedef enum {
+    SubGhzLoadTypeFileNoLoad,
+    SubGhzLoadTypeFileKey,
+    SubGhzLoadTypeFileRaw,
+} SubGhzLoadTypeFile;

+ 2 - 2
applications/main/subghz/scenes/subghz_scene_delete.c

@@ -19,7 +19,7 @@ void subghz_scene_delete_on_enter(void* context) {
     modulation_str = furi_string_alloc();
     text = furi_string_alloc();
 
-    subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
+    subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str);
     widget_add_string_element(
         subghz->widget,
         78,
@@ -37,7 +37,7 @@ void subghz_scene_delete_on_enter(void* context) {
         AlignTop,
         FontSecondary,
         furi_string_get_cstr(modulation_str));
-    subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text);
+    subghz_protocol_decoder_base_get_string(subghz_txrx_get_decoder(subghz->txrx), text);
     widget_add_string_multiline_element(
         subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(text));
 

+ 1 - 1
applications/main/subghz/scenes/subghz_scene_delete_raw.c

@@ -33,7 +33,7 @@ void subghz_scene_delete_raw_on_enter(void* context) {
 
     widget_add_string_element(
         subghz->widget, 38, 25, AlignLeft, AlignTop, FontSecondary, "RAW signal");
-    subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
+    subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str);
     widget_add_string_element(
         subghz->widget,
         35,

+ 7 - 11
applications/main/subghz/scenes/subghz_scene_need_saving.c

@@ -37,27 +37,23 @@ void subghz_scene_need_saving_on_enter(void* context) {
 bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) {
     SubGhz* subghz = context;
     if(event.type == SceneManagerEventTypeBack) {
-        subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
+        subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack);
         scene_manager_previous_scene(subghz->scene_manager);
         return true;
     } else if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == SubGhzCustomEventSceneStay) {
-            subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
+            subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack);
             scene_manager_previous_scene(subghz->scene_manager);
             return true;
         } else if(event.event == SubGhzCustomEventSceneExit) {
-            if(subghz->txrx->rx_key_state == SubGhzRxKeyStateExit) {
-                subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
-                subghz_preset_init(
-                    subghz,
-                    "AM650",
-                    subghz_setting_get_default_frequency(subghz->setting),
-                    NULL,
-                    0);
+            SubGhzRxKeyState state = subghz_rx_key_state_get(subghz);
+            subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
+
+            if(state == SubGhzRxKeyStateExit) {
+                subghz_set_default_preset(subghz);
                 scene_manager_search_and_switch_to_previous_scene(
                     subghz->scene_manager, SubGhzSceneStart);
             } else {
-                subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
                 scene_manager_previous_scene(subghz->scene_manager);
             }
 

+ 69 - 160
applications/main/subghz/scenes/subghz_scene_read_raw.c

@@ -3,11 +3,9 @@
 #include <dolphin/dolphin.h>
 #include <lib/subghz/protocols/raw.h>
 #include <lib/toolbox/path.h>
-#include <float_tools.h>
 
 #define RAW_FILE_NAME "Raw_signal_"
 #define TAG "SubGhzSceneReadRAW"
-#define RAW_THRESHOLD_RSSI_LOW_COUNT 10
 
 bool subghz_scene_read_raw_update_filename(SubGhz* subghz) {
     bool ret = false;
@@ -15,12 +13,13 @@ bool subghz_scene_read_raw_update_filename(SubGhz* subghz) {
     FuriString* temp_str;
     temp_str = furi_string_alloc();
     do {
-        if(!flipper_format_rewind(subghz->txrx->fff_data)) {
+        FlipperFormat* fff_data = subghz_txrx_get_fff_data(subghz->txrx);
+        if(!flipper_format_rewind(fff_data)) {
             FURI_LOG_E(TAG, "Rewind error");
             break;
         }
 
-        if(!flipper_format_read_string(subghz->txrx->fff_data, "File_name", temp_str)) {
+        if(!flipper_format_read_string(fff_data, "File_name", temp_str)) {
             FURI_LOG_E(TAG, "Missing File_name");
             break;
         }
@@ -38,13 +37,10 @@ static void subghz_scene_read_raw_update_statusbar(void* context) {
     furi_assert(context);
     SubGhz* subghz = context;
 
-    FuriString* frequency_str;
-    FuriString* modulation_str;
+    FuriString* frequency_str = furi_string_alloc();
+    FuriString* modulation_str = furi_string_alloc();
 
-    frequency_str = furi_string_alloc();
-    modulation_str = furi_string_alloc();
-
-    subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
+    subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str);
     subghz_read_raw_add_data_statusbar(
         subghz->subghz_read_raw,
         furi_string_get_cstr(frequency_str),
@@ -69,13 +65,13 @@ void subghz_scene_read_raw_callback_end_tx(void* context) {
 
 void subghz_scene_read_raw_on_enter(void* context) {
     SubGhz* subghz = context;
-    FuriString* file_name;
-    file_name = furi_string_alloc();
+    FuriString* file_name = furi_string_alloc();
 
-    switch(subghz->txrx->rx_key_state) {
+    float threshold_rssi = subghz_threshold_rssi_get(subghz->threshold_rssi);
+    switch(subghz_rx_key_state_get(subghz)) {
     case SubGhzRxKeyStateBack:
         subghz_read_raw_set_status(
-            subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "", subghz->txrx->raw_threshold_rssi);
+            subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "", threshold_rssi);
         break;
     case SubGhzRxKeyStateRAWLoad:
         path_extract_filename(subghz->file_path, file_name, true);
@@ -83,8 +79,7 @@ void subghz_scene_read_raw_on_enter(void* context) {
             subghz->subghz_read_raw,
             SubGhzReadRAWStatusLoadKeyTX,
             furi_string_get_cstr(file_name),
-            subghz->txrx->raw_threshold_rssi);
-        subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
+            threshold_rssi);
         break;
     case SubGhzRxKeyStateRAWSave:
         path_extract_filename(subghz->file_path, file_name, true);
@@ -92,66 +87,51 @@ void subghz_scene_read_raw_on_enter(void* context) {
             subghz->subghz_read_raw,
             SubGhzReadRAWStatusSaveKey,
             furi_string_get_cstr(file_name),
-            subghz->txrx->raw_threshold_rssi);
-        subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
+            threshold_rssi);
         break;
     default:
         subghz_read_raw_set_status(
-            subghz->subghz_read_raw,
-            SubGhzReadRAWStatusStart,
-            "",
-            subghz->txrx->raw_threshold_rssi);
-        subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
+            subghz->subghz_read_raw, SubGhzReadRAWStatusStart, "", threshold_rssi);
         break;
     }
+
+    if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateBack) {
+        subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
+    }
     furi_string_free(file_name);
     subghz_scene_read_raw_update_statusbar(subghz);
 
     //set callback view raw
     subghz_read_raw_set_callback(subghz->subghz_read_raw, subghz_scene_read_raw_callback, subghz);
 
-    subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
-        subghz->txrx->receiver, SUBGHZ_PROTOCOL_RAW_NAME);
-    furi_assert(subghz->txrx->decoder_result);
+    furi_check(subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, SUBGHZ_PROTOCOL_RAW_NAME));
 
     //set filter RAW feed
-    subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_RAW);
+    subghz_txrx_receiver_set_filter(subghz->txrx, SubGhzProtocolFlag_RAW);
     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReadRAW);
 }
 
 bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
     SubGhz* subghz = context;
     bool consumed = false;
+    SubGhzProtocolDecoderRAW* decoder_raw =
+        (SubGhzProtocolDecoderRAW*)subghz_txrx_get_decoder(subghz->txrx);
     if(event.type == SceneManagerEventTypeCustom) {
         switch(event.event) {
         case SubGhzCustomEventViewReadRAWBack:
-            //Stop TX
-            if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
-                subghz_tx_stop(subghz);
-                subghz_sleep(subghz);
-            }
-            //Stop RX
-            if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
-                subghz_rx_end(subghz);
-                subghz_sleep(subghz);
-            };
+
+            subghz_txrx_stop(subghz->txrx);
             //Stop save file
-            subghz_protocol_raw_save_to_file_stop(
-                (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result);
+            subghz_protocol_raw_save_to_file_stop(decoder_raw);
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             //needed save?
-            if((subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) ||
-               (subghz->txrx->rx_key_state == SubGhzRxKeyStateBack)) {
-                subghz->txrx->rx_key_state = SubGhzRxKeyStateExit;
+            if((subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) ||
+               (subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateBack)) {
+                subghz_rx_key_state_set(subghz, SubGhzRxKeyStateExit);
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
             } else {
                 //Restore default setting
-                subghz_preset_init(
-                    subghz,
-                    "AM650",
-                    subghz_setting_get_default_frequency(subghz->setting),
-                    NULL,
-                    0);
+                subghz_set_default_preset(subghz);
                 if(!scene_manager_search_and_switch_to_previous_scene(
                        subghz->scene_manager, SubGhzSceneSaved)) {
                     if(!scene_manager_search_and_switch_to_previous_scene(
@@ -165,16 +145,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
             break;
 
         case SubGhzCustomEventViewReadRAWTXRXStop:
-            //Stop TX
-            if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
-                subghz_tx_stop(subghz);
-                subghz_sleep(subghz);
-            }
-            //Stop RX
-            if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
-                subghz_rx_end(subghz);
-                subghz_sleep(subghz);
-            };
+            subghz_txrx_stop(subghz->txrx);
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             consumed = true;
             break;
@@ -187,13 +158,13 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
             break;
 
         case SubGhzCustomEventViewReadRAWErase:
-            if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) {
+            if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) {
                 if(subghz_scene_read_raw_update_filename(subghz)) {
                     furi_string_set(subghz->file_path_tmp, subghz->file_path);
                     subghz_delete_file(subghz);
                 }
             }
-            subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
+            subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
             notification_message(subghz->notifications, &sequence_reset_rgb);
             consumed = true;
             break;
@@ -203,7 +174,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
                 if(subghz_scene_read_raw_update_filename(subghz)) {
                     scene_manager_set_scene_state(
                         subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet);
-                    subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
+                    subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad);
                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW);
                     consumed = true;
                 } else {
@@ -223,33 +194,22 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
             if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) {
                 //start send
                 subghz->state_notifications = SubGhzNotificationStateIDLE;
-                if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
-                    subghz_rx_end(subghz);
-                }
-                if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
-                   (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
-                    if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) {
-                        subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
-                        subghz_read_raw_set_status(
-                            subghz->subghz_read_raw,
-                            SubGhzReadRAWStatusIDLE,
-                            "",
-                            subghz->txrx->raw_threshold_rssi);
-                    } else {
-                        if(scene_manager_has_previous_scene(
-                               subghz->scene_manager, SubGhzSceneSaved) ||
-                           !scene_manager_has_previous_scene(
-                               subghz->scene_manager, SubGhzSceneStart)) {
-                            DOLPHIN_DEED(DolphinDeedSubGhzSend);
-                        }
-                        // set callback end tx
-                        subghz_protocol_raw_file_encoder_worker_set_callback_end(
-                            (SubGhzProtocolEncoderRAW*)subghz_transmitter_get_protocol_instance(
-                                subghz->txrx->transmitter),
-                            subghz_scene_read_raw_callback_end_tx,
-                            subghz);
-                        subghz->state_notifications = SubGhzNotificationStateTx;
+                if(!subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) {
+                    subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack);
+                    subghz_read_raw_set_status(
+                        subghz->subghz_read_raw,
+                        SubGhzReadRAWStatusIDLE,
+                        "",
+                        subghz_threshold_rssi_get(subghz->threshold_rssi));
+                } else {
+                    if(scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneSaved) ||
+                       !scene_manager_has_previous_scene(subghz->scene_manager, SubGhzSceneStart)) {
+                        DOLPHIN_DEED(DolphinDeedSubGhzSend);
                     }
+                    // set callback end tx
+                    subghz_txrx_set_raw_file_encoder_worker_callback_end(
+                        subghz->txrx, subghz_scene_read_raw_callback_end_tx, subghz);
+                    subghz->state_notifications = SubGhzNotificationStateTx;
                 }
             } else {
                 if(!scene_manager_search_and_switch_to_previous_scene(
@@ -263,33 +223,22 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
 
         case SubGhzCustomEventViewReadRAWSendStop:
             subghz->state_notifications = SubGhzNotificationStateIDLE;
-            if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
-                subghz_speaker_unmute(subghz);
-                subghz_tx_stop(subghz);
-                subghz_sleep(subghz);
-            }
+            subghz_txrx_stop(subghz->txrx);
             subghz_read_raw_stop_send(subghz->subghz_read_raw);
             consumed = true;
             break;
 
         case SubGhzCustomEventViewReadRAWIDLE:
-            if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
-                subghz_rx_end(subghz);
-                subghz_sleep(subghz);
-            };
-
-            size_t spl_count = subghz_protocol_raw_get_sample_write(
-                (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result);
+            subghz_txrx_stop(subghz->txrx);
+            size_t spl_count = subghz_protocol_raw_get_sample_write(decoder_raw);
 
-            subghz_protocol_raw_save_to_file_stop(
-                (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result);
+            subghz_protocol_raw_save_to_file_stop(decoder_raw);
 
-            FuriString* temp_str;
-            temp_str = furi_string_alloc();
+            FuriString* temp_str = furi_string_alloc();
             furi_string_printf(
                 temp_str, "%s/%s%s", SUBGHZ_RAW_FOLDER, RAW_FILE_NAME, SUBGHZ_APP_EXTENSION);
             subghz_protocol_raw_gen_fff_data(
-                subghz->txrx->fff_data, furi_string_get_cstr(temp_str));
+                subghz_txrx_get_fff_data(subghz->txrx), furi_string_get_cstr(temp_str));
             furi_string_free(temp_str);
 
             if(spl_count > 0) {
@@ -299,32 +248,21 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
             }
 
             subghz->state_notifications = SubGhzNotificationStateIDLE;
-            subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
+            subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey);
 
             consumed = true;
             break;
 
         case SubGhzCustomEventViewReadRAWREC:
-            if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) {
+            if(subghz_rx_key_state_get(subghz) != SubGhzRxKeyStateIDLE) {
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
             } else {
-                subghz->txrx->raw_threshold_rssi_low_count = RAW_THRESHOLD_RSSI_LOW_COUNT;
-                if(subghz_protocol_raw_save_to_file_init(
-                       (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result,
-                       RAW_FILE_NAME,
-                       subghz->txrx->preset)) {
+                SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
+                if(subghz_protocol_raw_save_to_file_init(decoder_raw, RAW_FILE_NAME, &preset)) {
                     DOLPHIN_DEED(DolphinDeedSubGhzRawRec);
-                    if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
-                       (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
-                        subghz_begin(
-                            subghz,
-                            subghz_setting_get_preset_data_by_name(
-                                subghz->setting,
-                                furi_string_get_cstr(subghz->txrx->preset->name)));
-                        subghz_rx(subghz, subghz->txrx->preset->frequency);
-                    }
+                    subghz_txrx_rx_start(subghz->txrx);
                     subghz->state_notifications = SubGhzNotificationStateRx;
-                    subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
+                    subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey);
                 } else {
                     furi_string_set(subghz->error_str, "Function requires\nan SD card.");
                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
@@ -337,7 +275,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
             if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) {
                 scene_manager_set_scene_state(
                     subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSetRAW);
-                subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
+                subghz_rx_key_state_set(subghz, SubGhzRxKeyStateBack);
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
             } else {
                 if(!scene_manager_search_and_switch_to_previous_scene(
@@ -356,41 +294,15 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
         switch(subghz->state_notifications) {
         case SubGhzNotificationStateRx:
             notification_message(subghz->notifications, &sequence_blink_cyan_10);
-            subghz_read_raw_update_sample_write(
-                subghz->subghz_read_raw,
-                subghz_protocol_raw_get_sample_write(
-                    (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result));
-
-            float rssi = furi_hal_subghz_get_rssi();
 
-            if(float_is_equal(subghz->txrx->raw_threshold_rssi, SUBGHZ_RAW_TRESHOLD_MIN)) {
-                subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true);
-                subghz_protocol_raw_save_to_file_pause(
-                    (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false);
-            } else {
-                if(rssi < subghz->txrx->raw_threshold_rssi) {
-                    subghz->txrx->raw_threshold_rssi_low_count++;
-                    if(subghz->txrx->raw_threshold_rssi_low_count > RAW_THRESHOLD_RSSI_LOW_COUNT) {
-                        subghz->txrx->raw_threshold_rssi_low_count = RAW_THRESHOLD_RSSI_LOW_COUNT;
-                    }
-                    subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false);
-                } else {
-                    subghz->txrx->raw_threshold_rssi_low_count = 0;
-                }
-
-                if(subghz->txrx->raw_threshold_rssi_low_count == RAW_THRESHOLD_RSSI_LOW_COUNT) {
-                    subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, false);
-                    subghz_protocol_raw_save_to_file_pause(
-                        (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, true);
-                    subghz_speaker_mute(subghz);
-                } else {
-                    subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true);
-                    subghz_protocol_raw_save_to_file_pause(
-                        (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false);
-                    subghz_speaker_unmute(subghz);
-                }
-            }
+            subghz_read_raw_update_sample_write(
+                subghz->subghz_read_raw, subghz_protocol_raw_get_sample_write(decoder_raw));
 
+            SubGhzThresholdRssiData ret_rssi =
+                subghz_threshold_get_rssi_data(subghz->threshold_rssi);
+            subghz_read_raw_add_data_rssi(
+                subghz->subghz_read_raw, ret_rssi.rssi, ret_rssi.is_above);
+            subghz_protocol_raw_save_to_file_pause(decoder_raw, !ret_rssi.is_above);
             break;
         case SubGhzNotificationStateTx:
             notification_message(subghz->notifications, &sequence_blink_magenta_10);
@@ -407,13 +319,10 @@ void subghz_scene_read_raw_on_exit(void* context) {
     SubGhz* subghz = context;
 
     //Stop CC1101
-    if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
-        subghz_rx_end(subghz);
-        subghz_sleep(subghz);
-    };
+    subghz_txrx_stop(subghz->txrx);
     subghz->state_notifications = SubGhzNotificationStateIDLE;
     notification_message(subghz->notifications, &sequence_reset_rgb);
 
     //filter restoration
-    subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter);
+    subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter);
 }

+ 48 - 74
applications/main/subghz/scenes/subghz_scene_receiver.c

@@ -35,16 +35,12 @@ static const NotificationSequence subghs_sequence_rx_locked = {
 
 static void subghz_scene_receiver_update_statusbar(void* context) {
     SubGhz* subghz = context;
-    FuriString* history_stat_str;
-    history_stat_str = furi_string_alloc();
-    if(!subghz_history_get_text_space_left(subghz->txrx->history, history_stat_str)) {
-        FuriString* frequency_str;
-        FuriString* modulation_str;
+    FuriString* history_stat_str = furi_string_alloc();
+    if(!subghz_history_get_text_space_left(subghz->history, history_stat_str)) {
+        FuriString* frequency_str = furi_string_alloc();
+        FuriString* modulation_str = furi_string_alloc();
 
-        frequency_str = furi_string_alloc();
-        modulation_str = furi_string_alloc();
-
-        subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
+        subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str);
 
         subghz_view_receiver_add_data_statusbar(
             subghz->subghz_receiver,
@@ -74,80 +70,68 @@ static void subghz_scene_add_to_history_callback(
     void* context) {
     furi_assert(context);
     SubGhz* subghz = context;
-    FuriString* str_buff;
-    str_buff = furi_string_alloc();
+    SubGhzHistory* history = subghz->history;
+    FuriString* str_buff = furi_string_alloc();
+
+    SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
 
-    if(subghz_history_add_to_history(subghz->txrx->history, decoder_base, subghz->txrx->preset)) {
+    if(subghz_history_add_to_history(history, decoder_base, &preset)) {
         furi_string_reset(str_buff);
 
         subghz->state_notifications = SubGhzNotificationStateRxDone;
-
-        subghz_history_get_text_item_menu(
-            subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1);
+        uint16_t item_history = subghz_history_get_item(history);
+        subghz_history_get_text_item_menu(history, str_buff, item_history - 1);
         subghz_view_receiver_add_item_to_menu(
             subghz->subghz_receiver,
             furi_string_get_cstr(str_buff),
-            subghz_history_get_type_protocol(
-                subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1));
+            subghz_history_get_type_protocol(history, item_history - 1));
 
         subghz_scene_receiver_update_statusbar(subghz);
     }
     subghz_receiver_reset(receiver);
     furi_string_free(str_buff);
-    subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
+    subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey);
 }
 
 void subghz_scene_receiver_on_enter(void* context) {
     SubGhz* subghz = context;
+    SubGhzHistory* history = subghz->history;
 
     FuriString* str_buff;
     str_buff = furi_string_alloc();
 
-    if(subghz->txrx->rx_key_state == SubGhzRxKeyStateIDLE) {
-        subghz_preset_init(
-            subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
-        subghz_history_reset(subghz->txrx->history);
-        subghz->txrx->rx_key_state = SubGhzRxKeyStateStart;
+    if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateIDLE) {
+        subghz_set_default_preset(subghz);
+        subghz_history_reset(history);
+        subghz_rx_key_state_set(subghz, SubGhzRxKeyStateStart);
     }
 
-    subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz->lock);
+    subghz_view_receiver_set_lock(subghz->subghz_receiver, subghz_is_locked(subghz));
 
     //Load history to receiver
     subghz_view_receiver_exit(subghz->subghz_receiver);
-    for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) {
+    for(uint8_t i = 0; i < subghz_history_get_item(history); i++) {
         furi_string_reset(str_buff);
-        subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i);
+        subghz_history_get_text_item_menu(history, str_buff, i);
         subghz_view_receiver_add_item_to_menu(
             subghz->subghz_receiver,
             furi_string_get_cstr(str_buff),
-            subghz_history_get_type_protocol(subghz->txrx->history, i));
-        subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
+            subghz_history_get_type_protocol(history, i));
+        subghz_rx_key_state_set(subghz, SubGhzRxKeyStateAddKey);
     }
     furi_string_free(str_buff);
     subghz_scene_receiver_update_statusbar(subghz);
     subghz_view_receiver_set_callback(
         subghz->subghz_receiver, subghz_scene_receiver_callback, subghz);
-    subghz_receiver_set_rx_callback(
-        subghz->txrx->receiver, subghz_scene_add_to_history_callback, subghz);
+    subghz_txrx_set_rx_calback(subghz->txrx, subghz_scene_add_to_history_callback, subghz);
 
     subghz->state_notifications = SubGhzNotificationStateRx;
-    if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
-        subghz_rx_end(subghz);
-    };
-    if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
-       (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
-        subghz_begin(
-            subghz,
-            subghz_setting_get_preset_data_by_name(
-                subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name)));
-        subghz_rx(subghz, subghz->txrx->preset->frequency);
-    }
-    subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen);
+    subghz_txrx_rx_start(subghz->txrx);
+    subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->idx_menu_chosen);
 
     //to use a universal decoder, we are looking for a link to it
-    subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
-        subghz->txrx->receiver, SUBGHZ_PROTOCOL_BIN_RAW_NAME);
-    furi_assert(subghz->txrx->decoder_result);
+    furi_check(
+        subghz_txrx_load_decoder_by_name_protocol(subghz->txrx, SUBGHZ_PROTOCOL_BIN_RAW_NAME));
 
     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver);
 }
@@ -160,41 +144,31 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
         case SubGhzCustomEventViewReceiverBack:
             // Stop CC1101 Rx
             subghz->state_notifications = SubGhzNotificationStateIDLE;
-            if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
-                subghz_rx_end(subghz);
-                subghz_sleep(subghz);
-            };
-            subghz->txrx->hopper_state = SubGhzHopperStateOFF;
-            subghz->txrx->idx_menu_chosen = 0;
-            subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz);
-
-            if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) {
-                subghz->txrx->rx_key_state = SubGhzRxKeyStateExit;
+            subghz_txrx_stop(subghz->txrx);
+            subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF);
+            subghz->idx_menu_chosen = 0;
+            subghz_txrx_set_rx_calback(subghz->txrx, NULL, subghz);
+
+            if(subghz_rx_key_state_get(subghz) == SubGhzRxKeyStateAddKey) {
+                subghz_rx_key_state_set(subghz, SubGhzRxKeyStateExit);
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
             } else {
-                subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
-                subghz_preset_init(
-                    subghz,
-                    "AM650",
-                    subghz_setting_get_default_frequency(subghz->setting),
-                    NULL,
-                    0);
+                subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
+                subghz_set_default_preset(subghz);
                 scene_manager_search_and_switch_to_previous_scene(
                     subghz->scene_manager, SubGhzSceneStart);
             }
             consumed = true;
             break;
         case SubGhzCustomEventViewReceiverOK:
-            subghz->txrx->idx_menu_chosen =
-                subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
+            subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo);
             DOLPHIN_DEED(DolphinDeedSubGhzReceiverInfo);
             consumed = true;
             break;
         case SubGhzCustomEventViewReceiverConfig:
             subghz->state_notifications = SubGhzNotificationStateIDLE;
-            subghz->txrx->idx_menu_chosen =
-                subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
+            subghz->idx_menu_chosen = subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig);
             consumed = true;
             break;
@@ -203,30 +177,30 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
             consumed = true;
             break;
         case SubGhzCustomEventViewReceiverUnlock:
-            subghz->lock = SubGhzLockOff;
+            subghz_unlock(subghz);
             consumed = true;
             break;
         default:
             break;
         }
     } else if(event.type == SceneManagerEventTypeTick) {
-        if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
-            subghz_hopper_update(subghz);
+        if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) {
+            subghz_txrx_hopper_update(subghz->txrx);
             subghz_scene_receiver_update_statusbar(subghz);
         }
 
-        //get RSSI
-        float rssi = furi_hal_subghz_get_rssi();
-        subghz_receiver_rssi(subghz->subghz_receiver, rssi);
+        SubGhzThresholdRssiData ret_rssi = subghz_threshold_get_rssi_data(subghz->threshold_rssi);
+
+        subghz_receiver_rssi(subghz->subghz_receiver, ret_rssi.rssi);
         subghz_protocol_decoder_bin_raw_data_input_rssi(
-            (SubGhzProtocolDecoderBinRAW*)subghz->txrx->decoder_result, rssi);
+            (SubGhzProtocolDecoderBinRAW*)subghz_txrx_get_decoder(subghz->txrx), ret_rssi.rssi);
 
         switch(subghz->state_notifications) {
         case SubGhzNotificationStateRx:
             notification_message(subghz->notifications, &sequence_blink_cyan_10);
             break;
         case SubGhzNotificationStateRxDone:
-            if(subghz->lock != SubGhzLockOn) {
+            if(!subghz_is_locked(subghz)) {
                 notification_message(subghz->notifications, &subghs_sequence_rx);
             } else {
                 notification_message(subghz->notifications, &subghs_sequence_rx_locked);

+ 78 - 55
applications/main/subghz/scenes/subghz_scene_receiver_config.c

@@ -72,13 +72,15 @@ const uint32_t bin_raw_value[BIN_RAW_COUNT] = {
 uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void* context) {
     furi_assert(context);
     SubGhz* subghz = context;
+    SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
+
     uint8_t index = 0;
-    for(uint8_t i = 0; i < subghz_setting_get_frequency_count(subghz->setting); i++) {
-        if(value == subghz_setting_get_frequency(subghz->setting, i)) {
+    for(uint8_t i = 0; i < subghz_setting_get_frequency_count(setting); i++) {
+        if(value == subghz_setting_get_frequency(setting, i)) {
             index = i;
             break;
         } else {
-            index = subghz_setting_get_frequency_default_index(subghz->setting);
+            index = subghz_setting_get_frequency_default_index(setting);
         }
     }
     return index;
@@ -87,13 +89,15 @@ uint8_t subghz_scene_receiver_config_next_frequency(const uint32_t value, void*
 uint8_t subghz_scene_receiver_config_next_preset(const char* preset_name, void* context) {
     furi_assert(context);
     SubGhz* subghz = context;
+    SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
+
     uint8_t index = 0;
-    for(uint8_t i = 0; i < subghz_setting_get_preset_count(subghz->setting); i++) {
-        if(!strcmp(subghz_setting_get_preset_name(subghz->setting, i), preset_name)) {
+    for(uint8_t i = 0; i < subghz_setting_get_preset_count(setting); i++) {
+        if(!strcmp(subghz_setting_get_preset_name(setting, i), preset_name)) {
             index = i;
             break;
         } else {
-            //  index = subghz_setting_get_frequency_default_index(subghz->setting);
+            //  index = subghz_setting_get_frequency_default_index(subghz_txrx_get_setting(subghz->txrx));
         }
     }
     return index;
@@ -122,70 +126,84 @@ uint8_t subghz_scene_receiver_config_hopper_value_index(
 static void subghz_scene_receiver_config_set_frequency(VariableItem* item) {
     SubGhz* subghz = variable_item_get_context(item);
     uint8_t index = variable_item_get_current_value_index(item);
+    SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
 
-    if(subghz->txrx->hopper_state == SubGhzHopperStateOFF) {
+    if(subghz_txrx_hopper_get_state(subghz->txrx) == SubGhzHopperStateOFF) {
         char text_buf[10] = {0};
+        uint32_t frequency = subghz_setting_get_frequency(setting, index);
+        SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
+
         snprintf(
             text_buf,
             sizeof(text_buf),
             "%lu.%02lu",
-            subghz_setting_get_frequency(subghz->setting, index) / 1000000,
-            (subghz_setting_get_frequency(subghz->setting, index) % 1000000) / 10000);
+            frequency / 1000000,
+            (frequency % 1000000) / 10000);
         variable_item_set_current_value_text(item, text_buf);
-        subghz->txrx->preset->frequency = subghz_setting_get_frequency(subghz->setting, index);
+        subghz_txrx_set_preset(
+            subghz->txrx,
+            furi_string_get_cstr(preset.name),
+            frequency,
+            preset.data,
+            preset.data_size);
     } else {
         variable_item_set_current_value_index(
-            item, subghz_setting_get_frequency_default_index(subghz->setting));
+            item, subghz_setting_get_frequency_default_index(setting));
     }
 }
 
 static void subghz_scene_receiver_config_set_preset(VariableItem* item) {
     SubGhz* subghz = variable_item_get_context(item);
     uint8_t index = variable_item_get_current_value_index(item);
-    variable_item_set_current_value_text(
-        item, subghz_setting_get_preset_name(subghz->setting, index));
-    subghz_preset_init(
-        subghz,
-        subghz_setting_get_preset_name(subghz->setting, index),
-        subghz->txrx->preset->frequency,
-        subghz_setting_get_preset_data(subghz->setting, index),
-        subghz_setting_get_preset_data_size(subghz->setting, index));
+    SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
+
+    variable_item_set_current_value_text(item, subghz_setting_get_preset_name(setting, index));
+
+    SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
+    subghz_txrx_set_preset(
+        subghz->txrx,
+        subghz_setting_get_preset_name(setting, index),
+        preset.frequency,
+        subghz_setting_get_preset_data(setting, index),
+        subghz_setting_get_preset_data_size(setting, index));
 }
 
 static void subghz_scene_receiver_config_set_hopping_running(VariableItem* item) {
     SubGhz* subghz = variable_item_get_context(item);
     uint8_t index = variable_item_get_current_value_index(item);
+    SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
+    VariableItem* frequency_item = (VariableItem*)scene_manager_get_scene_state(
+        subghz->scene_manager, SubGhzSceneReceiverConfig);
 
     variable_item_set_current_value_text(item, hopping_text[index]);
     if(hopping_value[index] == SubGhzHopperStateOFF) {
         char text_buf[10] = {0};
+        uint32_t frequency = subghz_setting_get_default_frequency(setting);
+        SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
+
         snprintf(
             text_buf,
             sizeof(text_buf),
             "%lu.%02lu",
-            subghz_setting_get_default_frequency(subghz->setting) / 1000000,
-            (subghz_setting_get_default_frequency(subghz->setting) % 1000000) / 10000);
-        variable_item_set_current_value_text(
-            (VariableItem*)scene_manager_get_scene_state(
-                subghz->scene_manager, SubGhzSceneReceiverConfig),
-            text_buf);
-        subghz->txrx->preset->frequency = subghz_setting_get_default_frequency(subghz->setting);
+            frequency / 1000000,
+            (frequency % 1000000) / 10000);
+        variable_item_set_current_value_text(frequency_item, text_buf);
+
+        subghz_txrx_set_preset(
+            subghz->txrx,
+            furi_string_get_cstr(preset.name),
+            frequency,
+            preset.data,
+            preset.data_size);
         variable_item_set_current_value_index(
-            (VariableItem*)scene_manager_get_scene_state(
-                subghz->scene_manager, SubGhzSceneReceiverConfig),
-            subghz_setting_get_frequency_default_index(subghz->setting));
+            frequency_item, subghz_setting_get_frequency_default_index(setting));
     } else {
-        variable_item_set_current_value_text(
-            (VariableItem*)scene_manager_get_scene_state(
-                subghz->scene_manager, SubGhzSceneReceiverConfig),
-            " -----");
+        variable_item_set_current_value_text(frequency_item, " -----");
         variable_item_set_current_value_index(
-            (VariableItem*)scene_manager_get_scene_state(
-                subghz->scene_manager, SubGhzSceneReceiverConfig),
-            subghz_setting_get_frequency_default_index(subghz->setting));
+            frequency_item, subghz_setting_get_frequency_default_index(setting));
     }
 
-    subghz->txrx->hopper_state = hopping_value[index];
+    subghz_txrx_hopper_set_state(subghz->txrx, hopping_value[index]);
 }
 
 static void subghz_scene_receiver_config_set_speaker(VariableItem* item) {
@@ -193,7 +211,7 @@ static void subghz_scene_receiver_config_set_speaker(VariableItem* item) {
     uint8_t index = variable_item_get_current_value_index(item);
 
     variable_item_set_current_value_text(item, speaker_text[index]);
-    subghz->txrx->speaker_state = speaker_value[index];
+    subghz_txrx_speaker_set_state(subghz->txrx, speaker_value[index]);
 }
 
 static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) {
@@ -201,8 +219,8 @@ static void subghz_scene_receiver_config_set_bin_raw(VariableItem* item) {
     uint8_t index = variable_item_get_current_value_index(item);
 
     variable_item_set_current_value_text(item, bin_raw_text[index]);
-    subghz->txrx->filter = bin_raw_value[index];
-    subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter);
+    subghz->filter = bin_raw_value[index];
+    subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter);
 }
 
 static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* item) {
@@ -210,7 +228,7 @@ static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* it
     uint8_t index = variable_item_get_current_value_index(item);
 
     variable_item_set_current_value_text(item, raw_theshold_rssi_text[index]);
-    subghz->txrx->raw_threshold_rssi = raw_theshold_rssi_value[index];
+    subghz_threshold_rssi_set(subghz->threshold_rssi, raw_theshold_rssi_value[index]);
 }
 
 static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) {
@@ -226,25 +244,27 @@ void subghz_scene_receiver_config_on_enter(void* context) {
     SubGhz* subghz = context;
     VariableItem* item;
     uint8_t value_index;
+    SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
+    SubGhzRadioPreset preset = subghz_txrx_get_preset(subghz->txrx);
 
     item = variable_item_list_add(
         subghz->variable_item_list,
         "Frequency:",
-        subghz_setting_get_frequency_count(subghz->setting),
+        subghz_setting_get_frequency_count(setting),
         subghz_scene_receiver_config_set_frequency,
         subghz);
-    value_index =
-        subghz_scene_receiver_config_next_frequency(subghz->txrx->preset->frequency, subghz);
+    value_index = subghz_scene_receiver_config_next_frequency(preset.frequency, subghz);
     scene_manager_set_scene_state(
         subghz->scene_manager, SubGhzSceneReceiverConfig, (uint32_t)item);
     variable_item_set_current_value_index(item, value_index);
     char text_buf[10] = {0};
+    uint32_t frequency = subghz_setting_get_frequency(setting, value_index);
     snprintf(
         text_buf,
         sizeof(text_buf),
         "%lu.%02lu",
-        subghz_setting_get_frequency(subghz->setting, value_index) / 1000000,
-        (subghz_setting_get_frequency(subghz->setting, value_index) % 1000000) / 10000);
+        frequency / 1000000,
+        (frequency % 1000000) / 10000);
     variable_item_set_current_value_text(item, text_buf);
 
     if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
@@ -256,7 +276,7 @@ void subghz_scene_receiver_config_on_enter(void* context) {
             subghz_scene_receiver_config_set_hopping_running,
             subghz);
         value_index = subghz_scene_receiver_config_hopper_value_index(
-            subghz->txrx->hopper_state, hopping_value, HOPPING_COUNT, subghz);
+            subghz_txrx_hopper_get_state(subghz->txrx), hopping_value, HOPPING_COUNT, subghz);
         variable_item_set_current_value_index(item, value_index);
         variable_item_set_current_value_text(item, hopping_text[value_index]);
     }
@@ -264,14 +284,14 @@ void subghz_scene_receiver_config_on_enter(void* context) {
     item = variable_item_list_add(
         subghz->variable_item_list,
         "Modulation:",
-        subghz_setting_get_preset_count(subghz->setting),
+        subghz_setting_get_preset_count(setting),
         subghz_scene_receiver_config_set_preset,
         subghz);
-    value_index = subghz_scene_receiver_config_next_preset(
-        furi_string_get_cstr(subghz->txrx->preset->name), subghz);
+    value_index =
+        subghz_scene_receiver_config_next_preset(furi_string_get_cstr(preset.name), subghz);
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_text(
-        item, subghz_setting_get_preset_name(subghz->setting, value_index));
+        item, subghz_setting_get_preset_name(setting, value_index));
 
     if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
        SubGhzCustomEventManagerSet) {
@@ -281,7 +301,7 @@ void subghz_scene_receiver_config_on_enter(void* context) {
             BIN_RAW_COUNT,
             subghz_scene_receiver_config_set_bin_raw,
             subghz);
-        value_index = value_index_uint32(subghz->txrx->filter, bin_raw_value, BIN_RAW_COUNT);
+        value_index = value_index_uint32(subghz->filter, bin_raw_value, BIN_RAW_COUNT);
         variable_item_set_current_value_index(item, value_index);
         variable_item_set_current_value_text(item, bin_raw_text[value_index]);
     }
@@ -292,7 +312,8 @@ void subghz_scene_receiver_config_on_enter(void* context) {
         SPEAKER_COUNT,
         subghz_scene_receiver_config_set_speaker,
         subghz);
-    value_index = value_index_uint32(subghz->txrx->speaker_state, speaker_value, SPEAKER_COUNT);
+    value_index = value_index_uint32(
+        subghz_txrx_speaker_get_state(subghz->txrx), speaker_value, SPEAKER_COUNT);
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_text(item, speaker_text[value_index]);
 
@@ -313,7 +334,9 @@ void subghz_scene_receiver_config_on_enter(void* context) {
             subghz_scene_receiver_config_set_raw_threshold_rssi,
             subghz);
         value_index = value_index_float(
-            subghz->txrx->raw_threshold_rssi, raw_theshold_rssi_value, RAW_THRESHOLD_RSSI_COUNT);
+            subghz_threshold_rssi_get(subghz->threshold_rssi),
+            raw_theshold_rssi_value,
+            RAW_THRESHOLD_RSSI_COUNT);
         variable_item_set_current_value_index(item, value_index);
         variable_item_set_current_value_text(item, raw_theshold_rssi_text[value_index]);
     }
@@ -326,7 +349,7 @@ bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent even
 
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == SubGhzCustomEventSceneSettingLock) {
-            subghz->lock = SubGhzLockOn;
+            subghz_lock(subghz);
             scene_manager_previous_scene(subghz->scene_manager);
             consumed = true;
         }

+ 35 - 77
applications/main/subghz/scenes/subghz_scene_receiver_info.c

@@ -19,20 +19,19 @@ void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, v
 
 static bool subghz_scene_receiver_info_update_parser(void* context) {
     SubGhz* subghz = context;
-    subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
-        subghz->txrx->receiver,
-        subghz_history_get_protocol_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
 
-    if(subghz->txrx->decoder_result) {
+    if(subghz_txrx_load_decoder_by_name_protocol(
+           subghz->txrx,
+           subghz_history_get_protocol_name(subghz->history, subghz->idx_menu_chosen))) {
         //todo we are trying to deserialize without checking for errors, since it is assumed that we just received this chignal
         subghz_protocol_decoder_base_deserialize(
-            subghz->txrx->decoder_result,
-            subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
+            subghz_txrx_get_decoder(subghz->txrx),
+            subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen));
 
         SubGhzRadioPreset* preset =
-            subghz_history_get_radio_preset(subghz->txrx->history, subghz->txrx->idx_menu_chosen);
-        subghz_preset_init(
-            subghz,
+            subghz_history_get_radio_preset(subghz->history, subghz->idx_menu_chosen);
+        subghz_txrx_set_preset(
+            subghz->txrx,
             furi_string_get_cstr(preset->name),
             preset->frequency,
             preset->data,
@@ -47,15 +46,11 @@ void subghz_scene_receiver_info_on_enter(void* context) {
     SubGhz* subghz = context;
 
     if(subghz_scene_receiver_info_update_parser(subghz)) {
-        FuriString* frequency_str;
-        FuriString* modulation_str;
-        FuriString* text;
+        FuriString* frequency_str = furi_string_alloc();
+        FuriString* modulation_str = furi_string_alloc();
+        FuriString* text = furi_string_alloc();
 
-        frequency_str = furi_string_alloc();
-        modulation_str = furi_string_alloc();
-        text = furi_string_alloc();
-
-        subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
+        subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str);
         widget_add_string_element(
             subghz->widget,
             78,
@@ -73,7 +68,7 @@ void subghz_scene_receiver_info_on_enter(void* context) {
             AlignTop,
             FontSecondary,
             furi_string_get_cstr(modulation_str));
-        subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text);
+        subghz_protocol_decoder_base_get_string(subghz_txrx_get_decoder(subghz->txrx), text);
         widget_add_string_multiline_element(
             subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(text));
 
@@ -81,8 +76,7 @@ void subghz_scene_receiver_info_on_enter(void* context) {
         furi_string_free(modulation_str);
         furi_string_free(text);
 
-        if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) ==
-           SubGhzProtocolFlag_Save) {
+        if(subghz_txrx_protocol_is_serializable(subghz->txrx)) {
             widget_add_button_element(
                 subghz->widget,
                 GuiButtonTypeRight,
@@ -90,10 +84,7 @@ void subghz_scene_receiver_info_on_enter(void* context) {
                 subghz_scene_receiver_info_callback,
                 subghz);
         }
-        if(((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) ==
-            SubGhzProtocolFlag_Send) &&
-           subghz->txrx->decoder_result->protocol->encoder->deserialize &&
-           subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeStatic) {
+        if(subghz_txrx_protocol_is_transmittable(subghz->txrx, true)) {
             widget_add_button_element(
                 subghz->widget,
                 GuiButtonTypeCenter,
@@ -114,82 +105,49 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
     SubGhz* subghz = context;
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == SubGhzCustomEventSceneReceiverInfoTxStart) {
-            //CC1101 Stop RX -> Start TX
-            if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
-                subghz->txrx->hopper_state = SubGhzHopperStatePause;
-            }
-            if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
-                subghz_rx_end(subghz);
-            }
             if(!subghz_scene_receiver_info_update_parser(subghz)) {
                 return false;
             }
-            if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE ||
-               subghz->txrx->txrx_state == SubGhzTxRxStateSleep) {
-                if(!subghz_tx_start(
-                       subghz,
-                       subghz_history_get_raw_data(
-                           subghz->txrx->history, subghz->txrx->idx_menu_chosen))) {
-                    if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
-                        subghz_tx_stop(subghz);
-                    }
-                    if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
-                        subghz_begin(
-                            subghz,
-                            subghz_setting_get_preset_data_by_name(
-                                subghz->setting,
-                                furi_string_get_cstr(subghz->txrx->preset->name)));
-                        subghz_rx(subghz, subghz->txrx->preset->frequency);
-                    }
-                    if(subghz->txrx->hopper_state == SubGhzHopperStatePause) {
-                        subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
-                    }
-                    subghz->state_notifications = SubGhzNotificationStateRx;
-                } else {
-                    subghz->state_notifications = SubGhzNotificationStateTx;
-                }
+            //CC1101 Stop RX -> Start TX
+            subghz_txrx_hopper_pause(subghz->txrx);
+            if(!subghz_tx_start(
+                   subghz,
+                   subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen))) {
+                subghz_txrx_rx_start(subghz->txrx);
+                subghz_txrx_hopper_unpause(subghz->txrx);
+                subghz->state_notifications = SubGhzNotificationStateRx;
+            } else {
+                subghz->state_notifications = SubGhzNotificationStateTx;
             }
             return true;
         } else if(event.event == SubGhzCustomEventSceneReceiverInfoTxStop) {
             //CC1101 Stop Tx -> Start RX
             subghz->state_notifications = SubGhzNotificationStateIDLE;
-            if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
-                subghz_tx_stop(subghz);
-            }
-            if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
-                subghz_begin(
-                    subghz,
-                    subghz_setting_get_preset_data_by_name(
-                        subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name)));
-                subghz_rx(subghz, subghz->txrx->preset->frequency);
-            }
-            if(subghz->txrx->hopper_state == SubGhzHopperStatePause) {
-                subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
-            }
+
+            subghz_txrx_rx_start(subghz->txrx);
+
+            subghz_txrx_hopper_unpause(subghz->txrx);
             subghz->state_notifications = SubGhzNotificationStateRx;
             return true;
         } else if(event.event == SubGhzCustomEventSceneReceiverInfoSave) {
             //CC1101 Stop RX -> Save
             subghz->state_notifications = SubGhzNotificationStateIDLE;
-            subghz->txrx->hopper_state = SubGhzHopperStateOFF;
-            if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
-                subghz_rx_end(subghz);
-                subghz_sleep(subghz);
-            }
+            subghz_txrx_hopper_set_state(subghz->txrx, SubGhzHopperStateOFF);
+
+            subghz_txrx_stop(subghz->txrx);
             if(!subghz_scene_receiver_info_update_parser(subghz)) {
                 return false;
             }
 
-            if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) ==
-               SubGhzProtocolFlag_Save) {
+            if(subghz_txrx_protocol_is_serializable(subghz->txrx)) {
                 subghz_file_name_clear(subghz);
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
             }
             return true;
         }
     } else if(event.type == SceneManagerEventTypeTick) {
-        if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
-            subghz_hopper_update(subghz);
+        if(subghz_txrx_hopper_get_state(subghz->txrx) != SubGhzHopperStateOFF) {
+            subghz_txrx_hopper_update(subghz->txrx);
         }
         switch(subghz->state_notifications) {
         case SubGhzNotificationStateTx:

+ 1 - 2
applications/main/subghz/scenes/subghz_scene_region_info.c

@@ -5,8 +5,7 @@
 void subghz_scene_region_info_on_enter(void* context) {
     SubGhz* subghz = context;
     const FuriHalRegion* const region = furi_hal_region_get();
-    FuriString* buffer;
-    buffer = furi_string_alloc();
+    FuriString* buffer = furi_string_alloc();
     if(region) {
         furi_string_cat_printf(buffer, "Region: %s,  bands:\n", region->country_code);
         for(uint16_t i = 0; i < region->bands_count; ++i) {

+ 10 - 10
applications/main/subghz/scenes/subghz_scene_rpc.c

@@ -3,6 +3,7 @@
 typedef enum {
     SubGhzRpcStateIdle,
     SubGhzRpcStateLoaded,
+    SubGhzRpcStateTx,
 } SubGhzRpcState;
 
 void subghz_scene_rpc_on_enter(void* context) {
@@ -38,9 +39,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
             view_dispatcher_stop(subghz->view_dispatcher);
         } else if(event.event == SubGhzCustomEventSceneRpcButtonPress) {
             bool result = false;
-            if((subghz->txrx->txrx_state == SubGhzTxRxStateSleep) &&
-               (state == SubGhzRpcStateLoaded)) {
-                result = subghz_tx_start(subghz, subghz->txrx->fff_data);
+            if((state == SubGhzRpcStateLoaded)) {
+                result = subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx));
+                state = SubGhzRpcStateTx;
                 if(result) subghz_blink_start(subghz);
             }
             if(!result) {
@@ -52,10 +53,10 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
             rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonPress, result);
         } else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) {
             bool result = false;
-            if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
+            if(state == SubGhzRpcStateTx) {
+                subghz_txrx_stop(subghz->txrx);
                 subghz_blink_stop(subghz);
-                subghz_tx_stop(subghz);
-                subghz_sleep(subghz);
+                state = SubGhzRpcStateIdle;
                 result = true;
             }
             rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonRelease, result);
@@ -93,10 +94,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
 
 void subghz_scene_rpc_on_exit(void* context) {
     SubGhz* subghz = context;
-
-    if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
-        subghz_tx_stop(subghz);
-        subghz_sleep(subghz);
+    SubGhzRpcState state = scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneRpc);
+    if(state != SubGhzRpcStateIdle) {
+        subghz_txrx_stop(subghz->txrx);
         subghz_blink_stop(subghz);
     }
 

+ 7 - 9
applications/main/subghz/scenes/subghz_scene_save_name.c

@@ -35,10 +35,8 @@ void subghz_scene_save_name_on_enter(void* context) {
     TextInput* text_input = subghz->text_input;
     bool dev_name_empty = false;
 
-    FuriString* file_name;
-    FuriString* dir_name;
-    file_name = furi_string_alloc();
-    dir_name = furi_string_alloc();
+    FuriString* file_name = furi_string_alloc();
+    FuriString* dir_name = furi_string_alloc();
 
     if(!subghz_path_is_file(subghz->file_path)) {
         char file_name_buf[SUBGHZ_MAX_LEN_NAME] = {0};
@@ -69,7 +67,7 @@ void subghz_scene_save_name_on_enter(void* context) {
         subghz_scene_save_name_text_input_callback,
         subghz,
         subghz->file_name_tmp,
-        MAX_TEXT_INPUT_LEN, // buffer size
+        MAX_TEXT_INPUT_LEN,
         dev_name_empty);
 
     ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
@@ -106,7 +104,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
                        SubGhzCustomEventManagerNoSet) {
                         subghz_save_protocol_to_file(
                             subghz,
-                            subghz->txrx->fff_data,
+                            subghz_txrx_get_fff_data(subghz->txrx),
                             furi_string_get_cstr(subghz->file_path));
                         scene_manager_set_scene_state(
                             subghz->scene_manager,
@@ -115,8 +113,7 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
                     } else {
                         subghz_save_protocol_to_file(
                             subghz,
-                            subghz_history_get_raw_data(
-                                subghz->txrx->history, subghz->txrx->idx_menu_chosen),
+                            subghz_history_get_raw_data(subghz->history, subghz->idx_menu_chosen),
                             furi_string_get_cstr(subghz->file_path));
                     }
                 }
@@ -124,7 +121,8 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
                 if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
                    SubGhzCustomEventManagerNoSet) {
                     subghz_protocol_raw_gen_fff_data(
-                        subghz->txrx->fff_data, furi_string_get_cstr(subghz->file_path));
+                        subghz_txrx_get_fff_data(subghz->txrx),
+                        furi_string_get_cstr(subghz->file_path));
                     scene_manager_set_scene_state(
                         subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
                 } else {

+ 2 - 2
applications/main/subghz/scenes/subghz_scene_save_success.c

@@ -26,10 +26,10 @@ bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event)
         if(event.event == SubGhzCustomEventSceneSaveSuccess) {
             if(!scene_manager_search_and_switch_to_previous_scene(
                    subghz->scene_manager, SubGhzSceneReceiver)) {
-                subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWSave;
+                subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWSave);
                 if(!scene_manager_search_and_switch_to_previous_scene(
                        subghz->scene_manager, SubGhzSceneReadRAW)) {
-                    subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
+                    subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
                     if(!scene_manager_search_and_switch_to_previous_scene(
                            subghz->scene_manager, SubGhzSceneSaved)) {
                         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved);

+ 2 - 2
applications/main/subghz/scenes/subghz_scene_saved.c

@@ -4,8 +4,8 @@ void subghz_scene_saved_on_enter(void* context) {
     SubGhz* subghz = context;
 
     if(subghz_load_protocol_from_file(subghz)) {
-        if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) {
-            subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
+        if(subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw) {
+            subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
         } else {
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSavedMenu);

+ 46 - 209
applications/main/subghz/scenes/subghz_scene_set_type.c

@@ -1,63 +1,10 @@
 #include "../subghz_i.h"
-#include <lib/subghz/protocols/keeloq.h>
-#include <lib/subghz/protocols/secplus_v1.h>
-#include <lib/subghz/protocols/secplus_v2.h>
+#include "../helpers/subghz_txrx_create_potocol_key.h"
 #include <lib/subghz/blocks/math.h>
-#include <flipper_format/flipper_format_i.h>
-#include <lib/toolbox/stream/stream.h>
 #include <lib/subghz/protocols/protocol_items.h>
 
 #define TAG "SubGhzSetType"
 
-bool subghz_scene_set_type_submenu_gen_data_protocol(
-    void* context,
-    const char* protocol_name,
-    uint64_t key,
-    uint32_t bit,
-    uint32_t frequency,
-    const char* preset_name) {
-    furi_assert(context);
-    SubGhz* subghz = context;
-
-    bool res = false;
-
-    subghz_preset_init(subghz, preset_name, frequency, NULL, 0);
-    subghz->txrx->decoder_result =
-        subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, protocol_name);
-
-    if(subghz->txrx->decoder_result == NULL) {
-        furi_string_set(subghz->error_str, "Protocol not\nfound!");
-        scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub);
-        return false;
-    }
-
-    do {
-        Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data);
-        stream_clean(fff_data_stream);
-        if(subghz_protocol_decoder_base_serialize(
-               subghz->txrx->decoder_result, subghz->txrx->fff_data, subghz->txrx->preset) !=
-           SubGhzProtocolStatusOk) {
-            FURI_LOG_E(TAG, "Unable to serialize");
-            break;
-        }
-        if(!flipper_format_update_uint32(subghz->txrx->fff_data, "Bit", &bit, 1)) {
-            FURI_LOG_E(TAG, "Unable to update Bit");
-            break;
-        }
-
-        uint8_t key_data[sizeof(uint64_t)] = {0};
-        for(size_t i = 0; i < sizeof(uint64_t); i++) {
-            key_data[sizeof(uint64_t) - i - 1] = (key >> (i * 8)) & 0xFF;
-        }
-        if(!flipper_format_update_hex(subghz->txrx->fff_data, "Key", key_data, sizeof(uint64_t))) {
-            FURI_LOG_E(TAG, "Unable to update Key");
-            break;
-        }
-        res = true;
-    } while(false);
-    return res;
-}
-
 void subghz_scene_set_type_submenu_callback(void* context, uint32_t index) {
     SubGhz* subghz = context;
     view_dispatcher_send_custom_event(subghz->view_dispatcher, index);
@@ -69,7 +16,13 @@ void subghz_scene_set_type_on_enter(void* context) {
     submenu_add_item(
         subghz->submenu,
         "Princeton_433",
-        SubmenuIndexPricenton,
+        SubmenuIndexPricenton_433,
+        subghz_scene_set_type_submenu_callback,
+        subghz);
+    submenu_add_item(
+        subghz->submenu,
+        "Princeton_315",
+        SubmenuIndexPricenton_315,
         subghz_scene_set_type_submenu_callback,
         subghz);
     submenu_add_item(
@@ -108,10 +61,6 @@ void subghz_scene_set_type_on_enter(void* context) {
         SubmenuIndexCAMETwee,
         subghz_scene_set_type_submenu_callback,
         subghz);
-    // submenu_add_item(
-    //     subghz->submenu, "Nero Sketch", SubmenuIndexNeroSketch, subghz_scene_set_type_submenu_callback, subghz);
-    // submenu_add_item(
-    //     subghz->submenu, "Nero Radio", SubmenuIndexNeroRadio, subghz_scene_set_type_submenu_callback, subghz);
     submenu_add_item(
         subghz->submenu,
         "Gate TX_433",
@@ -172,94 +121,59 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
     bool generated_protocol = false;
 
     if(event.type == SceneManagerEventTypeCustom) {
-        //ToDo Fix
-        uint32_t key = subghz_random_serial();
+        uint32_t key = (uint32_t)rand();
         switch(event.event) {
-        case SubmenuIndexPricenton:
+        case SubmenuIndexPricenton_433:
             key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
-            if(subghz_scene_set_type_submenu_gen_data_protocol(
-                   subghz, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 433920000, "AM650")) {
-                uint32_t te = 400;
-                flipper_format_update_uint32(subghz->txrx->fff_data, "TE", (uint32_t*)&te, 1);
-                generated_protocol = true;
-            }
+            generated_protocol = subghz_txrx_gen_data_protocol_and_te(
+                subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400);
+            break;
+        case SubmenuIndexPricenton_315:
+            key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
+            generated_protocol = subghz_txrx_gen_data_protocol_and_te(
+                subghz->txrx, "AM650", 315000000, SUBGHZ_PROTOCOL_PRINCETON_NAME, key, 24, 400);
             break;
         case SubmenuIndexNiceFlo12bit:
             key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
-            if(subghz_scene_set_type_submenu_gen_data_protocol(
-                   subghz, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 12, 433920000, "AM650")) {
-                generated_protocol = true;
-            }
+            generated_protocol = subghz_txrx_gen_data_protocol(
+                subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 12);
             break;
         case SubmenuIndexNiceFlo24bit:
             key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
-            if(subghz_scene_set_type_submenu_gen_data_protocol(
-                   subghz, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 24, 433920000, "AM650")) {
-                generated_protocol = true;
-            }
+            generated_protocol = subghz_txrx_gen_data_protocol(
+                subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_NICE_FLO_NAME, key, 24);
             break;
         case SubmenuIndexCAME12bit:
             key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
-            if(subghz_scene_set_type_submenu_gen_data_protocol(
-                   subghz, SUBGHZ_PROTOCOL_CAME_NAME, key, 12, 433920000, "AM650")) {
-                generated_protocol = true;
-            }
+            generated_protocol = subghz_txrx_gen_data_protocol(
+                subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 12);
             break;
         case SubmenuIndexCAME24bit:
             key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
-            if(subghz_scene_set_type_submenu_gen_data_protocol(
-                   subghz, SUBGHZ_PROTOCOL_CAME_NAME, key, 24, 433920000, "AM650")) {
-                generated_protocol = true;
-            }
+            generated_protocol = subghz_txrx_gen_data_protocol(
+                subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_NAME, key, 24);
             break;
         case SubmenuIndexLinear_300_00:
             key = (key & 0x3FF);
-            if(subghz_scene_set_type_submenu_gen_data_protocol(
-                   subghz, SUBGHZ_PROTOCOL_LINEAR_NAME, key, 10, 300000000, "AM650")) {
-                generated_protocol = true;
-            }
+            generated_protocol = subghz_txrx_gen_data_protocol(
+                subghz->txrx, "AM650", 300000000, SUBGHZ_PROTOCOL_LINEAR_NAME, key, 10);
             break;
         case SubmenuIndexCAMETwee:
             key = (key & 0x0FFFFFF0);
             key = 0x003FFF7200000000 | (key ^ 0xE0E0E0EE);
-            if(subghz_scene_set_type_submenu_gen_data_protocol(
-                   subghz, SUBGHZ_PROTOCOL_CAME_TWEE_NAME, key, 54, 433920000, "AM650")) {
-                generated_protocol = true;
-            }
+
+            generated_protocol = subghz_txrx_gen_data_protocol(
+                subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_CAME_TWEE_NAME, key, 54);
             break;
-        // case SubmenuIndexNeroSketch:
-        //     /* code */
-        //     break;
-        // case SubmenuIndexNeroRadio:
-        //     /* code */
-        //     break;
         case SubmenuIndexGateTX:
             key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?)
             uint64_t rev_key = subghz_protocol_blocks_reverse_key(key, 24);
-            if(subghz_scene_set_type_submenu_gen_data_protocol(
-                   subghz, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24, 433920000, "AM650")) {
-                generated_protocol = true;
-            }
+            generated_protocol = subghz_txrx_gen_data_protocol(
+                subghz->txrx, "AM650", 433920000, SUBGHZ_PROTOCOL_GATE_TX_NAME, rev_key, 24);
             break;
         case SubmenuIndexDoorHan_433_92:
-            subghz->txrx->transmitter = subghz_transmitter_alloc_init(
-                subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
-            subghz_preset_init(
-                subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
-            if(subghz->txrx->transmitter) {
-                subghz_protocol_keeloq_create_data(
-                    subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
-                    subghz->txrx->fff_data,
-                    key & 0x0FFFFFFF,
-                    0x2,
-                    0x0003,
-                    "DoorHan",
-                    subghz->txrx->preset);
-                generated_protocol = true;
-            } else {
-                generated_protocol = false;
-            }
-            subghz_transmitter_free(subghz->txrx->transmitter);
+            generated_protocol = subghz_txrx_gen_keelog_protocol(
+                subghz->txrx, "AM650", 433920000, "DoorHan", key, 0x2, 0x0003);
             if(!generated_protocol) {
                 furi_string_set(
                     subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
@@ -267,23 +181,8 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
             }
             break;
         case SubmenuIndexDoorHan_315_00:
-            subghz->txrx->transmitter = subghz_transmitter_alloc_init(
-                subghz->txrx->environment, SUBGHZ_PROTOCOL_KEELOQ_NAME);
-            subghz_preset_init(subghz, "AM650", 315000000, NULL, 0);
-            if(subghz->txrx->transmitter) {
-                subghz_protocol_keeloq_create_data(
-                    subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
-                    subghz->txrx->fff_data,
-                    key & 0x0FFFFFFF,
-                    0x2,
-                    0x0003,
-                    "DoorHan",
-                    subghz->txrx->preset);
-                generated_protocol = true;
-            } else {
-                generated_protocol = false;
-            }
-            subghz_transmitter_free(subghz->txrx->transmitter);
+            generated_protocol = subghz_txrx_gen_keelog_protocol(
+                subghz->txrx, "AM650", 315000000, "DoorHan", key, 0x2, 0x0003);
             if(!generated_protocol) {
                 furi_string_set(
                     subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
@@ -291,86 +190,24 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
             }
             break;
         case SubmenuIndexLiftMaster_315_00:
-            while(!subghz_protocol_secplus_v1_check_fixed(key)) {
-                key = subghz_random_serial();
-            }
-            if(subghz_scene_set_type_submenu_gen_data_protocol(
-                   subghz,
-                   SUBGHZ_PROTOCOL_SECPLUS_V1_NAME,
-                   (uint64_t)key << 32 | 0xE6000000,
-                   42,
-                   315000000,
-                   "AM650")) {
-                generated_protocol = true;
-            }
+            generated_protocol =
+                subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 315000000);
             break;
         case SubmenuIndexLiftMaster_390_00:
-            while(!subghz_protocol_secplus_v1_check_fixed(key)) {
-                key = subghz_random_serial();
-            }
-            if(subghz_scene_set_type_submenu_gen_data_protocol(
-                   subghz,
-                   SUBGHZ_PROTOCOL_SECPLUS_V1_NAME,
-                   (uint64_t)key << 32 | 0xE6000000,
-                   42,
-                   390000000,
-                   "AM650")) {
-                generated_protocol = true;
-            }
+            generated_protocol =
+                subghz_txrx_gen_secplus_v1_protocol(subghz->txrx, "AM650", 390000000);
             break;
         case SubmenuIndexSecPlus_v2_310_00:
-            subghz->txrx->transmitter = subghz_transmitter_alloc_init(
-                subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
-            subghz_preset_init(subghz, "AM650", 310000000, NULL, 0);
-            if(subghz->txrx->transmitter) {
-                subghz_protocol_secplus_v2_create_data(
-                    subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
-                    subghz->txrx->fff_data,
-                    key,
-                    0x68,
-                    0xE500000,
-                    subghz->txrx->preset);
-                generated_protocol = true;
-            } else {
-                generated_protocol = false;
-            }
-            subghz_transmitter_free(subghz->txrx->transmitter);
+            generated_protocol = subghz_txrx_gen_secplus_v2_protocol(
+                subghz->txrx, "AM650", 310000000, key, 0x68, 0xE500000);
             break;
         case SubmenuIndexSecPlus_v2_315_00:
-            subghz->txrx->transmitter = subghz_transmitter_alloc_init(
-                subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
-            subghz_preset_init(subghz, "AM650", 315000000, NULL, 0);
-            if(subghz->txrx->transmitter) {
-                subghz_protocol_secplus_v2_create_data(
-                    subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
-                    subghz->txrx->fff_data,
-                    key,
-                    0x68,
-                    0xE500000,
-                    subghz->txrx->preset);
-                generated_protocol = true;
-            } else {
-                generated_protocol = false;
-            }
-            subghz_transmitter_free(subghz->txrx->transmitter);
+            generated_protocol = subghz_txrx_gen_secplus_v2_protocol(
+                subghz->txrx, "AM650", 315000000, key, 0x68, 0xE500000);
             break;
         case SubmenuIndexSecPlus_v2_390_00:
-            subghz->txrx->transmitter = subghz_transmitter_alloc_init(
-                subghz->txrx->environment, SUBGHZ_PROTOCOL_SECPLUS_V2_NAME);
-            subghz_preset_init(subghz, "AM650", 390000000, NULL, 0);
-            if(subghz->txrx->transmitter) {
-                subghz_protocol_secplus_v2_create_data(
-                    subghz_transmitter_get_protocol_instance(subghz->txrx->transmitter),
-                    subghz->txrx->fff_data,
-                    key,
-                    0x68,
-                    0xE500000,
-                    subghz->txrx->preset);
-                generated_protocol = true;
-            } else {
-                generated_protocol = false;
-            }
-            subghz_transmitter_free(subghz->txrx->transmitter);
+            generated_protocol = subghz_txrx_gen_secplus_v2_protocol(
+                subghz->txrx, "AM650", 390000000, key, 0x68, 0xE500000);
             break;
         default:
             return false;

+ 5 - 6
applications/main/subghz/scenes/subghz_scene_show_error.c

@@ -50,9 +50,10 @@ void subghz_scene_show_error_on_enter(void* context) {
 
 bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) {
     SubGhz* subghz = context;
+    SubGhzCustomEvent scene_state =
+        scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError);
     if(event.type == SceneManagerEventTypeBack) {
-        if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) ==
-           SubGhzCustomEventManagerSet) {
+        if(scene_state == SubGhzCustomEventManagerSet) {
             return false;
         } else {
             scene_manager_search_and_switch_to_previous_scene(
@@ -61,14 +62,12 @@ bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) {
         return true;
     } else if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == SubGhzCustomEventSceneShowErrorOk) {
-            if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) ==
-               SubGhzCustomEventManagerSet) {
+            if(scene_state == SubGhzCustomEventManagerSet) {
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart);
             }
             return true;
         } else if(event.event == SubGhzCustomEventSceneShowErrorBack) {
-            if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) ==
-               SubGhzCustomEventManagerSet) {
+            if(scene_state == SubGhzCustomEventManagerSet) {
                 //exit app
                 if(!scene_manager_previous_scene(subghz->scene_manager)) {
                     scene_manager_stop(subghz->scene_manager);

+ 1 - 1
applications/main/subghz/scenes/subghz_scene_start.c

@@ -70,7 +70,7 @@ bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) {
         if(event.event == SubmenuIndexReadRAW) {
             scene_manager_set_scene_state(
                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexReadRAW);
-            subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
+            subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
             return true;
         } else if(event.event == SubmenuIndexRead) {

+ 15 - 31
applications/main/subghz/scenes/subghz_scene_transmitter.c

@@ -11,32 +11,24 @@ void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) {
 bool subghz_scene_transmitter_update_data_show(void* context) {
     SubGhz* subghz = context;
     bool ret = false;
-    if(subghz->txrx->decoder_result) {
-        FuriString* key_str;
-        FuriString* frequency_str;
-        FuriString* modulation_str;
+    SubGhzProtocolDecoderBase* decoder = subghz_txrx_get_decoder(subghz->txrx);
 
-        key_str = furi_string_alloc();
-        frequency_str = furi_string_alloc();
-        modulation_str = furi_string_alloc();
-        uint8_t show_button = 0;
+    if(decoder) {
+        FuriString* key_str = furi_string_alloc();
+        FuriString* frequency_str = furi_string_alloc();
+        FuriString* modulation_str = furi_string_alloc();
 
         if(subghz_protocol_decoder_base_deserialize(
-               subghz->txrx->decoder_result, subghz->txrx->fff_data) == SubGhzProtocolStatusOk) {
-            subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, key_str);
+               decoder, subghz_txrx_get_fff_data(subghz->txrx)) == SubGhzProtocolStatusOk) {
+            subghz_protocol_decoder_base_get_string(decoder, key_str);
 
-            if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) ==
-               SubGhzProtocolFlag_Send) {
-                show_button = 1;
-            }
-
-            subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
+            subghz_txrx_get_frequency_and_modulation(subghz->txrx, frequency_str, modulation_str);
             subghz_view_transmitter_add_data_to_show(
                 subghz->subghz_transmitter,
                 furi_string_get_cstr(key_str),
                 furi_string_get_cstr(frequency_str),
                 furi_string_get_cstr(modulation_str),
-                show_button);
+                subghz_txrx_protocol_is_transmittable(subghz->txrx, false));
             ret = true;
         }
         furi_string_free(frequency_str);
@@ -65,24 +57,16 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == SubGhzCustomEventViewTransmitterSendStart) {
             subghz->state_notifications = SubGhzNotificationStateIDLE;
-            if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
-                subghz_rx_end(subghz);
-            }
-            if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
-               (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
-                if(subghz_tx_start(subghz, subghz->txrx->fff_data)) {
-                    subghz->state_notifications = SubGhzNotificationStateTx;
-                    subghz_scene_transmitter_update_data_show(subghz);
-                    DOLPHIN_DEED(DolphinDeedSubGhzSend);
-                }
+
+            if(subghz_tx_start(subghz, subghz_txrx_get_fff_data(subghz->txrx))) {
+                subghz->state_notifications = SubGhzNotificationStateTx;
+                subghz_scene_transmitter_update_data_show(subghz);
+                DOLPHIN_DEED(DolphinDeedSubGhzSend);
             }
             return true;
         } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) {
             subghz->state_notifications = SubGhzNotificationStateIDLE;
-            if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
-                subghz_tx_stop(subghz);
-                subghz_sleep(subghz);
-            }
+            subghz_txrx_stop(subghz->txrx);
             return true;
         } else if(event.event == SubGhzCustomEventViewTransmitterBack) {
             subghz->state_notifications = SubGhzNotificationStateIDLE;

+ 24 - 71
applications/main/subghz/subghz.c

@@ -1,9 +1,6 @@
 /* Abandon hope, all ye who enter here. */
 
-#include "subghz/types.h"
 #include "subghz_i.h"
-#include <lib/toolbox/path.h>
-#include <lib/subghz/protocols/protocol_items.h>
 
 bool subghz_custom_event_callback(void* context, uint32_t event) {
     furi_assert(context);
@@ -49,16 +46,6 @@ static void subghz_rpc_command_callback(RpcAppSystemEvent event, void* context)
     }
 }
 
-void subghz_blink_start(SubGhz* instance) {
-    furi_assert(instance);
-    notification_message(instance->notifications, &sequence_blink_start_magenta);
-}
-
-void subghz_blink_stop(SubGhz* instance) {
-    furi_assert(instance);
-    notification_message(instance->notifications, &sequence_blink_stop);
-}
-
 SubGhz* subghz_alloc() {
     SubGhz* subghz = malloc(sizeof(SubGhz));
 
@@ -163,45 +150,18 @@ SubGhz* subghz_alloc() {
         SubGhzViewIdStatic,
         subghz_test_static_get_view(subghz->subghz_test_static));
 
-    //init setting
-    subghz->setting = subghz_setting_alloc();
-    subghz_setting_load(subghz->setting, EXT_PATH("subghz/assets/setting_user"));
-
-    //init Worker & Protocol & History & KeyBoard
-    subghz->lock = SubGhzLockOff;
-    subghz->txrx = malloc(sizeof(SubGhzTxRx));
-    subghz->txrx->preset = malloc(sizeof(SubGhzRadioPreset));
-    subghz->txrx->preset->name = furi_string_alloc();
-    subghz_preset_init(
-        subghz, "AM650", subghz_setting_get_default_frequency(subghz->setting), NULL, 0);
-
-    subghz->txrx->txrx_state = SubGhzTxRxStateSleep;
-    subghz->txrx->hopper_state = SubGhzHopperStateOFF;
-    subghz->txrx->speaker_state = SubGhzSpeakerStateDisable;
-    subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
-    subghz->txrx->raw_threshold_rssi = SUBGHZ_RAW_TRESHOLD_MIN;
-    subghz->txrx->history = subghz_history_alloc();
-    subghz->txrx->worker = subghz_worker_alloc();
-    subghz->txrx->fff_data = flipper_format_string_alloc();
-
-    subghz->txrx->environment = subghz_environment_alloc();
-    subghz_environment_set_came_atomo_rainbow_table_file_name(
-        subghz->txrx->environment, EXT_PATH("subghz/assets/came_atomo"));
-    subghz_environment_set_alutech_at_4n_rainbow_table_file_name(
-        subghz->txrx->environment, EXT_PATH("subghz/assets/alutech_at_4n"));
-    subghz_environment_set_nice_flor_s_rainbow_table_file_name(
-        subghz->txrx->environment, EXT_PATH("subghz/assets/nice_flor_s"));
-    subghz_environment_set_protocol_registry(
-        subghz->txrx->environment, (void*)&subghz_protocol_registry);
-    subghz->txrx->receiver = subghz_receiver_alloc_init(subghz->txrx->environment);
-    subghz->txrx->filter = SubGhzProtocolFlag_Decodable;
-    subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter);
-
-    subghz_worker_set_overrun_callback(
-        subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset);
-    subghz_worker_set_pair_callback(
-        subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode);
-    subghz_worker_set_context(subghz->txrx->worker, subghz->txrx->receiver);
+    //init threshold rssi
+    subghz->threshold_rssi = subghz_threshold_rssi_alloc();
+
+    subghz_unlock(subghz);
+    subghz_rx_key_state_set(subghz, SubGhzRxKeyStateIDLE);
+    subghz->history = subghz_history_alloc();
+    subghz->filter = SubGhzProtocolFlag_Decodable;
+
+    //init TxRx & History & KeyBoard
+    subghz->txrx = subghz_txrx_alloc();
+    subghz_txrx_receiver_set_filter(subghz->txrx, subghz->filter);
+    subghz_txrx_set_need_save_callback(subghz->txrx, subghz_save_to_file, subghz);
 
     //Init Error_str
     subghz->error_str = furi_string_alloc();
@@ -219,7 +179,9 @@ void subghz_free(SubGhz* subghz) {
         subghz->rpc_ctx = NULL;
     }
 
-    subghz_speaker_off(subghz);
+    subghz_txrx_speaker_off(subghz->txrx);
+    subghz_txrx_stop(subghz->txrx);
+    subghz_txrx_sleep(subghz->txrx);
 
     // Packet Test
     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTestPacket);
@@ -282,18 +244,14 @@ void subghz_free(SubGhz* subghz) {
     furi_record_close(RECORD_GUI);
     subghz->gui = NULL;
 
-    //setting
-    subghz_setting_free(subghz->setting);
+    // threshold rssi
+    subghz_threshold_rssi_free(subghz->threshold_rssi);
 
     //Worker & Protocol & History
-    subghz_receiver_free(subghz->txrx->receiver);
-    subghz_environment_free(subghz->txrx->environment);
-    subghz_worker_free(subghz->txrx->worker);
-    flipper_format_free(subghz->txrx->fff_data);
-    subghz_history_free(subghz->txrx->history);
-    furi_string_free(subghz->txrx->preset->name);
-    free(subghz->txrx->preset);
-    free(subghz->txrx);
+    subghz_history_free(subghz->history);
+
+    //TxRx
+    subghz_txrx_free(subghz->txrx);
 
     //Error string
     furi_string_free(subghz->error_str);
@@ -319,11 +277,6 @@ int32_t subghz_app(void* p) {
         return 1;
     }
 
-    //Load database
-    bool load_database = subghz_environment_load_keystore(
-        subghz->txrx->environment, EXT_PATH("subghz/assets/keeloq_mfcodes"));
-    subghz_environment_load_keystore(
-        subghz->txrx->environment, EXT_PATH("subghz/assets/keeloq_mfcodes_user"));
     // Check argument and run corresponding scene
     if(p && strlen(p)) {
         uint32_t rpc_ctx = 0;
@@ -340,9 +293,9 @@ int32_t subghz_app(void* p) {
             if(subghz_key_load(subghz, p, true)) {
                 furi_string_set(subghz->file_path, (const char*)p);
 
-                if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) {
+                if(subghz_get_load_type_file(subghz) == SubGhzLoadTypeFileRaw) {
                     //Load Raw TX
-                    subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
+                    subghz_rx_key_state_set(subghz, SubGhzRxKeyStateRAWLoad);
                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
                 } else {
                     //Load transmitter TX
@@ -358,7 +311,7 @@ int32_t subghz_app(void* p) {
         view_dispatcher_attach_to_gui(
             subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen);
         furi_string_set(subghz->file_path, SUBGHZ_APP_FOLDER);
-        if(load_database) {
+        if(subghz_txrx_is_database_loaded(subghz->txrx)) {
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart);
         } else {
             scene_manager_set_scene_state(

+ 90 - 313
applications/main/subghz/subghz_i.c

@@ -18,214 +18,42 @@
 
 #define TAG "SubGhz"
 
-void subghz_preset_init(
-    void* context,
-    const char* preset_name,
-    uint32_t frequency,
-    uint8_t* preset_data,
-    size_t preset_data_size) {
-    furi_assert(context);
-    SubGhz* subghz = context;
-    furi_string_set(subghz->txrx->preset->name, preset_name);
-    subghz->txrx->preset->frequency = frequency;
-    subghz->txrx->preset->data = preset_data;
-    subghz->txrx->preset->data_size = preset_data_size;
-}
-
-bool subghz_set_preset(SubGhz* subghz, const char* preset) {
-    if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) {
-        furi_string_set(subghz->txrx->preset->name, "AM270");
-    } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) {
-        furi_string_set(subghz->txrx->preset->name, "AM650");
-    } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev238Async")) {
-        furi_string_set(subghz->txrx->preset->name, "FM238");
-    } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) {
-        furi_string_set(subghz->txrx->preset->name, "FM476");
-    } else if(!strcmp(preset, "FuriHalSubGhzPresetCustom")) {
-        furi_string_set(subghz->txrx->preset->name, "CUSTOM");
-    } else {
-        FURI_LOG_E(TAG, "Unknown preset");
-        return false;
-    }
-    return true;
-}
-
-void subghz_get_frequency_modulation(SubGhz* subghz, FuriString* frequency, FuriString* modulation) {
+void subghz_set_default_preset(SubGhz* subghz) {
     furi_assert(subghz);
-    if(frequency != NULL) {
-        furi_string_printf(
-            frequency,
-            "%03ld.%02ld",
-            subghz->txrx->preset->frequency / 1000000 % 1000,
-            subghz->txrx->preset->frequency / 10000 % 100);
-    }
-    if(modulation != NULL) {
-        furi_string_printf(modulation, "%.2s", furi_string_get_cstr(subghz->txrx->preset->name));
-    }
+    subghz_txrx_set_preset(
+        subghz->txrx,
+        "AM650",
+        subghz_setting_get_default_frequency(subghz_txrx_get_setting(subghz->txrx)),
+        NULL,
+        0);
 }
 
-void subghz_begin(SubGhz* subghz, uint8_t* preset_data) {
+void subghz_blink_start(SubGhz* subghz) {
     furi_assert(subghz);
-    furi_hal_subghz_reset();
-    furi_hal_subghz_idle();
-    furi_hal_subghz_load_custom_preset(preset_data);
-    furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
-    subghz->txrx->txrx_state = SubGhzTxRxStateIDLE;
+    notification_message(subghz->notifications, &sequence_blink_stop);
+    notification_message(subghz->notifications, &sequence_blink_start_magenta);
 }
 
-uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency) {
+void subghz_blink_stop(SubGhz* subghz) {
     furi_assert(subghz);
-    if(!furi_hal_subghz_is_frequency_valid(frequency)) {
-        furi_crash("SubGhz: Incorrect RX frequency.");
-    }
-    furi_assert(
-        subghz->txrx->txrx_state != SubGhzTxRxStateRx &&
-        subghz->txrx->txrx_state != SubGhzTxRxStateSleep);
-
-    furi_hal_subghz_idle();
-    uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency);
-    furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
-    furi_hal_subghz_flush_rx();
-    subghz_speaker_on(subghz);
-    furi_hal_subghz_rx();
-
-    furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz->txrx->worker);
-    subghz_worker_start(subghz->txrx->worker);
-    subghz->txrx->txrx_state = SubGhzTxRxStateRx;
-    return value;
-}
-
-static bool subghz_tx(SubGhz* subghz, uint32_t frequency) {
-    furi_assert(subghz);
-    if(!furi_hal_subghz_is_frequency_valid(frequency)) {
-        furi_crash("SubGhz: Incorrect TX frequency.");
-    }
-    furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep);
-    furi_hal_subghz_idle();
-    furi_hal_subghz_set_frequency_and_path(frequency);
-    furi_hal_gpio_write(&gpio_cc1101_g0, false);
-    furi_hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
-    bool ret = furi_hal_subghz_tx();
-    if(ret) {
-        subghz_speaker_on(subghz);
-        subghz->txrx->txrx_state = SubGhzTxRxStateTx;
-    }
-    return ret;
-}
-
-void subghz_idle(SubGhz* subghz) {
-    furi_assert(subghz);
-    furi_assert(subghz->txrx->txrx_state != SubGhzTxRxStateSleep);
-    furi_hal_subghz_idle();
-    subghz_speaker_off(subghz);
-    subghz->txrx->txrx_state = SubGhzTxRxStateIDLE;
-}
-
-void subghz_rx_end(SubGhz* subghz) {
-    furi_assert(subghz);
-    furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateRx);
-
-    if(subghz_worker_is_running(subghz->txrx->worker)) {
-        subghz_worker_stop(subghz->txrx->worker);
-        furi_hal_subghz_stop_async_rx();
-    }
-    furi_hal_subghz_idle();
-    subghz_speaker_off(subghz);
-    subghz->txrx->txrx_state = SubGhzTxRxStateIDLE;
-}
-
-void subghz_sleep(SubGhz* subghz) {
-    furi_assert(subghz);
-    furi_hal_subghz_sleep();
-    subghz->txrx->txrx_state = SubGhzTxRxStateSleep;
+    notification_message(subghz->notifications, &sequence_blink_stop);
 }
 
 bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) {
-    furi_assert(subghz);
-
-    bool ret = false;
-    FuriString* temp_str;
-    temp_str = furi_string_alloc();
-    uint32_t repeat = 200;
-    do {
-        if(!flipper_format_rewind(flipper_format)) {
-            FURI_LOG_E(TAG, "Rewind error");
-            break;
-        }
-        if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) {
-            FURI_LOG_E(TAG, "Missing Protocol");
-            break;
-        }
-        if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) {
-            FURI_LOG_E(TAG, "Unable Repeat");
-            break;
-        }
-
-        subghz->txrx->transmitter = subghz_transmitter_alloc_init(
-            subghz->txrx->environment, furi_string_get_cstr(temp_str));
-
-        if(subghz->txrx->transmitter) {
-            if(subghz_transmitter_deserialize(subghz->txrx->transmitter, flipper_format) ==
-               SubGhzProtocolStatusOk) {
-                if(strcmp(furi_string_get_cstr(subghz->txrx->preset->name), "") != 0) {
-                    subghz_begin(
-                        subghz,
-                        subghz_setting_get_preset_data_by_name(
-                            subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name)));
-                } else {
-                    FURI_LOG_E(
-                        TAG,
-                        "Unknown name preset \" %s \"",
-                        furi_string_get_cstr(subghz->txrx->preset->name));
-                    subghz_begin(
-                        subghz, subghz_setting_get_preset_data_by_name(subghz->setting, "AM650"));
-                }
-                if(subghz->txrx->preset->frequency) {
-                    ret = subghz_tx(subghz, subghz->txrx->preset->frequency);
-                } else {
-                    ret = subghz_tx(subghz, 433920000);
-                }
-                if(ret) {
-                    //Start TX
-                    furi_hal_subghz_start_async_tx(
-                        subghz_transmitter_yield, subghz->txrx->transmitter);
-                } else {
-                    subghz_dialog_message_show_only_rx(subghz);
-                }
-            } else {
-                dialog_message_show_storage_error(
-                    subghz->dialogs, "Error in protocol\nparameters\ndescription");
-            }
-        }
-        if(!ret) {
-            subghz_transmitter_free(subghz->txrx->transmitter);
-            if(subghz->txrx->txrx_state != SubGhzTxRxStateSleep) {
-                subghz_idle(subghz);
-            }
-        }
-
-    } while(false);
-    furi_string_free(temp_str);
-    return ret;
-}
+    switch(subghz_txrx_tx_start(subghz->txrx, flipper_format)) {
+    case SubGhzTxRxStartTxStateErrorParserOthers:
+        dialog_message_show_storage_error(
+            subghz->dialogs, "Error in protocol\nparameters\ndescription");
+        break;
+    case SubGhzTxRxStartTxStateErrorOnlyRx:
+        subghz_dialog_message_show_only_rx(subghz);
+        break;
 
-void subghz_tx_stop(SubGhz* subghz) {
-    furi_assert(subghz);
-    furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateTx);
-    //Stop TX
-    furi_hal_subghz_stop_async_tx();
-    subghz_transmitter_stop(subghz->txrx->transmitter);
-    subghz_transmitter_free(subghz->txrx->transmitter);
-
-    //if protocol dynamic then we save the last upload
-    if((subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) &&
-       (subghz_path_is_file(subghz->file_path))) {
-        subghz_save_protocol_to_file(
-            subghz, subghz->txrx->fff_data, furi_string_get_cstr(subghz->file_path));
+    default:
+        return true;
+        break;
     }
-    subghz_idle(subghz);
-    subghz_speaker_off(subghz);
-    notification_message(subghz->notifications, &sequence_reset_red);
+    return false;
 }
 
 void subghz_dialog_message_show_only_rx(SubGhz* subghz) {
@@ -254,11 +82,11 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
 
     Storage* storage = furi_record_open(RECORD_STORAGE);
     FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
-    Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data);
+    Stream* fff_data_stream =
+        flipper_format_get_raw_stream(subghz_txrx_get_fff_data(subghz->txrx));
 
     SubGhzLoadKeyState load_key_state = SubGhzLoadKeyStateParseErr;
-    FuriString* temp_str;
-    temp_str = furi_string_alloc();
+    FuriString* temp_str = furi_string_alloc();
     uint32_t temp_data32;
 
     do {
@@ -281,6 +109,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
             break;
         }
 
+        //Load frequency
         if(!flipper_format_read_uint32(fff_data_file, "Frequency", &temp_data32, 1)) {
             FURI_LOG_E(TAG, "Missing Frequency");
             break;
@@ -291,58 +120,61 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
             break;
         }
 
-        subghz->txrx->preset->frequency = temp_data32;
-
+        //Load preset
         if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
             FURI_LOG_E(TAG, "Missing Preset");
             break;
         }
 
-        if(!subghz_set_preset(subghz, furi_string_get_cstr(temp_str))) {
+        furi_string_set_str(
+            temp_str, subghz_txrx_get_preset_name(subghz->txrx, furi_string_get_cstr(temp_str)));
+        if(!strcmp(furi_string_get_cstr(temp_str), "")) {
             break;
         }
+        SubGhzSetting* setting = subghz_txrx_get_setting(subghz->txrx);
 
-        if(!strcmp(furi_string_get_cstr(temp_str), "FuriHalSubGhzPresetCustom")) {
+        if(!strcmp(furi_string_get_cstr(temp_str), "CUSTOM")) {
             //Todo add Custom_preset_module
             //delete preset if it already exists
-            subghz_setting_delete_custom_preset(
-                subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name));
+            subghz_setting_delete_custom_preset(setting, furi_string_get_cstr(temp_str));
             //load custom preset from file
             if(!subghz_setting_load_custom_preset(
-                   subghz->setting,
-                   furi_string_get_cstr(subghz->txrx->preset->name),
-                   fff_data_file)) {
+                   setting, furi_string_get_cstr(temp_str), fff_data_file)) {
                 FURI_LOG_E(TAG, "Missing Custom preset");
                 break;
             }
         }
-        size_t preset_index = subghz_setting_get_inx_preset_by_name(
-            subghz->setting, furi_string_get_cstr(subghz->txrx->preset->name));
-        subghz_preset_init(
-            subghz,
-            furi_string_get_cstr(subghz->txrx->preset->name),
-            subghz->txrx->preset->frequency,
-            subghz_setting_get_preset_data(subghz->setting, preset_index),
-            subghz_setting_get_preset_data_size(subghz->setting, preset_index));
-
+        size_t preset_index =
+            subghz_setting_get_inx_preset_by_name(setting, furi_string_get_cstr(temp_str));
+        subghz_txrx_set_preset(
+            subghz->txrx,
+            furi_string_get_cstr(temp_str),
+            temp_data32,
+            subghz_setting_get_preset_data(setting, preset_index),
+            subghz_setting_get_preset_data_size(setting, preset_index));
+
+        //Load protocol
         if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
             FURI_LOG_E(TAG, "Missing Protocol");
             break;
         }
+
+        FlipperFormat* fff_data = subghz_txrx_get_fff_data(subghz->txrx);
         if(!strcmp(furi_string_get_cstr(temp_str), "RAW")) {
             //if RAW
-            subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, file_path);
+            subghz->load_type_file = SubGhzLoadTypeFileRaw;
+            subghz_protocol_raw_gen_fff_data(fff_data, file_path);
         } else {
+            subghz->load_type_file = SubGhzLoadTypeFileKey;
             stream_copy_full(
                 flipper_format_get_raw_stream(fff_data_file),
-                flipper_format_get_raw_stream(subghz->txrx->fff_data));
+                flipper_format_get_raw_stream(fff_data));
         }
 
-        subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
-            subghz->txrx->receiver, furi_string_get_cstr(temp_str));
-        if(subghz->txrx->decoder_result) {
+        if(subghz_txrx_load_decoder_by_name_protocol(
+               subghz->txrx, furi_string_get_cstr(temp_str))) {
             SubGhzProtocolStatus status = subghz_protocol_decoder_base_deserialize(
-                subghz->txrx->decoder_result, subghz->txrx->fff_data);
+                subghz_txrx_get_decoder(subghz->txrx), fff_data);
             if(status != SubGhzProtocolStatusOk) {
                 load_key_state = SubGhzLoadKeyStateProtocolDescriptionErr;
                 break;
@@ -381,17 +213,18 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog) {
     }
 }
 
+SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz) {
+    furi_assert(subghz);
+    return subghz->load_type_file;
+}
+
 bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len) {
     furi_assert(subghz);
 
     Storage* storage = furi_record_open(RECORD_STORAGE);
-    FuriString* temp_str;
-    FuriString* file_name;
-    FuriString* file_path;
-
-    temp_str = furi_string_alloc();
-    file_name = furi_string_alloc();
-    file_path = furi_string_alloc();
+    FuriString* temp_str = furi_string_alloc();
+    FuriString* file_name = furi_string_alloc();
+    FuriString* file_path = furi_string_alloc();
 
     bool res = false;
 
@@ -438,8 +271,7 @@ bool subghz_save_protocol_to_file(
     Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format);
 
     bool saved = false;
-    FuriString* file_dir;
-    file_dir = furi_string_alloc();
+    FuriString* file_dir = furi_string_alloc();
 
     path_extract_dirname(dev_file_name, file_dir);
     do {
@@ -467,11 +299,21 @@ bool subghz_save_protocol_to_file(
     return saved;
 }
 
+void subghz_save_to_file(void* context) {
+    furi_assert(context);
+    SubGhz* subghz = context;
+    if(subghz_path_is_file(subghz->file_path)) {
+        subghz_save_protocol_to_file(
+            subghz,
+            subghz_txrx_get_fff_data(subghz->txrx),
+            furi_string_get_cstr(subghz->file_path));
+    }
+}
+
 bool subghz_load_protocol_from_file(SubGhz* subghz) {
     furi_assert(subghz);
 
-    FuriString* file_path;
-    file_path = furi_string_alloc();
+    FuriString* file_path = furi_string_alloc();
 
     DialogsFileBrowserOptions browser_options;
     dialog_file_browser_set_basic_options(&browser_options, SUBGHZ_APP_EXTENSION, &I_sub1_10px);
@@ -551,92 +393,27 @@ bool subghz_path_is_file(FuriString* path) {
     return furi_string_end_with(path, SUBGHZ_APP_EXTENSION);
 }
 
-uint32_t subghz_random_serial(void) {
-    return (uint32_t)rand();
-}
-
-void subghz_hopper_update(SubGhz* subghz) {
+void subghz_lock(SubGhz* subghz) {
     furi_assert(subghz);
-
-    switch(subghz->txrx->hopper_state) {
-    case SubGhzHopperStateOFF:
-    case SubGhzHopperStatePause:
-        return;
-    case SubGhzHopperStateRSSITimeOut:
-        if(subghz->txrx->hopper_timeout != 0) {
-            subghz->txrx->hopper_timeout--;
-            return;
-        }
-        break;
-    default:
-        break;
-    }
-    float rssi = -127.0f;
-    if(subghz->txrx->hopper_state != SubGhzHopperStateRSSITimeOut) {
-        // See RSSI Calculation timings in CC1101 17.3 RSSI
-        rssi = furi_hal_subghz_get_rssi();
-
-        // Stay if RSSI is high enough
-        if(rssi > -90.0f) {
-            subghz->txrx->hopper_timeout = 10;
-            subghz->txrx->hopper_state = SubGhzHopperStateRSSITimeOut;
-            return;
-        }
-    } else {
-        subghz->txrx->hopper_state = SubGhzHopperStateRunnig;
-    }
-    // Select next frequency
-    if(subghz->txrx->hopper_idx_frequency <
-       subghz_setting_get_hopper_frequency_count(subghz->setting) - 1) {
-        subghz->txrx->hopper_idx_frequency++;
-    } else {
-        subghz->txrx->hopper_idx_frequency = 0;
-    }
-
-    if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
-        subghz_rx_end(subghz);
-    };
-    if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
-        subghz_receiver_reset(subghz->txrx->receiver);
-        subghz->txrx->preset->frequency = subghz_setting_get_hopper_frequency(
-            subghz->setting, subghz->txrx->hopper_idx_frequency);
-        subghz_rx(subghz, subghz->txrx->preset->frequency);
-    }
+    subghz->lock = SubGhzLockOn;
 }
 
-void subghz_speaker_on(SubGhz* subghz) {
-    if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) {
-        if(furi_hal_speaker_acquire(30)) {
-            furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
-        } else {
-            subghz->txrx->speaker_state = SubGhzSpeakerStateDisable;
-        }
-    }
+void subghz_unlock(SubGhz* subghz) {
+    furi_assert(subghz);
+    subghz->lock = SubGhzLockOff;
 }
 
-void subghz_speaker_off(SubGhz* subghz) {
-    if(subghz->txrx->speaker_state != SubGhzSpeakerStateDisable) {
-        if(furi_hal_speaker_is_mine()) {
-            furi_hal_subghz_set_async_mirror_pin(NULL);
-            furi_hal_speaker_release();
-            if(subghz->txrx->speaker_state == SubGhzSpeakerStateShutdown)
-                subghz->txrx->speaker_state = SubGhzSpeakerStateDisable;
-        }
-    }
+bool subghz_is_locked(SubGhz* subghz) {
+    furi_assert(subghz);
+    return (subghz->lock == SubGhzLockOn);
 }
 
-void subghz_speaker_mute(SubGhz* subghz) {
-    if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) {
-        if(furi_hal_speaker_is_mine()) {
-            furi_hal_subghz_set_async_mirror_pin(NULL);
-        }
-    }
+void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state) {
+    furi_assert(subghz);
+    subghz->rx_key_state = state;
 }
 
-void subghz_speaker_unmute(SubGhz* subghz) {
-    if(subghz->txrx->speaker_state == SubGhzSpeakerStateEnable) {
-        if(furi_hal_speaker_is_mine()) {
-            furi_hal_subghz_set_async_mirror_pin(&gpio_speaker);
-        }
-    }
+SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz) {
+    furi_assert(subghz);
+    return subghz->rx_key_state;
 }

+ 23 - 53
applications/main/subghz/subghz_i.h

@@ -25,10 +25,6 @@
 #include <gui/modules/widget.h>
 
 #include <subghz/scenes/subghz_scene.h>
-#include <lib/subghz/subghz_worker.h>
-#include <lib/subghz/subghz_setting.h>
-#include <lib/subghz/receiver.h>
-#include <lib/subghz/transmitter.h>
 
 #include "subghz_history.h"
 
@@ -37,33 +33,11 @@
 
 #include "rpc/rpc_app.h"
 
-#define SUBGHZ_MAX_LEN_NAME 64
-
-struct SubGhzTxRx {
-    SubGhzWorker* worker;
-
-    SubGhzEnvironment* environment;
-    SubGhzReceiver* receiver;
-    SubGhzTransmitter* transmitter;
-    SubGhzProtocolFlag filter;
-    SubGhzProtocolDecoderBase* decoder_result;
-    FlipperFormat* fff_data;
-
-    SubGhzRadioPreset* preset;
-    SubGhzHistory* history;
-    uint16_t idx_menu_chosen;
-    SubGhzTxRxState txrx_state;
-    SubGhzHopperState hopper_state;
-    SubGhzSpeakerState speaker_state;
-    uint8_t hopper_timeout;
-    uint8_t hopper_idx_frequency;
-    SubGhzRxKeyState rx_key_state;
+#include "helpers/subghz_threshold_rssi.h"
 
-    float raw_threshold_rssi;
-    uint8_t raw_threshold_rssi_low_count;
-};
+#include "helpers/subghz_txrx.h"
 
-typedef struct SubGhzTxRx SubGhzTxRx;
+#define SUBGHZ_MAX_LEN_NAME 64
 
 struct SubGhz {
     Gui* gui;
@@ -93,47 +67,43 @@ struct SubGhz {
     SubGhzTestStatic* subghz_test_static;
     SubGhzTestCarrier* subghz_test_carrier;
     SubGhzTestPacket* subghz_test_packet;
+
+    SubGhzProtocolFlag filter;
     FuriString* error_str;
-    SubGhzSetting* setting;
     SubGhzLock lock;
-
+    SubGhzThresholdRssi* threshold_rssi;
+    SubGhzRxKeyState rx_key_state;
+    SubGhzHistory* history;
+    uint16_t idx_menu_chosen;
+    SubGhzLoadTypeFile load_type_file;
     void* rpc_ctx;
 };
 
-void subghz_preset_init(
-    void* context,
-    const char* preset_name,
-    uint32_t frequency,
-    uint8_t* preset_data,
-    size_t preset_data_size);
-bool subghz_set_preset(SubGhz* subghz, const char* preset);
-void subghz_get_frequency_modulation(SubGhz* subghz, FuriString* frequency, FuriString* modulation);
-void subghz_begin(SubGhz* subghz, uint8_t* preset_data);
-uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency);
-void subghz_rx_end(SubGhz* subghz);
-void subghz_sleep(SubGhz* subghz);
-
-void subghz_blink_start(SubGhz* instance);
-void subghz_blink_stop(SubGhz* instance);
+void subghz_set_default_preset(SubGhz* subghz);
+void subghz_blink_start(SubGhz* subghz);
+void subghz_blink_stop(SubGhz* subghz);
 
 bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format);
-void subghz_tx_stop(SubGhz* subghz);
 void subghz_dialog_message_show_only_rx(SubGhz* subghz);
+
 bool subghz_key_load(SubGhz* subghz, const char* file_path, bool show_dialog);
 bool subghz_get_next_name_file(SubGhz* subghz, uint8_t max_len);
 bool subghz_save_protocol_to_file(
     SubGhz* subghz,
     FlipperFormat* flipper_format,
     const char* dev_file_name);
+void subghz_save_to_file(void* context);
 bool subghz_load_protocol_from_file(SubGhz* subghz);
 bool subghz_rename_file(SubGhz* subghz);
 bool subghz_file_available(SubGhz* subghz);
 bool subghz_delete_file(SubGhz* subghz);
 void subghz_file_name_clear(SubGhz* subghz);
 bool subghz_path_is_file(FuriString* path);
-uint32_t subghz_random_serial(void);
-void subghz_hopper_update(SubGhz* subghz);
-void subghz_speaker_on(SubGhz* subghz);
-void subghz_speaker_off(SubGhz* subghz);
-void subghz_speaker_mute(SubGhz* subghz);
-void subghz_speaker_unmute(SubGhz* subghz);
+SubGhzLoadTypeFile subghz_get_load_type_file(SubGhz* subghz);
+
+void subghz_lock(SubGhz* subghz);
+void subghz_unlock(SubGhz* subghz);
+bool subghz_is_locked(SubGhz* subghz);
+
+void subghz_rx_key_state_set(SubGhz* subghz, SubGhzRxKeyState state);
+SubGhzRxKeyState subghz_rx_key_state_get(SubGhz* subghz);

+ 12 - 11
applications/main/subghz/views/receiver.c

@@ -12,7 +12,7 @@
 #define MENU_ITEMS 4u
 #define UNLOCK_CNT 3
 
-#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f
+#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f
 
 typedef struct {
     FuriString* item_str;
@@ -44,7 +44,7 @@ typedef enum {
 } SubGhzViewReceiverBarShow;
 
 struct SubGhzViewReceiver {
-    SubGhzLock lock;
+    bool lock;
     uint8_t lock_count;
     FuriTimer* timer;
     View* view;
@@ -70,20 +70,21 @@ void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi) {
         instance->view,
         SubGhzViewReceiverModel * model,
         {
-            if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) {
+            if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) {
                 model->u_rssi = 0;
             } else {
-                model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN);
+                model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN);
             }
         },
         true);
 }
 
-void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock lock) {
+void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, bool lock) {
     furi_assert(subghz_receiver);
     subghz_receiver->lock_count = 0;
-    if(lock == SubGhzLockOn) {
-        subghz_receiver->lock = lock;
+
+    if(lock == true) {
+        subghz_receiver->lock = true;
         with_view_model(
             subghz_receiver->view,
             SubGhzViewReceiverModel * model,
@@ -280,7 +281,7 @@ static void subghz_view_receiver_timer_callback(void* context) {
         subghz_receiver->callback(
             SubGhzCustomEventViewReceiverOffDisplay, subghz_receiver->context);
     } else {
-        subghz_receiver->lock = SubGhzLockOff;
+        subghz_receiver->lock = false;
         subghz_receiver->callback(SubGhzCustomEventViewReceiverUnlock, subghz_receiver->context);
     }
     subghz_receiver->lock_count = 0;
@@ -290,7 +291,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
     furi_assert(context);
     SubGhzViewReceiver* subghz_receiver = context;
 
-    if(subghz_receiver->lock == SubGhzLockOn) {
+    if(subghz_receiver->lock == true) {
         with_view_model(
             subghz_receiver->view,
             SubGhzViewReceiverModel * model,
@@ -310,7 +311,7 @@ bool subghz_view_receiver_input(InputEvent* event, void* context) {
                 SubGhzViewReceiverModel * model,
                 { model->bar_show = SubGhzViewReceiverBarShowUnlock; },
                 true);
-            //subghz_receiver->lock = SubGhzLockOff;
+            //subghz_receiver->lock = false;
             furi_timer_start(subghz_receiver->timer, pdMS_TO_TICKS(650));
         }
 
@@ -394,7 +395,7 @@ SubGhzViewReceiver* subghz_view_receiver_alloc() {
     // View allocation and configuration
     subghz_receiver->view = view_alloc();
 
-    subghz_receiver->lock = SubGhzLockOff;
+    subghz_receiver->lock = false;
     subghz_receiver->lock_count = 0;
     view_allocate_model(
         subghz_receiver->view, ViewModelTypeLocking, sizeof(SubGhzViewReceiverModel));

+ 1 - 1
applications/main/subghz/views/receiver.h

@@ -10,7 +10,7 @@ typedef void (*SubGhzViewReceiverCallback)(SubGhzCustomEvent event, void* contex
 
 void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi);
 
-void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, SubGhzLock keyboard);
+void subghz_view_receiver_set_lock(SubGhzViewReceiver* subghz_receiver, bool keyboard);
 
 void subghz_view_receiver_set_callback(
     SubGhzViewReceiver* subghz_receiver,

+ 4 - 4
applications/main/subghz/views/subghz_read_raw.c

@@ -60,10 +60,10 @@ void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi, bool tra
     furi_assert(instance);
     uint8_t u_rssi = 0;
 
-    if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) {
+    if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) {
         u_rssi = 0;
     } else {
-        u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7);
+        u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_THRESHOLD_MIN) / 2.7);
     }
 
     with_view_model(
@@ -261,9 +261,9 @@ void subghz_read_raw_draw_threshold_rssi(Canvas* canvas, SubGhzReadRAWModel* mod
     uint8_t x = 118;
     uint8_t y = 48;
 
-    if(model->raw_threshold_rssi > SUBGHZ_RAW_TRESHOLD_MIN) {
+    if(model->raw_threshold_rssi > SUBGHZ_RAW_THRESHOLD_MIN) {
         uint8_t x = 118;
-        y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7);
+        y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_THRESHOLD_MIN) / 2.7);
 
         uint8_t width = 3;
         for(uint8_t i = 0; i < x; i += width * 2) {

+ 1 - 1
applications/main/subghz/views/subghz_read_raw.h

@@ -3,7 +3,7 @@
 #include <gui/view.h>
 #include "../helpers/subghz_custom_event.h"
 
-#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f
+#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f
 
 typedef struct SubGhzReadRAW SubGhzReadRAW;
 

+ 3 - 3
applications/main/subghz/views/transmitter.c

@@ -14,7 +14,7 @@ typedef struct {
     FuriString* frequency_str;
     FuriString* preset_str;
     FuriString* key_str;
-    uint8_t show_button;
+    bool show_button;
 } SubGhzViewTransmitterModel;
 
 void subghz_view_transmitter_set_callback(
@@ -32,7 +32,7 @@ void subghz_view_transmitter_add_data_to_show(
     const char* key_str,
     const char* frequency_str,
     const char* preset_str,
-    uint8_t show_button) {
+    bool show_button) {
     furi_assert(subghz_transmitter);
     with_view_model(
         subghz_transmitter->view,
@@ -104,7 +104,7 @@ bool subghz_view_transmitter_input(InputEvent* event, void* context) {
                 furi_string_reset(model->frequency_str);
                 furi_string_reset(model->preset_str);
                 furi_string_reset(model->key_str);
-                model->show_button = 0;
+                model->show_button = false;
             },
             false);
         return false;

+ 1 - 1
applications/main/subghz/views/transmitter.h

@@ -23,4 +23,4 @@ void subghz_view_transmitter_add_data_to_show(
     const char* key_str,
     const char* frequency_str,
     const char* preset_str,
-    uint8_t show_button);
+    bool show_button);

+ 2 - 0
lib/subghz/environment.c

@@ -16,6 +16,7 @@ SubGhzEnvironment* subghz_environment_alloc() {
     instance->protocol_registry = NULL;
     instance->came_atomo_rainbow_table_file_name = NULL;
     instance->nice_flor_s_rainbow_table_file_name = NULL;
+    instance->alutech_at_4n_rainbow_table_file_name = NULL;
 
     return instance;
 }
@@ -26,6 +27,7 @@ void subghz_environment_free(SubGhzEnvironment* instance) {
     instance->protocol_registry = NULL;
     instance->came_atomo_rainbow_table_file_name = NULL;
     instance->nice_flor_s_rainbow_table_file_name = NULL;
+    instance->alutech_at_4n_rainbow_table_file_name = NULL;
     subghz_keystore_free(instance->keystore);
 
     free(instance);