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

Skorp subghz signal archive (#667)

* SubGhz: Add millis() furi, add subghz history struct
* SubGhz: Fix subghz history
* Gubghz: Fix code repeat  history, add clean history
* SubGhz: reading and adding keys to history
* Gui: Renaming Sub 1-Ghz -> SubGhz
* Archive: Renaming Sub 1-Ghz -> SubGhz
* SubGhz:  Add menu history, modified button for sending a signal, changed output of data about accepted protocol
* Archive: Fix name subghz
* SubGhz: Menu navigation
* Assets: Add assets/SubGHz/icon.png
* Assets: add new icons for subghz
* SubGhz: Fix name Add manually scene
* SubGhz: Fix load icon Read scene. rename encoder struct,  rename protocol function load from file, add load raw data protocol, add info pleasant signals all protocol
* SubGhz: fix memory leak
* SubGhz: change of receiving frequency for read scene
* SubGhz: Add save/load frequency and preset, add automatic configuration of transmit/receive to the desired frequency and modulation, add button "save" config scene
* SubGhz: Fix frequency and preset, fix frequency add manualli scene, fix re-executing the parser
* Furi-hal-subghz: add 2-FSK config, fix ook config 650KHz BW Tx filter
* Fix formatting and release build
* SubGhz: Delete read scene
* SubGhz: Fix frequency add manualli scene,  refactoring code
* SubGhz: 2 profiles for OOK, fix broken build.
* SubGhz: Add passing static codes from read scene, add notification read scene, refactoring code
* SubGhz: fix assert on worker double stop.

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
Skorpionm 4 лет назад
Родитель
Сommit
0a8a944e10
64 измененных файлов с 1545 добавлено и 402 удалено
  1. 1 1
      applications/applications.c
  2. 7 7
      applications/archive/archive_i.h
  3. 2 2
      applications/archive/archive_views.c
  4. 2 2
      applications/archive/archive_views.h
  5. 0 1
      applications/subghz/scenes/subghz_scene_config.h
  6. 0 62
      applications/subghz/scenes/subghz_scene_read.c
  7. 46 3
      applications/subghz/scenes/subghz_scene_receiver.c
  8. 1 1
      applications/subghz/scenes/subghz_scene_save_name.c
  9. 1 1
      applications/subghz/scenes/subghz_scene_saved.c
  10. 9 7
      applications/subghz/scenes/subghz_scene_set_type.c
  11. 4 1
      applications/subghz/scenes/subghz_scene_start.c
  12. 2 0
      applications/subghz/scenes/subghz_scene_transmitter.c
  13. 5 5
      applications/subghz/subghz_cli.c
  14. 155 0
      applications/subghz/subghz_history.c
  15. 22 0
      applications/subghz/subghz_history.h
  16. 111 17
      applications/subghz/subghz_i.c
  17. 10 6
      applications/subghz/subghz_i.h
  18. 2 2
      applications/subghz/views/subghz_analyze.c
  19. 409 26
      applications/subghz/views/subghz_receiver.c
  20. 18 1
      applications/subghz/views/subghz_receiver.h
  21. 1 1
      applications/subghz/views/subghz_static.c
  22. 1 1
      applications/subghz/views/subghz_test_carrier.c
  23. 1 1
      applications/subghz/views/subghz_test_packet.c
  24. 57 3
      applications/subghz/views/subghz_transmitter.c
  25. 4 0
      applications/subghz/views/subghz_transmitter.h
  26. 6 0
      assets/compiled/assets_icons.c
  27. 6 0
      assets/compiled/assets_icons.h
  28. BIN
      assets/icons/GubGHz/Broadcast_dolph_67-61.png
  29. BIN
      assets/icons/GubGHz/Scanning_dolph_67-61.png
  30. BIN
      assets/icons/GubGHz/Top-frame_128-13.png
  31. BIN
      assets/icons/GubGHz/lock_7x8.png
  32. BIN
      assets/icons/GubGHz/quest_7x8.png
  33. BIN
      assets/icons/GubGHz/unlock_7x8.png
  34. 4 0
      firmware/targets/f6/furi-hal/furi-hal-delay.c
  35. 2 0
      firmware/targets/f6/furi-hal/furi-hal-irda.c
  36. 131 5
      firmware/targets/f6/furi-hal/furi-hal-subghz.c
  37. 3 0
      firmware/targets/furi-hal-include/furi-hal-delay.h
  38. 3 1
      firmware/targets/furi-hal-include/furi-hal-subghz.h
  39. 5 3
      lib/irda/worker/irda_worker.c
  40. 95 48
      lib/subghz/protocols/subghz_protocol.c
  41. 20 8
      lib/subghz/protocols/subghz_protocol_came.c
  42. 4 3
      lib/subghz/protocols/subghz_protocol_came.h
  43. 5 5
      lib/subghz/protocols/subghz_protocol_common.c
  44. 35 18
      lib/subghz/protocols/subghz_protocol_common.h
  45. 18 5
      lib/subghz/protocols/subghz_protocol_faac_slh.c
  46. 2 0
      lib/subghz/protocols/subghz_protocol_faac_slh.h
  47. 21 8
      lib/subghz/protocols/subghz_protocol_gate_tx.c
  48. 4 3
      lib/subghz/protocols/subghz_protocol_gate_tx.h
  49. 64 37
      lib/subghz/protocols/subghz_protocol_ido.c
  50. 1 0
      lib/subghz/protocols/subghz_protocol_ido.h
  51. 62 32
      lib/subghz/protocols/subghz_protocol_keeloq.c
  52. 6 3
      lib/subghz/protocols/subghz_protocol_keeloq.h
  53. 20 8
      lib/subghz/protocols/subghz_protocol_nero_sketch.c
  54. 4 3
      lib/subghz/protocols/subghz_protocol_nero_sketch.h
  55. 22 8
      lib/subghz/protocols/subghz_protocol_nice_flo.c
  56. 4 3
      lib/subghz/protocols/subghz_protocol_nice_flo.h
  57. 17 4
      lib/subghz/protocols/subghz_protocol_nice_flor_s.c
  58. 1 0
      lib/subghz/protocols/subghz_protocol_nice_flor_s.h
  59. 49 26
      lib/subghz/protocols/subghz_protocol_princeton.c
  60. 17 11
      lib/subghz/protocols/subghz_protocol_princeton.h
  61. 29 9
      lib/subghz/protocols/subghz_protocol_star_line.c
  62. 3 0
      lib/subghz/protocols/subghz_protocol_star_line.h
  63. 5 0
      lib/subghz/subghz_worker.c
  64. 6 0
      lib/subghz/subghz_worker.h

+ 1 - 1
applications/applications.c

@@ -148,7 +148,7 @@ const FlipperApplication FLIPPER_APPS[] = {
 #endif
 
 #ifdef APP_SUBGHZ
-    {.app = subghz_app, .name = "Sub-1 GHz", .stack_size = 2048, .icon = &A_Sub1ghz_14},
+    {.app = subghz_app, .name = "Sub-GHz", .stack_size = 2048, .icon = &A_Sub1ghz_14},
 #endif
 
 #ifdef APP_LF_RFID

+ 7 - 7
applications/archive/archive_i.h

@@ -30,7 +30,7 @@ typedef enum {
 static const char* flipper_app_name[] = {
     [ArchiveFileTypeIButton] = "iButton",
     [ArchiveFileTypeNFC] = "NFC",
-    [ArchiveFileTypeSubOne] = "Sub-1 GHz",
+    [ArchiveFileTypeSubGhz] = "Sub-GHz",
     [ArchiveFileTypeLFRFID] = "125 kHz RFID",
     [ArchiveFileTypeIrda] = "Infrared",
 };
@@ -38,7 +38,7 @@ static const char* flipper_app_name[] = {
 static const char* known_ext[] = {
     [ArchiveFileTypeIButton] = ".ibtn",
     [ArchiveFileTypeNFC] = ".nfc",
-    [ArchiveFileTypeSubOne] = ".sub",
+    [ArchiveFileTypeSubGhz] = ".sub",
     [ArchiveFileTypeLFRFID] = ".rfid",
     [ArchiveFileTypeIrda] = ".ir",
 };
@@ -47,7 +47,7 @@ static const char* tab_default_paths[] = {
     [ArchiveTabFavorites] = "/any/favorites",
     [ArchiveTabIButton] = "/any/ibutton",
     [ArchiveTabNFC] = "/any/nfc",
-    [ArchiveTabSubOne] = "/any/subghz/saved",
+    [ArchiveTabSubGhz] = "/any/subghz/saved",
     [ArchiveTabLFRFID] = "/any/lfrfid",
     [ArchiveTabIrda] = "/any/irda",
     [ArchiveTabBrowser] = "/any",
@@ -59,8 +59,8 @@ static inline const char* get_tab_ext(ArchiveTabEnum tab) {
         return known_ext[ArchiveFileTypeIButton];
     case ArchiveTabNFC:
         return known_ext[ArchiveFileTypeNFC];
-    case ArchiveTabSubOne:
-        return known_ext[ArchiveFileTypeSubOne];
+    case ArchiveTabSubGhz:
+        return known_ext[ArchiveFileTypeSubGhz];
     case ArchiveTabLFRFID:
         return known_ext[ArchiveFileTypeLFRFID];
     case ArchiveTabIrda:
@@ -76,8 +76,8 @@ static inline const char* get_default_path(ArchiveFileTypeEnum type) {
         return tab_default_paths[ArchiveTabIButton];
     case ArchiveFileTypeNFC:
         return tab_default_paths[ArchiveTabNFC];
-    case ArchiveFileTypeSubOne:
-        return tab_default_paths[ArchiveTabSubOne];
+    case ArchiveFileTypeSubGhz:
+        return tab_default_paths[ArchiveTabSubGhz];
     case ArchiveFileTypeLFRFID:
         return tab_default_paths[ArchiveTabLFRFID];
     case ArchiveFileTypeIrda:

+ 2 - 2
applications/archive/archive_views.c

@@ -4,7 +4,7 @@ static const char* ArchiveTabNames[] = {
     [ArchiveTabFavorites] = "Favorites",
     [ArchiveTabIButton] = "iButton",
     [ArchiveTabNFC] = "NFC",
-    [ArchiveTabSubOne] = "SubGhz",
+    [ArchiveTabSubGhz] = "Sub-GHz",
     [ArchiveTabLFRFID] = "RFID LF",
     [ArchiveTabIrda] = "Infrared",
     [ArchiveTabBrowser] = "Browser"};
@@ -12,7 +12,7 @@ static const char* ArchiveTabNames[] = {
 static const Icon* ArchiveItemIcons[] = {
     [ArchiveFileTypeIButton] = &I_ibutt_10px,
     [ArchiveFileTypeNFC] = &I_Nfc_10px,
-    [ArchiveFileTypeSubOne] = &I_sub1_10px,
+    [ArchiveFileTypeSubGhz] = &I_sub1_10px,
     [ArchiveFileTypeLFRFID] = &I_125_10px,
     [ArchiveFileTypeIrda] = &I_ir_10px,
     [ArchiveFileTypeFolder] = &I_dir_10px,

+ 2 - 2
applications/archive/archive_views.h

@@ -14,7 +14,7 @@
 typedef enum {
     ArchiveFileTypeIButton,
     ArchiveFileTypeNFC,
-    ArchiveFileTypeSubOne,
+    ArchiveFileTypeSubGhz,
     ArchiveFileTypeLFRFID,
     ArchiveFileTypeIrda,
     ArchiveFileTypeFolder,
@@ -25,7 +25,7 @@ typedef enum {
 typedef enum {
     ArchiveTabFavorites,
     ArchiveTabLFRFID,
-    ArchiveTabSubOne,
+    ArchiveTabSubGhz,
     ArchiveTabNFC,
     ArchiveTabIButton,
     ArchiveTabIrda,

+ 0 - 1
applications/subghz/scenes/subghz_scene_config.h

@@ -1,6 +1,5 @@
 ADD_SCENE(subghz, start, Start)
 ADD_SCENE(subghz, analyze, Analyze)
-ADD_SCENE(subghz, read, Read)
 ADD_SCENE(subghz, receiver, Receiver)
 ADD_SCENE(subghz, save_name, SaveName)
 ADD_SCENE(subghz, save_success, SaveSuccess)

+ 0 - 62
applications/subghz/scenes/subghz_scene_read.c

@@ -1,62 +0,0 @@
-#include "../subghz_i.h"
-
-#define GUBGHZ_READ_CUSTOM_EVENT (10UL)
-
-void subghz_read_protocol_callback(SubGhzProtocolCommon* parser, void* context) {
-    furi_assert(context);
-    SubGhz* subghz = context;
-    subghz->protocol_result = parser;
-    view_dispatcher_send_custom_event(subghz->view_dispatcher, GUBGHZ_READ_CUSTOM_EVENT);
-}
-void subghz_scene_read_callback(DialogExResult result, void* context) {
-    SubGhz* subghz = context;
-    view_dispatcher_send_custom_event(subghz->view_dispatcher, result);
-}
-
-const void subghz_scene_read_on_enter(void* context) {
-    SubGhz* subghz = context;
-
-    // Setup view
-    DialogEx* dialog_ex = subghz->dialog_ex;
-
-    dialog_ex_set_header(dialog_ex, "SubGhz 433.92", 36, 6, AlignLeft, AlignCenter);
-    dialog_ex_set_icon(dialog_ex, 10, 12, &I_RFIDDolphinReceive_97x61);
-
-    //Start CC1101 rx
-    subghz_begin(FuriHalSubGhzPresetOokAsync);
-    subghz_rx(433920000);
-
-    furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz->worker);
-    subghz_worker_start(subghz->worker);
-    subghz_protocol_enable_dump(subghz->protocol, subghz_read_protocol_callback, subghz);
-
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewDialogEx);
-}
-
-const bool subghz_scene_read_on_event(void* context, SceneManagerEvent event) {
-    SubGhz* subghz = context;
-    if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == GUBGHZ_READ_CUSTOM_EVENT) {
-            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiver);
-            notification_message(subghz->notifications, &sequence_success);
-            return true;
-        }
-    } else if(event.type == SceneManagerEventTypeTick) {
-        notification_message(subghz->notifications, &sequence_blink_blue_10);
-        return true;
-    }
-    return false;
-}
-
-const void subghz_scene_read_on_exit(void* context) {
-    SubGhz* subghz = context;
-
-    // Stop CC1101
-    subghz_worker_stop(subghz->worker);
-    furi_hal_subghz_stop_async_rx();
-    subghz_end();
-
-    DialogEx* dialog_ex = subghz->dialog_ex;
-    dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
-    dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
-}

+ 46 - 3
applications/subghz/scenes/subghz_scene_receiver.c

@@ -13,7 +13,9 @@ const void subghz_scene_receiver_on_enter(void* context) {
 
     subghz_receiver_set_callback(subghz_receiver, subghz_scene_receiver_callback, subghz);
 
-    subghz_receiver_set_protocol(subghz_receiver, subghz->protocol_result);
+    subghz_receiver_set_protocol(subghz_receiver, subghz->protocol_result, subghz->protocol);
+    subghz_receiver_set_worker(subghz_receiver, subghz->worker);
+    subghz->state_notifications = NOTIFICATION_RX_STATE;
     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewReceiver);
 }
 
@@ -21,12 +23,53 @@ const bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event
     SubGhz* subghz = context;
 
     if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubghzReceverEventSave) {
+        switch(event.event) {
+        case SubghzReceverEventSave:
+            subghz->state_notifications = NOTIFICATION_IDLE_STATE;
+            subghz->frequency = subghz_receiver_get_frequency(subghz->subghz_receiver);
+            subghz->preset = subghz_receiver_get_preset(subghz->subghz_receiver);
+            subghz->protocol_result = subghz_receiver_get_protocol(subghz->subghz_receiver);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
             return true;
-        } else if(event.event == SubghzReceverEventBack) {
+            break;
+        case SubghzReceverEventBack:
             scene_manager_previous_scene(subghz->scene_manager);
             return true;
+            break;
+        case SubghzReceverEventSendStart:
+            subghz->state_notifications = NOTIFICATION_TX_STATE;
+            subghz->frequency = subghz_receiver_get_frequency(subghz->subghz_receiver);
+            subghz->preset = subghz_receiver_get_preset(subghz->subghz_receiver);
+            subghz->protocol_result = subghz_receiver_get_protocol(subghz->subghz_receiver);
+            subghz_transmitter_tx_start(subghz);
+            return true;
+            break;
+        case SubghzReceverEventSendStop:
+            subghz->state_notifications = NOTIFICATION_IDLE_STATE;
+            subghz_transmitter_tx_stop(subghz);
+            return true;
+            break;
+        case SubghzReceverEventMain:
+            subghz->state_notifications = NOTIFICATION_RX_STATE;
+            return true;
+            break;
+        case SubghzReceverEventConfig:
+            subghz->state_notifications = NOTIFICATION_IDLE_STATE;
+            return true;
+            break;
+        default:
+            break;
+        }
+    } else if(event.type == SceneManagerEventTypeTick) {
+        switch(subghz->state_notifications) {
+        case NOTIFICATION_TX_STATE:
+            notification_message(subghz->notifications, &sequence_blink_red_10);
+            break;
+        case NOTIFICATION_RX_STATE:
+            notification_message(subghz->notifications, &sequence_blink_blue_10);
+            break;
+        default:
+            break;
         }
     }
     return false;

+ 1 - 1
applications/subghz/scenes/subghz_scene_save_name.c

@@ -19,7 +19,7 @@ const void subghz_scene_save_name_on_enter(void* context) {
     set_random_name(subghz->text_store, sizeof(subghz->text_store));
     dev_name_empty = true;
 
-    text_input_set_header_text(text_input, "Name the KEY");
+    text_input_set_header_text(text_input, "Name signal");
     text_input_set_result_callback(
         text_input,
         subghz_scene_save_name_text_input_callback,

+ 1 - 1
applications/subghz/scenes/subghz_scene_saved.c

@@ -3,7 +3,7 @@
 const void subghz_scene_saved_on_enter(void* context) {
     SubGhz* subghz = context;
 
-    if(subghz_saved_protocol_select(subghz)) {
+    if(subghz_load_protocol_from_file(subghz)) {
         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter);
     } else {
         scene_manager_search_and_switch_to_previous_scene(subghz->scene_manager, SubGhzSceneStart);

+ 9 - 7
applications/subghz/scenes/subghz_scene_set_type.c

@@ -32,31 +32,31 @@ const void subghz_scene_set_type_on_enter(void* context) {
 
     submenu_add_item(
         subghz->submenu,
-        "Pricenton",
+        "Princeton_433",
         SubmenuIndexPricenton,
         subghz_scene_set_type_submenu_callback,
         subghz);
     submenu_add_item(
         subghz->submenu,
-        "Nice Flo 12bit",
+        "Nice Flo 12bit_433",
         SubmenuIndexNiceFlo12bit,
         subghz_scene_set_type_submenu_callback,
         subghz);
     submenu_add_item(
         subghz->submenu,
-        "Nice Flo 24bit",
+        "Nice Flo 24bit_433",
         SubmenuIndexNiceFlo24bit,
         subghz_scene_set_type_submenu_callback,
         subghz);
     submenu_add_item(
         subghz->submenu,
-        "CAME 12bit",
+        "CAME 12bit_433",
         SubmenuIndexCAME12bit,
         subghz_scene_set_type_submenu_callback,
         subghz);
     submenu_add_item(
         subghz->submenu,
-        "CAME 24bit",
+        "CAME 24bit_433",
         SubmenuIndexCAME24bit,
         subghz_scene_set_type_submenu_callback,
         subghz);
@@ -64,13 +64,13 @@ const void subghz_scene_set_type_on_enter(void* context) {
     //     subghz->submenu, "Nero Sketch", SubmenuIndexNeroSketch, subghz_scene_set_type_submenu_callback, subghz);
     submenu_add_item(
         subghz->submenu,
-        "Gate TX",
+        "Gate TX_433",
         SubmenuIndexGateTX,
         subghz_scene_set_type_submenu_callback,
         subghz);
     submenu_add_item(
         subghz->submenu,
-        "DoorHan",
+        "DoorHan_433",
         SubmenuIndexDoorHan,
         subghz_scene_set_type_submenu_callback,
         subghz);
@@ -159,6 +159,8 @@ const bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event
             break;
         }
         if(generated_protocol) {
+            subghz->frequency = subghz_frequencies[subghz_frequencies_433_92];
+            subghz->preset = FuriHalSubGhzPresetOok650Async;
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
             return true;
         }

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

@@ -56,9 +56,12 @@ const bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) {
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneAnalyze);
             return true;
         } else if(event.event == SubmenuIndexRead) {
+            // scene_manager_set_scene_state(
+            //     subghz->scene_manager, SubGhzSceneStart, SubmenuIndexRead);
+            // scene_manager_next_scene(subghz->scene_manager, SubGhzSceneRead);
             scene_manager_set_scene_state(
                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexRead);
-            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneRead);
+            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiver);
             return true;
         } else if(event.event == SubmenuIndexSaved) {
             scene_manager_set_scene_state(

+ 2 - 0
applications/subghz/scenes/subghz_scene_transmitter.c

@@ -13,6 +13,7 @@ const void subghz_scene_transmitter_on_enter(void* context) {
 
     subghz_transmitter_set_callback(subghz_transmitter, subghz_scene_transmitter_callback, subghz);
     subghz_transmitter_set_protocol(subghz_transmitter, subghz->protocol_result);
+    subghz_transmitter_set_frequency_preset(subghz_transmitter, subghz->frequency, subghz->preset);
 
     view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTransmitter);
 
@@ -30,6 +31,7 @@ const bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent ev
         } else if(event.event == SubghzTransmitterEventSendStop) {
             subghz->state_notifications = NOTIFICATION_IDLE_STATE;
             subghz_transmitter_tx_stop(subghz);
+            subghz_sleep();
             return true;
         } else if(event.event == SubghzTransmitterEventBack) {
             subghz->state_notifications = NOTIFICATION_IDLE_STATE;

+ 5 - 5
applications/subghz/subghz_cli.c

@@ -42,7 +42,7 @@ void subghz_cli_command_tx_carrier(Cli* cli, string_t args, void* context) {
     }
 
     furi_hal_subghz_reset();
-    furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync);
+    furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
     frequency = furi_hal_subghz_set_frequency_and_path(frequency);
 
     hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
@@ -79,7 +79,7 @@ void subghz_cli_command_rx_carrier(Cli* cli, string_t args, void* context) {
     }
 
     furi_hal_subghz_reset();
-    furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync);
+    furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
     frequency = furi_hal_subghz_set_frequency_and_path(frequency);
     printf("Receiving at frequency %lu Hz\r\n", frequency);
     printf("Press CTRL+C to stop\r\n");
@@ -134,12 +134,12 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) {
     protocol->common.code_last_found = key;
     protocol->common.code_last_count_bit = 24;
 
-    SubGhzProtocolEncoderCommon* encoder = subghz_protocol_encoder_common_alloc();
+    SubGhzProtocolCommonEncoder* encoder = subghz_protocol_encoder_common_alloc();
     encoder->repeat = repeat;
 
     subghz_protocol_princeton_send_key(protocol, encoder);
     furi_hal_subghz_reset();
-    furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync);
+    furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
     frequency = furi_hal_subghz_set_frequency_and_path(frequency);
     furi_hal_subghz_start_async_tx(subghz_protocol_encoder_common_yield, encoder);
 
@@ -212,7 +212,7 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
 
     // Configure radio
     furi_hal_subghz_reset();
-    furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync);
+    furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
     frequency = furi_hal_subghz_set_frequency_and_path(frequency);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
 

+ 155 - 0
applications/subghz/subghz_history.c

@@ -0,0 +1,155 @@
+#include "subghz_history.h"
+#include <lib/subghz/protocols/subghz_protocol_keeloq.h>
+#include <lib/subghz/protocols/subghz_protocol_star_line.h>
+#include <lib/subghz/protocols/subghz_protocol_princeton.h>
+
+#include <furi.h>
+#include <m-string.h>
+
+#define SUBGHZ_HISTORY_MAX 20
+
+typedef struct SubGhzHistoryStruct SubGhzHistoryStruct;
+
+struct SubGhzHistoryStruct {
+    const char* name;
+    const char* manufacture_name;
+    uint8_t type_protocol;
+    uint8_t code_count_bit;
+    uint64_t code_found;
+    uint16_t te;
+    FuriHalSubGhzPreset preset;
+    uint32_t real_frequency;
+};
+
+struct SubGhzHistory {
+    uint32_t last_update_timestamp;
+    uint16_t last_index_write;
+    uint64_t code_last_found;
+    SubGhzHistoryStruct history[SUBGHZ_HISTORY_MAX];
+    SubGhzProtocolCommonLoad data;
+};
+
+SubGhzHistory* subghz_history_alloc(void) {
+    SubGhzHistory* instance = furi_alloc(sizeof(SubGhzHistory));
+    return instance;
+}
+
+void subghz_history_free(SubGhzHistory* instance) {
+    furi_assert(instance);
+    free(instance);
+}
+
+void subghz_history_set_frequency_preset(
+    SubGhzHistory* instance,
+    uint16_t idx,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    furi_assert(instance);
+    if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return;
+    instance->history[idx].preset = preset;
+    instance->history[idx].real_frequency = frequency;
+}
+
+uint32_t subghz_history_get_frequency(SubGhzHistory* instance, uint16_t idx) {
+    furi_assert(instance);
+    return instance->history[idx].real_frequency;
+}
+
+FuriHalSubGhzPreset subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx) {
+    furi_assert(instance);
+    return instance->history[idx].preset;
+}
+
+void subghz_history_clean(SubGhzHistory* instance) {
+    furi_assert(instance);
+    instance->last_index_write = 0;
+    instance->code_last_found = 0;
+}
+
+uint16_t subghz_history_get_item(SubGhzHistory* instance) {
+    furi_assert(instance);
+    return instance->last_index_write;
+}
+
+uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx) {
+    furi_assert(instance);
+    return instance->history[idx].type_protocol;
+}
+
+const char* subghz_history_get_name(SubGhzHistory* instance, uint16_t idx) {
+    furi_assert(instance);
+    return instance->history[idx].name;
+}
+
+SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx) {
+    furi_assert(instance);
+    instance->data.code_found = instance->history[idx].code_found;
+    instance->data.code_count_bit = instance->history[idx].code_count_bit;
+    instance->data.param1 = instance->history[idx].te;
+    return &instance->data;
+}
+
+void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output, uint16_t idx) {
+    if(instance->history[idx].code_count_bit < 33) {
+        string_printf(
+            output,
+            "%s %lX",
+            instance->history[idx].name,
+            (uint32_t)(instance->history[idx].code_found & 0xFFFFFFFF));
+    } else {
+        string_t str_buff;
+        string_init(str_buff);
+        if(strcmp(instance->history[idx].name, "KeeLoq") == 0) {
+            string_set(str_buff, "KL ");
+            string_cat(str_buff, instance->history[idx].manufacture_name);
+        } else if(strcmp(instance->history[idx].name, "Star Line") == 0) {
+            string_set(str_buff, "SL ");
+            string_cat(str_buff, instance->history[idx].manufacture_name);
+        } else {
+            string_set(str_buff, instance->history[idx].name);
+        }
+
+        string_printf(
+            output,
+            "%s %lX%08lX",
+            string_get_cstr(str_buff),
+            (uint32_t)(instance->history[idx].code_found >> 32),
+            (uint32_t)(instance->history[idx].code_found & 0xFFFFFFFF));
+        string_clear(str_buff);
+    }
+}
+
+void subghz_history_add_to_history(SubGhzHistory* instance, void* context) {
+    furi_assert(instance);
+    furi_assert(context);
+    SubGhzProtocolCommon* protocol = context;
+
+    if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return;
+    if((instance->code_last_found == (protocol->code_last_found & 0xFFFF0FFFFFFFFFFF)) &&
+       ((millis() - instance->last_update_timestamp) < 500)) {
+        instance->last_update_timestamp = millis();
+        return;
+    }
+
+    instance->code_last_found = protocol->code_last_found & 0xFFFF0FFFFFFFFFFF;
+    instance->last_update_timestamp = millis();
+
+    instance->history[instance->last_index_write].te = 0;
+    instance->history[instance->last_index_write].manufacture_name = NULL;
+    instance->history[instance->last_index_write].name = protocol->name;
+    instance->history[instance->last_index_write].code_count_bit = protocol->code_last_count_bit;
+    instance->history[instance->last_index_write].code_found = protocol->code_last_found;
+    if(strcmp(protocol->name, "KeeLoq") == 0) {
+        instance->history[instance->last_index_write].manufacture_name =
+            subghz_protocol_keeloq_get_manufacture_name(protocol);
+    } else if(strcmp(protocol->name, "Star Line") == 0) {
+        instance->history[instance->last_index_write].manufacture_name =
+            subghz_protocol_star_line_get_manufacture_name(protocol);
+    } else if(strcmp(protocol->name, "Princeton") == 0) {
+        instance->history[instance->last_index_write].te =
+            subghz_protocol_princeton_get_te(protocol);
+    }
+    instance->history[instance->last_index_write].type_protocol = protocol->type_protocol;
+
+    instance->last_index_write++;
+}

+ 22 - 0
applications/subghz/subghz_history.h

@@ -0,0 +1,22 @@
+#pragma once
+
+#include <lib/subghz/protocols/subghz_protocol_common.h>
+
+typedef struct SubGhzHistory SubGhzHistory;
+
+SubGhzHistory* subghz_history_alloc(void);
+void subghz_history_free(SubGhzHistory* instance);
+void subghz_history_clean(SubGhzHistory* instance);
+void subghz_history_set_frequency_preset(
+    SubGhzHistory* instance,
+    uint16_t idx,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset);
+uint32_t subghz_history_get_frequency(SubGhzHistory* instance, uint16_t idx);
+FuriHalSubGhzPreset subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx);
+uint16_t subghz_history_get_item(SubGhzHistory* instance);
+uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx);
+const char* subghz_history_get_name(SubGhzHistory* instance, uint16_t idx);
+void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output, uint16_t idx);
+void subghz_history_add_to_history(SubGhzHistory* instance, void* context);
+SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx);

+ 111 - 17
applications/subghz/subghz_i.c

@@ -8,6 +8,7 @@
 #include <notification/notification-messages.h>
 #include "file-worker.h"
 #include "../notification/notification.h"
+#include "views/subghz_receiver.h"
 
 void subghz_begin(FuriHalSubGhzPreset preset) {
     furi_hal_subghz_reset();
@@ -16,30 +17,59 @@ void subghz_begin(FuriHalSubGhzPreset preset) {
     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
 }
 
-void subghz_rx(uint32_t frequency) {
+uint32_t subghz_rx(void* context, uint32_t frequency) {
+    furi_assert(context);
+    SubGhzWorker* worker = context;
+
     furi_hal_subghz_idle();
-    furi_hal_subghz_set_frequency_and_path(frequency);
+    uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
     furi_hal_subghz_flush_rx();
     furi_hal_subghz_rx();
+
+    furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, worker);
+    subghz_worker_start(worker);
+    return value;
 }
 
-void subghz_tx(uint32_t frequency) {
+uint32_t subghz_tx(uint32_t frequency) {
     furi_hal_subghz_idle();
-    furi_hal_subghz_set_frequency_and_path(frequency);
+    uint32_t value = furi_hal_subghz_set_frequency_and_path(frequency);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
     hal_gpio_write(&gpio_cc1101_g0, true);
     furi_hal_subghz_tx();
+    return value;
 }
 
 void subghz_idle(void) {
     furi_hal_subghz_idle();
 }
 
-void subghz_end(void) {
+void subghz_rx_end(void* context) {
+    furi_assert(context);
+    SubGhzWorker* worker = context;
+
+    if(subghz_worker_is_running(worker)) {
+        subghz_worker_stop(worker);
+        furi_hal_subghz_stop_async_rx();
+    }
+}
+
+void subghz_sleep(void) {
     furi_hal_subghz_sleep();
 }
 
+void subghz_frequency_preset_to_str(void* context, string_t output) {
+    furi_assert(context);
+    SubGhz* subghz = context;
+    string_cat_printf(
+        output,
+        "Frequency: %d\n"
+        "Preset: %d\n",
+        (int)subghz->frequency,
+        (int)subghz->preset);
+}
+
 void subghz_transmitter_tx_start(void* context) {
     SubGhz* subghz = context;
     subghz->encoder = subghz_protocol_encoder_common_alloc();
@@ -47,8 +77,17 @@ void subghz_transmitter_tx_start(void* context) {
     //get upload
     if(subghz->protocol_result->get_upload_protocol) {
         if(subghz->protocol_result->get_upload_protocol(subghz->protocol_result, subghz->encoder)) {
-            subghz_begin(FuriHalSubGhzPresetOokAsync);
-            subghz_tx(433920000);
+            if(subghz->preset) {
+                subghz_begin(subghz->preset);
+            } else {
+                subghz_begin(FuriHalSubGhzPresetOok650Async);
+            }
+            if(subghz->frequency) {
+                subghz_tx(subghz->frequency);
+            } else {
+                subghz_tx(433920000);
+            }
+
             //Start TX
             furi_hal_subghz_start_async_tx(subghz_protocol_encoder_common_yield, subghz->encoder);
         }
@@ -59,7 +98,6 @@ void subghz_transmitter_tx_stop(void* context) {
     SubGhz* subghz = context;
     //Stop TX
     furi_hal_subghz_stop_async_tx();
-    subghz_end();
     subghz_protocol_encoder_common_free(subghz->encoder);
     //if protocol dynamic then we save the last upload
     if(subghz->protocol_result->type_protocol == TYPE_PROTOCOL_DYNAMIC) {
@@ -79,12 +117,35 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) {
     string_init_set_str(path, file_path);
     string_t temp_str;
     string_init(temp_str);
+    int res = 0;
+    int data = 0;
 
     do {
         if(!file_worker_open(file_worker, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
             break;
         }
-        // Read and parse name protocol from 1st line
+
+        // Read and parse frequency from 1st line
+        if(!file_worker_read_until(file_worker, temp_str, '\n')) {
+            break;
+        }
+        res = sscanf(string_get_cstr(temp_str), "Frequency: %d\n", &data);
+        if(res != 1) {
+            break;
+        }
+        subghz->frequency = (uint32_t)data;
+
+        // Read and parse preset from 2st line
+        if(!file_worker_read_until(file_worker, temp_str, '\n')) {
+            break;
+        }
+        res = sscanf(string_get_cstr(temp_str), "Preset: %d\n", &data);
+        if(res != 1) {
+            break;
+        }
+        subghz->preset = (FuriHalSubGhzPreset)data;
+
+        // Read and parse name protocol from 2st line
         if(!file_worker_read_until(file_worker, temp_str, '\n')) {
             break;
         }
@@ -93,16 +154,18 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) {
         subghz->protocol_result =
             subghz_protocol_get_by_name(subghz->protocol, string_get_cstr(temp_str));
         if(subghz->protocol_result == NULL) {
-            file_worker_show_error(file_worker, "Cannot parse\nfile");
             break;
         }
-        if(!subghz->protocol_result->to_load_protocol(file_worker, subghz->protocol_result)) {
-            file_worker_show_error(file_worker, "Cannot parse\nfile");
+        if(!subghz->protocol_result->to_load_protocol_from_file(
+               file_worker, subghz->protocol_result)) {
             break;
         }
         loaded = true;
     } while(0);
 
+    if(!loaded) {
+        file_worker_show_error(file_worker, "Cannot parse\nfile");
+    }
     string_clear(temp_str);
     string_clear(path);
     file_worker_close(file_worker);
@@ -113,6 +176,7 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) {
 
 bool subghz_save_protocol_to_file(void* context, const char* dev_name) {
     SubGhz* subghz = context;
+    furi_assert(subghz->protocol_result);
     FileWorker* file_worker = file_worker_alloc(false);
     string_t dev_file_name;
     string_init(dev_file_name);
@@ -140,6 +204,11 @@ bool subghz_save_protocol_to_file(void* context, const char* dev_name) {
                file_worker, string_get_cstr(dev_file_name), FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
             break;
         }
+        //Get string frequency preset protocol
+        subghz_frequency_preset_to_str(subghz, temp_str);
+        if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_size(temp_str))) {
+            break;
+        }
         //Get string save
         subghz->protocol_result->to_save_string(subghz->protocol_result, temp_str);
         // Prepare and write data to file
@@ -157,7 +226,7 @@ bool subghz_save_protocol_to_file(void* context, const char* dev_name) {
     return saved;
 }
 
-bool subghz_saved_protocol_select(SubGhz* subghz) {
+bool subghz_load_protocol_from_file(SubGhz* subghz) {
     furi_assert(subghz);
 
     FileWorker* file_worker = file_worker_alloc(false);
@@ -165,6 +234,8 @@ bool subghz_saved_protocol_select(SubGhz* subghz) {
     string_init(protocol_file_name);
     string_t temp_str;
     string_init(temp_str);
+    int sscanf_res = 0;
+    int data = 0;
 
     // Input events and views are managed by file_select
     bool res = file_worker_file_select(
@@ -197,7 +268,27 @@ bool subghz_saved_protocol_select(SubGhz* subghz) {
                file_worker, string_get_cstr(protocol_file_name), FSAM_READ, FSOM_OPEN_EXISTING)) {
             break;
         }
-        // Read and parse name protocol from 1st line
+        // Read and parse frequency from 1st line
+        if(!file_worker_read_until(file_worker, temp_str, '\n')) {
+            break;
+        }
+        sscanf_res = sscanf(string_get_cstr(temp_str), "Frequency: %d\n", &data);
+        if(sscanf_res != 1) {
+            break;
+        }
+        subghz->frequency = (uint32_t)data;
+
+        // Read and parse preset from 2st line
+        if(!file_worker_read_until(file_worker, temp_str, '\n')) {
+            break;
+        }
+        sscanf_res = sscanf(string_get_cstr(temp_str), "Preset: %d\n", &data);
+        if(sscanf_res != 1) {
+            break;
+        }
+        subghz->preset = (FuriHalSubGhzPreset)data;
+
+        // Read and parse name protocol from 3st line
         if(!file_worker_read_until(file_worker, temp_str, '\n')) {
             break;
         }
@@ -206,16 +297,19 @@ bool subghz_saved_protocol_select(SubGhz* subghz) {
         subghz->protocol_result =
             subghz_protocol_get_by_name(subghz->protocol, string_get_cstr(temp_str));
         if(subghz->protocol_result == NULL) {
-            file_worker_show_error(file_worker, "Cannot parse\nfile");
             break;
         }
-        if(!subghz->protocol_result->to_load_protocol(file_worker, subghz->protocol_result)) {
-            file_worker_show_error(file_worker, "Cannot parse\nfile");
+        if(!subghz->protocol_result->to_load_protocol_from_file(
+               file_worker, subghz->protocol_result)) {
             break;
         }
         res = true;
     } while(0);
 
+    if(!res) {
+        file_worker_show_error(file_worker, "Cannot parse\nfile");
+    }
+
     string_clear(temp_str);
     string_clear(protocol_file_name);
 

+ 10 - 6
applications/subghz/subghz_i.h

@@ -25,12 +25,14 @@
 #include <lib/subghz/subghz_worker.h>
 #include <lib/subghz/protocols/subghz_protocol.h>
 #include <lib/subghz/protocols/subghz_protocol_common.h>
+#include "subghz_history.h"
 
 #define SUBGHZ_TEXT_STORE_SIZE 128
 
 #define NOTIFICATION_STARTING_STATE 0u
 #define NOTIFICATION_IDLE_STATE 1u
 #define NOTIFICATION_TX_STATE 2u
+#define NOTIFICATION_RX_STATE 3u
 
 extern const uint32_t subghz_frequencies[];
 extern const uint32_t subghz_frequencies_count;
@@ -43,10 +45,11 @@ struct SubGhz {
     SubGhzWorker* worker;
     SubGhzProtocol* protocol;
     SubGhzProtocolCommon* protocol_result;
-    SubGhzProtocolEncoderCommon* encoder;
+    SubGhzProtocolCommonEncoder* encoder;
+    uint32_t frequency;
+    FuriHalSubGhzPreset preset;
 
     SceneManager* scene_manager;
-
     ViewDispatcher* view_dispatcher;
 
     Submenu* submenu;
@@ -81,13 +84,14 @@ typedef enum {
 } SubGhzView;
 
 void subghz_begin(FuriHalSubGhzPreset preset);
-void subghz_rx(uint32_t frequency);
-void subghz_tx(uint32_t frequency);
+uint32_t subghz_rx(void* context, uint32_t frequency);
+uint32_t subghz_tx(uint32_t frequency);
 void subghz_idle(void);
-void subghz_end(void);
+void subghz_rx_end(void* context);
+void subghz_sleep(void);
 void subghz_transmitter_tx_start(void* context);
 void subghz_transmitter_tx_stop(void* context);
 bool subghz_key_load(SubGhz* subghz, const char* file_path);
 bool subghz_save_protocol_to_file(void* context, const char* dev_name);
-bool subghz_saved_protocol_select(SubGhz* subghz);
+bool subghz_load_protocol_from_file(SubGhz* subghz);
 uint32_t subghz_random_serial(void);

+ 2 - 2
applications/subghz/views/subghz_analyze.c

@@ -58,7 +58,7 @@ void subghz_analyze_draw(Canvas* canvas, SubghzAnalyzeModel* model) {
 
     default:
         canvas_set_font(canvas, FontSecondary);
-        elements_multiline_text(canvas, 0, 20, string_get_cstr(model->text));
+        elements_multiline_text(canvas, 0, 18, string_get_cstr(model->text));
         break;
     }
 }
@@ -144,7 +144,7 @@ void subghz_analyze_enter(void* context) {
 
     furi_hal_subghz_reset();
     furi_hal_subghz_idle();
-    furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync);
+    furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
 
     with_view_model(
         subghz_analyze->view, (SubghzAnalyzeModel * model) {

+ 409 - 26
applications/subghz/views/subghz_receiver.c

@@ -1,25 +1,55 @@
 #include "subghz_receiver.h"
 #include "../subghz_i.h"
-
 #include <math.h>
 #include <furi.h>
 #include <furi-hal.h>
 #include <input/input.h>
 #include <gui/elements.h>
 #include <notification/notification-messages.h>
+#include <lib/subghz/protocols/subghz_protocol_princeton.h>
 
 #include <assets_icons.h>
 
+#define FRAME_HEIGHT 12
+#define MAX_LEN_PX 100
+#define MENU_ITEMS 4
+
+typedef enum {
+    ReceiverSceneStart,
+    ReceiverSceneMain,
+    ReceiverSceneConfig,
+    ReceiverSceneInfo,
+} SubghzReceiverScene;
+
+static const Icon* ReceiverItemIcons[] = {
+    [TYPE_PROTOCOL_UNKNOWN] = &I_quest_7x8,
+    [TYPE_PROTOCOL_STATIC] = &I_unlock_7x8,
+    [TYPE_PROTOCOL_DYNAMIC] = &I_lock_7x8,
+};
+
 struct SubghzReceiver {
     View* view;
     SubghzReceiverCallback callback;
     void* context;
+    SubGhzWorker* worker;
+    SubGhzProtocol* protocol;
 };
 
 typedef struct {
     string_t text;
     uint16_t scene;
-    SubGhzProtocolCommon* protocol;
+    SubGhzProtocolCommon* protocol_result;
+    SubGhzHistory* history;
+    uint8_t frequency;
+    uint8_t temp_frequency;
+    uint32_t real_frequency;
+
+    uint8_t tab_idx;
+    uint8_t menu_idx;
+    uint16_t idx;
+    uint16_t list_offset;
+    uint16_t history_item;
+    bool menu;
 } SubghzReceiverModel;
 
 void subghz_receiver_set_callback(
@@ -32,50 +62,323 @@ void subghz_receiver_set_callback(
     subghz_receiver->context = context;
 }
 
-void subghz_receiver_set_protocol(SubghzReceiver* subghz_receiver, SubGhzProtocolCommon* protocol) {
+void subghz_receiver_set_protocol(
+    SubghzReceiver* subghz_receiver,
+    SubGhzProtocolCommon* protocol_result,
+    SubGhzProtocol* protocol) {
+    furi_assert(subghz_receiver);
     with_view_model(
         subghz_receiver->view, (SubghzReceiverModel * model) {
-            model->protocol = protocol;
+            model->protocol_result = protocol_result;
             return true;
         });
+    subghz_receiver->protocol = protocol;
+}
+
+SubGhzProtocolCommon* subghz_receiver_get_protocol(SubghzReceiver* subghz_receiver) {
+    furi_assert(subghz_receiver);
+    SubGhzProtocolCommon* result = NULL;
+    with_view_model(
+        subghz_receiver->view, (SubghzReceiverModel * model) {
+            result = model->protocol_result;
+            return false;
+        });
+    return result;
+}
+
+void subghz_receiver_set_worker(SubghzReceiver* subghz_receiver, SubGhzWorker* worker) {
+    furi_assert(subghz_receiver);
+    subghz_receiver->worker = worker;
+}
+
+static void subghz_receiver_update_offset(SubghzReceiver* subghz_receiver) {
+    furi_assert(subghz_receiver);
+
+    with_view_model(
+        subghz_receiver->view, (SubghzReceiverModel * model) {
+            size_t history_item = model->history_item;
+            uint16_t bounds = history_item > 3 ? 2 : history_item;
+
+            if(history_item > 3 && model->idx >= history_item - 1) {
+                model->list_offset = model->idx - 3;
+            } else if(model->list_offset < model->idx - bounds) {
+                model->list_offset = CLAMP(model->list_offset + 1, history_item - bounds, 0);
+            } else if(model->list_offset > model->idx - bounds) {
+                model->list_offset = CLAMP(model->idx - 1, history_item - bounds, 0);
+            }
+            return true;
+        });
+}
+
+static void subghz_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) {
+    canvas_set_color(canvas, ColorBlack);
+    canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT);
+
+    canvas_set_color(canvas, ColorWhite);
+    canvas_draw_dot(canvas, 0, 0 + idx * FRAME_HEIGHT);
+    canvas_draw_dot(canvas, 1, 0 + idx * FRAME_HEIGHT);
+    canvas_draw_dot(canvas, 0, (0 + idx * FRAME_HEIGHT) + 1);
+
+    canvas_draw_dot(canvas, 0, (0 + idx * FRAME_HEIGHT) + 11);
+    canvas_draw_dot(canvas, scrollbar ? 121 : 126, 0 + idx * FRAME_HEIGHT);
+    canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11);
 }
 
 void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
+    bool scrollbar = model->history_item > 4;
+    string_t str_buff;
+    char buffer[64];
+    string_init(str_buff);
+
     canvas_clear(canvas);
     canvas_set_color(canvas, ColorBlack);
-    canvas_set_font(canvas, FontSecondary);
-    elements_multiline_text(canvas, 0, 10, string_get_cstr(model->text));
 
-    elements_button_left(canvas, "Back");
-    if(model->protocol && model->protocol->to_save_string &&
-       strcmp(model->protocol->name, "KeeLoq")) {
-        elements_button_right(canvas, "Save");
+    switch(model->scene) {
+    case ReceiverSceneMain:
+        for(size_t i = 0; i < MIN(model->history_item, MENU_ITEMS); ++i) {
+            size_t idx = CLAMP(i + model->list_offset, model->history_item, 0);
+            subghz_history_get_text_item_menu(model->history, str_buff, idx);
+            elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX);
+            if(model->idx == idx) {
+                subghz_receiver_draw_frame(canvas, i, scrollbar);
+            } else {
+                canvas_set_color(canvas, ColorBlack);
+            }
+            canvas_draw_icon(
+                canvas,
+                1,
+                2 + i * FRAME_HEIGHT,
+                ReceiverItemIcons[subghz_history_get_type_protocol(model->history, idx)]);
+            canvas_draw_str(canvas, 15, 9 + i * FRAME_HEIGHT, string_get_cstr(str_buff));
+            string_clean(str_buff);
+        }
+        if(scrollbar) {
+            elements_scrollbar_pos(canvas, 126, 0, 49, model->idx, model->history_item);
+        }
+        canvas_set_color(canvas, ColorBlack);
+        canvas_set_font(canvas, FontPrimary);
+        snprintf(
+            buffer,
+            sizeof(buffer),
+            "%03ld.%03ld  OOK",
+            model->real_frequency / 1000000 % 1000,
+            model->real_frequency / 1000 % 1000);
+        canvas_draw_str(canvas, 60, 61, buffer);
+        elements_button_left(canvas, "Config");
+        break;
+
+    case ReceiverSceneStart:
+        canvas_draw_icon(canvas, 0, 0, &I_RFIDDolphinReceive_97x61);
+        canvas_invert_color(canvas);
+        canvas_draw_box(canvas, 80, 2, 20, 20);
+        canvas_invert_color(canvas);
+        canvas_draw_icon(canvas, 75, 8, &I_sub1_10px);
+        canvas_set_font(canvas, FontPrimary);
+        canvas_draw_str(canvas, 63, 40, "Scanning...");
+        canvas_set_color(canvas, ColorBlack);
+        canvas_set_font(canvas, FontPrimary);
+        snprintf(
+            buffer,
+            sizeof(buffer),
+            "%03ld.%03ld  OOK",
+            model->real_frequency / 1000000 % 1000,
+            model->real_frequency / 1000 % 1000);
+        canvas_draw_str(canvas, 60, 61, buffer);
+        elements_button_left(canvas, "Config");
+        break;
+
+    case ReceiverSceneConfig:
+        snprintf(
+            buffer,
+            sizeof(buffer),
+            "Frequency:  < %03ld.%03ldMHz >",
+            model->real_frequency / 1000000 % 1000,
+            model->real_frequency / 1000 % 1000);
+        canvas_draw_str(canvas, 0, 8, buffer);
+        elements_button_center(canvas, "Save");
+        break;
+
+    case ReceiverSceneInfo:
+        canvas_set_font(canvas, FontSecondary);
+        elements_multiline_text(canvas, 0, 8, string_get_cstr(model->text));
+        snprintf(
+            buffer,
+            sizeof(buffer),
+            "%03ld.%03ld",
+            subghz_history_get_frequency(model->history, model->idx) / 1000000 % 1000,
+            subghz_history_get_frequency(model->history, model->idx) / 1000 % 1000);
+        canvas_draw_str(canvas, 90, 8, buffer);
+        if(model->protocol_result && model->protocol_result->to_save_string &&
+           strcmp(model->protocol_result->name, "KeeLoq")) {
+            elements_button_right(canvas, "Save");
+            elements_button_center(canvas, "Send");
+        }
+        break;
+
+    default:
+
+        break;
     }
+
+    string_clear(str_buff);
 }
 
 bool subghz_receiver_input(InputEvent* event, void* context) {
     furi_assert(context);
-    SubghzReceiver* subghz_receiver = context;
 
-    if(event->type != InputTypeShort) return false;
-
-    bool can_be_saved = false;
+    uint8_t scene = 0;
+    SubghzReceiver* subghz_receiver = context;
     with_view_model(
         subghz_receiver->view, (SubghzReceiverModel * model) {
-            can_be_saved =
-                (model->protocol && model->protocol->to_save_string &&
-                 strcmp(model->protocol->name, "KeeLoq"));
+            scene = model->scene;
             return false;
         });
 
-    if(event->key == InputKeyBack) {
-        return false;
-    } else if(event->key == InputKeyLeft) {
-        subghz_receiver->callback(SubghzReceverEventBack, subghz_receiver->context);
-    } else if(can_be_saved && event->key == InputKeyRight) {
-        subghz_receiver->callback(SubghzReceverEventSave, subghz_receiver->context);
+    if(scene != ReceiverSceneInfo && event->type != InputTypeShort) return false;
+
+    bool can_be_saved = false;
+
+    switch(scene) {
+    case ReceiverSceneMain:
+        if(event->key == InputKeyBack) {
+            return false;
+        } else if(event->key == InputKeyUp) {
+            with_view_model(
+                subghz_receiver->view, (SubghzReceiverModel * model) {
+                    if(model->idx != 0) model->idx--;
+                    return true;
+                });
+        } else if(event->key == InputKeyDown) {
+            with_view_model(
+                subghz_receiver->view, (SubghzReceiverModel * model) {
+                    if(model->idx != subghz_history_get_item(model->history) - 1) model->idx++;
+                    return true;
+                });
+        } else if(event->key == InputKeyLeft) {
+            with_view_model(
+                subghz_receiver->view, (SubghzReceiverModel * model) {
+                    model->scene = ReceiverSceneConfig;
+                    model->temp_frequency = model->frequency;
+                    return true;
+                });
+            subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context);
+        } else if(event->key == InputKeyOk) {
+            with_view_model(
+                subghz_receiver->view, (SubghzReceiverModel * model) {
+                    string_clean(model->text);
+                    model->protocol_result = subghz_protocol_get_by_name(
+                        subghz_receiver->protocol,
+                        subghz_history_get_name(model->history, model->idx));
+                    if(model->protocol_result->to_load_protocol != NULL) {
+                        model->protocol_result->to_load_protocol(
+                            model->protocol_result,
+                            subghz_history_get_raw_data(model->history, model->idx));
+                        model->protocol_result->to_string(model->protocol_result, model->text);
+                        model->scene = ReceiverSceneInfo;
+                    }
+                    return true;
+                });
+        }
+        break;
+
+    case ReceiverSceneInfo:
+        with_view_model(
+            subghz_receiver->view, (SubghzReceiverModel * model) {
+                can_be_saved =
+                    (model->protocol_result && model->protocol_result->to_save_string &&
+                     strcmp(model->protocol_result->name, "KeeLoq"));
+                return false;
+            });
+        if(event->key == InputKeyBack && event->type == InputTypeShort) {
+            with_view_model(
+                subghz_receiver->view, (SubghzReceiverModel * model) {
+                    subghz_rx_end(subghz_receiver->worker);
+                    model->real_frequency =
+                        subghz_rx(subghz_receiver->worker, subghz_frequencies[model->frequency]);
+                    model->scene = ReceiverSceneMain;
+                    return true;
+                });
+            subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context);
+        } else if(can_be_saved && event->key == InputKeyRight) {
+            subghz_receiver->callback(SubghzReceverEventSave, subghz_receiver->context);
+            return false;
+        } else if(can_be_saved && event->key == InputKeyOk && event->type == InputTypePress) {
+            subghz_rx_end(subghz_receiver->worker);
+            subghz_receiver->callback(SubghzReceverEventSendStart, subghz_receiver->context);
+            return true;
+        } else if(can_be_saved && event->key == InputKeyOk && event->type == InputTypeRelease) {
+            subghz_receiver->callback(SubghzReceverEventSendStop, subghz_receiver->context);
+            return true;
+        }
+        break;
+
+    case ReceiverSceneConfig:
+        if(event->key == InputKeyBack) {
+            with_view_model(
+                subghz_receiver->view, (SubghzReceiverModel * model) {
+                    model->frequency = model->temp_frequency;
+                    model->real_frequency = subghz_frequencies[model->frequency];
+                    if(subghz_history_get_item(model->history) == 0) {
+                        model->scene = ReceiverSceneStart;
+                    } else {
+                        model->scene = ReceiverSceneMain;
+                    }
+                    return true;
+                });
+            subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context);
+        } else if(event->key == InputKeyOk) {
+            with_view_model(
+                subghz_receiver->view, (SubghzReceiverModel * model) {
+                    subghz_rx_end(subghz_receiver->worker);
+                    model->real_frequency =
+                        subghz_rx(subghz_receiver->worker, subghz_frequencies[model->frequency]);
+                    if(subghz_history_get_item(model->history) == 0) {
+                        model->scene = ReceiverSceneStart;
+                    } else {
+                        model->scene = ReceiverSceneMain;
+                    }
+                    return true;
+                });
+            subghz_receiver->callback(SubghzReceverEventMain, subghz_receiver->context);
+        } else {
+            with_view_model(
+                subghz_receiver->view, (SubghzReceiverModel * model) {
+                    bool model_updated = false;
+
+                    if(event->key == InputKeyLeft) {
+                        if(model->frequency > 0) model->frequency--;
+                        model_updated = true;
+                    } else if(event->key == InputKeyRight) {
+                        if(model->frequency < subghz_frequencies_count - 1) model->frequency++;
+                        model_updated = true;
+                    }
+                    if(model_updated) {
+                        model->real_frequency = subghz_frequencies[model->frequency];
+                    }
+                    return model_updated;
+                });
+        }
+        break;
+
+    case ReceiverSceneStart:
+        if(event->key == InputKeyBack) {
+            return false;
+        } else if(event->key == InputKeyLeft) {
+            with_view_model(
+                subghz_receiver->view, (SubghzReceiverModel * model) {
+                    model->temp_frequency = model->frequency;
+                    model->scene = ReceiverSceneConfig;
+                    return true;
+                });
+            subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context);
+        }
+        break;
+
+    default:
+        break;
     }
 
+    subghz_receiver_update_offset(subghz_receiver);
     return true;
 }
 
@@ -86,19 +389,53 @@ void subghz_receiver_text_callback(string_t text, void* context) {
     with_view_model(
         subghz_receiver->view, (SubghzReceiverModel * model) {
             string_set(model->text, text);
-            model->scene = 0;
+            model->scene = ReceiverSceneMain;
             return true;
         });
 }
 
+void subghz_receiver_protocol_callback(SubGhzProtocolCommon* parser, void* context) {
+    furi_assert(context);
+    SubghzReceiver* subghz_receiver = context;
+
+    with_view_model(
+        subghz_receiver->view, (SubghzReceiverModel * model) {
+            model->protocol_result = parser;
+            subghz_history_set_frequency_preset(
+                model->history,
+                model->history_item,
+                model->real_frequency,
+                FuriHalSubGhzPresetOok650Async);
+            subghz_history_add_to_history(model->history, parser);
+
+            model->history_item = subghz_history_get_item(model->history);
+            model->scene = ReceiverSceneMain;
+            return true;
+        });
+    subghz_protocol_reset(subghz_receiver->protocol);
+    subghz_receiver_update_offset(subghz_receiver);
+}
+
 void subghz_receiver_enter(void* context) {
     furi_assert(context);
     SubghzReceiver* subghz_receiver = context;
+    //Start CC1101 Rx
+    subghz_begin(FuriHalSubGhzPresetOok650Async);
     with_view_model(
         subghz_receiver->view, (SubghzReceiverModel * model) {
-            model->protocol->to_string(model->protocol, model->text);
+            subghz_rx_end(subghz_receiver->worker);
+            model->frequency = subghz_frequencies_433_92;
+            model->real_frequency =
+                subghz_rx(subghz_receiver->worker, subghz_frequencies[model->frequency]);
+            if(subghz_history_get_item(model->history) == 0) {
+                model->scene = ReceiverSceneStart;
+            } else {
+                model->scene = ReceiverSceneMain;
+            }
             return true;
         });
+    subghz_protocol_enable_dump(
+        subghz_receiver->protocol, subghz_receiver_protocol_callback, subghz_receiver);
 }
 
 void subghz_receiver_exit(void* context) {
@@ -109,6 +446,9 @@ void subghz_receiver_exit(void* context) {
             string_clean(model->text);
             return true;
         });
+    // Stop CC1101 Rx
+    subghz_rx_end(subghz_receiver->worker);
+    subghz_sleep();
 }
 
 SubghzReceiver* subghz_receiver_alloc() {
@@ -126,6 +466,7 @@ SubghzReceiver* subghz_receiver_alloc() {
     with_view_model(
         subghz_receiver->view, (SubghzReceiverModel * model) {
             string_init(model->text);
+            model->history = subghz_history_alloc();
             return true;
         });
     return subghz_receiver;
@@ -137,7 +478,8 @@ void subghz_receiver_free(SubghzReceiver* subghz_receiver) {
     with_view_model(
         subghz_receiver->view, (SubghzReceiverModel * model) {
             string_clear(model->text);
-            return true;
+            subghz_history_free(model->history);
+            return false;
         });
     view_free(subghz_receiver->view);
     free(subghz_receiver);
@@ -147,3 +489,44 @@ View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver) {
     furi_assert(subghz_receiver);
     return subghz_receiver->view;
 }
+
+uint32_t subghz_receiver_get_frequency(SubghzReceiver* subghz_receiver) {
+    furi_assert(subghz_receiver);
+    uint32_t frequency;
+    with_view_model(
+        subghz_receiver->view, (SubghzReceiverModel * model) {
+            frequency = subghz_history_get_frequency(model->history, model->idx);
+            return false;
+        });
+    return frequency;
+}
+
+FuriHalSubGhzPreset subghz_receiver_get_preset(SubghzReceiver* subghz_receiver) {
+    furi_assert(subghz_receiver);
+    FuriHalSubGhzPreset preset;
+    with_view_model(
+        subghz_receiver->view, (SubghzReceiverModel * model) {
+            preset = subghz_history_get_preset(model->history, model->idx);
+            return false;
+        });
+    return preset;
+}
+
+void subghz_receiver_frequency_preset_to_str(SubghzReceiver* subghz_receiver, string_t output) {
+    furi_assert(subghz_receiver);
+    uint32_t frequency;
+    uint32_t preset;
+    with_view_model(
+        subghz_receiver->view, (SubghzReceiverModel * model) {
+            frequency = subghz_history_get_frequency(model->history, model->idx);
+            preset = (uint32_t)subghz_history_get_preset(model->history, model->idx);
+            return false;
+        });
+
+    string_cat_printf(
+        output,
+        "Frequency: %d\n"
+        "Preset: %d\n",
+        (int)frequency,
+        (int)preset);
+}

+ 18 - 1
applications/subghz/views/subghz_receiver.h

@@ -2,10 +2,19 @@
 
 #include <gui/view.h>
 #include <lib/subghz/protocols/subghz_protocol_common.h>
+#include <lib/subghz/protocols/subghz_protocol.h>
+#include <lib/subghz/subghz_worker.h>
+#include "../subghz_history.h"
 
 typedef enum {
+    SubghzReceverEventOK,
+    SubghzReceverEventConfig,
+    SubghzReceverEventMain,
     SubghzReceverEventSave,
     SubghzReceverEventBack,
+    SubghzReceverEventMore,
+    SubghzReceverEventSendStart,
+    SubghzReceverEventSendStop
 } SubghzReceverEvent;
 
 typedef struct SubghzReceiver SubghzReceiver;
@@ -23,4 +32,12 @@ void subghz_receiver_free(SubghzReceiver* subghz_receiver);
 
 View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver);
 
-void subghz_receiver_set_protocol(SubghzReceiver* subghz_receiver, SubGhzProtocolCommon* protocol);
+void subghz_receiver_set_protocol(
+    SubghzReceiver* subghz_receiver,
+    SubGhzProtocolCommon* protocol_result,
+    SubGhzProtocol* protocol);
+SubGhzProtocolCommon* subghz_receiver_get_protocol(SubghzReceiver* subghz_receiver);
+void subghz_receiver_set_worker(SubghzReceiver* subghz_receiver, SubGhzWorker* worker);
+uint32_t subghz_receiver_get_frequency(SubghzReceiver* subghz_receiver);
+FuriHalSubGhzPreset subghz_receiver_get_preset(SubghzReceiver* subghz_receiver);
+void subghz_receiver_frequency_preset_to_str(SubghzReceiver* subghz_receiver, string_t output);

+ 1 - 1
applications/subghz/views/subghz_static.c

@@ -112,7 +112,7 @@ void subghz_static_enter(void* context) {
     SubghzStatic* instance = context;
 
     furi_hal_subghz_reset();
-    furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync);
+    furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
 
     hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
     hal_gpio_write(&gpio_cc1101_g0, false);

+ 1 - 1
applications/subghz/views/subghz_test_carrier.c

@@ -119,7 +119,7 @@ void subghz_test_carrier_enter(void* context) {
     SubghzTestCarrier* subghz_test_carrier = context;
 
     furi_hal_subghz_reset();
-    furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync);
+    furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
 
     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
 

+ 1 - 1
applications/subghz/views/subghz_test_packet.c

@@ -166,7 +166,7 @@ void subghz_test_packet_enter(void* context) {
     SubghzTestPacket* instance = context;
 
     furi_hal_subghz_reset();
-    furi_hal_subghz_load_preset(FuriHalSubGhzPresetOokAsync);
+    furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
 
     with_view_model(
         instance->view, (SubghzTestPacketModel * model) {

+ 57 - 3
applications/subghz/views/subghz_transmitter.c

@@ -8,7 +8,8 @@
 #include <gui/elements.h>
 #include <notification/notification-messages.h>
 
-#include <assets_icons.h>
+//#include <assets_icons.h>
+#include <gui/icon_i.h>
 
 struct SubghzTransmitter {
     View* view;
@@ -19,6 +20,8 @@ struct SubghzTransmitter {
 typedef struct {
     string_t text;
     uint16_t scene;
+    uint32_t real_frequency;
+    FuriHalSubGhzPreset preset;
     SubGhzProtocolCommon* protocol;
 } SubghzTransmitterModel;
 
@@ -42,14 +45,65 @@ void subghz_transmitter_set_protocol(
         });
 }
 
+void subghz_transmitter_set_frequency_preset(
+    SubghzTransmitter* subghz_transmitter,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    with_view_model(
+        subghz_transmitter->view, (SubghzTransmitterModel * model) {
+            model->real_frequency = frequency;
+            model->preset = preset;
+            return true;
+        });
+}
+
+static void subghz_transmitter_button_right(Canvas* canvas, const char* str) {
+    const uint8_t button_height = 13;
+    const uint8_t vertical_offset = 3;
+    const uint8_t horizontal_offset = 1;
+    const uint8_t string_width = canvas_string_width(canvas, str);
+    const Icon* icon = &I_ButtonCenter_7x7;
+    const uint8_t icon_offset = 3;
+    const uint8_t icon_width_with_offset = icon->width + icon_offset;
+    const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset;
+
+    const uint8_t x = (canvas_width(canvas) - button_width) / 2 + 40;
+    const uint8_t y = canvas_height(canvas);
+
+    canvas_draw_box(canvas, x, y - button_height, button_width, button_height);
+
+    canvas_draw_line(canvas, x - 1, y, x - 1, y - button_height + 0);
+    canvas_draw_line(canvas, x - 2, y, x - 2, y - button_height + 1);
+    canvas_draw_line(canvas, x - 3, y, x - 3, y - button_height + 2);
+
+    canvas_draw_line(canvas, x + button_width + 0, y, x + button_width + 0, y - button_height + 0);
+    canvas_draw_line(canvas, x + button_width + 1, y, x + button_width + 1, y - button_height + 1);
+    canvas_draw_line(canvas, x + button_width + 2, y, x + button_width + 2, y - button_height + 2);
+
+    canvas_invert_color(canvas);
+    canvas_draw_icon(
+        canvas, x + horizontal_offset, y - button_height + vertical_offset, &I_ButtonCenter_7x7);
+    canvas_draw_str(
+        canvas, x + horizontal_offset + icon_width_with_offset, y - vertical_offset, str);
+    canvas_invert_color(canvas);
+}
+
 void subghz_transmitter_draw(Canvas* canvas, SubghzTransmitterModel* model) {
+    char buffer[64];
     canvas_clear(canvas);
     canvas_set_color(canvas, ColorBlack);
     canvas_set_font(canvas, FontSecondary);
-    elements_multiline_text(canvas, 0, 10, string_get_cstr(model->text));
+    elements_multiline_text(canvas, 0, 8, string_get_cstr(model->text));
+    snprintf(
+        buffer,
+        sizeof(buffer),
+        "%03ld.%03ld",
+        model->real_frequency / 1000000 % 1000,
+        model->real_frequency / 1000 % 1000);
+    canvas_draw_str(canvas, 90, 8, buffer);
 
     if(model->protocol && model->protocol->get_upload_protocol) {
-        elements_button_center(canvas, "Send");
+        subghz_transmitter_button_right(canvas, "Send");
     }
 }
 

+ 4 - 0
applications/subghz/views/subghz_transmitter.h

@@ -27,3 +27,7 @@ View* subghz_transmitter_get_view(SubghzTransmitter* subghz_transmitter);
 void subghz_transmitter_set_protocol(
     SubghzTransmitter* subghz_transmitter,
     SubGhzProtocolCommon* protocol);
+void subghz_transmitter_set_frequency_preset(
+    SubghzTransmitter* subghz_transmitter,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset);

Разница между файлами не показана из-за своего большого размера
+ 6 - 0
assets/compiled/assets_icons.c


+ 6 - 0
assets/compiled/assets_icons.h

@@ -29,6 +29,12 @@ extern const Icon I_DolphinFirstStart8_56x51;
 extern const Icon I_DolphinFirstStart7_61x51;
 extern const Icon I_Flipper_young_80x60;
 extern const Icon I_DolphinFirstStart3_57x48;
+extern const Icon I_quest_7x8;
+extern const Icon I_unlock_7x8;
+extern const Icon I_Scanning_dolph_67_61;
+extern const Icon I_Broadcast_dolph_67_61;
+extern const Icon I_lock_7x8;
+extern const Icon I_Top_frame_128_13;
 extern const Icon I_PassportBottom_128x17;
 extern const Icon I_DoorLeft_8x56;
 extern const Icon I_DoorLocked_10x56;

BIN
assets/icons/GubGHz/Broadcast_dolph_67-61.png


BIN
assets/icons/GubGHz/Scanning_dolph_67-61.png


BIN
assets/icons/GubGHz/Top-frame_128-13.png


BIN
assets/icons/GubGHz/lock_7x8.png


BIN
assets/icons/GubGHz/quest_7x8.png


BIN
assets/icons/GubGHz/unlock_7x8.png


+ 4 - 0
firmware/targets/f6/furi-hal/furi-hal-delay.c

@@ -28,3 +28,7 @@ void delay(float milliseconds) {
     (void)result;
     furi_assert(result == osOK);
 }
+
+uint32_t millis(void){
+    return HAL_GetTick();
+}

+ 2 - 0
firmware/targets/f6/furi-hal/furi-hal-irda.c

@@ -411,7 +411,9 @@ static void furi_hal_irda_tx_fill_buffer_last(uint8_t buf_num) {
     furi_assert(irda_tim_tx.data_callback);
     IrdaTxBuf* buffer = &irda_tim_tx.buffer[buf_num];
     furi_assert(buffer->data != NULL);
+    (void)buffer->data;
     furi_assert(buffer->polarity != NULL);
+    (void)buffer->polarity;
 
     irda_tim_tx.buffer[buf_num].data[0] = 0;       // 1 pulse
     irda_tim_tx.buffer[buf_num].polarity[0] = IRDA_TX_CCMR_LOW;

+ 131 - 5
firmware/targets/f6/furi-hal/furi-hal-subghz.c

@@ -11,14 +11,14 @@
 
 static volatile SubGhzState furi_hal_subghz_state = SubGhzStateInit;
 
-static const uint8_t furi_hal_subghz_preset_ook_async_regs[][2] = {
+static const uint8_t furi_hal_subghz_preset_ook_270khz_async_regs[][2] = {
     // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration
 
     /* GPIO GD0 */
     { CC1101_IOCFG0,    0x0D }, // GD0 as async serial data output/input
 
     /* FIFO and internals */
-    { CC1101_FIFOTHR,   0x47 }, // The only important bit is ADC_RETENTION
+    { CC1101_FIFOTHR,   0x47 }, // The only important bit is ADC_RETENTION, FIFO Tx=33 Rx=32
 
     /* Packet engine */
     { CC1101_PKTCTRL0,  0x32 }, // Async, continious, no whitening
@@ -66,6 +66,116 @@ static const uint8_t furi_hal_subghz_preset_ook_async_regs[][2] = {
     { 0, 0 },
 };
 
+static const uint8_t furi_hal_subghz_preset_ook_650khz_async_regs[][2] = {
+    // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration
+
+    /* GPIO GD0 */
+    { CC1101_IOCFG0,    0x0D }, // GD0 as async serial data output/input
+
+    /* FIFO and internals */
+    { CC1101_FIFOTHR,   0x07 }, // The only important bit is ADC_RETENTION
+
+    /* Packet engine */
+    { CC1101_PKTCTRL0,  0x32 }, // Async, continious, no whitening
+
+    /* Frequency Synthesizer Control */
+    { CC1101_FSCTRL1,   0x06 }, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz
+
+    // Modem Configuration
+    { CC1101_MDMCFG0,   0x00 }, // Channel spacing is 25kHz
+    { CC1101_MDMCFG1,   0x00 }, // Channel spacing is 25kHz
+    { CC1101_MDMCFG2,   0x30 }, // Format ASK/OOK, No preamble/sync
+    { CC1101_MDMCFG3,   0x32 }, // Data rate is 3.79372 kBaud
+    { CC1101_MDMCFG4,   0x17  }, // Rx BW filter is 650.000kHz
+    
+    /* Main Radio Control State Machine */
+    { CC1101_MCSM0,     0x18 }, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us)
+
+    /* Frequency Offset Compensation Configuration */
+    { CC1101_FOCCFG,    0x18 }, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off
+
+    /* Automatic Gain Control */
+    { CC1101_AGCTRL0,   0x40 }, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary
+    { CC1101_AGCTRL1,   0x00 }, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET
+    { CC1101_AGCTRL2,   0x03 }, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB
+
+    /* Wake on radio and timeouts control */
+    { CC1101_WORCTRL,   0xFB }, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours 
+
+    /* Frontend configuration */
+    { CC1101_FREND0,    0x11 }, // Adjusts current TX LO buffer + high is PATABLE[1]
+    { CC1101_FREND1,    0xB6 }, // 
+
+    /* Frequency Synthesizer Calibration, valid for 433.92 */
+    { CC1101_FSCAL3,    0xE9 },
+    { CC1101_FSCAL2,    0x2A },
+    { CC1101_FSCAL1,    0x00 },
+    { CC1101_FSCAL0,    0x1F }, 
+
+    /* Magic f4ckery */
+    { CC1101_TEST2,     0x88 },
+    { CC1101_TEST1,     0x31 },
+    { CC1101_TEST0,     0x09 }, // VCO selection calibration stage is disabled
+
+    /* End  */
+    { 0, 0 },
+};
+static const uint8_t furi_hal_subghz_preset_2fsk_async_regs[][2] = {
+    // https://e2e.ti.com/support/wireless-connectivity/sub-1-ghz-group/sub-1-ghz/f/sub-1-ghz-forum/382066/cc1101---don-t-know-the-correct-registers-configuration
+
+    /* GPIO GD0 */
+    { CC1101_IOCFG0,    0x0D }, // GD0 as async serial data output/input
+
+    /* FIFO and internals */
+    { CC1101_FIFOTHR,   0x47 }, // The only important bit is ADC_RETENTION
+
+    /* Packet engine */
+    { CC1101_PKTCTRL0,  0x32 }, // Async, continious, no whitening
+
+    /* Frequency Synthesizer Control */
+    { CC1101_FSCTRL1,   0x06 }, // IF = (26*10^6) / (2^10) * 0x06 = 152343.75Hz
+
+    // Modem Configuration
+    { CC1101_MDMCFG0,   0xF8 }, 
+    { CC1101_MDMCFG1,   0x00 }, // No preamble/sync
+    { CC1101_MDMCFG2,   0x80 }, // Format 2-FSK/FM, No preamble/sync, Disable (current optimized)
+    { CC1101_MDMCFG3,   0x83 }, // Data rate is 9.59587 kBaud
+    { CC1101_MDMCFG4,   0x88 }, // Rx BW filter is 203.125000kHz
+
+    { CC1101_DEVIATN,  0x14}, //Deviation 4.760742 khz
+
+    /* Main Radio Control State Machine */
+    { CC1101_MCSM0,     0x18 }, // Autocalibrate on idle-to-rx/tx, PO_TIMEOUT is 64 cycles(149-155us)
+
+    /* Frequency Offset Compensation Configuration */
+    { CC1101_FOCCFG,    0x18 }, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off
+
+    /* Automatic Gain Control */
+    { CC1101_AGCTRL0,   0x40 }, // 01 - Low hysteresis, small asymmetric dead zone, medium gain; 00 - 8 samples agc; 00 - Normal AGC, 00 - 4dB boundary
+    { CC1101_AGCTRL1,   0x00 }, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET
+    { CC1101_AGCTRL2,   0x03 }, // 00 - DVGA all; 000 - MAX LNA+LNA2; 011 - MAIN_TARGET 24 dB
+
+    /* Wake on radio and timeouts control */
+    { CC1101_WORCTRL,   0xFB }, // WOR_RES is 2^15 periods (0.91 - 0.94 s) 16.5 - 17.2 hours 
+
+    /* Frontend configuration */
+    { CC1101_FREND0,    0x10 }, // Adjusts current TX LO buffer
+    { CC1101_FREND1,    0xB6 }, // 
+
+    /* Frequency Synthesizer Calibration, valid for 433.92 */
+    { CC1101_FSCAL3,    0xE9 },
+    { CC1101_FSCAL2,    0x2A },
+    { CC1101_FSCAL1,    0x00 },
+    { CC1101_FSCAL0,    0x1F }, 
+
+    /* Magic f4ckery */
+    { CC1101_TEST2,     0x81 }, // FIFOTHR ADC_RETENTION=1 matched value
+    { CC1101_TEST1,     0x35 }, // FIFOTHR ADC_RETENTION=1 matched value
+    { CC1101_TEST0,     0x09 }, // VCO selection calibration stage is disabled
+
+    /* End  */
+    { 0, 0 },
+};
 static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = {
     0x00,
     0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12
@@ -76,6 +186,16 @@ static const uint8_t furi_hal_subghz_preset_ook_async_patable[8] = {
     0x00,
     0x00
 };
+static const uint8_t furi_hal_subghz_preset_2fsk_async_patable[8] = {
+    0xC0, // 10dBm 0xC0, 7dBm 0xC8, 5dBm 0x84, 0dBm 0x60, -10dBm 0x34, -15dBm 0x1D, -20dBm 0x0E, -30dBm 0x12
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00,
+    0x00
+};
 
 void furi_hal_subghz_init() {
     furi_assert(furi_hal_subghz_state == SubGhzStateInit);
@@ -143,10 +263,16 @@ void furi_hal_subghz_dump_state() {
 }
 
 void furi_hal_subghz_load_preset(FuriHalSubGhzPreset preset) {
-    if(preset == FuriHalSubGhzPresetOokAsync) {
-        furi_hal_subghz_load_registers(furi_hal_subghz_preset_ook_async_regs);
+    if(preset == FuriHalSubGhzPresetOok650Async) {
+        furi_hal_subghz_load_registers(furi_hal_subghz_preset_ook_650khz_async_regs);
         furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable);
-    } else {
+    } else if(preset == FuriHalSubGhzPresetOok270Async){
+        furi_hal_subghz_load_registers(furi_hal_subghz_preset_ook_270khz_async_regs);
+        furi_hal_subghz_load_patable(furi_hal_subghz_preset_ook_async_patable);
+    } else if(preset == FuriHalSubGhzPreset2FSKAsync){
+        furi_hal_subghz_load_registers(furi_hal_subghz_preset_2fsk_async_regs);
+        furi_hal_subghz_load_patable(furi_hal_subghz_preset_2fsk_async_patable);
+    }else {
         furi_check(0);
     }
 }

+ 3 - 0
firmware/targets/furi-hal-include/furi-hal-delay.h

@@ -17,6 +17,9 @@ void delay(float milliseconds);
 /** Delay in microseconds */
 void delay_us(float microseconds);
 
+/** Get current millisecond */
+uint32_t millis(void);
+
 #ifdef __cplusplus
 }
 #endif

+ 3 - 1
firmware/targets/furi-hal-include/furi-hal-subghz.h

@@ -11,7 +11,9 @@ extern "C" {
 
 /** Radio Presets */
 typedef enum {
-    FuriHalSubGhzPresetOokAsync,     /** OOK, asynchronous */
+    FuriHalSubGhzPresetOok270Async,     /** OOK, bandwidth 270kHz, asynchronous */
+    FuriHalSubGhzPresetOok650Async,     /** OOK, bandwidth 650kHz, asynchronous */
+    FuriHalSubGhzPreset2FSKAsync,       /** FM, asynchronous */
 } FuriHalSubGhzPreset;
 
 /**  Switchable Radio Paths */

+ 5 - 3
lib/irda/worker/irda_worker.c

@@ -267,10 +267,10 @@ void irda_worker_rx_stop(IrdaWorker* instance) {
     osEventFlagsSet(instance->events, IRDA_WORKER_EXIT);
     furi_thread_join(instance->thread);
 
-    BaseType_t xReturn = pdFAIL;
-    xReturn = xStreamBufferReset(instance->stream);
+    BaseType_t xReturn = xStreamBufferReset(instance->stream);
     furi_assert(xReturn == pdPASS);
-    instance->state = IrdaWorkerStateIdle;
+    (void)xReturn;
+
     instance->state = IrdaWorkerStateIdle;
 }
 
@@ -424,6 +424,7 @@ static bool irda_worker_tx_fill_buffer(IrdaWorker* instance) {
         }
         uint32_t written_size = xStreamBufferSend(instance->stream, &timing, sizeof(IrdaWorkerTiming), 0);
         furi_assert(sizeof(IrdaWorkerTiming) == written_size);
+        (void)written_size;
     }
 
     return new_data_available;
@@ -528,6 +529,7 @@ void irda_worker_tx_stop(IrdaWorker* instance) {
     BaseType_t xReturn = pdFAIL;
     xReturn = xStreamBufferReset(instance->stream);
     furi_assert(xReturn == pdPASS);
+    (void)xReturn;
     instance->state = IrdaWorkerStateIdle;
 }
 

+ 95 - 48
lib/subghz/protocols/subghz_protocol.c

@@ -31,7 +31,6 @@ typedef enum {
     SubGhzProtocolTypeMax,
 } SubGhzProtocolType;
 
-
 struct SubGhzProtocol {
     SubGhzKeystore* keystore;
 
@@ -49,7 +48,7 @@ static void subghz_protocol_text_rx_callback(SubGhzProtocolCommon* parser, void*
     string_t output;
     string_init(output);
     subghz_protocol_common_to_str((SubGhzProtocolCommon*)parser, output);
-    if (instance->text_callback) {
+    if(instance->text_callback) {
         instance->text_callback(output, instance->text_callback_context);
     } else {
         printf(string_get_cstr(output));
@@ -59,9 +58,9 @@ static void subghz_protocol_text_rx_callback(SubGhzProtocolCommon* parser, void*
 
 static void subghz_protocol_parser_rx_callback(SubGhzProtocolCommon* parser, void* context) {
     SubGhzProtocol* instance = context;
-    if (instance->parser_callback) {
+    if(instance->parser_callback) {
         instance->parser_callback(parser, instance->parser_callback_context);
-    } 
+    }
 }
 
 SubGhzProtocol* subghz_protocol_alloc() {
@@ -69,16 +68,26 @@ SubGhzProtocol* subghz_protocol_alloc() {
 
     instance->keystore = subghz_keystore_alloc();
 
-    instance->protocols[SubGhzProtocolTypeCame] =(SubGhzProtocolCommon*)subghz_protocol_came_alloc();
-    instance->protocols[SubGhzProtocolTypeKeeloq] = (SubGhzProtocolCommon*)subghz_protocol_keeloq_alloc(instance->keystore);
-    instance->protocols[SubGhzProtocolTypePrinceton]  = (SubGhzProtocolCommon*)subghz_decoder_princeton_alloc();
-    instance->protocols[SubGhzProtocolTypeNiceFlo] = (SubGhzProtocolCommon*)subghz_protocol_nice_flo_alloc();
-    instance->protocols[SubGhzProtocolTypeNiceFlorS]  = (SubGhzProtocolCommon*)subghz_protocol_nice_flor_s_alloc();
-    instance->protocols[SubGhzProtocolTypeGateTX]  = (SubGhzProtocolCommon*)subghz_protocol_gate_tx_alloc();
-    instance->protocols[SubGhzProtocolTypeIDo]  = (SubGhzProtocolCommon*)subghz_protocol_ido_alloc();
-    instance->protocols[SubGhzProtocolTypeFaacSLH]  = (SubGhzProtocolCommon*)subghz_protocol_faac_slh_alloc();
-    instance->protocols[SubGhzProtocolTypeNeroSketch] = (SubGhzProtocolCommon*)subghz_protocol_nero_sketch_alloc();
-    instance->protocols[SubGhzProtocolTypeStarLine]  = (SubGhzProtocolCommon*)subghz_protocol_star_line_alloc(instance->keystore);
+    instance->protocols[SubGhzProtocolTypeCame] =
+        (SubGhzProtocolCommon*)subghz_protocol_came_alloc();
+    instance->protocols[SubGhzProtocolTypeKeeloq] =
+        (SubGhzProtocolCommon*)subghz_protocol_keeloq_alloc(instance->keystore);
+    instance->protocols[SubGhzProtocolTypePrinceton] =
+        (SubGhzProtocolCommon*)subghz_decoder_princeton_alloc();
+    instance->protocols[SubGhzProtocolTypeNiceFlo] =
+        (SubGhzProtocolCommon*)subghz_protocol_nice_flo_alloc();
+    instance->protocols[SubGhzProtocolTypeNiceFlorS] =
+        (SubGhzProtocolCommon*)subghz_protocol_nice_flor_s_alloc();
+    instance->protocols[SubGhzProtocolTypeGateTX] =
+        (SubGhzProtocolCommon*)subghz_protocol_gate_tx_alloc();
+    instance->protocols[SubGhzProtocolTypeIDo] =
+        (SubGhzProtocolCommon*)subghz_protocol_ido_alloc();
+    instance->protocols[SubGhzProtocolTypeFaacSLH] =
+        (SubGhzProtocolCommon*)subghz_protocol_faac_slh_alloc();
+    instance->protocols[SubGhzProtocolTypeNeroSketch] =
+        (SubGhzProtocolCommon*)subghz_protocol_nero_sketch_alloc();
+    instance->protocols[SubGhzProtocolTypeStarLine] =
+        (SubGhzProtocolCommon*)subghz_protocol_star_line_alloc(instance->keystore);
 
     return instance;
 }
@@ -87,15 +96,23 @@ void subghz_protocol_free(SubGhzProtocol* instance) {
     furi_assert(instance);
 
     subghz_protocol_came_free((SubGhzProtocolCame*)instance->protocols[SubGhzProtocolTypeCame]);
-    subghz_protocol_keeloq_free((SubGhzProtocolKeeloq*)instance->protocols[SubGhzProtocolTypeKeeloq]);
-    subghz_decoder_princeton_free((SubGhzDecoderPrinceton*)instance->protocols[SubGhzProtocolTypePrinceton]);
-    subghz_protocol_nice_flo_free((SubGhzProtocolNiceFlo*)instance->protocols[SubGhzProtocolTypeNiceFlo]);
-    subghz_protocol_nice_flor_s_free((SubGhzProtocolNiceFlorS*)instance->protocols[SubGhzProtocolTypeNiceFlorS]);
-    subghz_protocol_gate_tx_free((SubGhzProtocolGateTX*)instance->protocols[SubGhzProtocolTypeGateTX]);
+    subghz_protocol_keeloq_free(
+        (SubGhzProtocolKeeloq*)instance->protocols[SubGhzProtocolTypeKeeloq]);
+    subghz_decoder_princeton_free(
+        (SubGhzDecoderPrinceton*)instance->protocols[SubGhzProtocolTypePrinceton]);
+    subghz_protocol_nice_flo_free(
+        (SubGhzProtocolNiceFlo*)instance->protocols[SubGhzProtocolTypeNiceFlo]);
+    subghz_protocol_nice_flor_s_free(
+        (SubGhzProtocolNiceFlorS*)instance->protocols[SubGhzProtocolTypeNiceFlorS]);
+    subghz_protocol_gate_tx_free(
+        (SubGhzProtocolGateTX*)instance->protocols[SubGhzProtocolTypeGateTX]);
     subghz_protocol_ido_free((SubGhzProtocolIDo*)instance->protocols[SubGhzProtocolTypeIDo]);
-    subghz_protocol_faac_slh_free((SubGhzProtocolFaacSLH*)instance->protocols[SubGhzProtocolTypeFaacSLH]);
-    subghz_protocol_nero_sketch_free((SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch]);
-    subghz_protocol_star_line_free((SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine]);
+    subghz_protocol_faac_slh_free(
+        (SubGhzProtocolFaacSLH*)instance->protocols[SubGhzProtocolTypeFaacSLH]);
+    subghz_protocol_nero_sketch_free(
+        (SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch]);
+    subghz_protocol_star_line_free(
+        (SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine]);
 
     subghz_keystore_free(instance->keystore);
 
@@ -115,32 +132,40 @@ SubGhzProtocolCommon* subghz_protocol_get_by_name(SubGhzProtocol* instance, cons
     return result;
 }
 
-void subghz_protocol_enable_dump_text(SubGhzProtocol* instance, SubGhzProtocolTextCallback callback, void* context) {
+void subghz_protocol_enable_dump_text(
+    SubGhzProtocol* instance,
+    SubGhzProtocolTextCallback callback,
+    void* context) {
     furi_assert(instance);
 
     for(size_t i = 0; i < SubGhzProtocolTypeMax; i++) {
-        subghz_protocol_common_set_callback(instance->protocols[i], subghz_protocol_text_rx_callback, instance);
+        subghz_protocol_common_set_callback(
+            instance->protocols[i], subghz_protocol_text_rx_callback, instance);
     }
 
     instance->text_callback = callback;
     instance->text_callback_context = context;
 }
 
-void subghz_protocol_enable_dump(SubGhzProtocol* instance, SubGhzProtocolCommonCallbackDump callback, void* context) {
+void subghz_protocol_enable_dump(
+    SubGhzProtocol* instance,
+    SubGhzProtocolCommonCallbackDump callback,
+    void* context) {
     furi_assert(instance);
 
     for(size_t i = 0; i < SubGhzProtocolTypeMax; i++) {
-        subghz_protocol_common_set_callback(instance->protocols[i], subghz_protocol_parser_rx_callback, instance);
+        subghz_protocol_common_set_callback(
+            instance->protocols[i], subghz_protocol_parser_rx_callback, instance);
     }
 
     instance->parser_callback = callback;
     instance->parser_callback_context = context;
 }
 
-
 void subghz_protocol_load_nice_flor_s_file(SubGhzProtocol* instance, const char* file_name) {
     // subghz_protocol_nice_flor_s_name_file(instance->nice_flor_s, file_name);
-    subghz_protocol_nice_flor_s_name_file((SubGhzProtocolNiceFlorS*) instance->protocols[SubGhzProtocolTypeNiceFlorS], file_name);
+    subghz_protocol_nice_flor_s_name_file(
+        (SubGhzProtocolNiceFlorS*)instance->protocols[SubGhzProtocolTypeNiceFlorS], file_name);
 }
 
 void subghz_protocol_load_keeloq_file(SubGhzProtocol* instance, const char* file_name) {
@@ -148,29 +173,51 @@ void subghz_protocol_load_keeloq_file(SubGhzProtocol* instance, const char* file
 }
 
 void subghz_protocol_reset(SubGhzProtocol* instance) {
-
     subghz_protocol_came_reset((SubGhzProtocolCame*)instance->protocols[SubGhzProtocolTypeCame]);
-    subghz_protocol_keeloq_reset((SubGhzProtocolKeeloq*)instance->protocols[SubGhzProtocolTypeKeeloq]);
-    subghz_decoder_princeton_reset((SubGhzDecoderPrinceton*)instance->protocols[SubGhzProtocolTypePrinceton]);
-    subghz_protocol_nice_flo_reset((SubGhzProtocolNiceFlo*)instance->protocols[SubGhzProtocolTypeNiceFlo]);
-    subghz_protocol_nice_flor_s_reset((SubGhzProtocolNiceFlorS*)instance->protocols[SubGhzProtocolTypeNiceFlorS]);
-    subghz_protocol_gate_tx_reset((SubGhzProtocolGateTX*)instance->protocols[SubGhzProtocolTypeGateTX]);
+    subghz_protocol_keeloq_reset(
+        (SubGhzProtocolKeeloq*)instance->protocols[SubGhzProtocolTypeKeeloq]);
+    subghz_decoder_princeton_reset(
+        (SubGhzDecoderPrinceton*)instance->protocols[SubGhzProtocolTypePrinceton]);
+    subghz_protocol_nice_flo_reset(
+        (SubGhzProtocolNiceFlo*)instance->protocols[SubGhzProtocolTypeNiceFlo]);
+    subghz_protocol_nice_flor_s_reset(
+        (SubGhzProtocolNiceFlorS*)instance->protocols[SubGhzProtocolTypeNiceFlorS]);
+    subghz_protocol_gate_tx_reset(
+        (SubGhzProtocolGateTX*)instance->protocols[SubGhzProtocolTypeGateTX]);
     subghz_protocol_ido_reset((SubGhzProtocolIDo*)instance->protocols[SubGhzProtocolTypeIDo]);
-    subghz_protocol_faac_slh_reset((SubGhzProtocolFaacSLH*)instance->protocols[SubGhzProtocolTypeFaacSLH]);
-    subghz_protocol_nero_sketch_reset((SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch]);
-    subghz_protocol_star_line_reset((SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine]);
+    subghz_protocol_faac_slh_reset(
+        (SubGhzProtocolFaacSLH*)instance->protocols[SubGhzProtocolTypeFaacSLH]);
+    subghz_protocol_nero_sketch_reset(
+        (SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch]);
+    subghz_protocol_star_line_reset(
+        (SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine]);
 }
 
 void subghz_protocol_parse(SubGhzProtocol* instance, bool level, uint32_t duration) {
-
-    subghz_protocol_came_parse((SubGhzProtocolCame*)instance->protocols[SubGhzProtocolTypeCame], level, duration);
-    subghz_protocol_keeloq_parse((SubGhzProtocolKeeloq*)instance->protocols[SubGhzProtocolTypeKeeloq], level, duration);
-    subghz_decoder_princeton_parse((SubGhzDecoderPrinceton*)instance->protocols[SubGhzProtocolTypePrinceton], level, duration);
-    subghz_protocol_nice_flo_parse((SubGhzProtocolNiceFlo*)instance->protocols[SubGhzProtocolTypeNiceFlo], level, duration);
-    subghz_protocol_nice_flor_s_parse((SubGhzProtocolNiceFlorS*)instance->protocols[SubGhzProtocolTypeNiceFlorS], level, duration);
-    subghz_protocol_gate_tx_parse((SubGhzProtocolGateTX*)instance->protocols[SubGhzProtocolTypeGateTX], level, duration);
-    subghz_protocol_ido_parse((SubGhzProtocolIDo*)instance->protocols[SubGhzProtocolTypeIDo], level, duration);
-    subghz_protocol_faac_slh_parse((SubGhzProtocolFaacSLH*)instance->protocols[SubGhzProtocolTypeFaacSLH], level, duration);
-    subghz_protocol_nero_sketch_parse((SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch], level, duration);
-    subghz_protocol_star_line_parse((SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine], level, duration);
+    subghz_protocol_came_parse(
+        (SubGhzProtocolCame*)instance->protocols[SubGhzProtocolTypeCame], level, duration);
+    subghz_protocol_keeloq_parse(
+        (SubGhzProtocolKeeloq*)instance->protocols[SubGhzProtocolTypeKeeloq], level, duration);
+    subghz_decoder_princeton_parse(
+        (SubGhzDecoderPrinceton*)instance->protocols[SubGhzProtocolTypePrinceton],
+        level,
+        duration);
+    subghz_protocol_nice_flo_parse(
+        (SubGhzProtocolNiceFlo*)instance->protocols[SubGhzProtocolTypeNiceFlo], level, duration);
+    subghz_protocol_nice_flor_s_parse(
+        (SubGhzProtocolNiceFlorS*)instance->protocols[SubGhzProtocolTypeNiceFlorS],
+        level,
+        duration);
+    subghz_protocol_gate_tx_parse(
+        (SubGhzProtocolGateTX*)instance->protocols[SubGhzProtocolTypeGateTX], level, duration);
+    subghz_protocol_ido_parse(
+        (SubGhzProtocolIDo*)instance->protocols[SubGhzProtocolTypeIDo], level, duration);
+    subghz_protocol_faac_slh_parse(
+        (SubGhzProtocolFaacSLH*)instance->protocols[SubGhzProtocolTypeFaacSLH], level, duration);
+    subghz_protocol_nero_sketch_parse(
+        (SubGhzProtocolNeroSketch*)instance->protocols[SubGhzProtocolTypeNeroSketch],
+        level,
+        duration);
+    subghz_protocol_star_line_parse(
+        (SubGhzProtocolStarLine*)instance->protocols[SubGhzProtocolTypeStarLine], level, duration);
 }

+ 20 - 8
lib/subghz/protocols/subghz_protocol_came.c

@@ -23,10 +23,12 @@ SubGhzProtocolCame* subghz_protocol_came_alloc() {
     instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_came_to_str;
     instance->common.to_save_string =
         (SubGhzProtocolCommonGetStrSave)subghz_protocol_came_to_save_str;
-    instance->common.to_load_protocol=
-        (SubGhzProtocolCommonLoad)subghz_protocol_came_to_load_protocol;
+    instance->common.to_load_protocol_from_file=
+        (SubGhzProtocolCommonLoadFromFile)subghz_protocol_came_to_load_protocol_from_file;
+    instance->common.to_load_protocol =
+        (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_came_to_load_protocol;
     instance->common.get_upload_protocol =
-        (SubGhzProtocolEncoderCommonGetUpLoad)subghz_protocol_came_send_key;
+        (SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_came_send_key;
 
     return instance;
 }
@@ -36,7 +38,7 @@ void subghz_protocol_came_free(SubGhzProtocolCame* instance) {
     free(instance);
 }
 
-bool subghz_protocol_came_send_key(SubGhzProtocolCame* instance, SubGhzProtocolEncoderCommon* encoder){
+bool subghz_protocol_came_send_key(SubGhzProtocolCame* instance, SubGhzProtocolCommonEncoder* encoder){
     furi_assert(instance);
     furi_assert(encoder);
     size_t index = 0;
@@ -142,9 +144,9 @@ void subghz_protocol_came_to_str(SubGhzProtocolCame* instance, string_t output)
 
     string_cat_printf(
         output,
-        "%s %d Bit\r\n"
-        " KEY:0x%08lX\r\n"
-        " YEK:0x%08lX\r\n",
+        "%s %dbit\r\n"
+        "Key:0x%08lX\r\n"
+        "Yek:0x%08lX\r\n",
         instance->common.name,
         instance->common.code_last_count_bit,
         code_found_lo,
@@ -163,7 +165,7 @@ void subghz_protocol_came_to_save_str(SubGhzProtocolCame* instance, string_t out
         (uint32_t)(instance->common.code_last_found & 0x00000000ffffffff));
 }
 
-bool subghz_protocol_came_to_load_protocol(FileWorker* file_worker, SubGhzProtocolCame* instance){
+bool subghz_protocol_came_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolCame* instance){
     bool loaded = false;
     string_t temp_str;
     string_init(temp_str);
@@ -199,3 +201,13 @@ bool subghz_protocol_came_to_load_protocol(FileWorker* file_worker, SubGhzProtoc
 
     return loaded;
 }
+
+void subghz_decoder_came_to_load_protocol(
+    SubGhzProtocolCame* instance,
+    void* context) {
+    furi_assert(context);
+    furi_assert(instance);
+    SubGhzProtocolCommonLoad* data = context;
+    instance->common.code_last_found = data->code_found;
+    instance->common.code_last_count_bit = data->code_count_bit;
+}

+ 4 - 3
lib/subghz/protocols/subghz_protocol_came.h

@@ -19,10 +19,10 @@ void subghz_protocol_came_free(SubGhzProtocolCame* instance);
 /** Get upload protocol
  * 
  * @param instance - SubGhzProtocolCame instance
- * @param encoder - SubGhzProtocolEncoderCommon encoder
+ * @param encoder - SubGhzProtocolCommonEncoder encoder
  * @return bool
  */
-bool subghz_protocol_came_send_key(SubGhzProtocolCame* instance, SubGhzProtocolEncoderCommon* encoder);
+bool subghz_protocol_came_send_key(SubGhzProtocolCame* instance, SubGhzProtocolCommonEncoder* encoder);
 
 /** Reset internal state
  * @param instance - SubGhzProtocolCame instance
@@ -44,4 +44,5 @@ void subghz_protocol_came_parse(SubGhzProtocolCame* instance, bool level, uint32
 void subghz_protocol_came_to_str(SubGhzProtocolCame* instance, string_t output);
 
 void subghz_protocol_came_to_save_str(SubGhzProtocolCame* instance, string_t output);
-bool subghz_protocol_came_to_load_protocol(FileWorker* file_worker, SubGhzProtocolCame* instance);
+bool subghz_protocol_came_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolCame* instance);
+void subghz_decoder_came_to_load_protocol(SubGhzProtocolCame* instance, void* context);

+ 5 - 5
lib/subghz/protocols/subghz_protocol_common.c

@@ -3,27 +3,27 @@
 #include <lib/toolbox/hex.h>
 
 
-SubGhzProtocolEncoderCommon* subghz_protocol_encoder_common_alloc() {
-    SubGhzProtocolEncoderCommon* instance = furi_alloc(sizeof(SubGhzProtocolEncoderCommon));
+SubGhzProtocolCommonEncoder* subghz_protocol_encoder_common_alloc() {
+    SubGhzProtocolCommonEncoder* instance = furi_alloc(sizeof(SubGhzProtocolCommonEncoder));
     instance->upload = furi_alloc(SUBGHZ_ENCODER_UPLOAD_MAX_SIZE * sizeof(LevelDuration));
     instance->start = true;
     instance->repeat = 10; //default number of repeat
     return instance;
 }
 
-void subghz_protocol_encoder_common_free(SubGhzProtocolEncoderCommon* instance) {
+void subghz_protocol_encoder_common_free(SubGhzProtocolCommonEncoder* instance) {
     furi_assert(instance);
     free(instance->upload);
     free(instance);
 }
 
-size_t subghz_encoder_common_get_repeat_left(SubGhzProtocolEncoderCommon* instance) {
+size_t subghz_encoder_common_get_repeat_left(SubGhzProtocolCommonEncoder* instance) {
     furi_assert(instance);
     return instance->repeat;
 }
 
 LevelDuration subghz_protocol_encoder_common_yield(void* context) {
-    SubGhzProtocolEncoderCommon* instance = context;
+    SubGhzProtocolCommonEncoder* instance = context;
 
     if(instance->repeat == 0){
         return level_duration_reset();

+ 35 - 18
lib/subghz/protocols/subghz_protocol_common.h

@@ -14,30 +14,37 @@
 #define SUBGHZ_TX_PIN_LOW()
 #define DURATION_DIFF(x, y) ((x < y) ? (y - x) : (x - y))
 
-//#define SUBGHZ_APP_PATH_FOLDER "/ext/subghz/saved"
 #define SUBGHZ_APP_FOLDER "/any/subghz"
 #define SUBGHZ_APP_PATH_FOLDER "/any/subghz/saved"
 #define SUBGHZ_APP_EXTENSION ".sub"
-#define SUBGHZ_ENCODER_UPLOAD_MAX_SIZE  512
+#define SUBGHZ_ENCODER_UPLOAD_MAX_SIZE 512
+
+enum {
+    TYPE_PROTOCOL_UNKNOWN,
+    TYPE_PROTOCOL_STATIC,
+    TYPE_PROTOCOL_DYNAMIC,
+};
 
-#define TYPE_PROTOCOL_STATIC    1u
-#define TYPE_PROTOCOL_DYNAMIC   2u
 
 typedef struct SubGhzProtocolCommon SubGhzProtocolCommon;
-typedef struct SubGhzProtocolEncoderCommon SubGhzProtocolEncoderCommon;
+typedef struct SubGhzProtocolCommonEncoder SubGhzProtocolCommonEncoder;
+typedef struct SubGhzProtocolCommonLoad SubGhzProtocolCommonLoad;
 
 typedef void (*SubGhzProtocolCommonCallback)(SubGhzProtocolCommon* parser, void* context);
 
 typedef void (*SubGhzProtocolCommonToStr)(SubGhzProtocolCommon* instance, string_t output);
 
-//Save
+//Get string to save
 typedef void (*SubGhzProtocolCommonGetStrSave)(SubGhzProtocolCommon* instance, string_t output);
 
-//Load
-typedef bool (*SubGhzProtocolCommonLoad)(FileWorker* file_worker, SubGhzProtocolCommon* instance);
-
+//Load protocol from file
+typedef bool (*SubGhzProtocolCommonLoadFromFile)(FileWorker* file_worker, SubGhzProtocolCommon* instance);
+//Load protocol
+typedef void (*SubGhzProtocolCommonLoadFromRAW)(SubGhzProtocolCommon* instance, void* context);
 //Get upload encoder protocol
-typedef bool (*SubGhzProtocolEncoderCommonGetUpLoad)(SubGhzProtocolCommon* instance, SubGhzProtocolEncoderCommon* encoder);
+typedef bool (*SubGhzProtocolCommonEncoderGetUpLoad)(
+    SubGhzProtocolCommon* instance,
+    SubGhzProtocolCommonEncoder* encoder);
 
 struct SubGhzProtocolCommon {
     const char* name;
@@ -65,13 +72,15 @@ struct SubGhzProtocolCommon {
     SubGhzProtocolCommonToStr to_string;
     /* Get string to save */
     SubGhzProtocolCommonGetStrSave to_save_string;
-    /*Load protocol by file*/
-    SubGhzProtocolCommonLoad to_load_protocol;
-    /*Get upload encoder protocol*/
-    SubGhzProtocolEncoderCommonGetUpLoad get_upload_protocol;
+    /* Load protocol from file */
+    SubGhzProtocolCommonLoadFromFile to_load_protocol_from_file;
+    /* Load protocol from RAW data */
+    SubGhzProtocolCommonLoadFromRAW to_load_protocol;
+    /* Get upload encoder protocol */
+    SubGhzProtocolCommonEncoderGetUpLoad get_upload_protocol;
 };
 
-struct SubGhzProtocolEncoderCommon {
+struct SubGhzProtocolCommonEncoder {
     bool start;
     size_t repeat;
     size_t front;
@@ -79,9 +88,17 @@ struct SubGhzProtocolEncoderCommon {
     LevelDuration* upload;
 };
 
-SubGhzProtocolEncoderCommon* subghz_protocol_encoder_common_alloc();
-void subghz_protocol_encoder_common_free(SubGhzProtocolEncoderCommon* instance);
-size_t subghz_encoder_common_get_repeat_left(SubGhzProtocolEncoderCommon* instance);
+struct SubGhzProtocolCommonLoad{
+    uint64_t code_found;
+    uint8_t code_count_bit;
+    uint32_t param1;
+    uint32_t param2;
+    uint32_t param3;
+};
+
+SubGhzProtocolCommonEncoder* subghz_protocol_encoder_common_alloc();
+void subghz_protocol_encoder_common_free(SubGhzProtocolCommonEncoder* instance);
+size_t subghz_encoder_common_get_repeat_left(SubGhzProtocolCommonEncoder* instance);
 LevelDuration subghz_protocol_encoder_common_yield(void* context);
 
 /** Add data bit to code_found

+ 18 - 5
lib/subghz/protocols/subghz_protocol_faac_slh.c

@@ -15,6 +15,8 @@ SubGhzProtocolFaacSLH* subghz_protocol_faac_slh_alloc(void) {
     instance->common.te_delta = 100;
     instance->common.type_protocol = TYPE_PROTOCOL_DYNAMIC;
     instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_faac_slh_to_str;
+    instance->common.to_load_protocol =
+        (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_faac_slh_to_load_protocol;
 
     return instance;
 }
@@ -145,11 +147,11 @@ void subghz_protocol_faac_slh_to_str(SubGhzProtocolFaacSLH* instance, string_t o
     uint32_t code_hop = (code_found_reverse >>32) & 0xFFFFFFFF;
 
     string_cat_printf(output,
-                      "%s, %d Bit\r\n"
-                      " KEY:0x%lX%08lX\r\n"
-                      " FIX:%08lX \r\n"
-                      " HOP:%08lX \r\n"
-                      " SN:%07lX BTN:%lX\r\n",
+                      "%s %dbit\r\n"
+                      "Key:0x%lX%08lX\r\n"
+                      "Fix:%08lX \r\n"
+                      "Hop:%08lX \r\n"
+                      "Sn:%07lX Btn:%lX\r\n",
                       instance->common.name,
                       instance->common.code_last_count_bit,
                       (uint32_t)(instance->common.code_last_found >> 32),
@@ -157,4 +159,15 @@ void subghz_protocol_faac_slh_to_str(SubGhzProtocolFaacSLH* instance, string_t o
                       code_fix, code_hop, 
                       instance->common.serial, 
                       instance->common.btn);
+}
+
+void subghz_decoder_faac_slh_to_load_protocol(
+    SubGhzProtocolFaacSLH* instance,
+    void* context) {
+    furi_assert(context);
+    furi_assert(instance);
+    SubGhzProtocolCommonLoad* data = context;
+    instance->common.code_last_found = data->code_found;
+    instance->common.code_last_count_bit = data->code_count_bit;
+    subghz_protocol_faac_slh_check_remote_controller(instance);
 }

+ 2 - 0
lib/subghz/protocols/subghz_protocol_faac_slh.h

@@ -49,3 +49,5 @@ void subghz_protocol_faac_slh_parse(SubGhzProtocolFaacSLH* instance, bool level,
  * @param output   - output string
  */
 void subghz_protocol_faac_slh_to_str(SubGhzProtocolFaacSLH* instance, string_t output);
+
+void subghz_decoder_faac_slh_to_load_protocol(SubGhzProtocolFaacSLH* instance, void* context);

+ 21 - 8
lib/subghz/protocols/subghz_protocol_gate_tx.c

@@ -17,10 +17,12 @@ SubGhzProtocolGateTX* subghz_protocol_gate_tx_alloc(void) {
     instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_gate_tx_to_str;
     instance->common.to_save_string =
         (SubGhzProtocolCommonGetStrSave)subghz_protocol_gate_tx_to_save_str;
-    instance->common.to_load_protocol=
-        (SubGhzProtocolCommonLoad)subghz_protocol_gate_tx_to_load_protocol;
+    instance->common.to_load_protocol_from_file=
+        (SubGhzProtocolCommonLoadFromFile)subghz_protocol_gate_tx_to_load_protocol_from_file;
+    instance->common.to_load_protocol =
+        (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_gate_tx_to_load_protocol;
     instance->common.get_upload_protocol =
-        (SubGhzProtocolEncoderCommonGetUpLoad)subghz_protocol_gate_tx_send_key;
+        (SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_gate_tx_send_key;
     return instance;
 }
 
@@ -29,7 +31,7 @@ void subghz_protocol_gate_tx_free(SubGhzProtocolGateTX* instance) {
     free(instance);
 }
 
-bool subghz_protocol_gate_tx_send_key(SubGhzProtocolGateTX* instance, SubGhzProtocolEncoderCommon* encoder){
+bool subghz_protocol_gate_tx_send_key(SubGhzProtocolGateTX* instance, SubGhzProtocolCommonEncoder* encoder){
     furi_assert(instance);
     furi_assert(encoder);
     size_t index = 0;
@@ -133,9 +135,9 @@ void subghz_protocol_gate_tx_parse(SubGhzProtocolGateTX* instance, bool level, u
 void subghz_protocol_gate_tx_to_str(SubGhzProtocolGateTX* instance, string_t output) {
     subghz_protocol_gate_tx_check_remote_controller(instance);
     string_cat_printf(output,
-                      "%s, %d Bit\r\n"
-                      " KEY:%06lX\r\n"
-                      " SN:%05lX  BTN:%lX\r\n",
+                      "%s %dbit\r\n"
+                      "Key:%06lX\r\n"
+                      "Sn:%05lX  Btn:%lX\r\n",
                       instance->common.name,
                       instance->common.code_last_count_bit,
                       (uint32_t)(instance->common.code_last_found & 0xFFFFFF),
@@ -155,7 +157,7 @@ void subghz_protocol_gate_tx_to_save_str(SubGhzProtocolGateTX* instance, string_
         (uint32_t)(instance->common.code_last_found & 0x00000000ffffffff));
 }
 
-bool subghz_protocol_gate_tx_to_load_protocol(FileWorker* file_worker, SubGhzProtocolGateTX* instance){
+bool subghz_protocol_gate_tx_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolGateTX* instance){
     bool loaded = false;
     string_t temp_str;
     string_init(temp_str);
@@ -192,3 +194,14 @@ bool subghz_protocol_gate_tx_to_load_protocol(FileWorker* file_worker, SubGhzPro
 
     return loaded;
 }
+
+void subghz_decoder_gate_tx_to_load_protocol(
+    SubGhzProtocolGateTX* instance,
+    void* context) {
+    furi_assert(context);
+    furi_assert(instance);
+    SubGhzProtocolCommonLoad* data = context;
+    instance->common.code_last_found = data->code_found;
+    instance->common.code_last_count_bit = data->code_count_bit;
+    subghz_protocol_gate_tx_check_remote_controller(instance);
+}

+ 4 - 3
lib/subghz/protocols/subghz_protocol_gate_tx.h

@@ -19,10 +19,10 @@ void subghz_protocol_gate_tx_free(SubGhzProtocolGateTX* instance);
 /** Get upload protocol
  * 
  * @param instance - SubGhzProtocolCame instance
- * @param encoder - SubGhzProtocolEncoderCommon encoder
+ * @param encoder - SubGhzProtocolCommonEncoder encoder
  * @return bool
  */
-bool subghz_protocol_gate_tx_send_key(SubGhzProtocolGateTX* instance, SubGhzProtocolEncoderCommon* encoder);
+bool subghz_protocol_gate_tx_send_key(SubGhzProtocolGateTX* instance, SubGhzProtocolCommonEncoder* encoder);
 
 /** Reset internal state
  * @param instance - SubGhzProtocolGateTX instance
@@ -44,4 +44,5 @@ void subghz_protocol_gate_tx_parse(SubGhzProtocolGateTX* instance, bool level, u
 void subghz_protocol_gate_tx_to_str(SubGhzProtocolGateTX* instance, string_t output);
 
 void subghz_protocol_gate_tx_to_save_str(SubGhzProtocolGateTX* instance, string_t output);
-bool subghz_protocol_gate_tx_to_load_protocol(FileWorker* file_worker, SubGhzProtocolGateTX* instance);
+bool subghz_protocol_gate_tx_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolGateTX* instance);
+void subghz_decoder_gate_tx_to_load_protocol(SubGhzProtocolGateTX* instance, void* context);

+ 64 - 37
lib/subghz/protocols/subghz_protocol_ido.c

@@ -1,6 +1,5 @@
 #include "subghz_protocol_ido.h"
 
-
 struct SubGhzProtocolIDo {
     SubGhzProtocolCommon common;
 };
@@ -15,6 +14,8 @@ SubGhzProtocolIDo* subghz_protocol_ido_alloc(void) {
     instance->common.te_delta = 150;
     instance->common.type_protocol = TYPE_PROTOCOL_DYNAMIC;
     instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_ido_to_str;
+    instance->common.to_load_protocol =
+        (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_ido_to_load_protocol;
 
     return instance;
 }
@@ -30,7 +31,7 @@ void subghz_protocol_ido_free(SubGhzProtocolIDo* instance) {
  * @param bit - bit
  */
 void subghz_protocol_ido_send_bit(SubGhzProtocolIDo* instance, uint8_t bit) {
-    if (bit) {
+    if(bit) {
         //send bit 1
         SUBGHZ_TX_PIN_HIGH();
         delay_us(instance->common.te_short);
@@ -45,15 +46,19 @@ void subghz_protocol_ido_send_bit(SubGhzProtocolIDo* instance, uint8_t bit) {
     }
 }
 
-void subghz_protocol_ido_send_key(SubGhzProtocolIDo* instance, uint64_t key, uint8_t bit,uint8_t repeat) {
-    while (repeat--) {
+void subghz_protocol_ido_send_key(
+    SubGhzProtocolIDo* instance,
+    uint64_t key,
+    uint8_t bit,
+    uint8_t repeat) {
+    while(repeat--) {
         SUBGHZ_TX_PIN_HIGH();
         //Send header
         delay_us(instance->common.te_short * 10);
         SUBGHZ_TX_PIN_LOW();
-        delay_us(instance->common.te_short * 10); 
+        delay_us(instance->common.te_short * 10);
         //Send key data
-        for (uint8_t i = bit; i > 0; i--) {
+        for(uint8_t i = bit; i > 0; i--) {
             subghz_protocol_ido_send_bit(instance, bit_read(key, i - 1));
         }
     }
@@ -68,7 +73,8 @@ void subghz_protocol_ido_reset(SubGhzProtocolIDo* instance) {
  * @param instance SubGhzProtocolIDo instance
  */
 void subghz_protocol_ido_check_remote_controller(SubGhzProtocolIDo* instance) {
-    uint64_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_last_found, instance->common.code_last_count_bit);
+    uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
+        instance->common.code_last_found, instance->common.code_last_count_bit);
     uint32_t code_fix = code_found_reverse & 0xFFFFFF;
 
     instance->common.serial = code_fix & 0xFFFFF;
@@ -76,18 +82,18 @@ void subghz_protocol_ido_check_remote_controller(SubGhzProtocolIDo* instance) {
 }
 
 void subghz_protocol_ido_parse(SubGhzProtocolIDo* instance, bool level, uint32_t duration) {
-    switch (instance->common.parser_step) {
+    switch(instance->common.parser_step) {
     case 0:
-        if ((level)
-                && (DURATION_DIFF(duration,instance->common.te_short * 10)< instance->common.te_delta * 5)) {
+        if((level) && (DURATION_DIFF(duration, instance->common.te_short * 10) <
+                       instance->common.te_delta * 5)) {
             instance->common.parser_step = 1;
         } else {
             instance->common.parser_step = 0;
         }
         break;
     case 1:
-        if ((!level)
-                && (DURATION_DIFF(duration,instance->common.te_short * 10)< instance->common.te_delta * 5)) {
+        if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 10) <
+                        instance->common.te_delta * 5)) {
             //Found Preambula
             instance->common.parser_step = 2;
             instance->common.code_found = 0;
@@ -97,13 +103,16 @@ void subghz_protocol_ido_parse(SubGhzProtocolIDo* instance, bool level, uint32_t
         }
         break;
     case 2:
-        if (level) {
-            if (duration >= (instance->common.te_short * 5 + instance->common.te_delta)) {
+        if(level) {
+            if(duration >= (instance->common.te_short * 5 + instance->common.te_delta)) {
                 instance->common.parser_step = 1;
-                if (instance->common.code_count_bit>= instance->common.code_min_count_bit_for_found) {
+                if(instance->common.code_count_bit >=
+                   instance->common.code_min_count_bit_for_found) {
                     instance->common.code_last_found = instance->common.code_found;
                     instance->common.code_last_count_bit = instance->common.code_count_bit;
-                    if (instance->common.callback) instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context);
+                    if(instance->common.callback)
+                        instance->common.callback(
+                            (SubGhzProtocolCommon*)instance, instance->common.context);
                 }
                 instance->common.code_found = 0;
                 instance->common.code_count_bit = 0;
@@ -113,18 +122,22 @@ void subghz_protocol_ido_parse(SubGhzProtocolIDo* instance, bool level, uint32_t
                 instance->common.parser_step = 3;
             }
 
-        }else{
+        } else {
             instance->common.parser_step = 0;
         }
         break;
     case 3:
-        if(!level){
-                if ((DURATION_DIFF(instance->common.te_last,instance->common.te_short)< instance->common.te_delta)
-                    && (DURATION_DIFF(duration,instance->common.te_long)< instance->common.te_delta*3)) {
+        if(!level) {
+            if((DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
+                instance->common.te_delta) &&
+               (DURATION_DIFF(duration, instance->common.te_long) <
+                instance->common.te_delta * 3)) {
                 subghz_protocol_common_add_bit(&instance->common, 0);
                 instance->common.parser_step = 2;
-            } else if ((DURATION_DIFF(instance->common.te_last,instance->common.te_short )< instance->common.te_delta*3)
-                    && (DURATION_DIFF(duration,instance->common.te_short)< instance->common.te_delta)) {
+            } else if(
+                (DURATION_DIFF(instance->common.te_last, instance->common.te_short) <
+                 instance->common.te_delta * 3) &&
+                (DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta)) {
                 subghz_protocol_common_add_bit(&instance->common, 1);
                 instance->common.parser_step = 2;
             } else {
@@ -139,21 +152,35 @@ void subghz_protocol_ido_parse(SubGhzProtocolIDo* instance, bool level, uint32_t
 
 void subghz_protocol_ido_to_str(SubGhzProtocolIDo* instance, string_t output) {
     subghz_protocol_ido_check_remote_controller(instance);
-    uint64_t code_found_reverse = subghz_protocol_common_reverse_key(instance->common.code_last_found, instance->common.code_last_count_bit);
+    uint64_t code_found_reverse = subghz_protocol_common_reverse_key(
+        instance->common.code_last_found, instance->common.code_last_count_bit);
     uint32_t code_fix = code_found_reverse & 0xFFFFFF;
-    uint32_t code_hop = (code_found_reverse >>24) & 0xFFFFFF;
+    uint32_t code_hop = (code_found_reverse >> 24) & 0xFFFFFF;
 
-    string_cat_printf(output,
-                      "%s, %d Bit\r\n"
-                      " KEY:0x%lX%08lX\r\n"
-                      " FIX:%06lX \r\n"
-                      " HOP:%06lX \r\n"
-                      " SN:%05lX BTN:%lX\r\n",
-                      instance->common.name,
-                      instance->common.code_last_count_bit,
-                      (uint32_t)(instance->common.code_last_found >> 32),
-                      (uint32_t)instance->common.code_last_found,
-                      code_fix, code_hop, 
-                      instance->common.serial, 
-                      instance->common.btn);
+    string_cat_printf(
+        output,
+        "%s %dbit\r\n"
+        "Key:0x%lX%08lX\r\n"
+        "Fix:%06lX \r\n"
+        "Hop:%06lX \r\n"
+        "Sn:%05lX Btn:%lX\r\n",
+        instance->common.name,
+        instance->common.code_last_count_bit,
+        (uint32_t)(instance->common.code_last_found >> 32),
+        (uint32_t)instance->common.code_last_found,
+        code_fix,
+        code_hop,
+        instance->common.serial,
+        instance->common.btn);
+}
+
+void subghz_decoder_ido_to_load_protocol(
+    SubGhzProtocolIDo* instance,
+    void* context) {
+    furi_assert(context);
+    furi_assert(instance);
+    SubGhzProtocolCommonLoad* data = context;
+    instance->common.code_last_found = data->code_found;
+    instance->common.code_last_count_bit = data->code_count_bit;
+    subghz_protocol_ido_check_remote_controller(instance);
 }

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

@@ -49,3 +49,4 @@ void subghz_protocol_ido_parse(SubGhzProtocolIDo* instance, bool level, uint32_t
  * @param output   - output string
  */
 void subghz_protocol_ido_to_str(SubGhzProtocolIDo* instance, string_t output);
+void subghz_decoder_ido_to_load_protocol(SubGhzProtocolIDo* instance, void* context);

+ 62 - 32
lib/subghz/protocols/subghz_protocol_keeloq.c

@@ -27,10 +27,12 @@ SubGhzProtocolKeeloq* subghz_protocol_keeloq_alloc(SubGhzKeystore* keystore) {
     instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_keeloq_to_str;
     instance->common.to_save_string =
         (SubGhzProtocolCommonGetStrSave)subghz_protocol_keeloq_to_save_str;
+    instance->common.to_load_protocol_from_file =
+        (SubGhzProtocolCommonLoadFromFile)subghz_protocol_keeloq_to_load_protocol_from_file;
     instance->common.to_load_protocol =
-        (SubGhzProtocolCommonLoad)subghz_protocol_keeloq_to_load_protocol;
+        (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_keeloq_to_load_protocol;
     instance->common.get_upload_protocol =
-        (SubGhzProtocolEncoderCommonGetUpLoad)subghz_protocol_keeloq_send_key;
+        (SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_keeloq_send_key;
 
     return instance;
 }
@@ -165,7 +167,14 @@ void subghz_protocol_keeloq_check_remote_controller(SubGhzProtocolKeeloq* instan
     instance->common.serial = key_fix & 0x0FFFFFFF;
     instance->common.btn = key_fix >> 28;
 }
-void subghz_protocol_keeloq_set_manufacture_name (void* context, const char* manufacture_name){
+
+const char* subghz_protocol_keeloq_get_manufacture_name(void* context) {
+    SubGhzProtocolKeeloq* instance = context;
+    subghz_protocol_keeloq_check_remote_controller(instance);
+    return instance->manufacture_name;
+}
+
+void subghz_protocol_keeloq_set_manufacture_name(void* context, const char* manufacture_name) {
     SubGhzProtocolKeeloq* instance = context;
     instance->manufacture_name = manufacture_name;
 }
@@ -205,17 +214,20 @@ uint64_t subghz_protocol_keeloq_gen_key(void* context) {
     return subghz_protocol_common_reverse_key(yek, instance->common.code_last_count_bit);
 }
 
-bool subghz_protocol_keeloq_send_key(SubGhzProtocolKeeloq* instance, SubGhzProtocolEncoderCommon* encoder){
+bool subghz_protocol_keeloq_send_key(
+    SubGhzProtocolKeeloq* instance,
+    SubGhzProtocolCommonEncoder* encoder) {
     furi_assert(instance);
     furi_assert(encoder);
 
     //gen new key
     instance->common.cnt++;
     instance->common.code_last_found = subghz_protocol_keeloq_gen_key(instance);
-    if(instance->common.callback)instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context);
-    
+    if(instance->common.callback)
+        instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context);
+
     size_t index = 0;
-    encoder->size_upload =11*2+2+(instance->common.code_last_count_bit * 2) + 4;
+    encoder->size_upload = 11 * 2 + 2 + (instance->common.code_last_count_bit * 2) + 4;
     if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
 
     //Send header
@@ -224,18 +236,23 @@ bool subghz_protocol_keeloq_send_key(SubGhzProtocolKeeloq* instance, SubGhzProto
         encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short);
     }
     encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
-    encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short*10);
+    encoder->upload[index++] =
+        level_duration_make(false, (uint32_t)instance->common.te_short * 10);
 
     //Send key data
-    for (uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
-        if(bit_read(instance->common.code_last_found, i - 1)){
+    for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
+        if(bit_read(instance->common.code_last_found, i - 1)) {
             //send bit 1
-            encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
-            encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_long);
-        }else{
+            encoder->upload[index++] =
+                level_duration_make(true, (uint32_t)instance->common.te_short);
+            encoder->upload[index++] =
+                level_duration_make(false, (uint32_t)instance->common.te_long);
+        } else {
             //send bit 0
-            encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_long);
-            encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short);
+            encoder->upload[index++] =
+                level_duration_make(true, (uint32_t)instance->common.te_long);
+            encoder->upload[index++] =
+                level_duration_make(false, (uint32_t)instance->common.te_short);
         }
     }
     // +send 2 status bit
@@ -247,7 +264,8 @@ bool subghz_protocol_keeloq_send_key(SubGhzProtocolKeeloq* instance, SubGhzProto
 
     // send end
     encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->common.te_short);
-    encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->common.te_short*40);
+    encoder->upload[index++] =
+        level_duration_make(false, (uint32_t)instance->common.te_short * 40);
 
     return true;
 }
@@ -353,25 +371,27 @@ void subghz_protocol_keeloq_to_str(SubGhzProtocolKeeloq* instance, string_t outp
     uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
     string_cat_printf(
         output,
-        "%s, %d Bit\r\n"
-        "KEY:0x%lX%lX\r\n"
-        "FIX:%08lX MF:%s \r\n"
-        "HOP:%08lX \r\n"
-        "SN:%07lX CNT:%04X B:%02lX\r\n",
+        "%s %dbit\r\n"
+        "Key:0x%lX%lX\r\n"
+        "Fix:0x%08lX     Cnt:%04X\r\n"
+        "Hop:0x%08lX     Btn:%02lX\r\n"
+        "MF:%s\r\n"
+        "Sn:0x%07lX \r\n",
         instance->common.name,
         instance->common.code_last_count_bit,
         code_found_hi,
         code_found_lo,
         code_found_reverse_hi,
-        instance->manufacture_name,
-        code_found_reverse_lo,
-        instance->common.serial,
         instance->common.cnt,
-        instance->common.btn);
+        code_found_reverse_lo,
+        instance->common.btn,
+        instance->manufacture_name,
+        instance->common.serial
+    );
 }
 
 void subghz_protocol_keeloq_to_save_str(SubGhzProtocolKeeloq* instance, string_t output) {
-        string_printf(
+    string_printf(
         output,
         "Protocol: %s\n"
         "Bit: %d\n"
@@ -379,11 +399,10 @@ void subghz_protocol_keeloq_to_save_str(SubGhzProtocolKeeloq* instance, string_t
         instance->common.name,
         instance->common.code_last_count_bit,
         (uint32_t)(instance->common.code_last_found >> 32),
-        (uint32_t)(instance->common.code_last_found & 0xFFFFFFFF)
-        );
+        (uint32_t)(instance->common.code_last_found & 0xFFFFFFFF));
 }
 
-bool subghz_protocol_keeloq_to_load_protocol(
+bool subghz_protocol_keeloq_to_load_protocol_from_file(
     FileWorker* file_worker,
     SubGhzProtocolKeeloq* instance) {
     bool loaded = false;
@@ -410,12 +429,12 @@ bool subghz_protocol_keeloq_to_load_protocol(
         // strlen("Key: ") = 5
         string_right(temp_str, 5);
 
-        uint8_t buf_key[8]={0};
-        if(!subghz_protocol_common_read_hex(temp_str, buf_key, 8)){
+        uint8_t buf_key[8] = {0};
+        if(!subghz_protocol_common_read_hex(temp_str, buf_key, 8)) {
             break;
         }
 
-        for(uint8_t i = 0; i < 8; i++){
+        for(uint8_t i = 0; i < 8; i++) {
             instance->common.code_last_found = instance->common.code_last_found << 8 | buf_key[i];
         }
         loaded = true;
@@ -424,3 +443,14 @@ bool subghz_protocol_keeloq_to_load_protocol(
 
     return loaded;
 }
+
+void subghz_decoder_keeloq_to_load_protocol(
+    SubGhzProtocolKeeloq* instance,
+    void* context) {
+    furi_assert(context);
+    furi_assert(instance);
+    SubGhzProtocolCommonLoad* data = context;
+    instance->common.code_last_found = data->code_found;
+    instance->common.code_last_count_bit = data->code_count_bit;
+    subghz_protocol_keeloq_check_remote_controller(instance);
+}

+ 6 - 3
lib/subghz/protocols/subghz_protocol_keeloq.h

@@ -18,6 +18,8 @@ SubGhzProtocolKeeloq* subghz_protocol_keeloq_alloc(SubGhzKeystore* keystore);
  */
 void subghz_protocol_keeloq_free(SubGhzProtocolKeeloq* instance);
 
+const char* subghz_protocol_keeloq_get_manufacture_name(void* context);
+
 /** Set manufacture name
  * 
  * @param manufacture_name - manufacture name
@@ -35,10 +37,10 @@ uint64_t subghz_protocol_keeloq_gen_key(void* context);
 /** Get upload protocol
  * 
  * @param instance - SubGhzProtocolCame instance
- * @param encoder - SubGhzProtocolEncoderCommon encoder
+ * @param encoder - SubGhzProtocolCommonEncoder encoder
  * @return bool
  */
-bool subghz_protocol_keeloq_send_key(SubGhzProtocolKeeloq* instance, SubGhzProtocolEncoderCommon* encoder);
+bool subghz_protocol_keeloq_send_key(SubGhzProtocolKeeloq* instance, SubGhzProtocolCommonEncoder* encoder);
 
 /** Reset internal state
  * @param instance - SubGhzProtocolKeeloq instance
@@ -60,4 +62,5 @@ void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, bool level, ui
 void subghz_protocol_keeloq_to_str(SubGhzProtocolKeeloq* instance, string_t output);
 
 void subghz_protocol_keeloq_to_save_str(SubGhzProtocolKeeloq* instance, string_t output);
-bool subghz_protocol_keeloq_to_load_protocol(FileWorker* file_worker, SubGhzProtocolKeeloq* instance);
+bool subghz_protocol_keeloq_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolKeeloq* instance);
+void subghz_decoder_keeloq_to_load_protocol(SubGhzProtocolKeeloq* instance, void* context);

+ 20 - 8
lib/subghz/protocols/subghz_protocol_nero_sketch.c

@@ -17,10 +17,12 @@ SubGhzProtocolNeroSketch* subghz_protocol_nero_sketch_alloc(void) {
     instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nero_sketch_to_str;
     instance->common.to_save_string =
         (SubGhzProtocolCommonGetStrSave)subghz_protocol_nero_sketch_to_save_str;
-    instance->common.to_load_protocol=
-        (SubGhzProtocolCommonLoad)subghz_protocol_nero_sketch_to_load_protocol;
+    instance->common.to_load_protocol_from_file=
+        (SubGhzProtocolCommonLoadFromFile)subghz_protocol_nero_sketch_to_load_protocol_from_file;
+    instance->common.to_load_protocol =
+        (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_nero_sketch_to_load_protocol;
     instance->common.get_upload_protocol =
-        (SubGhzProtocolEncoderCommonGetUpLoad)subghz_protocol_nero_sketch_send_key;
+        (SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_nero_sketch_send_key;
 
     return instance;
 }
@@ -30,7 +32,7 @@ void subghz_protocol_nero_sketch_free(SubGhzProtocolNeroSketch* instance) {
     free(instance);
 }
 
-bool subghz_protocol_nero_sketch_send_key(SubGhzProtocolNeroSketch* instance, SubGhzProtocolEncoderCommon* encoder){
+bool subghz_protocol_nero_sketch_send_key(SubGhzProtocolNeroSketch* instance, SubGhzProtocolCommonEncoder* encoder){
     furi_assert(instance);
     furi_assert(encoder);
     size_t index = 0;
@@ -184,9 +186,9 @@ void subghz_protocol_nero_sketch_to_str(SubGhzProtocolNeroSketch* instance, stri
     uint32_t code_found_reverse_lo = code_found_reverse&0x00000000ffffffff;
 
     string_cat_printf(output,
-                      "%s, %d Bit\r\n"
-                      " KEY:0x%lX%08lX\r\n"
-                      " YEK:0x%lX%08lX\r\n",
+                      "%s %dbit\r\n"
+                      "Key:0x%lX%08lX\r\n"
+                      "Yek:0x%lX%08lX\r\n",
                       instance->common.name,
                       instance->common.code_last_count_bit,
                       code_found_hi,
@@ -212,7 +214,7 @@ void subghz_protocol_nero_sketch_to_save_str(SubGhzProtocolNeroSketch* instance,
         );
 }
 
-bool subghz_protocol_nero_sketch_to_load_protocol(FileWorker* file_worker, SubGhzProtocolNeroSketch* instance){
+bool subghz_protocol_nero_sketch_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolNeroSketch* instance){
     bool loaded = false;
     string_t temp_str;
     string_init(temp_str);
@@ -249,3 +251,13 @@ bool subghz_protocol_nero_sketch_to_load_protocol(FileWorker* file_worker, SubGh
 
     return loaded;
 }
+
+void subghz_decoder_nero_sketch_to_load_protocol(
+    SubGhzProtocolNeroSketch* instance,
+    void* context) {
+    furi_assert(context);
+    furi_assert(instance);
+    SubGhzProtocolCommonLoad* data = context;
+    instance->common.code_last_found = data->code_found;
+    instance->common.code_last_count_bit = data->code_count_bit;
+}

+ 4 - 3
lib/subghz/protocols/subghz_protocol_nero_sketch.h

@@ -19,10 +19,10 @@ void subghz_protocol_nero_sketch_free(SubGhzProtocolNeroSketch* instance);
 /** Get upload protocol
  * 
  * @param instance - SubGhzProtocolCame instance
- * @param encoder - SubGhzProtocolEncoderCommon encoder
+ * @param encoder - SubGhzProtocolCommonEncoder encoder
  * @return bool
  */
-bool subghz_protocol_nero_sketch_send_key(SubGhzProtocolNeroSketch* instance, SubGhzProtocolEncoderCommon* encoder);
+bool subghz_protocol_nero_sketch_send_key(SubGhzProtocolNeroSketch* instance, SubGhzProtocolCommonEncoder* encoder);
 
 /** Reset internal state
  * @param instance - SubGhzProtocolNeroSketch instance
@@ -50,4 +50,5 @@ void subghz_protocol_nero_sketch_parse(SubGhzProtocolNeroSketch* instance, bool
 void subghz_protocol_nero_sketch_to_str(SubGhzProtocolNeroSketch* instance, string_t output);
 
 void subghz_protocol_nero_sketch_to_save_str(SubGhzProtocolNeroSketch* instance, string_t output);
-bool subghz_protocol_nero_sketch_to_load_protocol(FileWorker* file_worker, SubGhzProtocolNeroSketch* instance);
+bool subghz_protocol_nero_sketch_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolNeroSketch* instance);
+void subghz_decoder_nero_sketch_to_load_protocol(SubGhzProtocolNeroSketch* instance, void* context);

+ 22 - 8
lib/subghz/protocols/subghz_protocol_nice_flo.c

@@ -22,10 +22,12 @@ SubGhzProtocolNiceFlo* subghz_protocol_nice_flo_alloc() {
     instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nice_flo_to_str;
     instance->common.to_save_string =
         (SubGhzProtocolCommonGetStrSave)subghz_protocol_nice_flo_to_save_str;
-    instance->common.to_load_protocol=
-        (SubGhzProtocolCommonLoad)subghz_protocol_nice_flo_to_load_protocol;
+    instance->common.to_load_protocol_from_file=
+        (SubGhzProtocolCommonLoadFromFile)subghz_protocol_nice_flo_to_load_protocol_from_file;
+    instance->common.to_load_protocol =
+        (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_nice_flo_to_load_protocol;
     instance->common.get_upload_protocol =
-        (SubGhzProtocolEncoderCommonGetUpLoad)subghz_protocol_nice_flo_send_key;
+        (SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_nice_flo_send_key;
     return instance;
 }
 
@@ -34,7 +36,7 @@ void subghz_protocol_nice_flo_free(SubGhzProtocolNiceFlo* instance) {
     free(instance);
 }
 
-bool subghz_protocol_nice_flo_send_key(SubGhzProtocolNiceFlo* instance, SubGhzProtocolEncoderCommon* encoder){
+bool subghz_protocol_nice_flo_send_key(SubGhzProtocolNiceFlo* instance, SubGhzProtocolCommonEncoder* encoder){
     furi_assert(instance);
     furi_assert(encoder);
     size_t index = 0;
@@ -137,9 +139,9 @@ void subghz_protocol_nice_flo_to_str(SubGhzProtocolNiceFlo* instance, string_t o
 
     string_cat_printf(
         output,
-        "%s %d Bit\r\n"
-        " KEY:0x%08lX\r\n"
-        " YEK:0x%08lX\r\n",
+        "%s %dbit\r\n"
+        "Key:0x%08lX\r\n"
+        "Yek:0x%08lX\r\n",
         instance->common.name,
         instance->common.code_last_count_bit,
         code_found_lo,
@@ -159,7 +161,7 @@ void subghz_protocol_nice_flo_to_save_str(SubGhzProtocolNiceFlo* instance, strin
         (uint32_t)(instance->common.code_last_found & 0x00000000ffffffff));
 }
 
-bool subghz_protocol_nice_flo_to_load_protocol(FileWorker* file_worker, SubGhzProtocolNiceFlo* instance){
+bool subghz_protocol_nice_flo_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolNiceFlo* instance){
     bool loaded = false;
     string_t temp_str;
     string_init(temp_str);
@@ -195,3 +197,15 @@ bool subghz_protocol_nice_flo_to_load_protocol(FileWorker* file_worker, SubGhzPr
 
     return loaded;
 }
+
+void subghz_decoder_nice_flo_to_load_protocol(
+    SubGhzProtocolNiceFlo* instance,
+    void* context) {
+    furi_assert(context);
+    furi_assert(instance);
+    SubGhzProtocolCommonLoad* data = context;
+    instance->common.code_last_found = data->code_found;
+    instance->common.code_last_count_bit = data->code_count_bit;
+    instance->common.serial = 0x0;
+    instance->common.btn = 0x0;
+}

+ 4 - 3
lib/subghz/protocols/subghz_protocol_nice_flo.h

@@ -19,10 +19,10 @@ void subghz_protocol_nice_flo_free(SubGhzProtocolNiceFlo* instance);
 /** Get upload protocol
  * 
  * @param instance - SubGhzProtocolCame instance
- * @param encoder - SubGhzProtocolEncoderCommon encoder
+ * @param encoder - SubGhzProtocolCommonEncoder encoder
  * @return bool
  */
-bool subghz_protocol_nice_flo_send_key(SubGhzProtocolNiceFlo* instance, SubGhzProtocolEncoderCommon* encoder);
+bool subghz_protocol_nice_flo_send_key(SubGhzProtocolNiceFlo* instance, SubGhzProtocolCommonEncoder* encoder);
 
 /** Reset internal state
  * @param instance - SubGhzProtocolNiceFlo instance
@@ -44,4 +44,5 @@ void subghz_protocol_nice_flo_parse(SubGhzProtocolNiceFlo* instance, bool level,
 void subghz_protocol_nice_flo_to_str(SubGhzProtocolNiceFlo* instance, string_t output);
 
 void subghz_protocol_nice_flo_to_save_str(SubGhzProtocolNiceFlo* instance, string_t output);
-bool subghz_protocol_nice_flo_to_load_protocol(FileWorker* file_worker, SubGhzProtocolNiceFlo* instance);
+bool subghz_protocol_nice_flo_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolNiceFlo* instance);
+void subghz_decoder_nice_flo_to_load_protocol(SubGhzProtocolNiceFlo* instance, void* context);

+ 17 - 4
lib/subghz/protocols/subghz_protocol_nice_flor_s.c

@@ -23,6 +23,8 @@ SubGhzProtocolNiceFlorS* subghz_protocol_nice_flor_s_alloc() {
     instance->common.te_delta = 300;
     instance->common.type_protocol = TYPE_PROTOCOL_DYNAMIC;
     instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_nice_flor_s_to_str;
+    instance->common.to_load_protocol =
+        (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_nice_flor_s_to_load_protocol;
 
     return instance;
 }
@@ -224,10 +226,10 @@ void subghz_protocol_nice_flor_s_to_str(SubGhzProtocolNiceFlorS* instance, strin
 
     string_cat_printf(
         output,
-        "%s, %d Bit\r\n"
-        " KEY:0x%lX%08lX\r\n"
-        " SN:%05lX\r\n"
-        " CNT:%04X BTN:%02lX\r\n",
+        "%s %dbit\r\n"
+        "Key:0x%lX%08lX\r\n"
+        "Sn:%05lX\r\n"
+        "Cnt:%04X Btn:%02lX\r\n",
         instance->common.name,
         instance->common.code_last_count_bit,
         code_found_hi,
@@ -236,4 +238,15 @@ void subghz_protocol_nice_flor_s_to_str(SubGhzProtocolNiceFlorS* instance, strin
         instance->common.cnt,
         instance->common.btn
     );
+}
+
+void subghz_decoder_nice_flor_s_to_load_protocol(
+    SubGhzProtocolNiceFlorS* instance,
+    void* context) {
+    furi_assert(context);
+    furi_assert(instance);
+    SubGhzProtocolCommonLoad* data = context;
+    instance->common.code_last_found = data->code_found;
+    instance->common.code_last_count_bit = data->code_count_bit;
+    subghz_nice_flor_s_decoder_decrypt(instance);
 }

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

@@ -50,3 +50,4 @@ void subghz_protocol_nice_flor_s_parse(SubGhzProtocolNiceFlorS* instance, bool l
  * @param output   - output string
  */
 void subghz_protocol_nice_flor_s_to_str(SubGhzProtocolNiceFlorS* instance, string_t output);
+void subghz_decoder_nice_flor_s_to_load_protocol(SubGhzProtocolNiceFlorS* instance, void* context);

+ 49 - 26
lib/subghz/protocols/subghz_protocol_princeton.c

@@ -16,7 +16,6 @@ struct SubGhzEncoderPrinceton {
     size_t front;
 };
 
-
 SubGhzEncoderPrinceton* subghz_encoder_princeton_alloc() {
     SubGhzEncoderPrinceton* instance = furi_alloc(sizeof(SubGhzEncoderPrinceton));
     return instance;
@@ -27,16 +26,15 @@ void subghz_encoder_princeton_free(SubGhzEncoderPrinceton* instance) {
     free(instance);
 }
 
-void subghz_encoder_princeton_set_te(SubGhzEncoderPrinceton* instance, void* decoder){
-   SubGhzDecoderPrinceton* pricenton = decoder;
-    if((pricenton->te) !=0){
+void subghz_encoder_princeton_set_te(SubGhzEncoderPrinceton* instance, void* decoder) {
+    SubGhzDecoderPrinceton* pricenton = decoder;
+    if((pricenton->te) != 0) {
         instance->te = pricenton->te;
-    }else{
+    } else {
         instance->te = SUBGHZ_PT_SHORT;
     }
 }
 
-
 void subghz_encoder_princeton_set(SubGhzEncoderPrinceton* instance, uint32_t key, size_t repeat) {
     furi_assert(instance);
     instance->te = SUBGHZ_PT_SHORT;
@@ -93,11 +91,13 @@ SubGhzDecoderPrinceton* subghz_decoder_princeton_alloc(void) {
     instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_decoder_princeton_to_str;
     instance->common.to_save_string =
         (SubGhzProtocolCommonGetStrSave)subghz_decoder_princeton_to_save_str;
-    instance->common.to_load_protocol=
-        (SubGhzProtocolCommonLoad)subghz_decoder_princeton_to_load_protocol;
+    instance->common.to_load_protocol_from_file =
+        (SubGhzProtocolCommonLoadFromFile)subghz_decoder_princeton_to_load_protocol_from_file;
+    instance->common.to_load_protocol =
+        (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_princeton_to_load_protocol;
     instance->common.get_upload_protocol =
-        (SubGhzProtocolEncoderCommonGetUpLoad)subghz_protocol_princeton_send_key;
-        
+        (SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_princeton_send_key;
+
     return instance;
 }
 
@@ -106,30 +106,37 @@ void subghz_decoder_princeton_free(SubGhzDecoderPrinceton* instance) {
     free(instance);
 }
 
-bool subghz_protocol_princeton_send_key(SubGhzDecoderPrinceton* instance, SubGhzProtocolEncoderCommon* encoder){
+uint16_t subghz_protocol_princeton_get_te(void* context) {
+    SubGhzDecoderPrinceton* instance = context;
+    return instance->te;
+}
+
+bool subghz_protocol_princeton_send_key(
+    SubGhzDecoderPrinceton* instance,
+    SubGhzProtocolCommonEncoder* encoder) {
     furi_assert(instance);
     furi_assert(encoder);
     size_t index = 0;
-    encoder->size_upload =(instance->common.code_last_count_bit * 2) + 2;
+    encoder->size_upload = (instance->common.code_last_count_bit * 2) + 2;
     if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
-    
+
     //Send key data
-    for (uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
-        if(bit_read(instance->common.code_last_found, i - 1)){
+    for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
+        if(bit_read(instance->common.code_last_found, i - 1)) {
             //send bit 1
-            encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->te*3);
+            encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->te * 3);
             encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->te);
-        }else{
+        } else {
             //send bit 0
             encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->te);
-            encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->te*3);
+            encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->te * 3);
         }
     }
 
     //Send Stop bit
     encoder->upload[index++] = level_duration_make(true, (uint32_t)instance->te);
     //Send PT_GUARD
-    encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->te*30);
+    encoder->upload[index++] = level_duration_make(false, (uint32_t)instance->te * 30);
 
     return true;
 }
@@ -221,17 +228,18 @@ void subghz_decoder_princeton_to_str(SubGhzDecoderPrinceton* instance, string_t
 
     string_cat_printf(
         output,
-        "%s %d Bit te %dus\r\n"
-        " KEY:0x%08lX\r\n"
-        " YEK:0x%08lX\r\n"
-        " SN:0x%05lX BTN:%02X\r\n",
+        "%s %dbit\r\n"
+        "Key:0x%08lX\r\n"
+        "Yek:0x%08lX\r\n"
+        "Sn:0x%05lX BTN:%02X\r\n"
+        "Te:%dus\r\n",
         instance->common.name,
         instance->common.code_last_count_bit,
-        instance->te,
         code_found_lo,
         code_found_reverse_lo,
         instance->common.serial,
-        instance->common.btn);
+        instance->common.btn,
+        instance->te);
 }
 
 void subghz_decoder_princeton_to_save_str(SubGhzDecoderPrinceton* instance, string_t output) {
@@ -247,7 +255,9 @@ void subghz_decoder_princeton_to_save_str(SubGhzDecoderPrinceton* instance, stri
         (uint32_t)(instance->common.code_last_found & 0x00000000ffffffff));
 }
 
-bool subghz_decoder_princeton_to_load_protocol(FileWorker* file_worker, SubGhzDecoderPrinceton* instance){
+bool subghz_decoder_princeton_to_load_protocol_from_file(
+    FileWorker* file_worker,
+    SubGhzDecoderPrinceton* instance) {
     bool loaded = false;
     string_t temp_str;
     string_init(temp_str);
@@ -295,3 +305,16 @@ bool subghz_decoder_princeton_to_load_protocol(FileWorker* file_worker, SubGhzDe
 
     return loaded;
 }
+
+void subghz_decoder_princeton_to_load_protocol(
+    SubGhzDecoderPrinceton* instance,
+    void* context) {
+    furi_assert(context);
+    furi_assert(instance);
+    SubGhzProtocolCommonLoad* data = context;
+    instance->common.code_last_found = data->code_found;
+    instance->common.code_last_count_bit = data->code_count_bit;
+    instance->te = data->param1;
+    instance->common.serial = instance->common.code_last_found >> 4;
+    instance->common.btn = (uint8_t)instance->common.code_last_found & 0x00000F;
+}

+ 17 - 11
lib/subghz/protocols/subghz_protocol_princeton.h

@@ -20,7 +20,6 @@ SubGhzEncoderPrinceton* subghz_encoder_princeton_alloc();
  */
 void subghz_encoder_princeton_free(SubGhzEncoderPrinceton* instance);
 
-
 /** Set new encoder params
  * @param instance - SubGhzEncoderPrinceton instance
  * @param key - 24bit key
@@ -40,14 +39,10 @@ size_t subghz_encoder_princeton_get_repeat_left(SubGhzEncoderPrinceton* instance
  */
 LevelDuration subghz_encoder_princeton_yield(void* context);
 
-
 /** SubGhzDecoderPrinceton anonymous type */
 typedef struct SubGhzDecoderPrinceton SubGhzDecoderPrinceton;
 
-
-void subghz_encoder_princeton_set_te(
-    SubGhzEncoderPrinceton* instance,
-    void* decoder);
+void subghz_encoder_princeton_set_te(SubGhzEncoderPrinceton* instance, void* decoder);
 
 /** Allocate SubGhzDecoderPrinceton
  * 
@@ -61,13 +56,17 @@ SubGhzDecoderPrinceton* subghz_decoder_princeton_alloc();
  */
 void subghz_decoder_princeton_free(SubGhzDecoderPrinceton* instance);
 
+uint16_t subghz_protocol_princeton_get_te(void* context);
+
 /** Get upload protocol
  * 
  * @param instance - SubGhzDecoderPrinceton instance
- * @param encoder - SubGhzProtocolEncoderCommon encoder
+ * @param encoder - SubGhzProtocolCommonEncoder encoder
  * @return bool
  */
-bool subghz_protocol_princeton_send_key(SubGhzDecoderPrinceton* instance, SubGhzProtocolEncoderCommon* encoder);
+bool subghz_protocol_princeton_send_key(
+    SubGhzDecoderPrinceton* instance,
+    SubGhzProtocolCommonEncoder* encoder);
 
 /** Reset internal state
  * @param instance - SubGhzDecoderPrinceton instance
@@ -79,7 +78,10 @@ void subghz_decoder_princeton_reset(SubGhzDecoderPrinceton* instance);
  * @param instance - SubGhzDecoderPrinceton instance
  * @param data - LevelDuration level_duration
  */
-void subghz_decoder_princeton_parse(SubGhzDecoderPrinceton* instance, bool level, uint32_t duration);
+void subghz_decoder_princeton_parse(
+    SubGhzDecoderPrinceton* instance,
+    bool level,
+    uint32_t duration);
 
 /** Outputting information from the parser
  * 
@@ -89,6 +91,10 @@ void subghz_decoder_princeton_parse(SubGhzDecoderPrinceton* instance, bool level
 void subghz_decoder_princeton_to_str(SubGhzDecoderPrinceton* instance, string_t output);
 
 void subghz_decoder_princeton_to_save_str(SubGhzDecoderPrinceton* instance, string_t output);
-bool subghz_decoder_princeton_to_load_protocol(FileWorker* file_worker, SubGhzDecoderPrinceton* instance);
-
+bool subghz_decoder_princeton_to_load_protocol_from_file(
+    FileWorker* file_worker,
+    SubGhzDecoderPrinceton* instance);
 
+void subghz_decoder_princeton_to_load_protocol(
+    SubGhzDecoderPrinceton* instance,
+    void* context) ;

+ 29 - 9
lib/subghz/protocols/subghz_protocol_star_line.c

@@ -27,6 +27,8 @@ SubGhzProtocolStarLine* subghz_protocol_star_line_alloc(SubGhzKeystore* keystore
     instance->common.te_delta = 120;
     instance->common.type_protocol = TYPE_PROTOCOL_DYNAMIC;
     instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_star_line_to_str;
+    instance->common.to_load_protocol =
+        (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_star_line_to_load_protocol;
 
     return instance;
 }
@@ -36,6 +38,12 @@ void subghz_protocol_star_line_free(SubGhzProtocolStarLine* instance) {
     free(instance);
 }
 
+const char* subghz_protocol_star_line_get_manufacture_name (void* context){
+    SubGhzProtocolStarLine* instance = context;
+    subghz_protocol_star_line_check_remote_controller(instance);
+    return instance->manufacture_name;
+}
+
 /** Send bit 
  * 
  * @param instance - SubGhzProtocolStarLine instance
@@ -268,20 +276,32 @@ void subghz_protocol_star_line_to_str(SubGhzProtocolStarLine* instance, string_t
     uint32_t code_found_reverse_lo = code_found_reverse&0x00000000ffffffff;
     string_cat_printf(
         output,
-        "%s, %d Bit\r\n"
-        "KEY:0x%lX%lX\r\n"
-        "FIX:%08lX MF:%s \r\n"
-        "HOP:%08lX \r\n"
-        "SN:%06lX CNT:%04X B:%02lX\r\n",
+        "%s %dbit\r\n"
+        "Key:0x%lX%lX\r\n"
+        "Fix:0x%08lX     Cnt:%04X\r\n"
+        "Hop:0x%08lX     Btn:%02lX\r\n"
+        "MF:%s\r\n"
+        "Sn:0x%07lX \r\n",
         instance->common.name,
         instance->common.code_last_count_bit,
         code_found_hi,
         code_found_lo,
         code_found_reverse_hi,
-        instance->manufacture_name,
+        instance->common.cnt,
         code_found_reverse_lo,
-        instance->common.serial,
-        instance->common.cnt, 
-        instance->common.btn
+        instance->common.btn,
+        instance->manufacture_name,
+        instance->common.serial
     );
 }
+
+void subghz_decoder_star_line_to_load_protocol(
+    SubGhzProtocolStarLine* instance,
+    void* context) {
+    furi_assert(context);
+    furi_assert(instance);
+    SubGhzProtocolCommonLoad* data = context;
+    instance->common.code_last_found = data->code_found;
+    instance->common.code_last_count_bit = data->code_count_bit;
+    subghz_protocol_star_line_check_remote_controller(instance);
+}

+ 3 - 0
lib/subghz/protocols/subghz_protocol_star_line.h

@@ -18,6 +18,8 @@ SubGhzProtocolStarLine* subghz_protocol_star_line_alloc(SubGhzKeystore* keystore
  */
 void subghz_protocol_star_line_free(SubGhzProtocolStarLine* instance);
 
+const char* subghz_protocol_star_line_get_manufacture_name(void* context);
+
 /** Sends the key on the air
  * 
  * @param instance - SubGhzProtocolStarLine instance
@@ -51,3 +53,4 @@ void subghz_protocol_star_line_parse(SubGhzProtocolStarLine* instance, bool leve
  * @param output   - output string
  */
 void subghz_protocol_star_line_to_str(SubGhzProtocolStarLine* instance, string_t output);
+void subghz_decoder_star_line_to_load_protocol(SubGhzProtocolStarLine* instance, void* context);

+ 5 - 0
lib/subghz/subghz_worker.c

@@ -117,3 +117,8 @@ void subghz_worker_stop(SubGhzWorker* instance) {
 
     furi_thread_join(instance->thread);
 }
+
+bool subghz_worker_is_running(SubGhzWorker* instance) {
+    furi_assert(instance);
+    return instance->running;
+}

+ 6 - 0
lib/subghz/subghz_worker.h

@@ -54,3 +54,9 @@ void subghz_worker_start(SubGhzWorker* instance);
  * @param instance SubGhzWorker instance
  */
 void subghz_worker_stop(SubGhzWorker* instance);
+
+/** Check if worker is running
+ * @param instance SubGhzWorker instance
+ * @return bool - true if running
+ */
+bool subghz_worker_is_running(SubGhzWorker* instance);

Некоторые файлы не были показаны из-за большого количества измененных файлов