Преглед изворни кода

[FL-2230] SubGhz: protocol API refactoring (#969)

* SubGhz: protocols library refactoring
* SubGhz: new architecture and refactoring
* SubGhz: simplify protocol structure, remove unused types
* SubGhz: rename Subghz to SubGhz
* SubGhz: add environment concept

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
Co-authored-by: DrZlo13 <who.just.the.doctor@gmail.com>
Skorpionm пре 3 година
родитељ
комит
3164184bbc
100 измењених фајлова са 6632 додато и 1141 уклоњено
  1. 3 3
      CODING_STYLE.md
  2. 5 0
      Makefile
  3. 1 1
      applications/ReadMe.md
  4. 12 12
      applications/subghz/helpers/subghz_chat.c
  5. 11 11
      applications/subghz/helpers/subghz_chat.h
  6. 37 37
      applications/subghz/helpers/subghz_custom_event.h
  7. 1 1
      applications/subghz/helpers/subghz_frequency_analyzer_worker.c
  8. 4 5
      applications/subghz/scenes/subghz_scene_delete.c
  9. 5 5
      applications/subghz/scenes/subghz_scene_delete_raw.c
  10. 3 3
      applications/subghz/scenes/subghz_scene_delete_success.c
  11. 2 2
      applications/subghz/scenes/subghz_scene_frequency_analyzer.c
  12. 2 2
      applications/subghz/scenes/subghz_scene_more_raw.c
  13. 5 5
      applications/subghz/scenes/subghz_scene_need_saving.c
  14. 64 59
      applications/subghz/scenes/subghz_scene_read_raw.c
  15. 29 20
      applications/subghz/scenes/subghz_scene_receiver.c
  16. 3 3
      applications/subghz/scenes/subghz_scene_receiver_config.c
  17. 28 22
      applications/subghz/scenes/subghz_scene_receiver_info.c
  18. 24 11
      applications/subghz/scenes/subghz_scene_save_name.c
  19. 3 3
      applications/subghz/scenes/subghz_scene_save_success.c
  20. 1 1
      applications/subghz/scenes/subghz_scene_saved.c
  21. 1 1
      applications/subghz/scenes/subghz_scene_saved_menu.c
  22. 90 55
      applications/subghz/scenes/subghz_scene_set_type.c
  23. 10 10
      applications/subghz/scenes/subghz_scene_show_error.c
  24. 3 3
      applications/subghz/scenes/subghz_scene_show_error_sub.c
  25. 3 3
      applications/subghz/scenes/subghz_scene_show_only_rx.c
  26. 1 1
      applications/subghz/scenes/subghz_scene_start.c
  27. 1 1
      applications/subghz/scenes/subghz_scene_test.c
  28. 3 3
      applications/subghz/scenes/subghz_scene_test_carrier.c
  29. 3 3
      applications/subghz/scenes/subghz_scene_test_packet.c
  30. 3 3
      applications/subghz/scenes/subghz_scene_test_static.c
  31. 19 20
      applications/subghz/scenes/subghz_scene_transmitter.c
  32. 52 44
      applications/subghz/subghz.c
  33. 61 31
      applications/subghz/subghz_cli.c
  34. 134 92
      applications/subghz/subghz_history.c
  35. 6 16
      applications/subghz/subghz_history.h
  36. 115 132
      applications/subghz/subghz_i.c
  37. 40 33
      applications/subghz/subghz_i.h
  38. 53 52
      applications/subghz/views/receiver.c
  39. 36 0
      applications/subghz/views/receiver.h
  40. 20 22
      applications/subghz/views/subghz_frequency_analyzer.c
  41. 7 7
      applications/subghz/views/subghz_frequency_analyzer.h
  42. 116 118
      applications/subghz/views/subghz_read_raw.c
  43. 25 25
      applications/subghz/views/subghz_read_raw.h
  44. 0 36
      applications/subghz/views/subghz_receiver.h
  45. 30 30
      applications/subghz/views/subghz_test_carrier.c
  46. 9 9
      applications/subghz/views/subghz_test_carrier.h
  47. 57 55
      applications/subghz/views/subghz_test_packet.c
  48. 9 9
      applications/subghz/views/subghz_test_packet.h
  49. 31 31
      applications/subghz/views/subghz_test_static.c
  50. 9 9
      applications/subghz/views/subghz_test_static.h
  51. 0 26
      applications/subghz/views/subghz_transmitter.h
  52. 33 34
      applications/subghz/views/transmitter.c
  53. 26 0
      applications/subghz/views/transmitter.h
  54. 0 5
      assets/resources/subghz/assets/nice_flor_s_rx
  55. 0 5
      assets/resources/subghz/assets/nice_flor_s_tx
  56. 6 0
      assets/resources/subghz/nice_flor_s
  57. 3 2
      bootloader/Makefile
  58. 3 2
      firmware/Makefile
  59. 1 1
      lib/ReadMe.md
  60. 1 0
      lib/subghz/blocks/const.c
  61. 12 0
      lib/subghz/blocks/const.h
  62. 17 0
      lib/subghz/blocks/decoder.c
  63. 17 0
      lib/subghz/blocks/decoder.h
  64. 3 0
      lib/subghz/blocks/encoder.c
  65. 16 0
      lib/subghz/blocks/encoder.h
  66. 118 0
      lib/subghz/blocks/generic.c
  67. 30 0
      lib/subghz/blocks/generic.h
  68. 9 0
      lib/subghz/blocks/math.c
  69. 13 0
      lib/subghz/blocks/math.h
  70. 67 0
      lib/subghz/environment.c
  71. 28 0
      lib/subghz/environment.h
  72. 64 0
      lib/subghz/protocols/base.c
  73. 51 0
      lib/subghz/protocols/base.h
  74. 313 0
      lib/subghz/protocols/came.c
  75. 63 0
      lib/subghz/protocols/came.h
  76. 338 0
      lib/subghz/protocols/came_atomo.c
  77. 24 0
      lib/subghz/protocols/came_atomo.h
  78. 445 0
      lib/subghz/protocols/came_twee.c
  79. 30 0
      lib/subghz/protocols/came_twee.h
  80. 218 0
      lib/subghz/protocols/faac_slh.c
  81. 25 0
      lib/subghz/protocols/faac_slh.h
  82. 308 0
      lib/subghz/protocols/gate_tx.c
  83. 30 0
      lib/subghz/protocols/gate_tx.h
  84. 331 0
      lib/subghz/protocols/hormann.c
  85. 30 0
      lib/subghz/protocols/hormann.h
  86. 218 0
      lib/subghz/protocols/ido.c
  87. 25 0
      lib/subghz/protocols/ido.h
  88. 681 0
      lib/subghz/protocols/keeloq.c
  89. 39 0
      lib/subghz/protocols/keeloq.h
  90. 2 2
      lib/subghz/protocols/keeloq_common.c
  91. 4 4
      lib/subghz/protocols/keeloq_common.h
  92. 268 0
      lib/subghz/protocols/kia.c
  93. 25 0
      lib/subghz/protocols/kia.h
  94. 375 0
      lib/subghz/protocols/nero_radio.c
  95. 30 0
      lib/subghz/protocols/nero_radio.h
  96. 366 0
      lib/subghz/protocols/nero_sketch.c
  97. 30 0
      lib/subghz/protocols/nero_sketch.h
  98. 310 0
      lib/subghz/protocols/nice_flo.c
  99. 30 0
      lib/subghz/protocols/nice_flo.h
  100. 366 0
      lib/subghz/protocols/nice_flor_s.c

+ 3 - 3
CODING_STYLE.md

@@ -58,7 +58,7 @@ Examples:
 
 
 	FuriHalUsb
 	FuriHalUsb
 	Gui
 	Gui
-	SubghzKeystore
+	SubGhzKeystore
 
 
 
 
 ### Functions are snake_case
 ### Functions are snake_case
@@ -73,8 +73,8 @@ This rule makes easier to locate types, functions and sources.
 
 
 For example:
 For example:
 
 
-We have abstraction that we call `Subghz Keystore`, so there will be:
-file `subghz_keystore.h` we have type `SubghzKeystore` and function `subghz_keystore_read`.
+We have abstraction that we call `SubGhz Keystore`, so there will be:
+file `subghz_keystore.h` we have type `SubGhzKeystore` and function `subghz_keystore_read`.
 
 
 ### File names
 ### File names
 
 

+ 5 - 0
Makefile

@@ -121,3 +121,8 @@ lint:
 format:
 format:
 	@echo "Reformating sources code"
 	@echo "Reformating sources code"
 	@$(PROJECT_ROOT)/scripts/lint.py format $(PROJECT_SOURCE_DIRECTORIES)
 	@$(PROJECT_ROOT)/scripts/lint.py format $(PROJECT_SOURCE_DIRECTORIES)
+
+.PHONY: guruguru
+guruguru:
+	@echo "ぐるぐる回る"
+	@$(PROJECT_ROOT)/scripts/guruguru.py $(PROJECT_ROOT)

+ 1 - 1
applications/ReadMe.md

@@ -30,7 +30,7 @@
 - `snake_game`          - Snake game application
 - `snake_game`          - Snake game application
 - `storage`             - Storage service, internal + sdcard
 - `storage`             - Storage service, internal + sdcard
 - `storage_settings`    - Storage settings app
 - `storage_settings`    - Storage settings app
-- `subghz`              - Subghz application, 433 fobs and etc
+- `subghz`              - SubGhz application, 433 fobs and etc
 - `system`              - System settings, tools and API
 - `system`              - System settings, tools and API
 - `tests`               - Unit tests and etc
 - `tests`               - Unit tests and etc
 - `u2f`                 - U2F Application
 - `u2f`                 - U2F Application

+ 12 - 12
applications/subghz/helpers/subghz_chat.c

@@ -23,12 +23,12 @@ static int32_t subghz_chat_worker_thread(void* context) {
     SubGhzChatWorker* instance = context;
     SubGhzChatWorker* instance = context;
     FURI_LOG_I(TAG, "Worker start");
     FURI_LOG_I(TAG, "Worker start");
     char c;
     char c;
-    SubghzChatEvent event;
-    event.event = SubghzChatEventUserEntrance;
+    SubGhzChatEvent event;
+    event.event = SubGhzChatEventUserEntrance;
     osMessageQueuePut(instance->event_queue, &event, 0, 0);
     osMessageQueuePut(instance->event_queue, &event, 0, 0);
     while(instance->worker_running) {
     while(instance->worker_running) {
         if(furi_hal_vcp_rx_with_timeout((uint8_t*)&c, 1, 1000) == 1) {
         if(furi_hal_vcp_rx_with_timeout((uint8_t*)&c, 1, 1000) == 1) {
-            event.event = SubghzChatEventInputData;
+            event.event = SubGhzChatEventInputData;
             event.c = c;
             event.c = c;
             osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
             osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
         }
         }
@@ -41,13 +41,13 @@ static int32_t subghz_chat_worker_thread(void* context) {
 static void subghz_chat_worker_update_rx_event_chat(void* context) {
 static void subghz_chat_worker_update_rx_event_chat(void* context) {
     furi_assert(context);
     furi_assert(context);
     SubGhzChatWorker* instance = context;
     SubGhzChatWorker* instance = context;
-    SubghzChatEvent event;
+    SubGhzChatEvent event;
     if((millis() - instance->last_time_rx_data) > SUBGHZ_CHAT_WORKER_TIMEOUT_BETWEEN_MESSAGES) {
     if((millis() - instance->last_time_rx_data) > SUBGHZ_CHAT_WORKER_TIMEOUT_BETWEEN_MESSAGES) {
-        event.event = SubghzChatEventNewMessage;
+        event.event = SubGhzChatEventNewMessage;
         osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
         osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
     }
     }
     instance->last_time_rx_data = millis();
     instance->last_time_rx_data = millis();
-    event.event = SubghzChatEventRXData;
+    event.event = SubGhzChatEventRXData;
     osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
     osMessageQueuePut(instance->event_queue, &event, 0, osWaitForever);
 }
 }
 
 
@@ -55,12 +55,12 @@ SubGhzChatWorker* subghz_chat_worker_alloc() {
     SubGhzChatWorker* instance = malloc(sizeof(SubGhzChatWorker));
     SubGhzChatWorker* instance = malloc(sizeof(SubGhzChatWorker));
 
 
     instance->thread = furi_thread_alloc();
     instance->thread = furi_thread_alloc();
-    furi_thread_set_name(instance->thread, "SubghzChat");
+    furi_thread_set_name(instance->thread, "SubGhzChat");
     furi_thread_set_stack_size(instance->thread, 2048);
     furi_thread_set_stack_size(instance->thread, 2048);
     furi_thread_set_context(instance->thread, instance);
     furi_thread_set_context(instance->thread, instance);
     furi_thread_set_callback(instance->thread, subghz_chat_worker_thread);
     furi_thread_set_callback(instance->thread, subghz_chat_worker_thread);
     instance->subghz_txrx = subghz_tx_rx_worker_alloc();
     instance->subghz_txrx = subghz_tx_rx_worker_alloc();
-    instance->event_queue = osMessageQueueNew(80, sizeof(SubghzChatEvent), NULL);
+    instance->event_queue = osMessageQueueNew(80, sizeof(SubGhzChatEvent), NULL);
     return instance;
     return instance;
 }
 }
 
 
@@ -109,18 +109,18 @@ bool subghz_chat_worker_is_running(SubGhzChatWorker* instance) {
     return instance->worker_running;
     return instance->worker_running;
 }
 }
 
 
-SubghzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance) {
+SubGhzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance) {
     furi_assert(instance);
     furi_assert(instance);
-    SubghzChatEvent event;
+    SubGhzChatEvent event;
     if(osMessageQueueGet(instance->event_queue, &event, NULL, osWaitForever) == osOK) {
     if(osMessageQueueGet(instance->event_queue, &event, NULL, osWaitForever) == osOK) {
         return event;
         return event;
     } else {
     } else {
-        event.event = SubghzChatEventNoEvent;
+        event.event = SubGhzChatEventNoEvent;
         return event;
         return event;
     }
     }
 }
 }
 
 
-void subghz_chat_worker_put_event_chat(SubGhzChatWorker* instance, SubghzChatEvent* event) {
+void subghz_chat_worker_put_event_chat(SubGhzChatWorker* instance, SubGhzChatEvent* event) {
     furi_assert(instance);
     furi_assert(instance);
     osMessageQueuePut(instance->event_queue, event, 0, osWaitForever);
     osMessageQueuePut(instance->event_queue, event, 0, osWaitForever);
 }
 }

+ 11 - 11
applications/subghz/helpers/subghz_chat.h

@@ -4,26 +4,26 @@
 typedef struct SubGhzChatWorker SubGhzChatWorker;
 typedef struct SubGhzChatWorker SubGhzChatWorker;
 
 
 typedef enum {
 typedef enum {
-    SubghzChatEventNoEvent,
-    SubghzChatEventUserEntrance,
-    SubghzChatEventUserExit,
-    SubghzChatEventInputData,
-    SubghzChatEventRXData,
-    SubghzChatEventNewMessage,
-} SubghzChatEventType;
+    SubGhzChatEventNoEvent,
+    SubGhzChatEventUserEntrance,
+    SubGhzChatEventUserExit,
+    SubGhzChatEventInputData,
+    SubGhzChatEventRXData,
+    SubGhzChatEventNewMessage,
+} SubGhzChatEventType;
 
 
 typedef struct {
 typedef struct {
-    SubghzChatEventType event;
+    SubGhzChatEventType event;
     char c;
     char c;
-} SubghzChatEvent;
+} SubGhzChatEvent;
 
 
 SubGhzChatWorker* subghz_chat_worker_alloc();
 SubGhzChatWorker* subghz_chat_worker_alloc();
 void subghz_chat_worker_free(SubGhzChatWorker* instance);
 void subghz_chat_worker_free(SubGhzChatWorker* instance);
 bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency);
 bool subghz_chat_worker_start(SubGhzChatWorker* instance, uint32_t frequency);
 void subghz_chat_worker_stop(SubGhzChatWorker* instance);
 void subghz_chat_worker_stop(SubGhzChatWorker* instance);
 bool subghz_chat_worker_is_running(SubGhzChatWorker* instance);
 bool subghz_chat_worker_is_running(SubGhzChatWorker* instance);
-SubghzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance);
-void subghz_chat_worker_put_event_chat(SubGhzChatWorker* instance, SubghzChatEvent* event);
+SubGhzChatEvent subghz_chat_worker_get_event_chat(SubGhzChatWorker* instance);
+void subghz_chat_worker_put_event_chat(SubGhzChatWorker* instance, SubGhzChatEvent* event);
 size_t subghz_chat_worker_available(SubGhzChatWorker* instance);
 size_t subghz_chat_worker_available(SubGhzChatWorker* instance);
 size_t subghz_chat_worker_read(SubGhzChatWorker* instance, uint8_t* data, size_t size);
 size_t subghz_chat_worker_read(SubGhzChatWorker* instance, uint8_t* data, size_t size);
 bool subghz_chat_worker_write(SubGhzChatWorker* instance, uint8_t* data, size_t size);
 bool subghz_chat_worker_write(SubGhzChatWorker* instance, uint8_t* data, size_t size);

+ 37 - 37
applications/subghz/helpers/subghz_custom_event.h

@@ -1,46 +1,46 @@
 #pragma once
 #pragma once
 
 
 typedef enum {
 typedef enum {
-    SubghzCustomEventManagerNoSet = 0,
-    SubghzCustomEventManagerSet,
-    SubghzCustomEventManagerSetRAW,
+    SubGhzCustomEventManagerNoSet = 0,
+    SubGhzCustomEventManagerSet,
+    SubGhzCustomEventManagerSetRAW,
 
 
-    SubghzCustomEventSceneDeleteSuccess = 100,
-    SubghzCustomEventSceneDelete,
-    SubghzCustomEventSceneDeleteRAW,
-    SubghzCustomEventSceneDeleteRAWBack,
+    SubGhzCustomEventSceneDeleteSuccess = 100,
+    SubGhzCustomEventSceneDelete,
+    SubGhzCustomEventSceneDeleteRAW,
+    SubGhzCustomEventSceneDeleteRAWBack,
 
 
-    SubghzCustomEventSceneReceiverInfoTxStart,
-    SubghzCustomEventSceneReceiverInfoTxStop,
-    SubghzCustomEventSceneReceiverInfoSave,
-    SubghzCustomEventSceneSaveName,
-    SubghzCustomEventSceneSaveSuccess,
-    SubghzCustomEventSceneShowErrorBack,
-    SubghzCustomEventSceneShowErrorOk,
-    SubghzCustomEventSceneShowErrorSub,
-    SubghzCustomEventSceneShowOnlyRX,
+    SubGhzCustomEventSceneReceiverInfoTxStart,
+    SubGhzCustomEventSceneReceiverInfoTxStop,
+    SubGhzCustomEventSceneReceiverInfoSave,
+    SubGhzCustomEventSceneSaveName,
+    SubGhzCustomEventSceneSaveSuccess,
+    SubGhzCustomEventSceneShowErrorBack,
+    SubGhzCustomEventSceneShowErrorOk,
+    SubGhzCustomEventSceneShowErrorSub,
+    SubGhzCustomEventSceneShowOnlyRX,
 
 
-    SubghzCustomEventSceneExit,
-    SubghzCustomEventSceneStay,
+    SubGhzCustomEventSceneExit,
+    SubGhzCustomEventSceneStay,
 
 
-    SubghzCustomEventViewReceverOK,
-    SubghzCustomEventViewReceverConfig,
-    SubghzCustomEventViewReceverBack,
+    SubGhzCustomEventViewReceverOK,
+    SubGhzCustomEventViewReceverConfig,
+    SubGhzCustomEventViewReceverBack,
 
 
-    SubghzCustomEventViewReadRAWBack,
-    SubghzCustomEventViewReadRAWIDLE,
-    SubghzCustomEventViewReadRAWREC,
-    SubghzCustomEventViewReadRAWConfig,
-    SubghzCustomEventViewReadRAWErase,
-    SubghzCustomEventViewReadRAWSendStart,
-    SubghzCustomEventViewReadRAWSendStop,
-    SubghzCustomEventViewReadRAWSave,
-    SubghzCustomEventViewReadRAWVibro,
-    SubghzCustomEventViewReadRAWTXRXStop,
-    SubghzCustomEventViewReadRAWMore,
+    SubGhzCustomEventViewReadRAWBack,
+    SubGhzCustomEventViewReadRAWIDLE,
+    SubGhzCustomEventViewReadRAWREC,
+    SubGhzCustomEventViewReadRAWConfig,
+    SubGhzCustomEventViewReadRAWErase,
+    SubGhzCustomEventViewReadRAWSendStart,
+    SubGhzCustomEventViewReadRAWSendStop,
+    SubGhzCustomEventViewReadRAWSave,
+    SubGhzCustomEventViewReadRAWVibro,
+    SubGhzCustomEventViewReadRAWTXRXStop,
+    SubGhzCustomEventViewReadRAWMore,
 
 
-    SubghzCustomEventViewTransmitterBack,
-    SubghzCustomEventViewTransmitterSendStart,
-    SubghzCustomEventViewTransmitterSendStop,
-    SubghzCustomEventViewTransmitterError,
-} SubghzCustomEvent;
+    SubGhzCustomEventViewTransmitterBack,
+    SubGhzCustomEventViewTransmitterSendStart,
+    SubGhzCustomEventViewTransmitterSendStop,
+    SubGhzCustomEventViewTransmitterError,
+} SubGhzCustomEvent;

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

@@ -145,7 +145,7 @@ SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc() {
     SubGhzFrequencyAnalyzerWorker* instance = malloc(sizeof(SubGhzFrequencyAnalyzerWorker));
     SubGhzFrequencyAnalyzerWorker* instance = malloc(sizeof(SubGhzFrequencyAnalyzerWorker));
 
 
     instance->thread = furi_thread_alloc();
     instance->thread = furi_thread_alloc();
-    furi_thread_set_name(instance->thread, "SubghzFAWorker");
+    furi_thread_set_name(instance->thread, "SubGhzFAWorker");
     furi_thread_set_stack_size(instance->thread, 2048);
     furi_thread_set_stack_size(instance->thread, 2048);
     furi_thread_set_context(instance->thread, instance);
     furi_thread_set_context(instance->thread, instance);
     furi_thread_set_callback(instance->thread, subghz_frequency_analyzer_worker_thread);
     furi_thread_set_callback(instance->thread, subghz_frequency_analyzer_worker_thread);

+ 4 - 5
applications/subghz/scenes/subghz_scene_delete.c

@@ -5,7 +5,7 @@ void subghz_scene_delete_callback(GuiButtonType result, InputType type, void* co
     furi_assert(context);
     furi_assert(context);
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     if((result == GuiButtonTypeRight) && (type == InputTypeShort)) {
     if((result == GuiButtonTypeRight) && (type == InputTypeShort)) {
-        view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneDelete);
+        view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneDelete);
     }
     }
 }
 }
 
 
@@ -31,8 +31,7 @@ void subghz_scene_delete_on_enter(void* context) {
         AlignTop,
         AlignTop,
         FontSecondary,
         FontSecondary,
         string_get_cstr(modulation_str));
         string_get_cstr(modulation_str));
-
-    subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, text);
+    subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text);
     widget_add_string_multiline_element(
     widget_add_string_multiline_element(
         subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, string_get_cstr(text));
         subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, string_get_cstr(text));
 
 
@@ -43,13 +42,13 @@ void subghz_scene_delete_on_enter(void* context) {
     widget_add_button_element(
     widget_add_button_element(
         subghz->widget, GuiButtonTypeRight, "Delete", subghz_scene_delete_callback, subghz);
         subghz->widget, GuiButtonTypeRight, "Delete", subghz_scene_delete_callback, subghz);
 
 
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdWidget);
 }
 }
 
 
 bool subghz_scene_delete_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_delete_on_event(void* context, SceneManagerEvent event) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubghzCustomEventSceneDelete) {
+        if(event.event == SubGhzCustomEventSceneDelete) {
             strcpy(subghz->file_name_tmp, subghz->file_name);
             strcpy(subghz->file_name_tmp, subghz->file_name);
             if(subghz_delete_file(subghz)) {
             if(subghz_delete_file(subghz)) {
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess);
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess);

+ 5 - 5
applications/subghz/scenes/subghz_scene_delete_raw.c

@@ -6,10 +6,10 @@ void subghz_scene_delete_raw_callback(GuiButtonType result, InputType type, void
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     if((result == GuiButtonTypeRight) && (type == InputTypeShort)) {
     if((result == GuiButtonTypeRight) && (type == InputTypeShort)) {
         view_dispatcher_send_custom_event(
         view_dispatcher_send_custom_event(
-            subghz->view_dispatcher, SubghzCustomEventSceneDeleteRAW);
+            subghz->view_dispatcher, SubGhzCustomEventSceneDeleteRAW);
     } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
     } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
         view_dispatcher_send_custom_event(
         view_dispatcher_send_custom_event(
-            subghz->view_dispatcher, SubghzCustomEventSceneDeleteRAWBack);
+            subghz->view_dispatcher, SubGhzCustomEventSceneDeleteRAWBack);
     }
     }
 }
 }
 
 
@@ -49,13 +49,13 @@ void subghz_scene_delete_raw_on_enter(void* context) {
     widget_add_button_element(
     widget_add_button_element(
         subghz->widget, GuiButtonTypeLeft, "Back", subghz_scene_delete_raw_callback, subghz);
         subghz->widget, GuiButtonTypeLeft, "Back", subghz_scene_delete_raw_callback, subghz);
 
 
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdWidget);
 }
 }
 
 
 bool subghz_scene_delete_raw_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_delete_raw_on_event(void* context, SceneManagerEvent event) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubghzCustomEventSceneDeleteRAW) {
+        if(event.event == SubGhzCustomEventSceneDeleteRAW) {
             strcpy(subghz->file_name_tmp, subghz->file_name);
             strcpy(subghz->file_name_tmp, subghz->file_name);
             if(subghz_delete_file(subghz)) {
             if(subghz_delete_file(subghz)) {
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess);
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteSuccess);
@@ -64,7 +64,7 @@ bool subghz_scene_delete_raw_on_event(void* context, SceneManagerEvent event) {
                     subghz->scene_manager, SubGhzSceneStart);
                     subghz->scene_manager, SubGhzSceneStart);
             }
             }
             return true;
             return true;
-        } else if(event.event == SubghzCustomEventSceneDeleteRAWBack) {
+        } else if(event.event == SubGhzCustomEventSceneDeleteRAWBack) {
             return scene_manager_previous_scene(subghz->scene_manager);
             return scene_manager_previous_scene(subghz->scene_manager);
         }
         }
     }
     }

+ 3 - 3
applications/subghz/scenes/subghz_scene_delete_success.c

@@ -4,7 +4,7 @@
 void subghz_scene_delete_success_popup_callback(void* context) {
 void subghz_scene_delete_success_popup_callback(void* context) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     view_dispatcher_send_custom_event(
     view_dispatcher_send_custom_event(
-        subghz->view_dispatcher, SubghzCustomEventSceneDeleteSuccess);
+        subghz->view_dispatcher, SubGhzCustomEventSceneDeleteSuccess);
 }
 }
 
 
 void subghz_scene_delete_success_on_enter(void* context) {
 void subghz_scene_delete_success_on_enter(void* context) {
@@ -18,14 +18,14 @@ void subghz_scene_delete_success_on_enter(void* context) {
     popup_set_context(popup, subghz);
     popup_set_context(popup, subghz);
     popup_set_callback(popup, subghz_scene_delete_success_popup_callback);
     popup_set_callback(popup, subghz_scene_delete_success_popup_callback);
     popup_enable_timeout(popup);
     popup_enable_timeout(popup);
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdPopup);
 }
 }
 
 
 bool subghz_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubghzCustomEventSceneDeleteSuccess) {
+        if(event.event == SubGhzCustomEventSceneDeleteSuccess) {
             if(!scene_manager_search_and_switch_to_previous_scene(
             if(!scene_manager_search_and_switch_to_previous_scene(
                    subghz->scene_manager, SubGhzSceneSaved)) {
                    subghz->scene_manager, SubGhzSceneSaved)) {
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved);
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaved);

+ 2 - 2
applications/subghz/scenes/subghz_scene_frequency_analyzer.c

@@ -2,7 +2,7 @@
 #include "../views/subghz_frequency_analyzer.h"
 #include "../views/subghz_frequency_analyzer.h"
 #include <dolphin/dolphin.h>
 #include <dolphin/dolphin.h>
 
 
-void subghz_scene_frequency_analyzer_callback(SubghzCustomEvent event, void* context) {
+void subghz_scene_frequency_analyzer_callback(SubGhzCustomEvent event, void* context) {
     furi_assert(context);
     furi_assert(context);
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
     view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
@@ -13,7 +13,7 @@ void subghz_scene_frequency_analyzer_on_enter(void* context) {
     DOLPHIN_DEED(DolphinDeedSubGhzFrequencyAnalyzer);
     DOLPHIN_DEED(DolphinDeedSubGhzFrequencyAnalyzer);
     subghz_frequency_analyzer_set_callback(
     subghz_frequency_analyzer_set_callback(
         subghz->subghz_frequency_analyzer, subghz_scene_frequency_analyzer_callback, subghz);
         subghz->subghz_frequency_analyzer, subghz_scene_frequency_analyzer_callback, subghz);
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewFrequencyAnalyzer);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdFrequencyAnalyzer);
 }
 }
 
 
 bool subghz_scene_frequency_analyzer_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_frequency_analyzer_on_event(void* context, SceneManagerEvent event) {

+ 2 - 2
applications/subghz/scenes/subghz_scene_more_raw.c

@@ -30,7 +30,7 @@ void subghz_scene_more_raw_on_enter(void* context) {
     submenu_set_selected_item(
     submenu_set_selected_item(
         subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneMoreRAW));
         subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneMoreRAW));
 
 
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewMenu);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdMenu);
 }
 }
 
 
 bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) {
@@ -39,7 +39,7 @@ bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) {
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == SubmenuIndexDelete) {
         if(event.event == SubmenuIndexDelete) {
             scene_manager_set_scene_state(
             scene_manager_set_scene_state(
-                subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet);
+                subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
             scene_manager_set_scene_state(
             scene_manager_set_scene_state(
                 subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexDelete);
                 subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexDelete);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteRAW);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteRAW);

+ 5 - 5
applications/subghz/scenes/subghz_scene_need_saving.c

@@ -6,9 +6,9 @@ void subghz_scene_need_saving_callback(GuiButtonType result, InputType type, voi
     SubGhz* subghz = context;
     SubGhz* subghz = context;
 
 
     if((result == GuiButtonTypeRight) && (type == InputTypeShort)) {
     if((result == GuiButtonTypeRight) && (type == InputTypeShort)) {
-        view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneStay);
+        view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneStay);
     } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
     } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
-        view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneExit);
+        view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneExit);
     }
     }
 }
 }
 
 
@@ -31,7 +31,7 @@ void subghz_scene_need_saving_on_enter(void* context) {
     widget_add_button_element(
     widget_add_button_element(
         subghz->widget, GuiButtonTypeLeft, "Exit", subghz_scene_need_saving_callback, subghz);
         subghz->widget, GuiButtonTypeLeft, "Exit", subghz_scene_need_saving_callback, subghz);
 
 
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdWidget);
 }
 }
 
 
 bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) {
@@ -41,11 +41,11 @@ bool subghz_scene_need_saving_on_event(void* context, SceneManagerEvent event) {
         scene_manager_previous_scene(subghz->scene_manager);
         scene_manager_previous_scene(subghz->scene_manager);
         return true;
         return true;
     } else if(event.type == SceneManagerEventTypeCustom) {
     } else if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubghzCustomEventSceneStay) {
+        if(event.event == SubGhzCustomEventSceneStay) {
             subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
             subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
             scene_manager_previous_scene(subghz->scene_manager);
             scene_manager_previous_scene(subghz->scene_manager);
             return true;
             return true;
-        } else if(event.event == SubghzCustomEventSceneExit) {
+        } else if(event.event == SubGhzCustomEventSceneExit) {
             if(subghz->txrx->rx_key_state == SubGhzRxKeyStateExit) {
             if(subghz->txrx->rx_key_state == SubGhzRxKeyStateExit) {
                 subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
                 subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
                 scene_manager_search_and_switch_to_previous_scene(
                 scene_manager_search_and_switch_to_previous_scene(

+ 64 - 59
applications/subghz/scenes/subghz_scene_read_raw.c

@@ -1,35 +1,35 @@
 #include "../subghz_i.h"
 #include "../subghz_i.h"
 #include "../views/subghz_read_raw.h"
 #include "../views/subghz_read_raw.h"
 #include <dolphin/dolphin.h>
 #include <dolphin/dolphin.h>
-#include <lib/subghz/protocols/subghz_protocol_raw.h>
-#include <lib/subghz/subghz_parser.h>
+#include <lib/subghz/protocols/raw.h>
 #include <lib/toolbox/path.h>
 #include <lib/toolbox/path.h>
 
 
 #define RAW_FILE_NAME "Raw_signal_"
 #define RAW_FILE_NAME "Raw_signal_"
+#define TAG "SubGhzSceneReadRAW"
 
 
 bool subghz_scene_read_raw_update_filename(SubGhz* subghz) {
 bool subghz_scene_read_raw_update_filename(SubGhz* subghz) {
     bool ret = false;
     bool ret = false;
     //set the path to read the file
     //set the path to read the file
-    if(strcmp(
-           subghz_protocol_raw_get_last_file_name(
-               (SubGhzProtocolRAW*)subghz->txrx->protocol_result),
-           "")) {
-        string_t temp_str;
-        string_init_printf(
-            temp_str,
-            "%s",
-            subghz_protocol_raw_get_last_file_name(
-                (SubGhzProtocolRAW*)subghz->txrx->protocol_result));
+    string_t temp_str;
+    string_init(temp_str);
+    do {
+        if(!flipper_format_rewind(subghz->txrx->fff_data)) {
+            FURI_LOG_E(TAG, "Rewind error");
+            break;
+        }
+
+        if(!flipper_format_read_string(subghz->txrx->fff_data, "File_name", temp_str)) {
+            FURI_LOG_E(TAG, "Missing File_name");
+            break;
+        }
+
         path_extract_filename_no_ext(string_get_cstr(temp_str), temp_str);
         path_extract_filename_no_ext(string_get_cstr(temp_str), temp_str);
         strcpy(subghz->file_name, string_get_cstr(temp_str));
         strcpy(subghz->file_name, string_get_cstr(temp_str));
-        string_printf(
-            temp_str, "%s/%s%s", SUBGHZ_APP_FOLDER, subghz->file_name, SUBGHZ_APP_EXTENSION);
 
 
-        subghz_protocol_raw_set_last_file_name(
-            (SubGhzProtocolRAW*)subghz->txrx->protocol_result, string_get_cstr(temp_str));
-        string_clear(temp_str);
         ret = true;
         ret = true;
-    }
+    } while(false);
+
+    string_clear(temp_str);
     return ret;
     return ret;
 }
 }
 
 
@@ -51,7 +51,7 @@ static void subghz_scene_read_raw_update_statusbar(void* context) {
     string_clear(modulation_str);
     string_clear(modulation_str);
 }
 }
 
 
-void subghz_scene_read_raw_callback(SubghzCustomEvent event, void* context) {
+void subghz_scene_read_raw_callback(SubGhzCustomEvent event, void* context) {
     furi_assert(context);
     furi_assert(context);
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
     view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
@@ -61,7 +61,7 @@ void subghz_scene_read_raw_callback_end_tx(void* context) {
     furi_assert(context);
     furi_assert(context);
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     view_dispatcher_send_custom_event(
     view_dispatcher_send_custom_event(
-        subghz->view_dispatcher, SubghzCustomEventViewReadRAWSendStop);
+        subghz->view_dispatcher, SubGhzCustomEventViewReadRAWSendStop);
 }
 }
 
 
 void subghz_scene_read_raw_on_enter(void* context) {
 void subghz_scene_read_raw_on_enter(void* context) {
@@ -69,46 +69,43 @@ void subghz_scene_read_raw_on_enter(void* context) {
 
 
     switch(subghz->txrx->rx_key_state) {
     switch(subghz->txrx->rx_key_state) {
     case SubGhzRxKeyStateBack:
     case SubGhzRxKeyStateBack:
-        subghz_read_raw_set_status(subghz->subghz_read_raw, SubghzReadRAWStatusIDLE, "");
+        subghz_read_raw_set_status(subghz->subghz_read_raw, SubGhzReadRAWStatusIDLE, "");
         break;
         break;
     case SubGhzRxKeyStateRAWLoad:
     case SubGhzRxKeyStateRAWLoad:
         subghz_read_raw_set_status(
         subghz_read_raw_set_status(
-            subghz->subghz_read_raw, SubghzReadRAWStatusLoadKeyTX, subghz->file_name);
+            subghz->subghz_read_raw, SubGhzReadRAWStatusLoadKeyTX, subghz->file_name);
         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
         break;
         break;
     case SubGhzRxKeyStateRAWSave:
     case SubGhzRxKeyStateRAWSave:
         subghz_read_raw_set_status(
         subghz_read_raw_set_status(
-            subghz->subghz_read_raw, SubghzReadRAWStatusSaveKey, subghz->file_name);
+            subghz->subghz_read_raw, SubGhzReadRAWStatusSaveKey, subghz->file_name);
         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
         break;
         break;
     default:
     default:
-        subghz_read_raw_set_status(subghz->subghz_read_raw, SubghzReadRAWStatusStart, "");
+        subghz_read_raw_set_status(subghz->subghz_read_raw, SubGhzReadRAWStatusStart, "");
         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
         subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
         break;
         break;
     }
     }
 
 
     subghz_scene_read_raw_update_statusbar(subghz);
     subghz_scene_read_raw_update_statusbar(subghz);
-    subghz_read_raw_set_callback(subghz->subghz_read_raw, subghz_scene_read_raw_callback, subghz);
-
-    subghz->txrx->protocol_result = subghz_parser_get_by_name(subghz->txrx->parser, "RAW");
-    furi_assert(subghz->txrx->protocol_result);
 
 
-    subghz_worker_set_pair_callback(
-        subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_parser_raw_parse);
+    //set callback view raw
+    subghz_read_raw_set_callback(subghz->subghz_read_raw, subghz_scene_read_raw_callback, subghz);
 
 
-    subghz_protocol_raw_file_encoder_worker_set_callback_end(
-        (SubGhzProtocolRAW*)subghz->txrx->protocol_result,
-        subghz_scene_read_raw_callback_end_tx,
-        subghz);
+    subghz->txrx->decoder_result =
+        subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, "RAW");
+    furi_assert(subghz->txrx->decoder_result);
 
 
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewReadRAW);
+    //set filter RAW feed
+    subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_RAW);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReadRAW);
 }
 }
 
 
 bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         switch(event.event) {
         switch(event.event) {
-        case SubghzCustomEventViewReadRAWBack:
+        case SubGhzCustomEventViewReadRAWBack:
             //Stop TX
             //Stop TX
             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
                 subghz_tx_stop(subghz);
                 subghz_tx_stop(subghz);
@@ -121,7 +118,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
             };
             };
             //Stop save file
             //Stop save file
             subghz_protocol_raw_save_to_file_stop(
             subghz_protocol_raw_save_to_file_stop(
-                (SubGhzProtocolRAW*)subghz->txrx->protocol_result);
+                (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result);
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             //needed save?
             //needed save?
             if((subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) ||
             if((subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) ||
@@ -144,7 +141,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
             return true;
             return true;
             break;
             break;
 
 
-        case SubghzCustomEventViewReadRAWTXRXStop:
+        case SubGhzCustomEventViewReadRAWTXRXStop:
             //Stop TX
             //Stop TX
             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
                 subghz_tx_stop(subghz);
                 subghz_tx_stop(subghz);
@@ -159,27 +156,27 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
             return true;
             return true;
             break;
             break;
 
 
-        case SubghzCustomEventViewReadRAWConfig:
+        case SubGhzCustomEventViewReadRAWConfig:
             scene_manager_set_scene_state(
             scene_manager_set_scene_state(
-                subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerSet);
+                subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig);
             return true;
             return true;
             break;
             break;
 
 
-        case SubghzCustomEventViewReadRAWErase:
+        case SubGhzCustomEventViewReadRAWErase:
             subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
             subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
             return true;
             return true;
             break;
             break;
 
 
-        case SubghzCustomEventViewReadRAWVibro:
+        case SubGhzCustomEventViewReadRAWVibro:
             notification_message(subghz->notifications, &sequence_single_vibro);
             notification_message(subghz->notifications, &sequence_single_vibro);
             return true;
             return true;
             break;
             break;
 
 
-        case SubghzCustomEventViewReadRAWMore:
+        case SubGhzCustomEventViewReadRAWMore:
             if(subghz_scene_read_raw_update_filename(subghz)) {
             if(subghz_scene_read_raw_update_filename(subghz)) {
                 scene_manager_set_scene_state(
                 scene_manager_set_scene_state(
-                    subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerSet);
+                    subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet);
                 subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
                 subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW);
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW);
                 return true;
                 return true;
@@ -188,7 +185,8 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
             }
             }
             break;
             break;
 
 
-        case SubghzCustomEventViewReadRAWSendStart:
+        case SubGhzCustomEventViewReadRAWSendStart:
+
             if(subghz_scene_read_raw_update_filename(subghz)) {
             if(subghz_scene_read_raw_update_filename(subghz)) {
                 //start send
                 //start send
                 subghz->state_notifications = SubGhzNotificationStateIDLE;
                 subghz->state_notifications = SubGhzNotificationStateIDLE;
@@ -197,10 +195,17 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
                 }
                 }
                 if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
                 if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
                    (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
                    (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
-                    if(!subghz_tx_start(subghz)) {
+                    //ToDo FIX
+
+                    if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) {
                         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
                         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
                     } else {
                     } else {
                         DOLPHIN_DEED(DolphinDeedSubGhzSend);
                         DOLPHIN_DEED(DolphinDeedSubGhzSend);
+                        // set callback end tx
+                        subghz_protocol_raw_file_encoder_worker_set_callback_end(
+                            (SubGhzProtocolEncoderRAW*)subghz->txrx->transmitter->protocol_instance,
+                            subghz_scene_read_raw_callback_end_tx,
+                            subghz);
                         subghz->state_notifications = SubGhzNotificationStateTX;
                         subghz->state_notifications = SubGhzNotificationStateTX;
                     }
                     }
                 }
                 }
@@ -208,7 +213,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
             return true;
             return true;
             break;
             break;
 
 
-        case SubghzCustomEventViewReadRAWSendStop:
+        case SubGhzCustomEventViewReadRAWSendStop:
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
                 subghz_tx_stop(subghz);
                 subghz_tx_stop(subghz);
@@ -218,13 +223,14 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
             return true;
             return true;
             break;
             break;
 
 
-        case SubghzCustomEventViewReadRAWIDLE:
+        case SubGhzCustomEventViewReadRAWIDLE:
             if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
             if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
                 subghz_rx_end(subghz);
                 subghz_rx_end(subghz);
                 subghz_sleep(subghz);
                 subghz_sleep(subghz);
             };
             };
             subghz_protocol_raw_save_to_file_stop(
             subghz_protocol_raw_save_to_file_stop(
-                (SubGhzProtocolRAW*)subghz->txrx->protocol_result);
+                (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result);
+            subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, RAW_FILE_NAME);
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             subghz->state_notifications = SubGhzNotificationStateIDLE;
 
 
             subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
             subghz->txrx->rx_key_state = SubGhzRxKeyStateAddKey;
@@ -232,16 +238,16 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
             return true;
             return true;
             break;
             break;
 
 
-        case SubghzCustomEventViewReadRAWREC:
+        case SubGhzCustomEventViewReadRAWREC:
             if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) {
             if(subghz->txrx->rx_key_state != SubGhzRxKeyStateIDLE) {
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNeedSaving);
             } else {
             } else {
-                subghz_get_preset_name(subghz, subghz->error_str);
+                //subghz_get_preset_name(subghz, subghz->error_str);
                 if(subghz_protocol_raw_save_to_file_init(
                 if(subghz_protocol_raw_save_to_file_init(
-                       (SubGhzProtocolRAW*)subghz->txrx->protocol_result,
+                       (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result,
                        RAW_FILE_NAME,
                        RAW_FILE_NAME,
                        subghz->txrx->frequency,
                        subghz->txrx->frequency,
-                       string_get_cstr(subghz->error_str))) {
+                       subghz->txrx->preset)) {
                     DOLPHIN_DEED(DolphinDeedSubGhzRawRec);
                     DOLPHIN_DEED(DolphinDeedSubGhzRawRec);
                     if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
                     if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
                        (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
                        (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
@@ -258,10 +264,10 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
             return true;
             return true;
             break;
             break;
 
 
-        case SubghzCustomEventViewReadRAWSave:
+        case SubGhzCustomEventViewReadRAWSave:
             if(subghz_scene_read_raw_update_filename(subghz)) {
             if(subghz_scene_read_raw_update_filename(subghz)) {
                 scene_manager_set_scene_state(
                 scene_manager_set_scene_state(
-                    subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerSetRAW);
+                    subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSetRAW);
                 subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
                 subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
             }
             }
@@ -278,7 +284,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
             subghz_read_raw_update_sample_write(
             subghz_read_raw_update_sample_write(
                 subghz->subghz_read_raw,
                 subghz->subghz_read_raw,
                 subghz_protocol_raw_get_sample_write(
                 subghz_protocol_raw_get_sample_write(
-                    (SubGhzProtocolRAW*)subghz->txrx->protocol_result));
+                    (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result));
             subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, furi_hal_subghz_get_rssi());
             subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, furi_hal_subghz_get_rssi());
             break;
             break;
         case SubGhzNotificationStateTX:
         case SubGhzNotificationStateTX:
@@ -302,7 +308,6 @@ void subghz_scene_read_raw_on_exit(void* context) {
     };
     };
     subghz->state_notifications = SubGhzNotificationStateIDLE;
     subghz->state_notifications = SubGhzNotificationStateIDLE;
 
 
-    //Сallback restoration
-    subghz_worker_set_pair_callback(
-        subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_parser_parse);
+    //filter restoration
+    subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_Decodable);
 }
 }

+ 29 - 20
applications/subghz/scenes/subghz_scene_receiver.c

@@ -1,5 +1,5 @@
 #include "../subghz_i.h"
 #include "../subghz_i.h"
-#include "../views/subghz_receiver.h"
+#include "../views/receiver.h"
 
 
 static void subghz_scene_receiver_update_statusbar(void* context) {
 static void subghz_scene_receiver_update_statusbar(void* context) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
@@ -14,7 +14,7 @@ static void subghz_scene_receiver_update_statusbar(void* context) {
 
 
         subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
         subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
 
 
-        subghz_receiver_add_data_statusbar(
+        subghz_view_receiver_add_data_statusbar(
             subghz->subghz_receiver,
             subghz->subghz_receiver,
             string_get_cstr(frequency_str),
             string_get_cstr(frequency_str),
             string_get_cstr(modulation_str),
             string_get_cstr(modulation_str),
@@ -23,36 +23,41 @@ static void subghz_scene_receiver_update_statusbar(void* context) {
         string_clear(frequency_str);
         string_clear(frequency_str);
         string_clear(modulation_str);
         string_clear(modulation_str);
     } else {
     } else {
-        subghz_receiver_add_data_statusbar(
+        subghz_view_receiver_add_data_statusbar(
             subghz->subghz_receiver, string_get_cstr(history_stat_str), "", "");
             subghz->subghz_receiver, string_get_cstr(history_stat_str), "", "");
         subghz->state_notifications = SubGhzNotificationStateIDLE;
         subghz->state_notifications = SubGhzNotificationStateIDLE;
     }
     }
     string_clear(history_stat_str);
     string_clear(history_stat_str);
 }
 }
 
 
-void subghz_scene_receiver_callback(SubghzCustomEvent event, void* context) {
+void subghz_scene_receiver_callback(SubGhzCustomEvent event, void* context) {
     furi_assert(context);
     furi_assert(context);
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
     view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
 }
 }
 
 
-void subghz_scene_add_to_history_callback(SubGhzProtocolCommon* parser, void* context) {
+static void subghz_scene_add_to_history_callback(
+    SubGhzReceiver* receiver,
+    SubGhzProtocolDecoderBase* decoder_base,
+    void* context) {
     furi_assert(context);
     furi_assert(context);
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     string_t str_buff;
     string_t str_buff;
     string_init(str_buff);
     string_init(str_buff);
 
 
     if(subghz_history_add_to_history(
     if(subghz_history_add_to_history(
-           subghz->txrx->history, parser, subghz->txrx->frequency, subghz->txrx->preset)) {
-        subghz_parser_reset(subghz->txrx->parser);
+           subghz->txrx->history, decoder_base, subghz->txrx->frequency, subghz->txrx->preset)) {
+        subghz_receiver_reset(receiver);
         string_reset(str_buff);
         string_reset(str_buff);
+
         subghz_history_get_text_item_menu(
         subghz_history_get_text_item_menu(
             subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1);
             subghz->txrx->history, str_buff, subghz_history_get_item(subghz->txrx->history) - 1);
-        subghz_receiver_add_item_to_menu(
+        subghz_view_receiver_add_item_to_menu(
             subghz->subghz_receiver,
             subghz->subghz_receiver,
             string_get_cstr(str_buff),
             string_get_cstr(str_buff),
             subghz_history_get_type_protocol(
             subghz_history_get_type_protocol(
                 subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1));
                 subghz->txrx->history, subghz_history_get_item(subghz->txrx->history) - 1));
+
         subghz_scene_receiver_update_statusbar(subghz);
         subghz_scene_receiver_update_statusbar(subghz);
     }
     }
     string_clear(str_buff);
     string_clear(str_buff);
@@ -70,11 +75,11 @@ void subghz_scene_receiver_on_enter(void* context) {
     }
     }
 
 
     //Load history to receiver
     //Load history to receiver
-    subghz_receiver_exit(subghz->subghz_receiver);
+    subghz_view_receiver_exit(subghz->subghz_receiver);
     for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) {
     for(uint8_t i = 0; i < subghz_history_get_item(subghz->txrx->history); i++) {
         string_reset(str_buff);
         string_reset(str_buff);
         subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i);
         subghz_history_get_text_item_menu(subghz->txrx->history, str_buff, i);
-        subghz_receiver_add_item_to_menu(
+        subghz_view_receiver_add_item_to_menu(
             subghz->subghz_receiver,
             subghz->subghz_receiver,
             string_get_cstr(str_buff),
             string_get_cstr(str_buff),
             subghz_history_get_type_protocol(subghz->txrx->history, i));
             subghz_history_get_type_protocol(subghz->txrx->history, i));
@@ -82,8 +87,10 @@ void subghz_scene_receiver_on_enter(void* context) {
     }
     }
     string_clear(str_buff);
     string_clear(str_buff);
     subghz_scene_receiver_update_statusbar(subghz);
     subghz_scene_receiver_update_statusbar(subghz);
-    subghz_receiver_set_callback(subghz->subghz_receiver, subghz_scene_receiver_callback, subghz);
-    subghz_parser_enable_dump(subghz->txrx->parser, subghz_scene_add_to_history_callback, subghz);
+    subghz_view_receiver_set_callback(
+        subghz->subghz_receiver, subghz_scene_receiver_callback, subghz);
+    subghz_receiver_set_rx_callback(
+        subghz->txrx->receiver, subghz_scene_add_to_history_callback, subghz);
 
 
     subghz->state_notifications = SubGhzNotificationStateRX;
     subghz->state_notifications = SubGhzNotificationStateRX;
     if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
     if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
@@ -94,9 +101,9 @@ void subghz_scene_receiver_on_enter(void* context) {
         subghz_begin(subghz, subghz->txrx->preset);
         subghz_begin(subghz, subghz->txrx->preset);
         subghz_rx(subghz, subghz->txrx->frequency);
         subghz_rx(subghz, subghz->txrx->frequency);
     }
     }
-    subghz_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen);
+    subghz_view_receiver_set_idx_menu(subghz->subghz_receiver, subghz->txrx->idx_menu_chosen);
 
 
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewReceiver);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdReceiver);
 }
 }
 
 
 bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
@@ -104,7 +111,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         switch(event.event) {
         switch(event.event) {
-        case SubghzCustomEventViewReceverBack:
+        case SubGhzCustomEventViewReceverBack:
 
 
             // Stop CC1101 Rx
             // Stop CC1101 Rx
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             subghz->state_notifications = SubGhzNotificationStateIDLE;
@@ -116,7 +123,7 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
             subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92];
             subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92];
             subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
             subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
             subghz->txrx->idx_menu_chosen = 0;
             subghz->txrx->idx_menu_chosen = 0;
-            subghz_parser_enable_dump(subghz->txrx->parser, NULL, subghz);
+            subghz_receiver_set_rx_callback(subghz->txrx->receiver, NULL, subghz);
 
 
             if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) {
             if(subghz->txrx->rx_key_state == SubGhzRxKeyStateAddKey) {
                 subghz->txrx->rx_key_state = SubGhzRxKeyStateExit;
                 subghz->txrx->rx_key_state = SubGhzRxKeyStateExit;
@@ -127,14 +134,16 @@ bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event) {
             }
             }
             return true;
             return true;
             break;
             break;
-        case SubghzCustomEventViewReceverOK:
-            subghz->txrx->idx_menu_chosen = subghz_receiver_get_idx_menu(subghz->subghz_receiver);
+        case SubGhzCustomEventViewReceverOK:
+            subghz->txrx->idx_menu_chosen =
+                subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverInfo);
             return true;
             return true;
             break;
             break;
-        case SubghzCustomEventViewReceverConfig:
+        case SubGhzCustomEventViewReceverConfig:
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             subghz->state_notifications = SubGhzNotificationStateIDLE;
-            subghz->txrx->idx_menu_chosen = subghz_receiver_get_idx_menu(subghz->subghz_receiver);
+            subghz->txrx->idx_menu_chosen =
+                subghz_view_receiver_get_idx_menu(subghz->subghz_receiver);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiverConfig);
             return true;
             return true;
             break;
             break;

+ 3 - 3
applications/subghz/scenes/subghz_scene_receiver_config.c

@@ -127,7 +127,7 @@ void subghz_scene_receiver_config_on_enter(void* context) {
     variable_item_set_current_value_text(item, subghz_frequencies_text[value_index]);
     variable_item_set_current_value_text(item, subghz_frequencies_text[value_index]);
 
 
     if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
     if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
-       SubghzCustomEventManagerSet) {
+       SubGhzCustomEventManagerSet) {
         item = variable_item_list_add(
         item = variable_item_list_add(
             subghz->variable_item_list,
             subghz->variable_item_list,
             "Hopping:",
             "Hopping:",
@@ -151,7 +151,7 @@ void subghz_scene_receiver_config_on_enter(void* context) {
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_index(item, value_index);
     variable_item_set_current_value_text(item, preset_text[value_index]);
     variable_item_set_current_value_text(item, preset_text[value_index]);
 
 
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewVariableItemList);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList);
 }
 }
 
 
 bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_receiver_config_on_event(void* context, SceneManagerEvent event) {
@@ -163,5 +163,5 @@ void subghz_scene_receiver_config_on_exit(void* context) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     variable_item_list_reset(subghz->variable_item_list);
     variable_item_list_reset(subghz->variable_item_list);
     scene_manager_set_scene_state(
     scene_manager_set_scene_state(
-        subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet);
+        subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
 }
 }

+ 28 - 22
applications/subghz/scenes/subghz_scene_receiver_info.c

@@ -8,25 +8,24 @@ void subghz_scene_receiver_info_callback(GuiButtonType result, InputType type, v
 
 
     if((result == GuiButtonTypeCenter) && (type == InputTypePress)) {
     if((result == GuiButtonTypeCenter) && (type == InputTypePress)) {
         view_dispatcher_send_custom_event(
         view_dispatcher_send_custom_event(
-            subghz->view_dispatcher, SubghzCustomEventSceneReceiverInfoTxStart);
+            subghz->view_dispatcher, SubGhzCustomEventSceneReceiverInfoTxStart);
     } else if((result == GuiButtonTypeCenter) && (type == InputTypeRelease)) {
     } else if((result == GuiButtonTypeCenter) && (type == InputTypeRelease)) {
         view_dispatcher_send_custom_event(
         view_dispatcher_send_custom_event(
-            subghz->view_dispatcher, SubghzCustomEventSceneReceiverInfoTxStop);
+            subghz->view_dispatcher, SubGhzCustomEventSceneReceiverInfoTxStop);
     } else if((result == GuiButtonTypeRight) && (type == InputTypeShort)) {
     } else if((result == GuiButtonTypeRight) && (type == InputTypeShort)) {
         view_dispatcher_send_custom_event(
         view_dispatcher_send_custom_event(
-            subghz->view_dispatcher, SubghzCustomEventSceneReceiverInfoSave);
+            subghz->view_dispatcher, SubGhzCustomEventSceneReceiverInfoSave);
     }
     }
 }
 }
 
 
 static bool subghz_scene_receiver_info_update_parser(void* context) {
 static bool subghz_scene_receiver_info_update_parser(void* context) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
-    subghz->txrx->protocol_result = subghz_parser_get_by_name(
-        subghz->txrx->parser,
-        subghz_history_get_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
-
-    if(subghz->txrx->protocol_result->to_load_protocol != NULL) {
-        subghz->txrx->protocol_result->to_load_protocol(
-            subghz->txrx->protocol_result,
+    subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
+        subghz->txrx->receiver,
+        subghz_history_get_protocol_name(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
+    if(subghz->txrx->decoder_result) {
+        subghz_protocol_decoder_base_deserialize(
+            subghz->txrx->decoder_result,
             subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
             subghz_history_get_raw_data(subghz->txrx->history, subghz->txrx->idx_menu_chosen));
         subghz->txrx->frequency =
         subghz->txrx->frequency =
             subghz_history_get_frequency(subghz->txrx->history, subghz->txrx->idx_menu_chosen);
             subghz_history_get_frequency(subghz->txrx->history, subghz->txrx->idx_menu_chosen);
@@ -68,8 +67,7 @@ void subghz_scene_receiver_info_on_enter(void* context) {
             AlignTop,
             AlignTop,
             FontSecondary,
             FontSecondary,
             string_get_cstr(modulation_str));
             string_get_cstr(modulation_str));
-
-        subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, text);
+        subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, text);
         widget_add_string_multiline_element(
         widget_add_string_multiline_element(
             subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, string_get_cstr(text));
             subghz->widget, 0, 0, AlignLeft, AlignTop, FontSecondary, string_get_cstr(text));
 
 
@@ -77,14 +75,19 @@ void subghz_scene_receiver_info_on_enter(void* context) {
         string_clear(modulation_str);
         string_clear(modulation_str);
         string_clear(text);
         string_clear(text);
 
 
-        if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->to_save_file &&
-           strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) {
+        if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) ==
+           SubGhzProtocolFlag_Save) {
             widget_add_button_element(
             widget_add_button_element(
                 subghz->widget,
                 subghz->widget,
                 GuiButtonTypeRight,
                 GuiButtonTypeRight,
                 "Save",
                 "Save",
                 subghz_scene_receiver_info_callback,
                 subghz_scene_receiver_info_callback,
                 subghz);
                 subghz);
+        }
+        if(((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) ==
+            SubGhzProtocolFlag_Send) &&
+           subghz->txrx->decoder_result->protocol->encoder->deserialize &&
+           subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeStatic) {
             widget_add_button_element(
             widget_add_button_element(
                 subghz->widget,
                 subghz->widget,
                 GuiButtonTypeCenter,
                 GuiButtonTypeCenter,
@@ -92,20 +95,19 @@ void subghz_scene_receiver_info_on_enter(void* context) {
                 subghz_scene_receiver_info_callback,
                 subghz_scene_receiver_info_callback,
                 subghz);
                 subghz);
         }
         }
-
     } else {
     } else {
         widget_add_icon_element(subghz->widget, 32, 12, &I_DolphinFirstStart7_61x51);
         widget_add_icon_element(subghz->widget, 32, 12, &I_DolphinFirstStart7_61x51);
         widget_add_string_element(
         widget_add_string_element(
             subghz->widget, 13, 8, AlignLeft, AlignBottom, FontSecondary, "Error history parse.");
             subghz->widget, 13, 8, AlignLeft, AlignBottom, FontSecondary, "Error history parse.");
     }
     }
 
 
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdWidget);
 }
 }
 
 
 bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubghzCustomEventSceneReceiverInfoTxStart) {
+        if(event.event == SubGhzCustomEventSceneReceiverInfoTxStart) {
             //CC1101 Stop RX -> Start TX
             //CC1101 Stop RX -> Start TX
             if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
             if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
                 subghz->txrx->hopper_state = SubGhzHopperStatePause;
                 subghz->txrx->hopper_state = SubGhzHopperStatePause;
@@ -118,14 +120,17 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
             }
             }
             if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE ||
             if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE ||
                subghz->txrx->txrx_state == SubGhzTxRxStateSleep) {
                subghz->txrx->txrx_state == SubGhzTxRxStateSleep) {
-                if(!subghz_tx_start(subghz)) {
+                if(!subghz_tx_start(
+                       subghz,
+                       subghz_history_get_raw_data(
+                           subghz->txrx->history, subghz->txrx->idx_menu_chosen))) {
                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
                 } else {
                 } else {
                     subghz->state_notifications = SubGhzNotificationStateTX;
                     subghz->state_notifications = SubGhzNotificationStateTX;
                 }
                 }
             }
             }
             return true;
             return true;
-        } else if(event.event == SubghzCustomEventSceneReceiverInfoTxStop) {
+        } else if(event.event == SubGhzCustomEventSceneReceiverInfoTxStop) {
             //CC1101 Stop Tx -> Start RX
             //CC1101 Stop Tx -> Start RX
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
@@ -140,7 +145,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
             }
             }
             subghz->state_notifications = SubGhzNotificationStateRX;
             subghz->state_notifications = SubGhzNotificationStateRX;
             return true;
             return true;
-        } else if(event.event == SubghzCustomEventSceneReceiverInfoSave) {
+        } else if(event.event == SubGhzCustomEventSceneReceiverInfoSave) {
             //CC1101 Stop RX -> Save
             //CC1101 Stop RX -> Save
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
             if(subghz->txrx->hopper_state != SubGhzHopperStateOFF) {
@@ -153,8 +158,9 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event)
             if(!subghz_scene_receiver_info_update_parser(subghz)) {
             if(!subghz_scene_receiver_info_update_parser(subghz)) {
                 return false;
                 return false;
             }
             }
-            if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->to_save_file &&
-               strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) {
+
+            if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Save) ==
+               SubGhzProtocolFlag_Save) {
                 subghz_file_name_clear(subghz);
                 subghz_file_name_clear(subghz);
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
             }
             }

+ 24 - 11
applications/subghz/scenes/subghz_scene_save_name.c

@@ -1,13 +1,13 @@
 #include "../subghz_i.h"
 #include "../subghz_i.h"
 #include <lib/toolbox/random_name.h>
 #include <lib/toolbox/random_name.h>
 #include "../helpers/subghz_custom_event.h"
 #include "../helpers/subghz_custom_event.h"
-#include <lib/subghz/protocols/subghz_protocol_raw.h>
+#include <lib/subghz/protocols/raw.h>
 #include <gui/modules/validators.h>
 #include <gui/modules/validators.h>
 
 
 void subghz_scene_save_name_text_input_callback(void* context) {
 void subghz_scene_save_name_text_input_callback(void* context) {
     furi_assert(context);
     furi_assert(context);
     SubGhz* subghz = context;
     SubGhz* subghz = context;
-    view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneSaveName);
+    view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneSaveName);
 }
 }
 
 
 void subghz_scene_save_name_on_enter(void* context) {
 void subghz_scene_save_name_on_enter(void* context) {
@@ -24,10 +24,10 @@ void subghz_scene_save_name_on_enter(void* context) {
     } else {
     } else {
         strcpy(subghz->file_name_tmp, subghz->file_name);
         strcpy(subghz->file_name_tmp, subghz->file_name);
         if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
         if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
-           SubghzCustomEventManagerNoSet) {
+           SubGhzCustomEventManagerNoSet) {
             subghz_get_next_name_file(subghz);
             subghz_get_next_name_file(subghz);
             if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) ==
             if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) ==
-               SubghzCustomEventManagerSetRAW) {
+               SubGhzCustomEventManagerSetRAW) {
                 dev_name_empty = true;
                 dev_name_empty = true;
             }
             }
         }
         }
@@ -46,7 +46,7 @@ void subghz_scene_save_name_on_enter(void* context) {
         validator_is_file_alloc_init(SUBGHZ_APP_FOLDER, SUBGHZ_APP_EXTENSION);
         validator_is_file_alloc_init(SUBGHZ_APP_FOLDER, SUBGHZ_APP_EXTENSION);
     text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
     text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
 
 
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTextInput);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdTextInput);
 }
 }
 
 
 bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
@@ -56,22 +56,35 @@ bool subghz_scene_save_name_on_event(void* context, SceneManagerEvent event) {
         scene_manager_previous_scene(subghz->scene_manager);
         scene_manager_previous_scene(subghz->scene_manager);
         return true;
         return true;
     } else if(event.type == SceneManagerEventTypeCustom) {
     } else if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubghzCustomEventSceneSaveName) {
+        if(event.event == SubGhzCustomEventSceneSaveName) {
             if(strcmp(subghz->file_name, "")) {
             if(strcmp(subghz->file_name, "")) {
                 if(strcmp(subghz->file_name_tmp, "")) {
                 if(strcmp(subghz->file_name_tmp, "")) {
                     if(!subghz_rename_file(subghz)) {
                     if(!subghz_rename_file(subghz)) {
                         return false;
                         return false;
                     }
                     }
                 } else {
                 } else {
-                    subghz_save_protocol_to_file(subghz, subghz->file_name);
+                    if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType) !=
+                       SubGhzCustomEventManagerNoSet) {
+                        subghz_save_protocol_to_file(
+                            subghz, subghz->txrx->fff_data, subghz->file_name);
+                        scene_manager_set_scene_state(
+                            subghz->scene_manager,
+                            SubGhzSceneSetType,
+                            SubGhzCustomEventManagerNoSet);
+                    } else {
+                        subghz_save_protocol_to_file(
+                            subghz,
+                            subghz_history_get_raw_data(
+                                subghz->txrx->history, subghz->txrx->idx_menu_chosen),
+                            subghz->file_name);
+                    }
                 }
                 }
 
 
                 if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
                 if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneReadRAW) !=
-                   SubghzCustomEventManagerNoSet) {
-                    subghz_protocol_raw_set_last_file_name(
-                        (SubGhzProtocolRAW*)subghz->txrx->protocol_result, subghz->file_name);
+                   SubGhzCustomEventManagerNoSet) {
+                    subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, subghz->file_name);
                     scene_manager_set_scene_state(
                     scene_manager_set_scene_state(
-                        subghz->scene_manager, SubGhzSceneReadRAW, SubghzCustomEventManagerNoSet);
+                        subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
                 } else {
                 } else {
                     subghz_file_name_clear(subghz);
                     subghz_file_name_clear(subghz);
                 }
                 }

+ 3 - 3
applications/subghz/scenes/subghz_scene_save_success.c

@@ -5,7 +5,7 @@
 
 
 void subghz_scene_save_success_popup_callback(void* context) {
 void subghz_scene_save_success_popup_callback(void* context) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
-    view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneSaveSuccess);
+    view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneSaveSuccess);
 }
 }
 
 
 void subghz_scene_save_success_on_enter(void* context) {
 void subghz_scene_save_success_on_enter(void* context) {
@@ -20,13 +20,13 @@ void subghz_scene_save_success_on_enter(void* context) {
     popup_set_context(popup, subghz);
     popup_set_context(popup, subghz);
     popup_set_callback(popup, subghz_scene_save_success_popup_callback);
     popup_set_callback(popup, subghz_scene_save_success_popup_callback);
     popup_enable_timeout(popup);
     popup_enable_timeout(popup);
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdPopup);
 }
 }
 
 
 bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubghzCustomEventSceneSaveSuccess) {
+        if(event.event == SubGhzCustomEventSceneSaveSuccess) {
             if(!scene_manager_search_and_switch_to_previous_scene(
             if(!scene_manager_search_and_switch_to_previous_scene(
                    subghz->scene_manager, SubGhzSceneReceiver)) {
                    subghz->scene_manager, SubGhzSceneReceiver)) {
                 subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWSave;
                 subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWSave;

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

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

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

@@ -38,7 +38,7 @@ void subghz_scene_saved_menu_on_enter(void* context) {
         subghz->submenu,
         subghz->submenu,
         scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSavedMenu));
         scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSavedMenu));
 
 
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewMenu);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdMenu);
 }
 }
 
 
 bool subghz_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {

+ 90 - 55
applications/subghz/scenes/subghz_scene_set_type.c

@@ -1,6 +1,11 @@
 #include "../subghz_i.h"
 #include "../subghz_i.h"
-#include "../lib/subghz/protocols/subghz_protocol_keeloq.h"
+#include <lib/subghz/protocols/keeloq.h>
+#include <lib/subghz/blocks/math.h>
 #include <dolphin/dolphin.h>
 #include <dolphin/dolphin.h>
+#include <flipper_format/flipper_format_i.h>
+#include <lib/toolbox/stream/stream.h>
+
+#define TAG "SubGhzSetType"
 
 
 enum SubmenuIndex {
 enum SubmenuIndex {
     SubmenuIndexPricenton,
     SubmenuIndexPricenton,
@@ -15,15 +20,52 @@ enum SubmenuIndex {
     SubmenuIndexDoorHan,
     SubmenuIndexDoorHan,
 };
 };
 
 
-bool subghz_scene_set_type_submenu_to_find_protocol(void* context, const char* protocol_name) {
+bool subghz_scene_set_type_submenu_gen_data_protocol(
+    void* context,
+    const char* protocol_name,
+    uint64_t key,
+    uint32_t bit) {
+    furi_assert(context);
     SubGhz* subghz = context;
     SubGhz* subghz = context;
-    subghz->txrx->protocol_result = subghz_parser_get_by_name(subghz->txrx->parser, protocol_name);
-    if(subghz->txrx->protocol_result == NULL) {
+
+    bool res = false;
+
+    subghz->txrx->decoder_result =
+        subghz_receiver_search_decoder_base_by_name(subghz->txrx->receiver, protocol_name);
+
+    if(subghz->txrx->decoder_result == NULL) {
         string_set(subghz->error_str, "Protocol not found");
         string_set(subghz->error_str, "Protocol not found");
         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub);
         scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub);
         return false;
         return false;
     }
     }
-    return true;
+
+    do {
+        Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data);
+        stream_clean(fff_data_stream);
+        if(!subghz_protocol_decoder_base_serialize(
+               subghz->txrx->decoder_result,
+               subghz->txrx->fff_data,
+               subghz_frequencies[subghz_frequencies_433_92],
+               FuriHalSubGhzPresetOok650Async)) {
+            FURI_LOG_E(TAG, "Unable to serialize");
+            break;
+        }
+        if(!flipper_format_update_uint32(subghz->txrx->fff_data, "Bit", &bit, 1)) {
+            FURI_LOG_E(TAG, "Unable to update Bit");
+            break;
+        }
+
+        uint8_t key_data[sizeof(uint64_t)] = {0};
+        for(size_t i = 0; i < sizeof(uint64_t); i++) {
+            key_data[sizeof(uint64_t) - i - 1] = (key >> i * 8) & 0xFF;
+        }
+        if(!flipper_format_update_hex(subghz->txrx->fff_data, "Key", key_data, sizeof(uint64_t))) {
+            FURI_LOG_E(TAG, "Unable to update Key");
+            break;
+        }
+        res = true;
+    } while(false);
+    return res;
 }
 }
 
 
 void subghz_scene_set_type_submenu_callback(void* context, uint32_t index) {
 void subghz_scene_set_type_submenu_callback(void* context, uint32_t index) {
@@ -90,7 +132,7 @@ void subghz_scene_set_type_on_enter(void* context) {
     submenu_set_selected_item(
     submenu_set_selected_item(
         subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType));
         subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneSetType));
 
 
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewMenu);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdMenu);
 }
 }
 
 
 bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
@@ -98,54 +140,45 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
     bool generated_protocol = false;
     bool generated_protocol = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
+        //ToDo Fix
         uint32_t key = subghz_random_serial();
         uint32_t key = subghz_random_serial();
         switch(event.event) {
         switch(event.event) {
         case SubmenuIndexPricenton:
         case SubmenuIndexPricenton:
-            if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "Princeton")) {
-                subghz->txrx->protocol_result->code_last_count_bit = 24;
-                key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
-                subghz->txrx->protocol_result->code_last_found = key;
+            key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
+            if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "Princeton", key, 24)) {
+                uint32_t te = 400;
+                flipper_format_update_uint32(subghz->txrx->fff_data, "TE", (uint32_t*)&te, 1);
                 generated_protocol = true;
                 generated_protocol = true;
             }
             }
             break;
             break;
         case SubmenuIndexNiceFlo12bit:
         case SubmenuIndexNiceFlo12bit:
-            if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "Nice FLO")) {
-                subghz->txrx->protocol_result->code_last_count_bit = 12;
-                key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
-                subghz->txrx->protocol_result->code_last_found = key;
+            key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
+            if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "Nice FLO", key, 12)) {
                 generated_protocol = true;
                 generated_protocol = true;
             }
             }
             break;
             break;
         case SubmenuIndexNiceFlo24bit:
         case SubmenuIndexNiceFlo24bit:
-            if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "Nice FLO")) {
-                subghz->txrx->protocol_result->code_last_count_bit = 24;
-                key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
-                subghz->txrx->protocol_result->code_last_found = key;
+            key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
+            if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "Nice FLO", key, 24)) {
                 generated_protocol = true;
                 generated_protocol = true;
             }
             }
             break;
             break;
         case SubmenuIndexCAME12bit:
         case SubmenuIndexCAME12bit:
-            if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "CAME")) {
-                subghz->txrx->protocol_result->code_last_count_bit = 12;
-                key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
-                subghz->txrx->protocol_result->code_last_found = key;
+            key = (key & 0x0000FFF0) | 0x1; //btn 0x1, 0x2, 0x4
+            if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "CAME", key, 12)) {
                 generated_protocol = true;
                 generated_protocol = true;
             }
             }
             break;
             break;
         case SubmenuIndexCAME24bit:
         case SubmenuIndexCAME24bit:
-            if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "CAME")) {
-                subghz->txrx->protocol_result->code_last_count_bit = 24;
-                key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
-                subghz->txrx->protocol_result->code_last_found = key;
+            key = (key & 0x00FFFFF0) | 0x4; //btn 0x1, 0x2, 0x4, 0x8
+            if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "CAME", key, 24)) {
                 generated_protocol = true;
                 generated_protocol = true;
             }
             }
             break;
             break;
         case SubmenuIndexCAMETwee:
         case SubmenuIndexCAMETwee:
-            if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "CAME TWEE")) {
-                subghz->txrx->protocol_result->code_last_count_bit = 54;
-                key = (key & 0x0FFFFFF0);
-                subghz->txrx->protocol_result->code_last_found = 0x003FFF7200000000 |
-                                                                 (key ^ 0xE0E0E0EE);
+            key = (key & 0x0FFFFFF0);
+            key = 0x003FFF7200000000 | (key ^ 0xE0E0E0EE);
+            if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "CAME TWEE", key, 54)) {
                 generated_protocol = true;
                 generated_protocol = true;
             }
             }
             break;
             break;
@@ -156,32 +189,34 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
         //     /* code */
         //     /* code */
         //     break;
         //     break;
         case SubmenuIndexGateTX:
         case SubmenuIndexGateTX:
-            if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "GateTX")) {
-                subghz->txrx->protocol_result->code_last_count_bit = 24;
-                key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?)
-                subghz->txrx->protocol_result->code_last_found =
-                    subghz_protocol_common_reverse_key(
-                        key, subghz->txrx->protocol_result->code_last_count_bit);
+            key = (key & 0x00F0FF00) | 0xF << 16 | 0x40; //btn 0xF, 0xC, 0xA, 0x6 (?)
+            uint64_t rev_key = subghz_protocol_blocks_reverse_key(key, 24);
+            if(subghz_scene_set_type_submenu_gen_data_protocol(subghz, "GateTX", rev_key, 24)) {
                 generated_protocol = true;
                 generated_protocol = true;
             }
             }
             break;
             break;
         case SubmenuIndexDoorHan:
         case SubmenuIndexDoorHan:
-            if(subghz_scene_set_type_submenu_to_find_protocol(subghz, "KeeLoq")) {
-                subghz->txrx->protocol_result->code_last_count_bit = 64;
-                subghz->txrx->protocol_result->serial = key & 0x0FFFFFFF;
-                subghz->txrx->protocol_result->btn = 0x2; //btn 0x1, 0x2, 0x4, 0x8
-                subghz->txrx->protocol_result->cnt = 0x0003;
-                if(subghz_protocol_keeloq_set_manufacture_name(
-                       subghz->txrx->protocol_result, "DoorHan")) {
-                    subghz->txrx->protocol_result->code_last_found =
-                        subghz_protocol_keeloq_gen_key(subghz->txrx->protocol_result);
-                    generated_protocol = true;
-                } else {
-                    generated_protocol = false;
-                    string_set(
-                        subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
-                    scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
-                }
+            subghz->txrx->transmitter =
+                subghz_transmitter_alloc_init(subghz->txrx->environment, "KeeLoq");
+            if(subghz->txrx->transmitter) {
+                subghz_protocol_keeloq_create_data(
+                    subghz->txrx->transmitter->protocol_instance,
+                    subghz->txrx->fff_data,
+                    key & 0x0FFFFFFF,
+                    0x2,
+                    0x0003,
+                    "DoorHan",
+                    subghz_frequencies[subghz_frequencies_433_92],
+                    FuriHalSubGhzPresetOok650Async);
+                generated_protocol = true;
+            } else {
+                generated_protocol = false;
+            }
+            subghz_transmitter_free(subghz->txrx->transmitter);
+            if(!generated_protocol) {
+                string_set(
+                    subghz->error_str, "Function requires\nan SD card with\nfresh databases.");
+                scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowError);
             }
             }
             break;
             break;
         default:
         default:
@@ -190,10 +225,10 @@ bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event) {
         }
         }
 
 
         if(generated_protocol) {
         if(generated_protocol) {
-            subghz->txrx->frequency = subghz_frequencies[subghz_frequencies_433_92];
-            subghz->txrx->preset = FuriHalSubGhzPresetOok650Async;
             subghz_file_name_clear(subghz);
             subghz_file_name_clear(subghz);
             DOLPHIN_DEED(DolphinDeedSubGhzAddManually);
             DOLPHIN_DEED(DolphinDeedSubGhzAddManually);
+            scene_manager_set_scene_state(
+                subghz->scene_manager, SubGhzSceneSetType, SubGhzCustomEventManagerSet);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
             return true;
             return true;
         }
         }

+ 10 - 10
applications/subghz/scenes/subghz_scene_show_error.c

@@ -7,10 +7,10 @@ void subghz_scene_show_error_callback(GuiButtonType result, InputType type, void
 
 
     if((result == GuiButtonTypeRight) && (type == InputTypeShort)) {
     if((result == GuiButtonTypeRight) && (type == InputTypeShort)) {
         view_dispatcher_send_custom_event(
         view_dispatcher_send_custom_event(
-            subghz->view_dispatcher, SubghzCustomEventSceneShowErrorOk);
+            subghz->view_dispatcher, SubGhzCustomEventSceneShowErrorOk);
     } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
     } else if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
         view_dispatcher_send_custom_event(
         view_dispatcher_send_custom_event(
-            subghz->view_dispatcher, SubghzCustomEventSceneShowErrorBack);
+            subghz->view_dispatcher, SubGhzCustomEventSceneShowErrorBack);
     }
     }
 }
 }
 
 
@@ -28,7 +28,7 @@ void subghz_scene_show_error_on_enter(void* context) {
         FontSecondary,
         FontSecondary,
         string_get_cstr(subghz->error_str));
         string_get_cstr(subghz->error_str));
     if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) ==
     if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) ==
-       SubghzCustomEventManagerSet) {
+       SubGhzCustomEventManagerSet) {
         widget_add_button_element(
         widget_add_button_element(
             subghz->widget, GuiButtonTypeRight, "Ok", subghz_scene_show_error_callback, subghz);
             subghz->widget, GuiButtonTypeRight, "Ok", subghz_scene_show_error_callback, subghz);
     }
     }
@@ -36,14 +36,14 @@ void subghz_scene_show_error_on_enter(void* context) {
     widget_add_button_element(
     widget_add_button_element(
         subghz->widget, GuiButtonTypeLeft, "Back", subghz_scene_show_error_callback, subghz);
         subghz->widget, GuiButtonTypeLeft, "Back", subghz_scene_show_error_callback, subghz);
 
 
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewWidget);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdWidget);
 }
 }
 
 
 bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     if(event.type == SceneManagerEventTypeBack) {
     if(event.type == SceneManagerEventTypeBack) {
         if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) ==
         if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) ==
-           SubghzCustomEventManagerSet) {
+           SubGhzCustomEventManagerSet) {
             return false;
             return false;
         } else {
         } else {
             scene_manager_search_and_switch_to_previous_scene(
             scene_manager_search_and_switch_to_previous_scene(
@@ -51,15 +51,15 @@ bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) {
         }
         }
         return true;
         return true;
     } else if(event.type == SceneManagerEventTypeCustom) {
     } else if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubghzCustomEventSceneShowErrorOk) {
+        if(event.event == SubGhzCustomEventSceneShowErrorOk) {
             if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) ==
             if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) ==
-               SubghzCustomEventManagerSet) {
+               SubGhzCustomEventManagerSet) {
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart);
                 scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart);
             }
             }
             return true;
             return true;
-        } else if(event.event == SubghzCustomEventSceneShowErrorBack) {
+        } else if(event.event == SubGhzCustomEventSceneShowErrorBack) {
             if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) ==
             if(scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneShowError) ==
-               SubghzCustomEventManagerSet) {
+               SubGhzCustomEventManagerSet) {
                 //exit app
                 //exit app
                 if(!scene_manager_previous_scene(subghz->scene_manager)) {
                 if(!scene_manager_previous_scene(subghz->scene_manager)) {
                     scene_manager_stop(subghz->scene_manager);
                     scene_manager_stop(subghz->scene_manager);
@@ -78,7 +78,7 @@ bool subghz_scene_show_error_on_event(void* context, SceneManagerEvent event) {
 void subghz_scene_show_error_on_exit(void* context) {
 void subghz_scene_show_error_on_exit(void* context) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     scene_manager_set_scene_state(
     scene_manager_set_scene_state(
-        subghz->scene_manager, SubGhzSceneShowError, SubghzCustomEventManagerNoSet);
+        subghz->scene_manager, SubGhzSceneShowError, SubGhzCustomEventManagerNoSet);
     widget_reset(subghz->widget);
     widget_reset(subghz->widget);
     string_reset(subghz->error_str);
     string_reset(subghz->error_str);
 }
 }

+ 3 - 3
applications/subghz/scenes/subghz_scene_show_error_sub.c

@@ -3,7 +3,7 @@
 
 
 void subghz_scene_show_error_sub_popup_callback(void* context) {
 void subghz_scene_show_error_sub_popup_callback(void* context) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
-    view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneShowErrorSub);
+    view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneShowErrorSub);
 }
 }
 
 
 void subghz_scene_show_error_sub_on_enter(void* context) {
 void subghz_scene_show_error_sub_on_enter(void* context) {
@@ -17,13 +17,13 @@ void subghz_scene_show_error_sub_on_enter(void* context) {
     popup_set_context(popup, subghz);
     popup_set_context(popup, subghz);
     popup_set_callback(popup, subghz_scene_show_error_sub_popup_callback);
     popup_set_callback(popup, subghz_scene_show_error_sub_popup_callback);
     popup_enable_timeout(popup);
     popup_enable_timeout(popup);
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdPopup);
 }
 }
 
 
 bool subghz_scene_show_error_sub_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_show_error_sub_on_event(void* context, SceneManagerEvent event) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubghzCustomEventSceneShowErrorSub) {
+        if(event.event == SubGhzCustomEventSceneShowErrorSub) {
             scene_manager_search_and_switch_to_previous_scene(
             scene_manager_search_and_switch_to_previous_scene(
                 subghz->scene_manager, SubGhzSceneStart);
                 subghz->scene_manager, SubGhzSceneStart);
             return true;
             return true;

+ 3 - 3
applications/subghz/scenes/subghz_scene_show_only_rx.c

@@ -3,7 +3,7 @@
 
 
 void subghz_scene_show_only_rx_popup_callback(void* context) {
 void subghz_scene_show_only_rx_popup_callback(void* context) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
-    view_dispatcher_send_custom_event(subghz->view_dispatcher, SubghzCustomEventSceneShowOnlyRX);
+    view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneShowOnlyRX);
 }
 }
 
 
 void subghz_scene_show_only_rx_on_enter(void* context) {
 void subghz_scene_show_only_rx_on_enter(void* context) {
@@ -23,13 +23,13 @@ void subghz_scene_show_only_rx_on_enter(void* context) {
     popup_set_context(popup, subghz);
     popup_set_context(popup, subghz);
     popup_set_callback(popup, subghz_scene_show_only_rx_popup_callback);
     popup_set_callback(popup, subghz_scene_show_only_rx_popup_callback);
     popup_enable_timeout(popup);
     popup_enable_timeout(popup);
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdPopup);
 }
 }
 
 
 const bool subghz_scene_show_only_rx_on_event(void* context, SceneManagerEvent event) {
 const bool subghz_scene_show_only_rx_on_event(void* context, SceneManagerEvent event) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubghzCustomEventSceneShowOnlyRX) {
+        if(event.event == SubGhzCustomEventSceneShowOnlyRX) {
             scene_manager_previous_scene(subghz->scene_manager);
             scene_manager_previous_scene(subghz->scene_manager);
             return true;
             return true;
         }
         }

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

@@ -48,7 +48,7 @@ void subghz_scene_start_on_enter(void* context) {
     submenu_set_selected_item(
     submenu_set_selected_item(
         subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneStart));
         subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneStart));
 
 
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewMenu);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdMenu);
 }
 }
 
 
 bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) {

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

@@ -28,7 +28,7 @@ void subghz_scene_test_on_enter(void* context) {
     submenu_set_selected_item(
     submenu_set_selected_item(
         subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneTest));
         subghz->submenu, scene_manager_get_scene_state(subghz->scene_manager, SubGhzSceneTest));
 
 
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewMenu);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdMenu);
 }
 }
 
 
 bool subghz_scene_test_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_test_on_event(void* context, SceneManagerEvent event) {

+ 3 - 3
applications/subghz/scenes/subghz_scene_test_carrier.c

@@ -1,7 +1,7 @@
 #include "../subghz_i.h"
 #include "../subghz_i.h"
 #include "../views/subghz_test_carrier.h"
 #include "../views/subghz_test_carrier.h"
 
 
-void subghz_scene_test_carrier_callback(SubghzTestCarrierEvent event, void* context) {
+void subghz_scene_test_carrier_callback(SubGhzTestCarrierEvent event, void* context) {
     furi_assert(context);
     furi_assert(context);
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
     view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
@@ -11,13 +11,13 @@ void subghz_scene_test_carrier_on_enter(void* context) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     subghz_test_carrier_set_callback(
     subghz_test_carrier_set_callback(
         subghz->subghz_test_carrier, subghz_scene_test_carrier_callback, subghz);
         subghz->subghz_test_carrier, subghz_scene_test_carrier_callback, subghz);
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTestCarrier);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdTestCarrier);
 }
 }
 
 
 bool subghz_scene_test_carrier_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_test_carrier_on_event(void* context, SceneManagerEvent event) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubghzTestCarrierEventOnlyRx) {
+        if(event.event == SubGhzTestCarrierEventOnlyRx) {
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
             return true;
             return true;
         }
         }

+ 3 - 3
applications/subghz/scenes/subghz_scene_test_packet.c

@@ -1,7 +1,7 @@
 #include "../subghz_i.h"
 #include "../subghz_i.h"
 #include "../views/subghz_test_packet.h"
 #include "../views/subghz_test_packet.h"
 
 
-void subghz_scene_test_packet_callback(SubghzTestPacketEvent event, void* context) {
+void subghz_scene_test_packet_callback(SubGhzTestPacketEvent event, void* context) {
     furi_assert(context);
     furi_assert(context);
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
     view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
@@ -11,13 +11,13 @@ void subghz_scene_test_packet_on_enter(void* context) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     subghz_test_packet_set_callback(
     subghz_test_packet_set_callback(
         subghz->subghz_test_packet, subghz_scene_test_packet_callback, subghz);
         subghz->subghz_test_packet, subghz_scene_test_packet_callback, subghz);
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTestPacket);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdTestPacket);
 }
 }
 
 
 bool subghz_scene_test_packet_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_test_packet_on_event(void* context, SceneManagerEvent event) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubghzTestPacketEventOnlyRx) {
+        if(event.event == SubGhzTestPacketEventOnlyRx) {
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
             return true;
             return true;
         }
         }

+ 3 - 3
applications/subghz/scenes/subghz_scene_test_static.c

@@ -1,7 +1,7 @@
 #include "../subghz_i.h"
 #include "../subghz_i.h"
 #include "../views/subghz_test_static.h"
 #include "../views/subghz_test_static.h"
 
 
-void subghz_scene_test_static_callback(SubghzTestStaticEvent event, void* context) {
+void subghz_scene_test_static_callback(SubGhzTestStaticEvent event, void* context) {
     furi_assert(context);
     furi_assert(context);
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
     view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
@@ -11,13 +11,13 @@ void subghz_scene_test_static_on_enter(void* context) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     subghz_test_static_set_callback(
     subghz_test_static_set_callback(
         subghz->subghz_test_static, subghz_scene_test_static_callback, subghz);
         subghz->subghz_test_static, subghz_scene_test_static_callback, subghz);
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewStatic);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdStatic);
 }
 }
 
 
 bool subghz_scene_test_static_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_test_static_on_event(void* context, SceneManagerEvent event) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubghzTestStaticEventOnlyRx) {
+        if(event.event == SubGhzTestStaticEventOnlyRx) {
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
             return true;
             return true;
         }
         }

+ 19 - 20
applications/subghz/scenes/subghz_scene_transmitter.c

@@ -1,18 +1,18 @@
 #include "../subghz_i.h"
 #include "../subghz_i.h"
-#include "../views/subghz_transmitter.h"
-#include <lib/subghz/protocols/subghz_protocol_keeloq.h>
+#include "../views/transmitter.h"
 #include <dolphin/dolphin.h>
 #include <dolphin/dolphin.h>
 
 
-void subghz_scene_transmitter_callback(SubghzCustomEvent event, void* context) {
+void subghz_scene_transmitter_callback(SubGhzCustomEvent event, void* context) {
     furi_assert(context);
     furi_assert(context);
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
     view_dispatcher_send_custom_event(subghz->view_dispatcher, event);
 }
 }
 
 
 bool subghz_scene_transmitter_update_data_show(void* context) {
 bool subghz_scene_transmitter_update_data_show(void* context) {
+    //ToDo Fix
     SubGhz* subghz = context;
     SubGhz* subghz = context;
 
 
-    if(subghz->txrx->protocol_result && subghz->txrx->protocol_result->get_upload_protocol) {
+    if(subghz->txrx->decoder_result) {
         string_t key_str;
         string_t key_str;
         string_t frequency_str;
         string_t frequency_str;
         string_t modulation_str;
         string_t modulation_str;
@@ -21,19 +21,18 @@ bool subghz_scene_transmitter_update_data_show(void* context) {
         string_init(frequency_str);
         string_init(frequency_str);
         string_init(modulation_str);
         string_init(modulation_str);
         uint8_t show_button = 0;
         uint8_t show_button = 0;
-        subghz->txrx->protocol_result->to_string(subghz->txrx->protocol_result, key_str);
 
 
-        if((!strcmp(subghz->txrx->protocol_result->name, "KeeLoq")) &&
-           (!strcmp(
-               subghz_protocol_keeloq_get_manufacture_name(subghz->txrx->protocol_result),
-               "Unknown"))) {
-            show_button = 0;
-        } else {
+        subghz_protocol_decoder_base_deserialize(
+            subghz->txrx->decoder_result, subghz->txrx->fff_data);
+        subghz_protocol_decoder_base_get_string(subghz->txrx->decoder_result, key_str);
+
+        if((subghz->txrx->decoder_result->protocol->flag & SubGhzProtocolFlag_Send) ==
+           SubGhzProtocolFlag_Send) {
             show_button = 1;
             show_button = 1;
         }
         }
 
 
         subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
         subghz_get_frequency_modulation(subghz, frequency_str, modulation_str);
-        subghz_transmitter_add_data_to_show(
+        subghz_view_transmitter_add_data_to_show(
             subghz->subghz_transmitter,
             subghz->subghz_transmitter,
             string_get_cstr(key_str),
             string_get_cstr(key_str),
             string_get_cstr(frequency_str),
             string_get_cstr(frequency_str),
@@ -54,27 +53,27 @@ void subghz_scene_transmitter_on_enter(void* context) {
     DOLPHIN_DEED(DolphinDeedSubGhzSend);
     DOLPHIN_DEED(DolphinDeedSubGhzSend);
     if(!subghz_scene_transmitter_update_data_show(subghz)) {
     if(!subghz_scene_transmitter_update_data_show(subghz)) {
         view_dispatcher_send_custom_event(
         view_dispatcher_send_custom_event(
-            subghz->view_dispatcher, SubghzCustomEventViewTransmitterError);
+            subghz->view_dispatcher, SubGhzCustomEventViewTransmitterError);
     }
     }
 
 
-    subghz_transmitter_set_callback(
+    subghz_view_transmitter_set_callback(
         subghz->subghz_transmitter, subghz_scene_transmitter_callback, subghz);
         subghz->subghz_transmitter, subghz_scene_transmitter_callback, subghz);
 
 
     subghz->state_notifications = SubGhzNotificationStateIDLE;
     subghz->state_notifications = SubGhzNotificationStateIDLE;
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewTransmitter);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdTransmitter);
 }
 }
 
 
 bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubghzCustomEventViewTransmitterSendStart) {
+        if(event.event == SubGhzCustomEventViewTransmitterSendStart) {
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
             if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
                 subghz_rx_end(subghz);
                 subghz_rx_end(subghz);
             }
             }
             if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
             if((subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) ||
                (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
                (subghz->txrx->txrx_state == SubGhzTxRxStateSleep)) {
-                if(!subghz_tx_start(subghz)) {
+                if(!subghz_tx_start(subghz, subghz->txrx->fff_data)) {
                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
                     scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowOnlyRx);
                 } else {
                 } else {
                     subghz->state_notifications = SubGhzNotificationStateTX;
                     subghz->state_notifications = SubGhzNotificationStateTX;
@@ -82,19 +81,19 @@ bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent event) {
                 }
                 }
             }
             }
             return true;
             return true;
-        } else if(event.event == SubghzCustomEventViewTransmitterSendStop) {
+        } else if(event.event == SubGhzCustomEventViewTransmitterSendStop) {
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
                 subghz_tx_stop(subghz);
                 subghz_tx_stop(subghz);
                 subghz_sleep(subghz);
                 subghz_sleep(subghz);
             }
             }
             return true;
             return true;
-        } else if(event.event == SubghzCustomEventViewTransmitterBack) {
+        } else if(event.event == SubGhzCustomEventViewTransmitterBack) {
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             subghz->state_notifications = SubGhzNotificationStateIDLE;
             scene_manager_search_and_switch_to_previous_scene(
             scene_manager_search_and_switch_to_previous_scene(
                 subghz->scene_manager, SubGhzSceneStart);
                 subghz->scene_manager, SubGhzSceneStart);
             return true;
             return true;
-        } else if(event.event == SubghzCustomEventViewTransmitterError) {
+        } else if(event.event == SubGhzCustomEventViewTransmitterError) {
             string_set(subghz->error_str, "Protocol not found");
             string_set(subghz->error_str, "Protocol not found");
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneShowErrorSub);
         }
         }

+ 52 - 44
applications/subghz/subghz.c

@@ -85,80 +85,80 @@ SubGhz* subghz_alloc() {
     // SubMenu
     // SubMenu
     subghz->submenu = submenu_alloc();
     subghz->submenu = submenu_alloc();
     view_dispatcher_add_view(
     view_dispatcher_add_view(
-        subghz->view_dispatcher, SubGhzViewMenu, submenu_get_view(subghz->submenu));
+        subghz->view_dispatcher, SubGhzViewIdMenu, submenu_get_view(subghz->submenu));
 
 
     // Receiver
     // Receiver
-    subghz->subghz_receiver = subghz_receiver_alloc();
+    subghz->subghz_receiver = subghz_view_receiver_alloc();
     view_dispatcher_add_view(
     view_dispatcher_add_view(
         subghz->view_dispatcher,
         subghz->view_dispatcher,
-        SubGhzViewReceiver,
-        subghz_receiver_get_view(subghz->subghz_receiver));
+        SubGhzViewIdReceiver,
+        subghz_view_receiver_get_view(subghz->subghz_receiver));
 
 
     // Popup
     // Popup
     subghz->popup = popup_alloc();
     subghz->popup = popup_alloc();
     view_dispatcher_add_view(
     view_dispatcher_add_view(
-        subghz->view_dispatcher, SubGhzViewPopup, popup_get_view(subghz->popup));
+        subghz->view_dispatcher, SubGhzViewIdPopup, popup_get_view(subghz->popup));
 
 
     // Text Input
     // Text Input
     subghz->text_input = text_input_alloc();
     subghz->text_input = text_input_alloc();
     view_dispatcher_add_view(
     view_dispatcher_add_view(
-        subghz->view_dispatcher, SubGhzViewTextInput, text_input_get_view(subghz->text_input));
+        subghz->view_dispatcher, SubGhzViewIdTextInput, text_input_get_view(subghz->text_input));
 
 
     // Custom Widget
     // Custom Widget
     subghz->widget = widget_alloc();
     subghz->widget = widget_alloc();
     view_dispatcher_add_view(
     view_dispatcher_add_view(
-        subghz->view_dispatcher, SubGhzViewWidget, widget_get_view(subghz->widget));
+        subghz->view_dispatcher, SubGhzViewIdWidget, widget_get_view(subghz->widget));
 
 
     //Dialog
     //Dialog
     subghz->dialogs = furi_record_open("dialogs");
     subghz->dialogs = furi_record_open("dialogs");
 
 
     // Transmitter
     // Transmitter
-    subghz->subghz_transmitter = subghz_transmitter_alloc();
+    subghz->subghz_transmitter = subghz_view_transmitter_alloc();
     view_dispatcher_add_view(
     view_dispatcher_add_view(
         subghz->view_dispatcher,
         subghz->view_dispatcher,
-        SubGhzViewTransmitter,
-        subghz_transmitter_get_view(subghz->subghz_transmitter));
+        SubGhzViewIdTransmitter,
+        subghz_view_transmitter_get_view(subghz->subghz_transmitter));
 
 
     // Variable Item List
     // Variable Item List
     subghz->variable_item_list = variable_item_list_alloc();
     subghz->variable_item_list = variable_item_list_alloc();
     view_dispatcher_add_view(
     view_dispatcher_add_view(
         subghz->view_dispatcher,
         subghz->view_dispatcher,
-        SubGhzViewVariableItemList,
+        SubGhzViewIdVariableItemList,
         variable_item_list_get_view(subghz->variable_item_list));
         variable_item_list_get_view(subghz->variable_item_list));
 
 
     // Frequency Analyzer
     // Frequency Analyzer
     subghz->subghz_frequency_analyzer = subghz_frequency_analyzer_alloc();
     subghz->subghz_frequency_analyzer = subghz_frequency_analyzer_alloc();
     view_dispatcher_add_view(
     view_dispatcher_add_view(
         subghz->view_dispatcher,
         subghz->view_dispatcher,
-        SubGhzViewFrequencyAnalyzer,
+        SubGhzViewIdFrequencyAnalyzer,
         subghz_frequency_analyzer_get_view(subghz->subghz_frequency_analyzer));
         subghz_frequency_analyzer_get_view(subghz->subghz_frequency_analyzer));
 
 
     // Read RAW
     // Read RAW
     subghz->subghz_read_raw = subghz_read_raw_alloc();
     subghz->subghz_read_raw = subghz_read_raw_alloc();
     view_dispatcher_add_view(
     view_dispatcher_add_view(
         subghz->view_dispatcher,
         subghz->view_dispatcher,
-        SubGhzViewReadRAW,
+        SubGhzViewIdReadRAW,
         subghz_read_raw_get_view(subghz->subghz_read_raw));
         subghz_read_raw_get_view(subghz->subghz_read_raw));
 
 
     // Carrier Test Module
     // Carrier Test Module
     subghz->subghz_test_carrier = subghz_test_carrier_alloc();
     subghz->subghz_test_carrier = subghz_test_carrier_alloc();
     view_dispatcher_add_view(
     view_dispatcher_add_view(
         subghz->view_dispatcher,
         subghz->view_dispatcher,
-        SubGhzViewTestCarrier,
+        SubGhzViewIdTestCarrier,
         subghz_test_carrier_get_view(subghz->subghz_test_carrier));
         subghz_test_carrier_get_view(subghz->subghz_test_carrier));
 
 
     // Packet Test
     // Packet Test
     subghz->subghz_test_packet = subghz_test_packet_alloc();
     subghz->subghz_test_packet = subghz_test_packet_alloc();
     view_dispatcher_add_view(
     view_dispatcher_add_view(
         subghz->view_dispatcher,
         subghz->view_dispatcher,
-        SubGhzViewTestPacket,
+        SubGhzViewIdTestPacket,
         subghz_test_packet_get_view(subghz->subghz_test_packet));
         subghz_test_packet_get_view(subghz->subghz_test_packet));
 
 
     // Static send
     // Static send
     subghz->subghz_test_static = subghz_test_static_alloc();
     subghz->subghz_test_static = subghz_test_static_alloc();
     view_dispatcher_add_view(
     view_dispatcher_add_view(
         subghz->view_dispatcher,
         subghz->view_dispatcher,
-        SubGhzViewStatic,
+        SubGhzViewIdStatic,
         subghz_test_static_get_view(subghz->subghz_test_static));
         subghz_test_static_get_view(subghz->subghz_test_static));
 
 
     //init Worker & Protocol & History
     //init Worker & Protocol & History
@@ -170,12 +170,21 @@ SubGhz* subghz_alloc() {
     subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
     subghz->txrx->rx_key_state = SubGhzRxKeyStateIDLE;
     subghz->txrx->history = subghz_history_alloc();
     subghz->txrx->history = subghz_history_alloc();
     subghz->txrx->worker = subghz_worker_alloc();
     subghz->txrx->worker = subghz_worker_alloc();
-    subghz->txrx->parser = subghz_parser_alloc();
+    subghz->txrx->fff_data = flipper_format_string_alloc();
+
+    subghz->txrx->environment = subghz_environment_alloc();
+    subghz_environment_set_came_atomo_rainbow_table_file_name(
+        subghz->txrx->environment, "/ext/subghz/assets/came_atomo");
+    subghz_environment_set_nice_flor_s_rainbow_table_file_name(
+        subghz->txrx->environment, "/ext/subghz/assets/nice_flor_s");
+    subghz->txrx->receiver = subghz_receiver_alloc(subghz->txrx->environment);
+    subghz_receiver_set_filter(subghz->txrx->receiver, SubGhzProtocolFlag_Decodable);
+
     subghz_worker_set_overrun_callback(
     subghz_worker_set_overrun_callback(
-        subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_parser_reset);
+        subghz->txrx->worker, (SubGhzWorkerOverrunCallback)subghz_receiver_reset);
     subghz_worker_set_pair_callback(
     subghz_worker_set_pair_callback(
-        subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_parser_parse);
-    subghz_worker_set_context(subghz->txrx->worker, subghz->txrx->parser);
+        subghz->txrx->worker, (SubGhzWorkerPairCallback)subghz_receiver_decode);
+    subghz_worker_set_context(subghz->txrx->worker, subghz->txrx->receiver);
 
 
     //Init Error_str
     //Init Error_str
     string_init(subghz->error_str);
     string_init(subghz->error_str);
@@ -187,54 +196,54 @@ void subghz_free(SubGhz* subghz) {
     furi_assert(subghz);
     furi_assert(subghz);
 
 
     // Packet Test
     // Packet Test
-    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTestPacket);
+    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTestPacket);
     subghz_test_packet_free(subghz->subghz_test_packet);
     subghz_test_packet_free(subghz->subghz_test_packet);
 
 
     // Carrier Test
     // Carrier Test
-    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTestCarrier);
+    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTestCarrier);
     subghz_test_carrier_free(subghz->subghz_test_carrier);
     subghz_test_carrier_free(subghz->subghz_test_carrier);
 
 
     // Static
     // Static
-    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewStatic);
+    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdStatic);
     subghz_test_static_free(subghz->subghz_test_static);
     subghz_test_static_free(subghz->subghz_test_static);
 
 
     // Receiver
     // Receiver
-    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewReceiver);
-    subghz_receiver_free(subghz->subghz_receiver);
+    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdReceiver);
+    subghz_view_receiver_free(subghz->subghz_receiver);
 
 
     // TextInput
     // TextInput
-    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTextInput);
+    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTextInput);
     text_input_free(subghz->text_input);
     text_input_free(subghz->text_input);
 
 
     // Custom Widget
     // Custom Widget
-    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewWidget);
+    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdWidget);
     widget_free(subghz->widget);
     widget_free(subghz->widget);
 
 
     //Dialog
     //Dialog
     furi_record_close("dialogs");
     furi_record_close("dialogs");
 
 
     // Transmitter
     // Transmitter
-    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewTransmitter);
-    subghz_transmitter_free(subghz->subghz_transmitter);
+    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdTransmitter);
+    subghz_view_transmitter_free(subghz->subghz_transmitter);
 
 
     // Variable Item List
     // Variable Item List
-    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewVariableItemList);
+    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList);
     variable_item_list_free(subghz->variable_item_list);
     variable_item_list_free(subghz->variable_item_list);
 
 
     // Frequency Analyzer
     // Frequency Analyzer
-    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewFrequencyAnalyzer);
+    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdFrequencyAnalyzer);
     subghz_frequency_analyzer_free(subghz->subghz_frequency_analyzer);
     subghz_frequency_analyzer_free(subghz->subghz_frequency_analyzer);
 
 
     // Read RAW
     // Read RAW
-    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewReadRAW);
+    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdReadRAW);
     subghz_read_raw_free(subghz->subghz_read_raw);
     subghz_read_raw_free(subghz->subghz_read_raw);
 
 
     // Submenu
     // Submenu
-    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewMenu);
+    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdMenu);
     submenu_free(subghz->submenu);
     submenu_free(subghz->submenu);
 
 
     // Popup
     // Popup
-    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewPopup);
+    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewIdPopup);
     popup_free(subghz->popup);
     popup_free(subghz->popup);
 
 
     // Scene manager
     // Scene manager
@@ -248,8 +257,10 @@ void subghz_free(SubGhz* subghz) {
     subghz->gui = NULL;
     subghz->gui = NULL;
 
 
     //Worker & Protocol & History
     //Worker & Protocol & History
-    subghz_parser_free(subghz->txrx->parser);
+    subghz_receiver_free(subghz->txrx->receiver);
+    subghz_environment_free(subghz->txrx->environment);
     subghz_worker_free(subghz->txrx->worker);
     subghz_worker_free(subghz->txrx->worker);
+    flipper_format_free(subghz->txrx->fff_data);
     subghz_history_free(subghz->txrx->history);
     subghz_history_free(subghz->txrx->history);
     free(subghz->txrx);
     free(subghz->txrx);
 
 
@@ -268,12 +279,10 @@ int32_t subghz_app(void* p) {
     SubGhz* subghz = subghz_alloc();
     SubGhz* subghz = subghz_alloc();
 
 
     //Load database
     //Load database
-    bool load_database =
-        subghz_parser_load_keeloq_file(subghz->txrx->parser, "/ext/subghz/assets/keeloq_mfcodes");
-    subghz_parser_load_keeloq_file(subghz->txrx->parser, "/ext/subghz/assets/keeloq_mfcodes_user");
-    subghz_parser_load_nice_flor_s_file(subghz->txrx->parser, "/ext/subghz/assets/nice_flor_s_rx");
-    subghz_parser_load_came_atomo_file(subghz->txrx->parser, "/ext/subghz/assets/came_atomo");
-
+    bool load_database = subghz_environment_load_keystore(
+        subghz->txrx->environment, "/ext/subghz/assets/keeloq_mfcodes");
+    subghz_environment_load_keystore(
+        subghz->txrx->environment, "/ext/subghz/assets/keeloq_mfcodes_user");
     // Check argument and run corresponding scene
     // Check argument and run corresponding scene
     if(p && subghz_key_load(subghz, p)) {
     if(p && subghz_key_load(subghz, p)) {
         string_t filename;
         string_t filename;
@@ -282,8 +291,7 @@ int32_t subghz_app(void* p) {
         path_extract_filename_no_ext(p, filename);
         path_extract_filename_no_ext(p, filename);
         strcpy(subghz->file_name, string_get_cstr(filename));
         strcpy(subghz->file_name, string_get_cstr(filename));
         string_clear(filename);
         string_clear(filename);
-
-        if((!strcmp(subghz->txrx->protocol_result->name, "RAW"))) {
+        if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) {
             //Load Raw TX
             //Load Raw TX
             subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
             subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
@@ -296,7 +304,7 @@ int32_t subghz_app(void* p) {
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart);
         } else {
         } else {
             scene_manager_set_scene_state(
             scene_manager_set_scene_state(
-                subghz->scene_manager, SubGhzSceneShowError, SubghzCustomEventManagerSet);
+                subghz->scene_manager, SubGhzSceneShowError, SubGhzCustomEventManagerSet);
             string_set(
             string_set(
                 subghz->error_str,
                 subghz->error_str,
                 "No SD card or\ndatabase found.\nSome app function\nmay be reduced.");
                 "No SD card or\ndatabase found.\nSome app function\nmay be reduced.");

+ 61 - 31
applications/subghz/subghz_cli.c

@@ -5,14 +5,15 @@
 #include <stream_buffer.h>
 #include <stream_buffer.h>
 
 
 #include <lib/toolbox/args.h>
 #include <lib/toolbox/args.h>
-#include <lib/subghz/subghz_parser.h>
 #include <lib/subghz/subghz_keystore.h>
 #include <lib/subghz/subghz_keystore.h>
-#include <lib/subghz/protocols/subghz_protocol_common.h>
-#include <lib/subghz/protocols/subghz_protocol_princeton.h>
+
+#include <lib/subghz/receiver.h>
+#include <lib/subghz/transmitter.h>
 
 
 #include "helpers/subghz_chat.h"
 #include "helpers/subghz_chat.h"
 
 
 #include <notification/notification_messages.h>
 #include <notification/notification_messages.h>
+#include <flipper_format/flipper_format_i.h>
 
 
 #define SUBGHZ_FREQUENCY_RANGE_STR \
 #define SUBGHZ_FREQUENCY_RANGE_STR \
     "299999755...348000000 or 386999938...464000000 or 778999847...928000000"
     "299999755...348000000 or 386999938...464000000 or 778999847...928000000"
@@ -134,21 +135,35 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) {
         key,
         key,
         repeat);
         repeat);
 
 
-    SubGhzDecoderPrinceton* protocol = subghz_decoder_princeton_alloc();
-    protocol->common.code_last_found = key;
-    protocol->common.code_last_count_bit = 24;
+    string_t flipper_format_string;
+    string_init_printf(
+        flipper_format_string,
+        "Protocol: Princeton\n"
+        "Bit: 24\n"
+        "Key: 00 00 00 00 00 %X %X %X\n"
+        "TE: 403\n"
+        "Repeat: %d\n",
+        (uint8_t)((key >> 16) & 0xFF),
+        (uint8_t)((key >> 8) & 0xFF),
+        (uint8_t)(key & 0xFF),
+        repeat);
+    FlipperFormat* flipper_format = flipper_format_string_alloc();
+    Stream* stream = flipper_format_get_raw_stream(flipper_format);
+    stream_clean(stream);
+    stream_write_cstring(stream, string_get_cstr(flipper_format_string));
+
+    SubGhzEnvironment* environment = subghz_environment_alloc();
 
 
-    SubGhzProtocolCommonEncoder* encoder = subghz_protocol_encoder_common_alloc();
-    encoder->repeat = repeat;
+    SubGhzTransmitter* transmitter = subghz_transmitter_alloc_init(environment, "Princeton");
+    subghz_transmitter_deserialize(transmitter, flipper_format);
 
 
-    subghz_protocol_princeton_send_key(protocol, encoder);
     furi_hal_subghz_reset();
     furi_hal_subghz_reset();
     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
     frequency = furi_hal_subghz_set_frequency_and_path(frequency);
     frequency = furi_hal_subghz_set_frequency_and_path(frequency);
 
 
     furi_hal_power_suppress_charge_enter();
     furi_hal_power_suppress_charge_enter();
 
 
-    furi_hal_subghz_start_async_tx(subghz_protocol_encoder_common_yield, encoder);
+    furi_hal_subghz_start_async_tx(subghz_transmitter_yield, transmitter);
 
 
     while(!(furi_hal_subghz_is_async_tx_complete() || cli_cmd_interrupt_received(cli))) {
     while(!(furi_hal_subghz_is_async_tx_complete() || cli_cmd_interrupt_received(cli))) {
         printf(".");
         printf(".");
@@ -160,8 +175,9 @@ void subghz_cli_command_tx(Cli* cli, string_t args, void* context) {
 
 
     furi_hal_power_suppress_charge_exit();
     furi_hal_power_suppress_charge_exit();
 
 
-    subghz_decoder_princeton_free(protocol);
-    subghz_protocol_encoder_common_free(encoder);
+    flipper_format_free(flipper_format);
+    subghz_transmitter_free(transmitter);
+    subghz_environment_free(environment);
 }
 }
 
 
 typedef struct {
 typedef struct {
@@ -170,7 +186,7 @@ typedef struct {
     size_t packet_count;
     size_t packet_count;
 } SubGhzCliCommandRx;
 } SubGhzCliCommandRx;
 
 
-static void subghz_cli_command_rx_callback(bool level, uint32_t duration, void* context) {
+static void subghz_cli_command_rx_capture_callback(bool level, uint32_t duration, void* context) {
     SubGhzCliCommandRx* instance = context;
     SubGhzCliCommandRx* instance = context;
 
 
     BaseType_t xHigherPriorityTaskWoken = pdFALSE;
     BaseType_t xHigherPriorityTaskWoken = pdFALSE;
@@ -185,10 +201,19 @@ static void subghz_cli_command_rx_callback(bool level, uint32_t duration, void*
     portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
     portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
 }
 }
 
 
-static void subghz_cli_command_rx_text_callback(string_t text, void* context) {
+static void subghz_cli_command_rx_callback(
+    SubGhzReceiver* receiver,
+    SubGhzProtocolDecoderBase* decoder_base,
+    void* context) {
     SubGhzCliCommandRx* instance = context;
     SubGhzCliCommandRx* instance = context;
     instance->packet_count++;
     instance->packet_count++;
+
+    string_t text;
+    string_init(text);
+    subghz_protocol_decoder_base_get_string(decoder_base, text);
+    subghz_receiver_reset(receiver);
     printf("%s", string_get_cstr(text));
     printf("%s", string_get_cstr(text));
+    string_clear(text);
 }
 }
 
 
 void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
 void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
@@ -214,12 +239,16 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
     instance->stream = xStreamBufferCreate(sizeof(LevelDuration) * 1024, sizeof(LevelDuration));
     instance->stream = xStreamBufferCreate(sizeof(LevelDuration) * 1024, sizeof(LevelDuration));
     furi_check(instance->stream);
     furi_check(instance->stream);
 
 
-    SubGhzParser* parser = subghz_parser_alloc();
-    subghz_parser_load_keeloq_file(parser, "/ext/subghz/assets/keeloq_mfcodes");
-    subghz_parser_load_keeloq_file(parser, "/ext/subghz/assets/keeloq_mfcodes_user");
-    subghz_parser_load_nice_flor_s_file(parser, "/ext/subghz/assets/nice_flor_s_rx");
-    subghz_parser_load_came_atomo_file(parser, "/ext/subghz/assets/came_atomo");
-    subghz_parser_enable_dump_text(parser, subghz_cli_command_rx_text_callback, instance);
+    SubGhzEnvironment* environment = subghz_environment_alloc();
+    subghz_environment_load_keystore(environment, "/ext/subghz/assets/keeloq_mfcodes");
+    subghz_environment_set_came_atomo_rainbow_table_file_name(
+        environment, "/ext/subghz/assets/came_atomo");
+    subghz_environment_set_nice_flor_s_rainbow_table_file_name(
+        environment, "/ext/subghz/assets/nice_flor_s");
+
+    SubGhzReceiver* receiver = subghz_receiver_alloc(environment);
+    subghz_receiver_set_filter(receiver, SubGhzProtocolFlag_Decodable);
+    subghz_receiver_set_rx_callback(receiver, subghz_cli_command_rx_callback, instance);
 
 
     // Configure radio
     // Configure radio
     furi_hal_subghz_reset();
     furi_hal_subghz_reset();
@@ -230,7 +259,7 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
     furi_hal_power_suppress_charge_enter();
     furi_hal_power_suppress_charge_enter();
 
 
     // Prepare and start RX
     // Prepare and start RX
-    furi_hal_subghz_start_async_rx(subghz_cli_command_rx_callback, instance);
+    furi_hal_subghz_start_async_rx(subghz_cli_command_rx_capture_callback, instance);
 
 
     // Wait for packets to arrive
     // Wait for packets to arrive
     printf("Listening at %lu. Press CTRL+C to stop\r\n", frequency);
     printf("Listening at %lu. Press CTRL+C to stop\r\n", frequency);
@@ -241,11 +270,11 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
         if(ret == sizeof(LevelDuration)) {
         if(ret == sizeof(LevelDuration)) {
             if(level_duration_is_reset(level_duration)) {
             if(level_duration_is_reset(level_duration)) {
                 printf(".");
                 printf(".");
-                subghz_parser_reset(parser);
+                subghz_receiver_reset(receiver);
             } else {
             } else {
                 bool level = level_duration_get_level(level_duration);
                 bool level = level_duration_get_level(level_duration);
                 uint32_t duration = level_duration_get_duration(level_duration);
                 uint32_t duration = level_duration_get_duration(level_duration);
-                subghz_parser_parse(parser, level, duration);
+                subghz_receiver_decode(receiver, level, duration);
             }
             }
         }
         }
     }
     }
@@ -259,7 +288,8 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
     printf("\r\nPackets recieved %u\r\n", instance->packet_count);
     printf("\r\nPackets recieved %u\r\n", instance->packet_count);
 
 
     // Cleanup
     // Cleanup
-    subghz_parser_free(parser);
+    subghz_receiver_free(receiver);
+    subghz_environment_free(environment);
     vStreamBufferDelete(instance->stream);
     vStreamBufferDelete(instance->stream);
     free(instance);
     free(instance);
 }
 }
@@ -416,7 +446,7 @@ static void subghz_cli_command_chat(Cli* cli, string_t args) {
     string_t sysmsg;
     string_t sysmsg;
     string_init(sysmsg);
     string_init(sysmsg);
     bool exit = false;
     bool exit = false;
-    SubghzChatEvent chat_event;
+    SubGhzChatEvent chat_event;
 
 
     NotificationApp* notification = furi_record_open("notification");
     NotificationApp* notification = furi_record_open("notification");
 
 
@@ -428,10 +458,10 @@ static void subghz_cli_command_chat(Cli* cli, string_t args) {
     while(!exit) {
     while(!exit) {
         chat_event = subghz_chat_worker_get_event_chat(subghz_chat);
         chat_event = subghz_chat_worker_get_event_chat(subghz_chat);
         switch(chat_event.event) {
         switch(chat_event.event) {
-        case SubghzChatEventInputData:
+        case SubGhzChatEventInputData:
             if(chat_event.c == CliSymbolAsciiETX) {
             if(chat_event.c == CliSymbolAsciiETX) {
                 printf("\r\n");
                 printf("\r\n");
-                chat_event.event = SubghzChatEventUserExit;
+                chat_event.event = SubGhzChatEventUserExit;
                 subghz_chat_worker_put_event_chat(subghz_chat, &chat_event);
                 subghz_chat_worker_put_event_chat(subghz_chat, &chat_event);
                 break;
                 break;
             } else if(
             } else if(
@@ -478,7 +508,7 @@ static void subghz_cli_command_chat(Cli* cli, string_t args) {
                 fflush(stdout);
                 fflush(stdout);
                 string_push_back(input, chat_event.c);
                 string_push_back(input, chat_event.c);
                 break;
                 break;
-            case SubghzChatEventRXData:
+            case SubGhzChatEventRXData:
                 do {
                 do {
                     memset(message, 0x00, message_max_len);
                     memset(message, 0x00, message_max_len);
                     size_t len = subghz_chat_worker_read(subghz_chat, message, message_max_len);
                     size_t len = subghz_chat_worker_read(subghz_chat, message, message_max_len);
@@ -497,10 +527,10 @@ static void subghz_cli_command_chat(Cli* cli, string_t args) {
                     }
                     }
                 } while(subghz_chat_worker_available(subghz_chat));
                 } while(subghz_chat_worker_available(subghz_chat));
                 break;
                 break;
-            case SubghzChatEventNewMessage:
+            case SubGhzChatEventNewMessage:
                 notification_message(notification, &sequence_single_vibro);
                 notification_message(notification, &sequence_single_vibro);
                 break;
                 break;
-            case SubghzChatEventUserEntrance:
+            case SubGhzChatEventUserEntrance:
                 string_printf(
                 string_printf(
                     sysmsg,
                     sysmsg,
                     "\033[0;34m%s joined chat.\033[0m\r\n",
                     "\033[0;34m%s joined chat.\033[0m\r\n",
@@ -510,7 +540,7 @@ static void subghz_cli_command_chat(Cli* cli, string_t args) {
                     (uint8_t*)string_get_cstr(sysmsg),
                     (uint8_t*)string_get_cstr(sysmsg),
                     strlen(string_get_cstr(sysmsg)));
                     strlen(string_get_cstr(sysmsg)));
                 break;
                 break;
-            case SubghzChatEventUserExit:
+            case SubGhzChatEventUserExit:
                 string_printf(
                 string_printf(
                     sysmsg, "\033[0;31m%s left chat.\033[0m\r\n", furi_hal_version_get_name_ptr());
                     sysmsg, "\033[0;31m%s left chat.\033[0m\r\n", furi_hal_version_get_name_ptr());
                 subghz_chat_worker_write(
                 subghz_chat_worker_write(

+ 134 - 92
applications/subghz/subghz_history.c

@@ -1,70 +1,83 @@
 #include "subghz_history.h"
 #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 <lib/subghz/protocols/subghz_protocol_somfy_keytis.h>
+#include <lib/subghz/receiver.h>
+#include <lib/subghz/protocols/came.h>
 
 
 #include <furi.h>
 #include <furi.h>
 #include <m-string.h>
 #include <m-string.h>
 
 
 #define SUBGHZ_HISTORY_MAX 50
 #define SUBGHZ_HISTORY_MAX 50
+#define TAG "SubGhzHistory"
 
 
-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;
-    uint32_t data1;
+typedef struct {
+    string_t item_str;
+    FlipperFormat* flipper_string;
+    uint8_t type;
     FuriHalSubGhzPreset preset;
     FuriHalSubGhzPreset preset;
-    uint32_t real_frequency;
-};
+    uint32_t frequency;
+} SubGhzHistoryItem;
+
+ARRAY_DEF(SubGhzHistoryItemArray, SubGhzHistoryItem, M_POD_OPLIST)
+
+#define M_OPL_SubGhzHistoryItemArray_t() ARRAY_OPLIST(SubGhzHistoryItemArray, M_POD_OPLIST)
+
+typedef struct {
+    SubGhzHistoryItemArray_t data;
+} SubGhzHistoryStruct;
 
 
 struct SubGhzHistory {
 struct SubGhzHistory {
     uint32_t last_update_timestamp;
     uint32_t last_update_timestamp;
     uint16_t last_index_write;
     uint16_t last_index_write;
-    uint64_t code_last_found;
-    SubGhzHistoryStruct history[SUBGHZ_HISTORY_MAX];
-    SubGhzProtocolCommonLoad data;
+    uint8_t code_last_hash_data;
+    string_t tmp_string;
+    SubGhzHistoryStruct* history;
 };
 };
 
 
 SubGhzHistory* subghz_history_alloc(void) {
 SubGhzHistory* subghz_history_alloc(void) {
     SubGhzHistory* instance = malloc(sizeof(SubGhzHistory));
     SubGhzHistory* instance = malloc(sizeof(SubGhzHistory));
+    string_init(instance->tmp_string);
+    instance->history = malloc(sizeof(SubGhzHistoryStruct));
+    SubGhzHistoryItemArray_init(instance->history->data);
     return instance;
     return instance;
 }
 }
 
 
 void subghz_history_free(SubGhzHistory* instance) {
 void subghz_history_free(SubGhzHistory* instance) {
     furi_assert(instance);
     furi_assert(instance);
+    string_clear(instance->tmp_string);
+    for
+        M_EACH(item, instance->history->data, SubGhzHistoryItemArray_t) {
+            string_clear(item->item_str);
+            flipper_format_free(item->flipper_string);
+            item->type = 0;
+        }
+    SubGhzHistoryItemArray_clear(instance->history->data);
+    free(instance->history);
     free(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) {
 uint32_t subghz_history_get_frequency(SubGhzHistory* instance, uint16_t idx) {
     furi_assert(instance);
     furi_assert(instance);
-    return instance->history[idx].real_frequency;
+    SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx);
+    return item->frequency;
 }
 }
 
 
 FuriHalSubGhzPreset subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx) {
 FuriHalSubGhzPreset subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx) {
     furi_assert(instance);
     furi_assert(instance);
-    return instance->history[idx].preset;
+    SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx);
+    return item->preset;
 }
 }
 
 
 void subghz_history_reset(SubGhzHistory* instance) {
 void subghz_history_reset(SubGhzHistory* instance) {
     furi_assert(instance);
     furi_assert(instance);
+    string_reset(instance->tmp_string);
+    for
+        M_EACH(item, instance->history->data, SubGhzHistoryItemArray_t) {
+            string_clear(item->item_str);
+            flipper_format_free(item->flipper_string);
+            item->type = 0;
+        }
+    SubGhzHistoryItemArray_reset(instance->history->data);
     instance->last_index_write = 0;
     instance->last_index_write = 0;
-    instance->code_last_found = 0;
+    instance->code_last_hash_data = 0;
 }
 }
 
 
 uint16_t subghz_history_get_item(SubGhzHistory* instance) {
 uint16_t subghz_history_get_item(SubGhzHistory* instance) {
@@ -74,20 +87,29 @@ uint16_t subghz_history_get_item(SubGhzHistory* instance) {
 
 
 uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx) {
 uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx) {
     furi_assert(instance);
     furi_assert(instance);
-    return instance->history[idx].type_protocol;
+    SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx);
+    return item->type;
 }
 }
 
 
-const char* subghz_history_get_name(SubGhzHistory* instance, uint16_t idx) {
+const char* subghz_history_get_protocol_name(SubGhzHistory* instance, uint16_t idx) {
     furi_assert(instance);
     furi_assert(instance);
-    return instance->history[idx].name;
+    SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx);
+    flipper_format_rewind(item->flipper_string);
+    if(!flipper_format_read_string(item->flipper_string, "Protocol", instance->tmp_string)) {
+        FURI_LOG_E(TAG, "Missing Protocol");
+        string_reset(instance->tmp_string);
+    }
+    return string_get_cstr(instance->tmp_string);
 }
 }
 
 
-SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx) {
+FlipperFormat* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx) {
     furi_assert(instance);
     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].data1;
-    return &instance->data;
+    SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx);
+    if(item->flipper_string) {
+        return item->flipper_string;
+    } else {
+        return NULL;
+    }
 }
 }
 bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output) {
 bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output) {
     furi_assert(instance);
     furi_assert(instance);
@@ -99,34 +121,10 @@ bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output
         string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX);
         string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX);
     return false;
     return false;
 }
 }
-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_get_text_item_menu(SubGhzHistory* instance, string_t output, uint16_t idx) {
+    SubGhzHistoryItem* item = SubGhzHistoryItemArray_get(instance->history->data, idx);
+    string_set(output, item->item_str);
 }
 }
 
 
 bool subghz_history_add_to_history(
 bool subghz_history_add_to_history(
@@ -136,41 +134,85 @@ bool subghz_history_add_to_history(
     FuriHalSubGhzPreset preset) {
     FuriHalSubGhzPreset preset) {
     furi_assert(instance);
     furi_assert(instance);
     furi_assert(context);
     furi_assert(context);
-    SubGhzProtocolCommon* protocol = context;
 
 
     if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return false;
     if(instance->last_index_write >= SUBGHZ_HISTORY_MAX) return false;
-    if((instance->code_last_found == (protocol->code_last_found & 0xFFFF0FFFFFFFFFFF)) &&
+
+    SubGhzProtocolDecoderBase* decoder_base = context;
+    if((instance->code_last_hash_data ==
+        subghz_protocol_decoder_base_get_hash_data(decoder_base)) &&
        ((millis() - instance->last_update_timestamp) < 500)) {
        ((millis() - instance->last_update_timestamp) < 500)) {
         instance->last_update_timestamp = millis();
         instance->last_update_timestamp = millis();
         return false;
         return false;
     }
     }
 
 
-    instance->code_last_found = protocol->code_last_found & 0xFFFF0FFFFFFFFFFF;
+    instance->code_last_hash_data = subghz_protocol_decoder_base_get_hash_data(decoder_base);
     instance->last_update_timestamp = millis();
     instance->last_update_timestamp = millis();
 
 
-    instance->history[instance->last_index_write].real_frequency = frequency;
-    instance->history[instance->last_index_write].preset = preset;
-    instance->history[instance->last_index_write].data1 = 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_find_and_get_manufacture_name(protocol);
-    } else if(strcmp(protocol->name, "Star Line") == 0) {
-        instance->history[instance->last_index_write].manufacture_name =
-            subghz_protocol_star_line_find_and_get_manufacture_name(protocol);
-    } else if(strcmp(protocol->name, "Princeton") == 0) {
-        instance->history[instance->last_index_write].data1 =
-            subghz_protocol_princeton_get_te(protocol);
-    } else if(strcmp(protocol->name, "Somfy Keytis") == 0) {
-        instance->history[instance->last_index_write].data1 =
-            subghz_protocol_somfy_keytis_get_press_duration(protocol);
-    }
-
-    instance->history[instance->last_index_write].type_protocol = protocol->type_protocol;
+    string_t text;
+    string_init(text);
+    SubGhzHistoryItem* item = SubGhzHistoryItemArray_push_raw(instance->history->data);
+    item->type = decoder_base->protocol->type;
+    item->frequency = frequency;
+    item->preset = preset;
+
+    string_init(item->item_str);
+    item->flipper_string = flipper_format_string_alloc();
+    subghz_protocol_decoder_base_serialize(decoder_base, item->flipper_string, frequency, preset);
+
+    do {
+        if(!flipper_format_rewind(item->flipper_string)) {
+            FURI_LOG_E(TAG, "Rewind error");
+            break;
+        }
+        if(!flipper_format_read_string(item->flipper_string, "Protocol", instance->tmp_string)) {
+            FURI_LOG_E(TAG, "Missing Protocol");
+            break;
+        }
+        if(!strcmp(string_get_cstr(instance->tmp_string), "KeeLoq")) {
+            string_set(instance->tmp_string, "KL ");
+            if(!flipper_format_read_string(item->flipper_string, "Manufacture", text)) {
+                FURI_LOG_E(TAG, "Missing Protocol");
+                break;
+            }
+            string_cat(instance->tmp_string, text);
+        } else if(!strcmp(string_get_cstr(instance->tmp_string), "Star Line")) {
+            string_set(instance->tmp_string, "SL ");
+            if(!flipper_format_read_string(item->flipper_string, "Manufacture", text)) {
+                FURI_LOG_E(TAG, "Missing Protocol");
+                break;
+            }
+            string_cat(instance->tmp_string, text);
+        }
+        if(!flipper_format_rewind(item->flipper_string)) {
+            FURI_LOG_E(TAG, "Rewind error");
+            break;
+        }
+        uint8_t key_data[sizeof(uint64_t)] = {0};
+        if(!flipper_format_read_hex(item->flipper_string, "Key", key_data, sizeof(uint64_t))) {
+            FURI_LOG_E(TAG, "Missing Key");
+            break;
+        }
+        uint64_t data = 0;
+        for(uint8_t i = 0; i < sizeof(uint64_t); i++) {
+            data = (data << 8) | key_data[i];
+        }
+        if(!(uint32_t)(data >> 32)) {
+            string_printf(
+                item->item_str,
+                "%s %lX",
+                string_get_cstr(instance->tmp_string),
+                (uint32_t)(data & 0xFFFFFFFF));
+        } else {
+            string_printf(
+                item->item_str,
+                "%s %lX%08lX",
+                string_get_cstr(instance->tmp_string),
+                (uint32_t)(data >> 32),
+                (uint32_t)(data & 0xFFFFFFFF));
+        }
+    } while(false);
 
 
+    string_clear(text);
     instance->last_index_write++;
     instance->last_index_write++;
     return true;
     return true;
 }
 }

+ 6 - 16
applications/subghz/subghz_history.h

@@ -1,7 +1,10 @@
 
 
 #pragma once
 #pragma once
 
 
-#include <lib/subghz/protocols/subghz_protocol_common.h>
+#include <math.h>
+#include <furi.h>
+#include <furi_hal.h>
+#include <lib/flipper_format/flipper_format.h>
 
 
 typedef struct SubGhzHistory SubGhzHistory;
 typedef struct SubGhzHistory SubGhzHistory;
 
 
@@ -23,19 +26,6 @@ void subghz_history_free(SubGhzHistory* instance);
  */
  */
 void subghz_history_reset(SubGhzHistory* instance);
 void subghz_history_reset(SubGhzHistory* instance);
 
 
-/** Set frequency and preset to history[idx]
- * 
- * @param instance  - SubGhzHistory instance
- * @param idx       - record index  
- * @param frequency - frequency Hz
- * @param preset    - FuriHalSubGhzPreset preset
- */
-void subghz_history_set_frequency_preset(
-    SubGhzHistory* instance,
-    uint16_t idx,
-    uint32_t frequency,
-    FuriHalSubGhzPreset preset);
-
 /** Get frequency to history[idx]
 /** Get frequency to history[idx]
  * 
  * 
  * @param instance  - SubGhzHistory instance
  * @param instance  - SubGhzHistory instance
@@ -73,7 +63,7 @@ uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx);
  * @param idx       - record index  
  * @param idx       - record index  
  * @return name      - const char* name protocol  
  * @return name      - const char* name protocol  
  */
  */
-const char* subghz_history_get_name(SubGhzHistory* instance, uint16_t idx);
+const char* subghz_history_get_protocol_name(SubGhzHistory* instance, uint16_t idx);
 
 
 /** Get string item menu to history[idx]
 /** Get string item menu to history[idx]
  * 
  * 
@@ -111,4 +101,4 @@ bool subghz_history_add_to_history(
  * @param idx       - record index
  * @param idx       - record index
  * @return SubGhzProtocolCommonLoad*
  * @return SubGhzProtocolCommonLoad*
  */
  */
-SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx);
+FlipperFormat* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx);

+ 115 - 132
applications/subghz/subghz_i.c

@@ -8,9 +8,16 @@
 #include <notification/notification_messages.h>
 #include <notification/notification_messages.h>
 #include <flipper_format/flipper_format.h>
 #include <flipper_format/flipper_format.h>
 #include "../notification/notification.h"
 #include "../notification/notification.h"
-#include "views/subghz_receiver.h"
+#include "views/receiver.h"
 
 
-bool subghz_set_pteset(SubGhz* subghz, const char* preset) {
+#include <flipper_format/flipper_format_i.h>
+#include <lib/toolbox/stream/stream.h>
+#include <lib/subghz/protocols/raw.h>
+#include <lib/toolbox/path.h>
+
+#define TAG "SubGhz"
+
+bool subghz_set_preset(SubGhz* subghz, const char* preset) {
     if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) {
     if(!strcmp(preset, "FuriHalSubGhzPresetOok270Async")) {
         subghz->txrx->preset = FuriHalSubGhzPresetOok270Async;
         subghz->txrx->preset = FuriHalSubGhzPresetOok270Async;
     } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) {
     } else if(!strcmp(preset, "FuriHalSubGhzPresetOok650Async")) {
@@ -20,33 +27,9 @@ bool subghz_set_pteset(SubGhz* subghz, const char* preset) {
     } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) {
     } else if(!strcmp(preset, "FuriHalSubGhzPreset2FSKDev476Async")) {
         subghz->txrx->preset = FuriHalSubGhzPreset2FSKDev476Async;
         subghz->txrx->preset = FuriHalSubGhzPreset2FSKDev476Async;
     } else {
     } else {
-        FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unknown preset");
-        return false;
-    }
-    return true;
-}
-
-bool subghz_get_preset_name(SubGhz* subghz, string_t preset) {
-    const char* preset_name;
-    switch(subghz->txrx->preset) {
-    case FuriHalSubGhzPresetOok270Async:
-        preset_name = "FuriHalSubGhzPresetOok270Async";
-        break;
-    case FuriHalSubGhzPresetOok650Async:
-        preset_name = "FuriHalSubGhzPresetOok650Async";
-        break;
-    case FuriHalSubGhzPreset2FSKDev238Async:
-        preset_name = "FuriHalSubGhzPreset2FSKDev238Async";
-        break;
-    case FuriHalSubGhzPreset2FSKDev476Async:
-        preset_name = "FuriHalSubGhzPreset2FSKDev476Async";
-        break;
-    default:
-        FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unknown preset");
+        FURI_LOG_E(TAG, "Unknown preset");
         return false;
         return false;
-        break;
     }
     }
-    string_set(preset, preset_name);
     return true;
     return true;
 }
 }
 
 
@@ -143,38 +126,57 @@ void subghz_sleep(SubGhz* subghz) {
     subghz->txrx->txrx_state = SubGhzTxRxStateSleep;
     subghz->txrx->txrx_state = SubGhzTxRxStateSleep;
 }
 }
 
 
-bool subghz_tx_start(SubGhz* subghz) {
+bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format) {
     furi_assert(subghz);
     furi_assert(subghz);
 
 
     bool ret = false;
     bool ret = false;
-    subghz->txrx->encoder = subghz_protocol_encoder_common_alloc();
-    subghz->txrx->encoder->repeat = 200; //max repeat with the button held down
-    //get upload
-    if(subghz->txrx->protocol_result->get_upload_protocol) {
-        if(subghz->txrx->protocol_result->get_upload_protocol(
-               subghz->txrx->protocol_result, subghz->txrx->encoder)) {
-            if(subghz->txrx->preset) {
-                subghz_begin(subghz, subghz->txrx->preset);
-            } else {
-                subghz_begin(subghz, FuriHalSubGhzPresetOok270Async);
-            }
-            if(subghz->txrx->frequency) {
-                ret = subghz_tx(subghz, subghz->txrx->frequency);
-            } else {
-                ret = subghz_tx(subghz, 433920000);
-            }
+    string_t temp_str;
+    string_init(temp_str);
+    uint32_t repeat = 200;
+    do {
+        if(!flipper_format_rewind(flipper_format)) {
+            FURI_LOG_E(TAG, "Rewind error");
+            break;
+        }
+        if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) {
+            FURI_LOG_E(TAG, "Missing Protocol");
+            break;
+        }
+        //ToDo FIX
+        if(!flipper_format_insert_or_update_uint32(flipper_format, "Repeat", &repeat, 1)) {
+            FURI_LOG_E(TAG, "Unable Repeat");
+            break;
+        }
 
 
-            if(ret) {
-                //Start TX
-                furi_hal_subghz_start_async_tx(
-                    subghz_protocol_encoder_common_yield, subghz->txrx->encoder);
+        subghz->txrx->transmitter =
+            subghz_transmitter_alloc_init(subghz->txrx->environment, string_get_cstr(temp_str));
+
+        if(subghz->txrx->transmitter) {
+            if(subghz_transmitter_deserialize(subghz->txrx->transmitter, flipper_format)) {
+                if(subghz->txrx->preset) {
+                    subghz_begin(subghz, subghz->txrx->preset);
+                } else {
+                    subghz_begin(subghz, FuriHalSubGhzPresetOok270Async);
+                }
+                if(subghz->txrx->frequency) {
+                    ret = subghz_tx(subghz, subghz->txrx->frequency);
+                } else {
+                    ret = subghz_tx(subghz, 433920000);
+                }
+                if(ret) {
+                    //Start TX
+                    furi_hal_subghz_start_async_tx(
+                        subghz_transmitter_yield, subghz->txrx->transmitter);
+                }
             }
             }
         }
         }
-    }
-    if(!ret) {
-        subghz_protocol_encoder_common_free(subghz->txrx->encoder);
-        subghz_idle(subghz);
-    }
+        if(!ret) {
+            subghz_transmitter_free(subghz->txrx->transmitter);
+            subghz_idle(subghz);
+        }
+
+    } while(false);
+    string_clear(temp_str);
     return ret;
     return ret;
 }
 }
 
 
@@ -183,13 +185,15 @@ void subghz_tx_stop(SubGhz* subghz) {
     furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateTx);
     furi_assert(subghz->txrx->txrx_state == SubGhzTxRxStateTx);
     //Stop TX
     //Stop TX
     furi_hal_subghz_stop_async_tx();
     furi_hal_subghz_stop_async_tx();
-    subghz_protocol_encoder_common_free(subghz->txrx->encoder);
-    subghz_idle(subghz);
+    subghz_transmitter_stop(subghz->txrx->transmitter);
+    subghz_transmitter_free(subghz->txrx->transmitter);
+
     //if protocol dynamic then we save the last upload
     //if protocol dynamic then we save the last upload
-    if((subghz->txrx->protocol_result->type_protocol == SubGhzProtocolCommonTypeDynamic) &&
+    if((subghz->txrx->decoder_result->protocol->type == SubGhzProtocolTypeDynamic) &&
        (strcmp(subghz->file_name, ""))) {
        (strcmp(subghz->file_name, ""))) {
-        subghz_save_protocol_to_file(subghz, subghz->file_name);
+        subghz_save_protocol_to_file(subghz, subghz->txrx->fff_data, subghz->file_name);
     }
     }
+    subghz_idle(subghz);
     notification_message(subghz->notifications, &sequence_reset_red);
     notification_message(subghz->notifications, &sequence_reset_red);
 }
 }
 
 
@@ -198,24 +202,23 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) {
     furi_assert(file_path);
     furi_assert(file_path);
 
 
     Storage* storage = furi_record_open("storage");
     Storage* storage = furi_record_open("storage");
-    FlipperFormat* flipper_format = flipper_format_file_alloc(storage);
+    FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
+    Stream* fff_data_stream = flipper_format_get_raw_stream(subghz->txrx->fff_data);
 
 
-    // Load device data
     bool loaded = false;
     bool loaded = false;
-    string_t path;
-    string_init_set_str(path, file_path);
     string_t temp_str;
     string_t temp_str;
     string_init(temp_str);
     string_init(temp_str);
     uint32_t version;
     uint32_t version;
 
 
     do {
     do {
-        if(!flipper_format_file_open_existing(flipper_format, string_get_cstr(path))) {
-            FURI_LOG_E(
-                SUBGHZ_PARSER_TAG, "Unable to open file for read: %s", string_get_cstr(path));
+        stream_clean(fff_data_stream);
+        if(!flipper_format_file_open_existing(fff_data_file, file_path)) {
+            FURI_LOG_E(TAG, "Error open file %s", file_path);
             break;
             break;
         }
         }
-        if(!flipper_format_read_header(flipper_format, temp_str, &version)) {
-            FURI_LOG_E(SUBGHZ_PARSER_TAG, "Missing or incorrect header");
+
+        if(!flipper_format_read_header(fff_data_file, temp_str, &version)) {
+            FURI_LOG_E(TAG, "Missing or incorrect header");
             break;
             break;
         }
         }
 
 
@@ -223,50 +226,59 @@ bool subghz_key_load(SubGhz* subghz, const char* file_path) {
             (!strcmp(string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE))) &&
             (!strcmp(string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE))) &&
            version == SUBGHZ_KEY_FILE_VERSION) {
            version == SUBGHZ_KEY_FILE_VERSION) {
         } else {
         } else {
-            FURI_LOG_E(SUBGHZ_PARSER_TAG, "Type or version mismatch");
+            FURI_LOG_E(TAG, "Type or version mismatch");
             break;
             break;
         }
         }
 
 
         if(!flipper_format_read_uint32(
         if(!flipper_format_read_uint32(
-               flipper_format, "Frequency", (uint32_t*)&subghz->txrx->frequency, 1)) {
-            FURI_LOG_E(SUBGHZ_PARSER_TAG, "Missing Frequency");
+               fff_data_file, "Frequency", (uint32_t*)&subghz->txrx->frequency, 1)) {
+            FURI_LOG_E(TAG, "Missing Frequency");
             break;
             break;
         }
         }
 
 
-        if(!flipper_format_read_string(flipper_format, "Preset", temp_str)) {
-            FURI_LOG_E(SUBGHZ_PARSER_TAG, "Missing Preset");
+        if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
+            FURI_LOG_E(TAG, "Missing Preset");
             break;
             break;
         }
         }
-        if(!subghz_set_pteset(subghz, string_get_cstr(temp_str))) {
+        if(!subghz_set_preset(subghz, string_get_cstr(temp_str))) {
             break;
             break;
         }
         }
 
 
-        if(!flipper_format_read_string(flipper_format, "Protocol", temp_str)) {
-            FURI_LOG_E(SUBGHZ_PARSER_TAG, "Missing Protocol");
+        if(!flipper_format_read_string(fff_data_file, "Protocol", temp_str)) {
+            FURI_LOG_E(TAG, "Missing Protocol");
             break;
             break;
         }
         }
+        if(!strcmp(string_get_cstr(temp_str), "RAW")) {
+            //if RAW
+            string_t file_name;
+            string_init(file_name);
+            path_extract_filename_no_ext(file_path, file_name);
+            subghz_protocol_raw_gen_fff_data(subghz->txrx->fff_data, string_get_cstr(file_name));
+            string_clear(file_name);
 
 
-        subghz->txrx->protocol_result =
-            subghz_parser_get_by_name(subghz->txrx->parser, string_get_cstr(temp_str));
-        if(subghz->txrx->protocol_result == NULL) {
-            FURI_LOG_E(SUBGHZ_PARSER_TAG, "This type of protocol was not found");
-            break;
+        } else {
+            stream_copy_full(
+                flipper_format_get_raw_stream(fff_data_file),
+                flipper_format_get_raw_stream(subghz->txrx->fff_data));
         }
         }
-        if(!subghz->txrx->protocol_result->to_load_protocol_from_file(
-               flipper_format, subghz->txrx->protocol_result, string_get_cstr(path))) {
-            break;
+
+        subghz->txrx->decoder_result = subghz_receiver_search_decoder_base_by_name(
+            subghz->txrx->receiver, string_get_cstr(temp_str));
+        if(subghz->txrx->decoder_result) {
+            subghz_protocol_decoder_base_deserialize(
+                subghz->txrx->decoder_result, subghz->txrx->fff_data);
         }
         }
+
         loaded = true;
         loaded = true;
     } while(0);
     } while(0);
 
 
     if(!loaded) {
     if(!loaded) {
         dialog_message_show_storage_error(subghz->dialogs, "Cannot parse\nfile");
         dialog_message_show_storage_error(subghz->dialogs, "Cannot parse\nfile");
     }
     }
-    string_clear(temp_str);
-    string_clear(path);
-
-    flipper_format_free(flipper_format);
 
 
+    string_clear(temp_str);
+    //string_clear(path);
+    flipper_format_free(fff_data_file);
     furi_record_close("storage");
     furi_record_close("storage");
 
 
     return loaded;
     return loaded;
@@ -295,24 +307,26 @@ bool subghz_get_next_name_file(SubGhz* subghz) {
     return res;
     return res;
 }
 }
 
 
-bool subghz_save_protocol_to_file(SubGhz* subghz, const char* dev_name) {
+bool subghz_save_protocol_to_file(
+    SubGhz* subghz,
+    FlipperFormat* flipper_format,
+    const char* dev_name) {
     furi_assert(subghz);
     furi_assert(subghz);
-    furi_assert(subghz->txrx->protocol_result);
+    furi_assert(flipper_format);
+    furi_assert(dev_name);
 
 
     Storage* storage = furi_record_open("storage");
     Storage* storage = furi_record_open("storage");
-    FlipperFormat* flipper_format = flipper_format_file_alloc(storage);
+    Stream* flipper_format_stream = flipper_format_get_raw_stream(flipper_format);
+
     string_t dev_file_name;
     string_t dev_file_name;
     string_init(dev_file_name);
     string_init(dev_file_name);
-    string_t temp_str;
-    string_init(temp_str);
     bool saved = false;
     bool saved = false;
 
 
     do {
     do {
-        // Checking that this type of people can be saved
-        if(subghz->txrx->protocol_result->to_save_file == NULL) {
-            FURI_LOG_E(SUBGHZ_PARSER_TAG, "No saving of this type of keys");
-            break;
-        }
+        //removing additional fields
+        flipper_format_delete_key(flipper_format, "Repeat");
+        flipper_format_delete_key(flipper_format, "Manufacture");
+
         // Create subghz folder directory if necessary
         // Create subghz folder directory if necessary
         if(!storage_simply_mkdir(storage, SUBGHZ_APP_FOLDER)) {
         if(!storage_simply_mkdir(storage, SUBGHZ_APP_FOLDER)) {
             dialog_message_show_storage_error(subghz->dialogs, "Cannot create\nfolder");
             dialog_message_show_storage_error(subghz->dialogs, "Cannot create\nfolder");
@@ -325,47 +339,16 @@ bool subghz_save_protocol_to_file(SubGhz* subghz, const char* dev_name) {
         if(!storage_simply_remove(storage, string_get_cstr(dev_file_name))) {
         if(!storage_simply_remove(storage, string_get_cstr(dev_file_name))) {
             break;
             break;
         }
         }
-
-        // Open file
-        if(!flipper_format_file_open_always(flipper_format, string_get_cstr(dev_file_name))) {
-            FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to open file for write: %s", dev_file_name);
-            break;
-        }
-
-        if(!flipper_format_write_header_cstr(
-               flipper_format, SUBGHZ_KEY_FILE_TYPE, SUBGHZ_KEY_FILE_VERSION)) {
-            FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to add header");
-            break;
-        }
-
-        if(!flipper_format_write_uint32(flipper_format, "Frequency", &subghz->txrx->frequency, 1)) {
-            FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to add Frequency");
-            break;
-        }
-
-        if(!subghz_get_preset_name(subghz, temp_str)) {
-            break;
-        }
-        if(!flipper_format_write_string_cstr(flipper_format, "Preset", string_get_cstr(temp_str))) {
-            FURI_LOG_E(SUBGHZ_PARSER_TAG, "Unable to add Preset");
-            break;
-        }
-
-        if(!subghz->txrx->protocol_result->to_save_file(
-               subghz->txrx->protocol_result, flipper_format)) {
-            break;
-        }
+        //ToDo check Write
+        stream_seek(flipper_format_stream, 0, StreamOffsetFromStart);
+        stream_save_to_file(
+            flipper_format_stream, storage, string_get_cstr(dev_file_name), FSOM_CREATE_ALWAYS);
 
 
         saved = true;
         saved = true;
     } while(0);
     } while(0);
 
 
-    string_clear(temp_str);
     string_clear(dev_file_name);
     string_clear(dev_file_name);
-
-    flipper_format_free(flipper_format);
-
     furi_record_close("storage");
     furi_record_close("storage");
-
     return saved;
     return saved;
 }
 }
 
 
@@ -501,7 +484,7 @@ void subghz_hopper_update(SubGhz* subghz) {
         subghz_rx_end(subghz);
         subghz_rx_end(subghz);
     };
     };
     if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
     if(subghz->txrx->txrx_state == SubGhzTxRxStateIDLE) {
-        subghz_parser_reset(subghz->txrx->parser);
+        subghz_receiver_reset(subghz->txrx->receiver);
         subghz->txrx->frequency = subghz_hopper_frequencies[subghz->txrx->hopper_idx_frequency];
         subghz->txrx->frequency = subghz_hopper_frequencies[subghz->txrx->hopper_idx_frequency];
         subghz_rx(subghz, subghz->txrx->frequency);
         subghz_rx(subghz, subghz->txrx->frequency);
     }
     }

+ 40 - 33
applications/subghz/subghz_i.h

@@ -1,8 +1,8 @@
 #pragma once
 #pragma once
 
 
 #include "subghz.h"
 #include "subghz.h"
-#include "views/subghz_receiver.h"
-#include "views/subghz_transmitter.h"
+#include "views/receiver.h"
+#include "views/transmitter.h"
 #include "views/subghz_frequency_analyzer.h"
 #include "views/subghz_frequency_analyzer.h"
 #include "views/subghz_read_raw.h"
 #include "views/subghz_read_raw.h"
 
 
@@ -26,8 +26,9 @@
 
 
 #include <lib/subghz/subghz_worker.h>
 #include <lib/subghz/subghz_worker.h>
 
 
-#include <lib/subghz/subghz_parser.h>
-#include <lib/subghz/protocols/subghz_protocol_common.h>
+#include <lib/subghz/receiver.h>
+#include <lib/subghz/transmitter.h>
+
 #include "subghz_history.h"
 #include "subghz_history.h"
 
 
 #include <gui/modules/variable_item_list.h>
 #include <gui/modules/variable_item_list.h>
@@ -79,9 +80,13 @@ typedef enum {
 
 
 struct SubGhzTxRx {
 struct SubGhzTxRx {
     SubGhzWorker* worker;
     SubGhzWorker* worker;
-    SubGhzParser* parser;
-    SubGhzProtocolCommon* protocol_result;
-    SubGhzProtocolCommonEncoder* encoder;
+
+    SubGhzEnvironment* environment;
+    SubGhzReceiver* receiver;
+    SubGhzTransmitter* transmitter;
+    SubGhzProtocolDecoderBase* decoder_result;
+    FlipperFormat* fff_data;
+
     uint32_t frequency;
     uint32_t frequency;
     FuriHalSubGhzPreset preset;
     FuriHalSubGhzPreset preset;
     SubGhzHistory* history;
     SubGhzHistory* history;
@@ -113,46 +118,48 @@ struct SubGhz {
     char file_name_tmp[SUBGHZ_TEXT_STORE_SIZE + 1];
     char file_name_tmp[SUBGHZ_TEXT_STORE_SIZE + 1];
     SubGhzNotificationState state_notifications;
     SubGhzNotificationState state_notifications;
 
 
-    SubghzReceiver* subghz_receiver;
-    SubghzTransmitter* subghz_transmitter;
+    SubGhzViewReceiver* subghz_receiver;
+    SubGhzViewTransmitter* subghz_transmitter;
     VariableItemList* variable_item_list;
     VariableItemList* variable_item_list;
 
 
-    SubghzFrequencyAnalyzer* subghz_frequency_analyzer;
-    SubghzReadRAW* subghz_read_raw;
-    SubghzTestStatic* subghz_test_static;
-    SubghzTestCarrier* subghz_test_carrier;
-    SubghzTestPacket* subghz_test_packet;
+    SubGhzFrequencyAnalyzer* subghz_frequency_analyzer;
+    SubGhzReadRAW* subghz_read_raw;
+    SubGhzTestStatic* subghz_test_static;
+    SubGhzTestCarrier* subghz_test_carrier;
+    SubGhzTestPacket* subghz_test_packet;
     string_t error_str;
     string_t error_str;
 };
 };
 
 
 typedef enum {
 typedef enum {
-    SubGhzViewMenu,
-
-    SubGhzViewReceiver,
-    SubGhzViewPopup,
-    SubGhzViewTextInput,
-    SubGhzViewWidget,
-    SubGhzViewTransmitter,
-    SubGhzViewVariableItemList,
-    SubGhzViewFrequencyAnalyzer,
-    SubGhzViewReadRAW,
-    SubGhzViewStatic,
-    SubGhzViewTestCarrier,
-    SubGhzViewTestPacket,
-} SubGhzView;
-
-bool subghz_set_pteset(SubGhz* subghz, const char* preset);
-bool subghz_get_preset_name(SubGhz* subghz, string_t preset);
+    SubGhzViewIdMenu,
+    SubGhzViewIdReceiver,
+    SubGhzViewIdPopup,
+    SubGhzViewIdTextInput,
+    SubGhzViewIdWidget,
+    SubGhzViewIdTransmitter,
+    SubGhzViewIdVariableItemList,
+    SubGhzViewIdFrequencyAnalyzer,
+    SubGhzViewIdReadRAW,
+
+    SubGhzViewIdStatic,
+    SubGhzViewIdTestCarrier,
+    SubGhzViewIdTestPacket,
+} SubGhzViewId;
+
+bool subghz_set_preset(SubGhz* subghz, const char* preset);
 void subghz_get_frequency_modulation(SubGhz* subghz, string_t frequency, string_t modulation);
 void subghz_get_frequency_modulation(SubGhz* subghz, string_t frequency, string_t modulation);
 void subghz_begin(SubGhz* subghz, FuriHalSubGhzPreset preset);
 void subghz_begin(SubGhz* subghz, FuriHalSubGhzPreset preset);
 uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency);
 uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency);
 void subghz_rx_end(SubGhz* subghz);
 void subghz_rx_end(SubGhz* subghz);
 void subghz_sleep(SubGhz* subghz);
 void subghz_sleep(SubGhz* subghz);
-bool subghz_tx_start(SubGhz* subghz);
+bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format);
 void subghz_tx_stop(SubGhz* subghz);
 void subghz_tx_stop(SubGhz* subghz);
 bool subghz_key_load(SubGhz* subghz, const char* file_path);
 bool subghz_key_load(SubGhz* subghz, const char* file_path);
 bool subghz_get_next_name_file(SubGhz* subghz);
 bool subghz_get_next_name_file(SubGhz* subghz);
-bool subghz_save_protocol_to_file(SubGhz* subghz, const char* dev_name);
+bool subghz_save_protocol_to_file(
+    SubGhz* subghz,
+    FlipperFormat* flipper_format,
+    const char* dev_name);
 bool subghz_load_protocol_from_file(SubGhz* subghz);
 bool subghz_load_protocol_from_file(SubGhz* subghz);
 bool subghz_rename_file(SubGhz* subghz);
 bool subghz_rename_file(SubGhz* subghz);
 bool subghz_delete_file(SubGhz* subghz);
 bool subghz_delete_file(SubGhz* subghz);

+ 53 - 52
applications/subghz/views/subghz_receiver.c → applications/subghz/views/receiver.c

@@ -1,4 +1,4 @@
-#include "subghz_receiver.h"
+#include "receiver.h"
 #include "../subghz_i.h"
 #include "../subghz_i.h"
 #include <math.h>
 #include <math.h>
 
 
@@ -29,14 +29,14 @@ struct SubGhzReceiverHistory {
 typedef struct SubGhzReceiverHistory SubGhzReceiverHistory;
 typedef struct SubGhzReceiverHistory SubGhzReceiverHistory;
 
 
 static const Icon* ReceiverItemIcons[] = {
 static const Icon* ReceiverItemIcons[] = {
-    [SubGhzProtocolCommonTypeUnknown] = &I_Quest_7x8,
-    [SubGhzProtocolCommonTypeStatic] = &I_Unlock_7x8,
-    [SubGhzProtocolCommonTypeDynamic] = &I_Lock_7x8,
+    [SubGhzProtocolTypeUnknown] = &I_Quest_7x8,
+    [SubGhzProtocolTypeStatic] = &I_Unlock_7x8,
+    [SubGhzProtocolTypeDynamic] = &I_Lock_7x8,
 };
 };
 
 
-struct SubghzReceiver {
+struct SubGhzViewReceiver {
     View* view;
     View* view;
-    SubghzReceiverCallback callback;
+    SubGhzViewReceiverCallback callback;
     void* context;
     void* context;
 };
 };
 
 
@@ -48,11 +48,11 @@ typedef struct {
     uint16_t idx;
     uint16_t idx;
     uint16_t list_offset;
     uint16_t list_offset;
     uint16_t history_item;
     uint16_t history_item;
-} SubghzReceiverModel;
+} SubGhzViewReceiverModel;
 
 
-void subghz_receiver_set_callback(
-    SubghzReceiver* subghz_receiver,
-    SubghzReceiverCallback callback,
+void subghz_view_receiver_set_callback(
+    SubGhzViewReceiver* subghz_receiver,
+    SubGhzViewReceiverCallback callback,
     void* context) {
     void* context) {
     furi_assert(subghz_receiver);
     furi_assert(subghz_receiver);
     furi_assert(callback);
     furi_assert(callback);
@@ -60,11 +60,11 @@ void subghz_receiver_set_callback(
     subghz_receiver->context = context;
     subghz_receiver->context = context;
 }
 }
 
 
-static void subghz_receiver_update_offset(SubghzReceiver* subghz_receiver) {
+static void subghz_view_receiver_update_offset(SubGhzViewReceiver* subghz_receiver) {
     furi_assert(subghz_receiver);
     furi_assert(subghz_receiver);
 
 
     with_view_model(
     with_view_model(
-        subghz_receiver->view, (SubghzReceiverModel * model) {
+        subghz_receiver->view, (SubGhzViewReceiverModel * model) {
             size_t history_item = model->history_item;
             size_t history_item = model->history_item;
             uint16_t bounds = history_item > 3 ? 2 : history_item;
             uint16_t bounds = history_item > 3 ? 2 : history_item;
 
 
@@ -79,13 +79,13 @@ static void subghz_receiver_update_offset(SubghzReceiver* subghz_receiver) {
         });
         });
 }
 }
 
 
-void subghz_receiver_add_item_to_menu(
-    SubghzReceiver* subghz_receiver,
+void subghz_view_receiver_add_item_to_menu(
+    SubGhzViewReceiver* subghz_receiver,
     const char* name,
     const char* name,
     uint8_t type) {
     uint8_t type) {
     furi_assert(subghz_receiver);
     furi_assert(subghz_receiver);
     with_view_model(
     with_view_model(
-        subghz_receiver->view, (SubghzReceiverModel * model) {
+        subghz_receiver->view, (SubGhzViewReceiverModel * model) {
             SubGhzReceiverMenuItem* item_menu =
             SubGhzReceiverMenuItem* item_menu =
                 SubGhzReceiverMenuItemArray_push_raw(model->history->data);
                 SubGhzReceiverMenuItemArray_push_raw(model->history->data);
             string_init_set_str(item_menu->item_str, name);
             string_init_set_str(item_menu->item_str, name);
@@ -99,17 +99,17 @@ void subghz_receiver_add_item_to_menu(
 
 
             return true;
             return true;
         });
         });
-    subghz_receiver_update_offset(subghz_receiver);
+    subghz_view_receiver_update_offset(subghz_receiver);
 }
 }
 
 
-void subghz_receiver_add_data_statusbar(
-    SubghzReceiver* subghz_receiver,
+void subghz_view_receiver_add_data_statusbar(
+    SubGhzViewReceiver* subghz_receiver,
     const char* frequency_str,
     const char* frequency_str,
     const char* preset_str,
     const char* preset_str,
     const char* history_stat_str) {
     const char* history_stat_str) {
     furi_assert(subghz_receiver);
     furi_assert(subghz_receiver);
     with_view_model(
     with_view_model(
-        subghz_receiver->view, (SubghzReceiverModel * model) {
+        subghz_receiver->view, (SubGhzViewReceiverModel * model) {
             string_set(model->frequency_str, frequency_str);
             string_set(model->frequency_str, frequency_str);
             string_set(model->preset_str, preset_str);
             string_set(model->preset_str, preset_str);
             string_set(model->history_stat_str, history_stat_str);
             string_set(model->history_stat_str, history_stat_str);
@@ -117,7 +117,7 @@ void subghz_receiver_add_data_statusbar(
         });
         });
 }
 }
 
 
-static void subghz_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) {
+static void subghz_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) {
     canvas_set_color(canvas, ColorBlack);
     canvas_set_color(canvas, ColorBlack);
     canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT);
     canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT);
 
 
@@ -131,7 +131,7 @@ static void subghz_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scroll
     canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11);
     canvas_draw_dot(canvas, scrollbar ? 121 : 126, (0 + idx * FRAME_HEIGHT) + 11);
 }
 }
 
 
-void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
+void subghz_view_receiver_draw(Canvas* canvas, SubGhzViewReceiverModel* model) {
     canvas_clear(canvas);
     canvas_clear(canvas);
     canvas_set_color(canvas, ColorBlack);
     canvas_set_color(canvas, ColorBlack);
     canvas_set_font(canvas, FontSecondary);
     canvas_set_font(canvas, FontSecondary);
@@ -162,7 +162,7 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
         string_set(str_buff, item_menu->item_str);
         string_set(str_buff, item_menu->item_str);
         elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX);
         elements_string_fit_width(canvas, str_buff, scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX);
         if(model->idx == idx) {
         if(model->idx == idx) {
-            subghz_receiver_draw_frame(canvas, i, scrollbar);
+            subghz_view_receiver_draw_frame(canvas, i, scrollbar);
         } else {
         } else {
             canvas_set_color(canvas, ColorBlack);
             canvas_set_color(canvas, ColorBlack);
         }
         }
@@ -176,17 +176,17 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
     string_clear(str_buff);
     string_clear(str_buff);
 }
 }
 
 
-bool subghz_receiver_input(InputEvent* event, void* context) {
+bool subghz_view_receiver_input(InputEvent* event, void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzReceiver* subghz_receiver = context;
+    SubGhzViewReceiver* subghz_receiver = context;
 
 
     if(event->key == InputKeyBack && event->type == InputTypeShort) {
     if(event->key == InputKeyBack && event->type == InputTypeShort) {
-        subghz_receiver->callback(SubghzCustomEventViewReceverBack, subghz_receiver->context);
+        subghz_receiver->callback(SubGhzCustomEventViewReceverBack, subghz_receiver->context);
     } else if(
     } else if(
         event->key == InputKeyUp &&
         event->key == InputKeyUp &&
         (event->type == InputTypeShort || event->type == InputTypeRepeat)) {
         (event->type == InputTypeShort || event->type == InputTypeRepeat)) {
         with_view_model(
         with_view_model(
-            subghz_receiver->view, (SubghzReceiverModel * model) {
+            subghz_receiver->view, (SubGhzViewReceiverModel * model) {
                 if(model->idx != 0) model->idx--;
                 if(model->idx != 0) model->idx--;
                 return true;
                 return true;
             });
             });
@@ -194,38 +194,38 @@ bool subghz_receiver_input(InputEvent* event, void* context) {
         event->key == InputKeyDown &&
         event->key == InputKeyDown &&
         (event->type == InputTypeShort || event->type == InputTypeRepeat)) {
         (event->type == InputTypeShort || event->type == InputTypeRepeat)) {
         with_view_model(
         with_view_model(
-            subghz_receiver->view, (SubghzReceiverModel * model) {
+            subghz_receiver->view, (SubGhzViewReceiverModel * model) {
                 if(model->idx != model->history_item - 1) model->idx++;
                 if(model->idx != model->history_item - 1) model->idx++;
                 return true;
                 return true;
             });
             });
     } else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
     } else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
-        subghz_receiver->callback(SubghzCustomEventViewReceverConfig, subghz_receiver->context);
+        subghz_receiver->callback(SubGhzCustomEventViewReceverConfig, subghz_receiver->context);
     } else if(event->key == InputKeyOk && event->type == InputTypeShort) {
     } else if(event->key == InputKeyOk && event->type == InputTypeShort) {
         with_view_model(
         with_view_model(
-            subghz_receiver->view, (SubghzReceiverModel * model) {
+            subghz_receiver->view, (SubGhzViewReceiverModel * model) {
                 if(model->history_item != 0) {
                 if(model->history_item != 0) {
                     subghz_receiver->callback(
                     subghz_receiver->callback(
-                        SubghzCustomEventViewReceverOK, subghz_receiver->context);
+                        SubGhzCustomEventViewReceverOK, subghz_receiver->context);
                 }
                 }
                 return false;
                 return false;
             });
             });
     }
     }
 
 
-    subghz_receiver_update_offset(subghz_receiver);
+    subghz_view_receiver_update_offset(subghz_receiver);
 
 
     return true;
     return true;
 }
 }
 
 
-void subghz_receiver_enter(void* context) {
+void subghz_view_receiver_enter(void* context) {
     furi_assert(context);
     furi_assert(context);
-    //SubghzReceiver* subghz_receiver = context;
+    //SubGhzViewReceiver* subghz_receiver = context;
 }
 }
 
 
-void subghz_receiver_exit(void* context) {
+void subghz_view_receiver_exit(void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzReceiver* subghz_receiver = context;
+    SubGhzViewReceiver* subghz_receiver = context;
     with_view_model(
     with_view_model(
-        subghz_receiver->view, (SubghzReceiverModel * model) {
+        subghz_receiver->view, (SubGhzViewReceiverModel * model) {
             string_reset(model->frequency_str);
             string_reset(model->frequency_str);
             string_reset(model->preset_str);
             string_reset(model->preset_str);
             string_reset(model->history_stat_str);
             string_reset(model->history_stat_str);
@@ -242,20 +242,21 @@ void subghz_receiver_exit(void* context) {
         });
         });
 }
 }
 
 
-SubghzReceiver* subghz_receiver_alloc() {
-    SubghzReceiver* subghz_receiver = malloc(sizeof(SubghzReceiver));
+SubGhzViewReceiver* subghz_view_receiver_alloc() {
+    SubGhzViewReceiver* subghz_receiver = malloc(sizeof(SubGhzViewReceiver));
 
 
     // View allocation and configuration
     // View allocation and configuration
     subghz_receiver->view = view_alloc();
     subghz_receiver->view = view_alloc();
-    view_allocate_model(subghz_receiver->view, ViewModelTypeLocking, sizeof(SubghzReceiverModel));
+    view_allocate_model(
+        subghz_receiver->view, ViewModelTypeLocking, sizeof(SubGhzViewReceiverModel));
     view_set_context(subghz_receiver->view, subghz_receiver);
     view_set_context(subghz_receiver->view, subghz_receiver);
-    view_set_draw_callback(subghz_receiver->view, (ViewDrawCallback)subghz_receiver_draw);
-    view_set_input_callback(subghz_receiver->view, subghz_receiver_input);
-    view_set_enter_callback(subghz_receiver->view, subghz_receiver_enter);
-    view_set_exit_callback(subghz_receiver->view, subghz_receiver_exit);
+    view_set_draw_callback(subghz_receiver->view, (ViewDrawCallback)subghz_view_receiver_draw);
+    view_set_input_callback(subghz_receiver->view, subghz_view_receiver_input);
+    view_set_enter_callback(subghz_receiver->view, subghz_view_receiver_enter);
+    view_set_exit_callback(subghz_receiver->view, subghz_view_receiver_exit);
 
 
     with_view_model(
     with_view_model(
-        subghz_receiver->view, (SubghzReceiverModel * model) {
+        subghz_receiver->view, (SubGhzViewReceiverModel * model) {
             string_init(model->frequency_str);
             string_init(model->frequency_str);
             string_init(model->preset_str);
             string_init(model->preset_str);
             string_init(model->history_stat_str);
             string_init(model->history_stat_str);
@@ -267,11 +268,11 @@ SubghzReceiver* subghz_receiver_alloc() {
     return subghz_receiver;
     return subghz_receiver;
 }
 }
 
 
-void subghz_receiver_free(SubghzReceiver* subghz_receiver) {
+void subghz_view_receiver_free(SubGhzViewReceiver* subghz_receiver) {
     furi_assert(subghz_receiver);
     furi_assert(subghz_receiver);
 
 
     with_view_model(
     with_view_model(
-        subghz_receiver->view, (SubghzReceiverModel * model) {
+        subghz_receiver->view, (SubGhzViewReceiverModel * model) {
             string_clear(model->frequency_str);
             string_clear(model->frequency_str);
             string_clear(model->preset_str);
             string_clear(model->preset_str);
             string_clear(model->history_stat_str);
             string_clear(model->history_stat_str);
@@ -288,29 +289,29 @@ void subghz_receiver_free(SubghzReceiver* subghz_receiver) {
     free(subghz_receiver);
     free(subghz_receiver);
 }
 }
 
 
-View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver) {
+View* subghz_view_receiver_get_view(SubGhzViewReceiver* subghz_receiver) {
     furi_assert(subghz_receiver);
     furi_assert(subghz_receiver);
     return subghz_receiver->view;
     return subghz_receiver->view;
 }
 }
 
 
-uint16_t subghz_receiver_get_idx_menu(SubghzReceiver* subghz_receiver) {
+uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver) {
     furi_assert(subghz_receiver);
     furi_assert(subghz_receiver);
     uint32_t idx = 0;
     uint32_t idx = 0;
     with_view_model(
     with_view_model(
-        subghz_receiver->view, (SubghzReceiverModel * model) {
+        subghz_receiver->view, (SubGhzViewReceiverModel * model) {
             idx = model->idx;
             idx = model->idx;
             return false;
             return false;
         });
         });
     return idx;
     return idx;
 }
 }
 
 
-void subghz_receiver_set_idx_menu(SubghzReceiver* subghz_receiver, uint16_t idx) {
+void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx) {
     furi_assert(subghz_receiver);
     furi_assert(subghz_receiver);
     with_view_model(
     with_view_model(
-        subghz_receiver->view, (SubghzReceiverModel * model) {
+        subghz_receiver->view, (SubGhzViewReceiverModel * model) {
             model->idx = idx;
             model->idx = idx;
             if(model->idx > 2) model->list_offset = idx - 2;
             if(model->idx > 2) model->list_offset = idx - 2;
             return true;
             return true;
         });
         });
-    subghz_receiver_update_offset(subghz_receiver);
+    subghz_view_receiver_update_offset(subghz_receiver);
 }
 }

+ 36 - 0
applications/subghz/views/receiver.h

@@ -0,0 +1,36 @@
+#pragma once
+
+#include <gui/view.h>
+#include "../helpers/subghz_custom_event.h"
+
+typedef struct SubGhzViewReceiver SubGhzViewReceiver;
+
+typedef void (*SubGhzViewReceiverCallback)(SubGhzCustomEvent event, void* context);
+
+void subghz_view_receiver_set_callback(
+    SubGhzViewReceiver* subghz_receiver,
+    SubGhzViewReceiverCallback callback,
+    void* context);
+
+SubGhzViewReceiver* subghz_view_receiver_alloc();
+
+void subghz_view_receiver_free(SubGhzViewReceiver* subghz_receiver);
+
+View* subghz_view_receiver_get_view(SubGhzViewReceiver* subghz_receiver);
+
+void subghz_view_receiver_add_data_statusbar(
+    SubGhzViewReceiver* subghz_receiver,
+    const char* frequency_str,
+    const char* preset_str,
+    const char* history_stat_str);
+
+void subghz_view_receiver_add_item_to_menu(
+    SubGhzViewReceiver* subghz_receiver,
+    const char* name,
+    uint8_t type);
+
+uint16_t subghz_view_receiver_get_idx_menu(SubGhzViewReceiver* subghz_receiver);
+
+void subghz_view_receiver_set_idx_menu(SubGhzViewReceiver* subghz_receiver, uint16_t idx);
+
+void subghz_view_receiver_exit(void* context);

+ 20 - 22
applications/subghz/views/subghz_frequency_analyzer.c

@@ -6,30 +6,29 @@
 #include <furi_hal.h>
 #include <furi_hal.h>
 #include <input/input.h>
 #include <input/input.h>
 #include <notification/notification_messages.h>
 #include <notification/notification_messages.h>
-#include <lib/subghz/protocols/subghz_protocol_princeton.h>
 #include "../helpers/subghz_frequency_analyzer_worker.h"
 #include "../helpers/subghz_frequency_analyzer_worker.h"
 
 
 #include <assets_icons.h>
 #include <assets_icons.h>
 
 
 typedef enum {
 typedef enum {
-    SubghzFrequencyAnalyzerStatusIDLE,
-} SubghzFrequencyAnalyzerStatus;
+    SubGhzFrequencyAnalyzerStatusIDLE,
+} SubGhzFrequencyAnalyzerStatus;
 
 
-struct SubghzFrequencyAnalyzer {
+struct SubGhzFrequencyAnalyzer {
     View* view;
     View* view;
     SubGhzFrequencyAnalyzerWorker* worker;
     SubGhzFrequencyAnalyzerWorker* worker;
-    SubghzFrequencyAnalyzerCallback callback;
+    SubGhzFrequencyAnalyzerCallback callback;
     void* context;
     void* context;
 };
 };
 
 
 typedef struct {
 typedef struct {
     uint32_t frequency;
     uint32_t frequency;
     float rssi;
     float rssi;
-} SubghzFrequencyAnalyzerModel;
+} SubGhzFrequencyAnalyzerModel;
 
 
 void subghz_frequency_analyzer_set_callback(
 void subghz_frequency_analyzer_set_callback(
-    SubghzFrequencyAnalyzer* subghz_frequency_analyzer,
-    SubghzFrequencyAnalyzerCallback callback,
+    SubGhzFrequencyAnalyzer* subghz_frequency_analyzer,
+    SubGhzFrequencyAnalyzerCallback callback,
     void* context) {
     void* context) {
     furi_assert(subghz_frequency_analyzer);
     furi_assert(subghz_frequency_analyzer);
     furi_assert(callback);
     furi_assert(callback);
@@ -53,7 +52,7 @@ void subghz_frequency_analyzer_draw_rssi(Canvas* canvas, float rssi) {
     }
     }
 }
 }
 
 
-void subghz_frequency_analyzer_draw(Canvas* canvas, SubghzFrequencyAnalyzerModel* model) {
+void subghz_frequency_analyzer_draw(Canvas* canvas, SubGhzFrequencyAnalyzerModel* model) {
     char buffer[64];
     char buffer[64];
 
 
     canvas_set_color(canvas, ColorBlack);
     canvas_set_color(canvas, ColorBlack);
@@ -77,7 +76,6 @@ void subghz_frequency_analyzer_draw(Canvas* canvas, SubghzFrequencyAnalyzerModel
 
 
 bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
 bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
     furi_assert(context);
     furi_assert(context);
-    //SubghzFrequencyAnalyzer* instance = context;
 
 
     if(event->key == InputKeyBack) {
     if(event->key == InputKeyBack) {
         return false;
         return false;
@@ -87,9 +85,9 @@ bool subghz_frequency_analyzer_input(InputEvent* event, void* context) {
 }
 }
 
 
 void subghz_frequency_analyzer_pair_callback(void* context, uint32_t frequency, float rssi) {
 void subghz_frequency_analyzer_pair_callback(void* context, uint32_t frequency, float rssi) {
-    SubghzFrequencyAnalyzer* instance = context;
+    SubGhzFrequencyAnalyzer* instance = context;
     with_view_model(
     with_view_model(
-        instance->view, (SubghzFrequencyAnalyzerModel * model) {
+        instance->view, (SubGhzFrequencyAnalyzerModel * model) {
             model->rssi = rssi;
             model->rssi = rssi;
             model->frequency = frequency;
             model->frequency = frequency;
             return true;
             return true;
@@ -98,7 +96,7 @@ void subghz_frequency_analyzer_pair_callback(void* context, uint32_t frequency,
 
 
 void subghz_frequency_analyzer_enter(void* context) {
 void subghz_frequency_analyzer_enter(void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzFrequencyAnalyzer* instance = context;
+    SubGhzFrequencyAnalyzer* instance = context;
 
 
     //Start worker
     //Start worker
     instance->worker = subghz_frequency_analyzer_worker_alloc();
     instance->worker = subghz_frequency_analyzer_worker_alloc();
@@ -111,7 +109,7 @@ void subghz_frequency_analyzer_enter(void* context) {
     subghz_frequency_analyzer_worker_start(instance->worker);
     subghz_frequency_analyzer_worker_start(instance->worker);
 
 
     with_view_model(
     with_view_model(
-        instance->view, (SubghzFrequencyAnalyzerModel * model) {
+        instance->view, (SubGhzFrequencyAnalyzerModel * model) {
             model->rssi = 0;
             model->rssi = 0;
             model->frequency = 0;
             model->frequency = 0;
             return true;
             return true;
@@ -120,7 +118,7 @@ void subghz_frequency_analyzer_enter(void* context) {
 
 
 void subghz_frequency_analyzer_exit(void* context) {
 void subghz_frequency_analyzer_exit(void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzFrequencyAnalyzer* instance = context;
+    SubGhzFrequencyAnalyzer* instance = context;
 
 
     //Stop worker
     //Stop worker
     if(subghz_frequency_analyzer_worker_is_running(instance->worker)) {
     if(subghz_frequency_analyzer_worker_is_running(instance->worker)) {
@@ -129,19 +127,19 @@ void subghz_frequency_analyzer_exit(void* context) {
     subghz_frequency_analyzer_worker_free(instance->worker);
     subghz_frequency_analyzer_worker_free(instance->worker);
 
 
     with_view_model(
     with_view_model(
-        instance->view, (SubghzFrequencyAnalyzerModel * model) {
+        instance->view, (SubGhzFrequencyAnalyzerModel * model) {
             model->rssi = 0;
             model->rssi = 0;
             return true;
             return true;
         });
         });
 }
 }
 
 
-SubghzFrequencyAnalyzer* subghz_frequency_analyzer_alloc() {
-    SubghzFrequencyAnalyzer* instance = malloc(sizeof(SubghzFrequencyAnalyzer));
+SubGhzFrequencyAnalyzer* subghz_frequency_analyzer_alloc() {
+    SubGhzFrequencyAnalyzer* instance = malloc(sizeof(SubGhzFrequencyAnalyzer));
 
 
     // View allocation and configuration
     // View allocation and configuration
     instance->view = view_alloc();
     instance->view = view_alloc();
     view_allocate_model(
     view_allocate_model(
-        instance->view, ViewModelTypeLocking, sizeof(SubghzFrequencyAnalyzerModel));
+        instance->view, ViewModelTypeLocking, sizeof(SubGhzFrequencyAnalyzerModel));
     view_set_context(instance->view, instance);
     view_set_context(instance->view, instance);
     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_frequency_analyzer_draw);
     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_frequency_analyzer_draw);
     view_set_input_callback(instance->view, subghz_frequency_analyzer_input);
     view_set_input_callback(instance->view, subghz_frequency_analyzer_input);
@@ -149,7 +147,7 @@ SubghzFrequencyAnalyzer* subghz_frequency_analyzer_alloc() {
     view_set_exit_callback(instance->view, subghz_frequency_analyzer_exit);
     view_set_exit_callback(instance->view, subghz_frequency_analyzer_exit);
 
 
     with_view_model(
     with_view_model(
-        instance->view, (SubghzFrequencyAnalyzerModel * model) {
+        instance->view, (SubGhzFrequencyAnalyzerModel * model) {
             model->rssi = 0;
             model->rssi = 0;
             return true;
             return true;
         });
         });
@@ -157,14 +155,14 @@ SubghzFrequencyAnalyzer* subghz_frequency_analyzer_alloc() {
     return instance;
     return instance;
 }
 }
 
 
-void subghz_frequency_analyzer_free(SubghzFrequencyAnalyzer* instance) {
+void subghz_frequency_analyzer_free(SubGhzFrequencyAnalyzer* instance) {
     furi_assert(instance);
     furi_assert(instance);
 
 
     view_free(instance->view);
     view_free(instance->view);
     free(instance);
     free(instance);
 }
 }
 
 
-View* subghz_frequency_analyzer_get_view(SubghzFrequencyAnalyzer* instance) {
+View* subghz_frequency_analyzer_get_view(SubGhzFrequencyAnalyzer* instance) {
     furi_assert(instance);
     furi_assert(instance);
     return instance->view;
     return instance->view;
 }
 }

+ 7 - 7
applications/subghz/views/subghz_frequency_analyzer.h

@@ -3,17 +3,17 @@
 #include <gui/view.h>
 #include <gui/view.h>
 #include "../helpers/subghz_custom_event.h"
 #include "../helpers/subghz_custom_event.h"
 
 
-typedef struct SubghzFrequencyAnalyzer SubghzFrequencyAnalyzer;
+typedef struct SubGhzFrequencyAnalyzer SubGhzFrequencyAnalyzer;
 
 
-typedef void (*SubghzFrequencyAnalyzerCallback)(SubghzCustomEvent event, void* context);
+typedef void (*SubGhzFrequencyAnalyzerCallback)(SubGhzCustomEvent event, void* context);
 
 
 void subghz_frequency_analyzer_set_callback(
 void subghz_frequency_analyzer_set_callback(
-    SubghzFrequencyAnalyzer* subghz_frequency_analyzer,
-    SubghzFrequencyAnalyzerCallback callback,
+    SubGhzFrequencyAnalyzer* subghz_frequency_analyzer,
+    SubGhzFrequencyAnalyzerCallback callback,
     void* context);
     void* context);
 
 
-SubghzFrequencyAnalyzer* subghz_frequency_analyzer_alloc();
+SubGhzFrequencyAnalyzer* subghz_frequency_analyzer_alloc();
 
 
-void subghz_frequency_analyzer_free(SubghzFrequencyAnalyzer* subghz_static);
+void subghz_frequency_analyzer_free(SubGhzFrequencyAnalyzer* subghz_static);
 
 
-View* subghz_frequency_analyzer_get_view(SubghzFrequencyAnalyzer* subghz_static);
+View* subghz_frequency_analyzer_get_view(SubGhzFrequencyAnalyzer* subghz_static);

+ 116 - 118
applications/subghz/views/subghz_read_raw.c

@@ -6,15 +6,14 @@
 #include <furi_hal.h>
 #include <furi_hal.h>
 #include <input/input.h>
 #include <input/input.h>
 #include <gui/elements.h>
 #include <gui/elements.h>
-#include <lib/subghz/protocols/subghz_protocol_princeton.h>
 
 
 #include <assets_icons.h>
 #include <assets_icons.h>
 #define SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE 100
 #define SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE 100
-#define TAG "SubghzReadRAW"
+#define TAG "SubGhzReadRAW"
 
 
-struct SubghzReadRAW {
+struct SubGhzReadRAW {
     View* view;
     View* view;
-    SubghzReadRAWCallback callback;
+    SubGhzReadRAWCallback callback;
     void* context;
     void* context;
 };
 };
 
 
@@ -27,12 +26,12 @@ typedef struct {
     bool rssi_history_end;
     bool rssi_history_end;
     uint8_t ind_write;
     uint8_t ind_write;
     uint8_t ind_sin;
     uint8_t ind_sin;
-    SubghzReadRAWStatus satus;
-} SubghzReadRAWModel;
+    SubGhzReadRAWStatus satus;
+} SubGhzReadRAWModel;
 
 
 void subghz_read_raw_set_callback(
 void subghz_read_raw_set_callback(
-    SubghzReadRAW* subghz_read_raw,
-    SubghzReadRAWCallback callback,
+    SubGhzReadRAW* subghz_read_raw,
+    SubGhzReadRAWCallback callback,
     void* context) {
     void* context) {
     furi_assert(subghz_read_raw);
     furi_assert(subghz_read_raw);
     furi_assert(callback);
     furi_assert(callback);
@@ -41,19 +40,19 @@ void subghz_read_raw_set_callback(
 }
 }
 
 
 void subghz_read_raw_add_data_statusbar(
 void subghz_read_raw_add_data_statusbar(
-    SubghzReadRAW* instance,
+    SubGhzReadRAW* instance,
     const char* frequency_str,
     const char* frequency_str,
     const char* preset_str) {
     const char* preset_str) {
     furi_assert(instance);
     furi_assert(instance);
     with_view_model(
     with_view_model(
-        instance->view, (SubghzReadRAWModel * model) {
+        instance->view, (SubGhzReadRAWModel * model) {
             string_set(model->frequency_str, frequency_str);
             string_set(model->frequency_str, frequency_str);
             string_set(model->preset_str, preset_str);
             string_set(model->preset_str, preset_str);
             return true;
             return true;
         });
         });
 }
 }
 
 
-void subghz_read_raw_add_data_rssi(SubghzReadRAW* instance, float rssi) {
+void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi) {
     furi_assert(instance);
     furi_assert(instance);
     uint8_t u_rssi = 0;
     uint8_t u_rssi = 0;
 
 
@@ -62,10 +61,9 @@ void subghz_read_raw_add_data_rssi(SubghzReadRAW* instance, float rssi) {
     } else {
     } else {
         u_rssi = (uint8_t)((rssi + 90) / 2.7);
         u_rssi = (uint8_t)((rssi + 90) / 2.7);
     }
     }
-    //if(u_rssi > 34) u_rssi = 34;
 
 
     with_view_model(
     with_view_model(
-        instance->view, (SubghzReadRAWModel * model) {
+        instance->view, (SubGhzReadRAWModel * model) {
             model->rssi_history[model->ind_write++] = u_rssi;
             model->rssi_history[model->ind_write++] = u_rssi;
             if(model->ind_write > SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE) {
             if(model->ind_write > SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE) {
                 model->rssi_history_end = true;
                 model->rssi_history_end = true;
@@ -75,46 +73,46 @@ void subghz_read_raw_add_data_rssi(SubghzReadRAW* instance, float rssi) {
         });
         });
 }
 }
 
 
-void subghz_read_raw_update_sample_write(SubghzReadRAW* instance, size_t sample) {
+void subghz_read_raw_update_sample_write(SubGhzReadRAW* instance, size_t sample) {
     furi_assert(instance);
     furi_assert(instance);
 
 
     with_view_model(
     with_view_model(
-        instance->view, (SubghzReadRAWModel * model) {
+        instance->view, (SubGhzReadRAWModel * model) {
             string_printf(model->sample_write, "%d spl.", sample);
             string_printf(model->sample_write, "%d spl.", sample);
             return false;
             return false;
         });
         });
 }
 }
 
 
-void subghz_read_raw_stop_send(SubghzReadRAW* instance) {
+void subghz_read_raw_stop_send(SubGhzReadRAW* instance) {
     furi_assert(instance);
     furi_assert(instance);
 
 
     with_view_model(
     with_view_model(
-        instance->view, (SubghzReadRAWModel * model) {
+        instance->view, (SubGhzReadRAWModel * model) {
             switch(model->satus) {
             switch(model->satus) {
-            case SubghzReadRAWStatusTXRepeat:
-            case SubghzReadRAWStatusLoadKeyTXRepeat:
-                instance->callback(SubghzCustomEventViewReadRAWSendStart, instance->context);
+            case SubGhzReadRAWStatusTXRepeat:
+            case SubGhzReadRAWStatusLoadKeyTXRepeat:
+                instance->callback(SubGhzCustomEventViewReadRAWSendStart, instance->context);
                 break;
                 break;
-            case SubghzReadRAWStatusTX:
-                model->satus = SubghzReadRAWStatusIDLE;
+            case SubGhzReadRAWStatusTX:
+                model->satus = SubGhzReadRAWStatusIDLE;
                 break;
                 break;
-            case SubghzReadRAWStatusLoadKeyTX:
-                model->satus = SubghzReadRAWStatusLoadKeyIDLE;
+            case SubGhzReadRAWStatusLoadKeyTX:
+                model->satus = SubGhzReadRAWStatusLoadKeyIDLE;
                 break;
                 break;
 
 
             default:
             default:
                 FURI_LOG_W(TAG, "unknown status");
                 FURI_LOG_W(TAG, "unknown status");
-                model->satus = SubghzReadRAWStatusIDLE;
+                model->satus = SubGhzReadRAWStatusIDLE;
                 break;
                 break;
             }
             }
             return true;
             return true;
         });
         });
 }
 }
 
 
-void subghz_read_raw_update_sin(SubghzReadRAW* instance) {
+void subghz_read_raw_update_sin(SubGhzReadRAW* instance) {
     furi_assert(instance);
     furi_assert(instance);
     with_view_model(
     with_view_model(
-        instance->view, (SubghzReadRAWModel * model) {
+        instance->view, (SubGhzReadRAWModel * model) {
             if(model->ind_sin++ > 62) {
             if(model->ind_sin++ > 62) {
                 model->ind_sin = 0;
                 model->ind_sin = 0;
             }
             }
@@ -134,7 +132,7 @@ static int8_t subghz_read_raw_tab_sin(uint8_t x) {
     return r;
     return r;
 }
 }
 
 
-void subghz_read_raw_draw_sin(Canvas* canvas, SubghzReadRAWModel* model) {
+void subghz_read_raw_draw_sin(Canvas* canvas, SubGhzReadRAWModel* model) {
 #define SUBGHZ_RAW_SIN_AMPLITUDE 11
 #define SUBGHZ_RAW_SIN_AMPLITUDE 11
     for(int i = 113; i > 0; i--) {
     for(int i = 113; i > 0; i--) {
         canvas_draw_line(
         canvas_draw_line(
@@ -154,7 +152,7 @@ void subghz_read_raw_draw_sin(Canvas* canvas, SubghzReadRAWModel* model) {
     }
     }
 }
 }
 
 
-void subghz_read_raw_draw_scale(Canvas* canvas, SubghzReadRAWModel* model) {
+void subghz_read_raw_draw_scale(Canvas* canvas, SubGhzReadRAWModel* model) {
 #define SUBGHZ_RAW_TOP_SCALE 14
 #define SUBGHZ_RAW_TOP_SCALE 14
 #define SUBGHZ_RAW_END_SCALE 115
 #define SUBGHZ_RAW_END_SCALE 115
 
 
@@ -178,7 +176,7 @@ void subghz_read_raw_draw_scale(Canvas* canvas, SubghzReadRAWModel* model) {
     }
     }
 }
 }
 
 
-void subghz_read_raw_draw_rssi(Canvas* canvas, SubghzReadRAWModel* model) {
+void subghz_read_raw_draw_rssi(Canvas* canvas, SubGhzReadRAWModel* model) {
     int ind = 0;
     int ind = 0;
     int base = 0;
     int base = 0;
     if(model->rssi_history_end == false) {
     if(model->rssi_history_end == false) {
@@ -214,7 +212,7 @@ void subghz_read_raw_draw_rssi(Canvas* canvas, SubghzReadRAWModel* model) {
     }
     }
 }
 }
 
 
-void subghz_read_raw_draw(Canvas* canvas, SubghzReadRAWModel* model) {
+void subghz_read_raw_draw(Canvas* canvas, SubGhzReadRAWModel* model) {
     uint8_t graphics_mode = 1;
     uint8_t graphics_mode = 1;
     canvas_set_color(canvas, ColorBlack);
     canvas_set_color(canvas, ColorBlack);
     canvas_set_font(canvas, FontSecondary);
     canvas_set_font(canvas, FontSecondary);
@@ -228,12 +226,12 @@ void subghz_read_raw_draw(Canvas* canvas, SubghzReadRAWModel* model) {
     canvas_draw_line(canvas, 115, 14, 115, 48);
     canvas_draw_line(canvas, 115, 14, 115, 48);
 
 
     switch(model->satus) {
     switch(model->satus) {
-    case SubghzReadRAWStatusIDLE:
+    case SubGhzReadRAWStatusIDLE:
         elements_button_left(canvas, "Erase");
         elements_button_left(canvas, "Erase");
         elements_button_center(canvas, "Send");
         elements_button_center(canvas, "Send");
         elements_button_right(canvas, "Save");
         elements_button_right(canvas, "Save");
         break;
         break;
-    case SubghzReadRAWStatusLoadKeyIDLE:
+    case SubGhzReadRAWStatusLoadKeyIDLE:
         elements_button_left(canvas, "New");
         elements_button_left(canvas, "New");
         elements_button_center(canvas, "Send");
         elements_button_center(canvas, "Send");
         elements_button_right(canvas, "More");
         elements_button_right(canvas, "More");
@@ -241,15 +239,15 @@ void subghz_read_raw_draw(Canvas* canvas, SubghzReadRAWModel* model) {
             canvas, 4, 12, 110, 44, AlignCenter, AlignCenter, string_get_cstr(model->file_name));
             canvas, 4, 12, 110, 44, AlignCenter, AlignCenter, string_get_cstr(model->file_name));
         break;
         break;
 
 
-    case SubghzReadRAWStatusTX:
-    case SubghzReadRAWStatusTXRepeat:
-    case SubghzReadRAWStatusLoadKeyTX:
-    case SubghzReadRAWStatusLoadKeyTXRepeat:
+    case SubGhzReadRAWStatusTX:
+    case SubGhzReadRAWStatusTXRepeat:
+    case SubGhzReadRAWStatusLoadKeyTX:
+    case SubGhzReadRAWStatusLoadKeyTXRepeat:
         graphics_mode = 0;
         graphics_mode = 0;
         elements_button_center(canvas, "Send");
         elements_button_center(canvas, "Send");
         break;
         break;
 
 
-    case SubghzReadRAWStatusStart:
+    case SubGhzReadRAWStatusStart:
         elements_button_left(canvas, "Config");
         elements_button_left(canvas, "Config");
         elements_button_center(canvas, "REC");
         elements_button_center(canvas, "REC");
         break;
         break;
@@ -272,7 +270,7 @@ void subghz_read_raw_draw(Canvas* canvas, SubghzReadRAWModel* model) {
 
 
 bool subghz_read_raw_input(InputEvent* event, void* context) {
 bool subghz_read_raw_input(InputEvent* event, void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzReadRAW* instance = context;
+    SubGhzReadRAW* instance = context;
 
 
     if((event->key == InputKeyOk) &&
     if((event->key == InputKeyOk) &&
        (event->type == InputTypeLong || event->type == InputTypeRepeat)) {
        (event->type == InputTypeLong || event->type == InputTypeRepeat)) {
@@ -281,30 +279,30 @@ bool subghz_read_raw_input(InputEvent* event, void* context) {
         return false;
         return false;
     } else if(event->key == InputKeyOk && event->type == InputTypePress) {
     } else if(event->key == InputKeyOk && event->type == InputTypePress) {
         with_view_model(
         with_view_model(
-            instance->view, (SubghzReadRAWModel * model) {
+            instance->view, (SubGhzReadRAWModel * model) {
                 uint8_t ret = false;
                 uint8_t ret = false;
                 switch(model->satus) {
                 switch(model->satus) {
-                case SubghzReadRAWStatusIDLE:
+                case SubGhzReadRAWStatusIDLE:
                     // Start TX
                     // Start TX
-                    instance->callback(SubghzCustomEventViewReadRAWSendStart, instance->context);
-                    instance->callback(SubghzCustomEventViewReadRAWVibro, instance->context);
-                    model->satus = SubghzReadRAWStatusTXRepeat;
+                    instance->callback(SubGhzCustomEventViewReadRAWSendStart, instance->context);
+                    instance->callback(SubGhzCustomEventViewReadRAWVibro, instance->context);
+                    model->satus = SubGhzReadRAWStatusTXRepeat;
                     ret = true;
                     ret = true;
                     break;
                     break;
-                case SubghzReadRAWStatusTX:
+                case SubGhzReadRAWStatusTX:
                     // Start TXRepeat
                     // Start TXRepeat
-                    model->satus = SubghzReadRAWStatusTXRepeat;
+                    model->satus = SubGhzReadRAWStatusTXRepeat;
                     break;
                     break;
-                case SubghzReadRAWStatusLoadKeyIDLE:
+                case SubGhzReadRAWStatusLoadKeyIDLE:
                     // Start Load Key TX
                     // Start Load Key TX
-                    instance->callback(SubghzCustomEventViewReadRAWSendStart, instance->context);
-                    instance->callback(SubghzCustomEventViewReadRAWVibro, instance->context);
-                    model->satus = SubghzReadRAWStatusLoadKeyTXRepeat;
+                    instance->callback(SubGhzCustomEventViewReadRAWSendStart, instance->context);
+                    instance->callback(SubGhzCustomEventViewReadRAWVibro, instance->context);
+                    model->satus = SubGhzReadRAWStatusLoadKeyTXRepeat;
                     ret = true;
                     ret = true;
                     break;
                     break;
-                case SubghzReadRAWStatusLoadKeyTX:
+                case SubGhzReadRAWStatusLoadKeyTX:
                     // Start Load Key TXRepeat
                     // Start Load Key TXRepeat
-                    model->satus = SubghzReadRAWStatusLoadKeyTXRepeat;
+                    model->satus = SubGhzReadRAWStatusLoadKeyTXRepeat;
                     break;
                     break;
 
 
                 default:
                 default:
@@ -314,91 +312,91 @@ bool subghz_read_raw_input(InputEvent* event, void* context) {
             });
             });
     } else if(event->key == InputKeyOk && event->type == InputTypeRelease) {
     } else if(event->key == InputKeyOk && event->type == InputTypeRelease) {
         with_view_model(
         with_view_model(
-            instance->view, (SubghzReadRAWModel * model) {
-                if(model->satus == SubghzReadRAWStatusTXRepeat) {
+            instance->view, (SubGhzReadRAWModel * model) {
+                if(model->satus == SubGhzReadRAWStatusTXRepeat) {
                     // Stop repeat TX
                     // Stop repeat TX
-                    model->satus = SubghzReadRAWStatusTX;
-                } else if(model->satus == SubghzReadRAWStatusLoadKeyTXRepeat) {
+                    model->satus = SubGhzReadRAWStatusTX;
+                } else if(model->satus == SubGhzReadRAWStatusLoadKeyTXRepeat) {
                     // Stop repeat TX
                     // Stop repeat TX
-                    model->satus = SubghzReadRAWStatusLoadKeyTX;
+                    model->satus = SubGhzReadRAWStatusLoadKeyTX;
                 }
                 }
                 return false;
                 return false;
             });
             });
     } else if(event->key == InputKeyBack && event->type == InputTypeShort) {
     } else if(event->key == InputKeyBack && event->type == InputTypeShort) {
         with_view_model(
         with_view_model(
-            instance->view, (SubghzReadRAWModel * model) {
+            instance->view, (SubGhzReadRAWModel * model) {
                 switch(model->satus) {
                 switch(model->satus) {
-                case SubghzReadRAWStatusREC:
+                case SubGhzReadRAWStatusREC:
                     //Stop REC
                     //Stop REC
-                    instance->callback(SubghzCustomEventViewReadRAWIDLE, instance->context);
-                    model->satus = SubghzReadRAWStatusIDLE;
+                    instance->callback(SubGhzCustomEventViewReadRAWIDLE, instance->context);
+                    model->satus = SubGhzReadRAWStatusIDLE;
                     break;
                     break;
-                case SubghzReadRAWStatusLoadKeyTX:
+                case SubGhzReadRAWStatusLoadKeyTX:
                     //Stop TxRx
                     //Stop TxRx
-                    instance->callback(SubghzCustomEventViewReadRAWTXRXStop, instance->context);
-                    model->satus = SubghzReadRAWStatusLoadKeyIDLE;
+                    instance->callback(SubGhzCustomEventViewReadRAWTXRXStop, instance->context);
+                    model->satus = SubGhzReadRAWStatusLoadKeyIDLE;
                     break;
                     break;
-                case SubghzReadRAWStatusTX:
+                case SubGhzReadRAWStatusTX:
                     //Stop TxRx
                     //Stop TxRx
-                    instance->callback(SubghzCustomEventViewReadRAWTXRXStop, instance->context);
-                    model->satus = SubghzReadRAWStatusIDLE;
+                    instance->callback(SubGhzCustomEventViewReadRAWTXRXStop, instance->context);
+                    model->satus = SubGhzReadRAWStatusIDLE;
                     break;
                     break;
-                case SubghzReadRAWStatusLoadKeyIDLE:
+                case SubGhzReadRAWStatusLoadKeyIDLE:
                     //Exit
                     //Exit
-                    instance->callback(SubghzCustomEventViewReadRAWBack, instance->context);
+                    instance->callback(SubGhzCustomEventViewReadRAWBack, instance->context);
                     break;
                     break;
 
 
                 default:
                 default:
                     //Exit
                     //Exit
-                    instance->callback(SubghzCustomEventViewReadRAWBack, instance->context);
+                    instance->callback(SubGhzCustomEventViewReadRAWBack, instance->context);
                     break;
                     break;
                 }
                 }
                 return true;
                 return true;
             });
             });
     } else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
     } else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
         with_view_model(
         with_view_model(
-            instance->view, (SubghzReadRAWModel * model) {
-                if(model->satus == SubghzReadRAWStatusStart) {
+            instance->view, (SubGhzReadRAWModel * model) {
+                if(model->satus == SubGhzReadRAWStatusStart) {
                     //Config
                     //Config
-                    instance->callback(SubghzCustomEventViewReadRAWConfig, instance->context);
+                    instance->callback(SubGhzCustomEventViewReadRAWConfig, instance->context);
                 } else if(
                 } else if(
-                    (model->satus == SubghzReadRAWStatusIDLE) ||
-                    (model->satus == SubghzReadRAWStatusLoadKeyIDLE)) {
+                    (model->satus == SubGhzReadRAWStatusIDLE) ||
+                    (model->satus == SubGhzReadRAWStatusLoadKeyIDLE)) {
                     //Erase
                     //Erase
-                    model->satus = SubghzReadRAWStatusStart;
+                    model->satus = SubGhzReadRAWStatusStart;
                     model->rssi_history_end = false;
                     model->rssi_history_end = false;
                     model->ind_write = 0;
                     model->ind_write = 0;
                     string_set(model->sample_write, "0 spl.");
                     string_set(model->sample_write, "0 spl.");
                     string_reset(model->file_name);
                     string_reset(model->file_name);
-                    instance->callback(SubghzCustomEventViewReadRAWErase, instance->context);
+                    instance->callback(SubGhzCustomEventViewReadRAWErase, instance->context);
                 }
                 }
                 return true;
                 return true;
             });
             });
     } else if(event->key == InputKeyRight && event->type == InputTypeShort) {
     } else if(event->key == InputKeyRight && event->type == InputTypeShort) {
         with_view_model(
         with_view_model(
-            instance->view, (SubghzReadRAWModel * model) {
-                if(model->satus == SubghzReadRAWStatusIDLE) {
+            instance->view, (SubGhzReadRAWModel * model) {
+                if(model->satus == SubGhzReadRAWStatusIDLE) {
                     //Save
                     //Save
-                    instance->callback(SubghzCustomEventViewReadRAWSave, instance->context);
-                } else if(model->satus == SubghzReadRAWStatusLoadKeyIDLE) {
+                    instance->callback(SubGhzCustomEventViewReadRAWSave, instance->context);
+                } else if(model->satus == SubGhzReadRAWStatusLoadKeyIDLE) {
                     //More
                     //More
-                    instance->callback(SubghzCustomEventViewReadRAWMore, instance->context);
+                    instance->callback(SubGhzCustomEventViewReadRAWMore, instance->context);
                 }
                 }
                 return true;
                 return true;
             });
             });
     } else if(event->key == InputKeyOk && event->type == InputTypeShort) {
     } else if(event->key == InputKeyOk && event->type == InputTypeShort) {
         with_view_model(
         with_view_model(
-            instance->view, (SubghzReadRAWModel * model) {
-                if(model->satus == SubghzReadRAWStatusStart) {
+            instance->view, (SubGhzReadRAWModel * model) {
+                if(model->satus == SubGhzReadRAWStatusStart) {
                     //Record
                     //Record
-                    instance->callback(SubghzCustomEventViewReadRAWREC, instance->context);
-                    model->satus = SubghzReadRAWStatusREC;
+                    instance->callback(SubGhzCustomEventViewReadRAWREC, instance->context);
+                    model->satus = SubGhzReadRAWStatusREC;
                     model->ind_write = 0;
                     model->ind_write = 0;
                     model->rssi_history_end = false;
                     model->rssi_history_end = false;
-                } else if(model->satus == SubghzReadRAWStatusREC) {
+                } else if(model->satus == SubGhzReadRAWStatusREC) {
                     //Stop
                     //Stop
-                    instance->callback(SubghzCustomEventViewReadRAWIDLE, instance->context);
-                    model->satus = SubghzReadRAWStatusIDLE;
+                    instance->callback(SubGhzCustomEventViewReadRAWIDLE, instance->context);
+                    model->satus = SubGhzReadRAWStatusIDLE;
                 }
                 }
                 return true;
                 return true;
             });
             });
@@ -407,16 +405,16 @@ bool subghz_read_raw_input(InputEvent* event, void* context) {
 }
 }
 
 
 void subghz_read_raw_set_status(
 void subghz_read_raw_set_status(
-    SubghzReadRAW* instance,
-    SubghzReadRAWStatus satus,
+    SubGhzReadRAW* instance,
+    SubGhzReadRAWStatus satus,
     const char* file_name) {
     const char* file_name) {
     furi_assert(instance);
     furi_assert(instance);
 
 
     switch(satus) {
     switch(satus) {
-    case SubghzReadRAWStatusStart:
+    case SubGhzReadRAWStatusStart:
         with_view_model(
         with_view_model(
-            instance->view, (SubghzReadRAWModel * model) {
-                model->satus = SubghzReadRAWStatusStart;
+            instance->view, (SubGhzReadRAWModel * model) {
+                model->satus = SubGhzReadRAWStatusStart;
                 model->rssi_history_end = false;
                 model->rssi_history_end = false;
                 model->ind_write = 0;
                 model->ind_write = 0;
                 string_reset(model->file_name);
                 string_reset(model->file_name);
@@ -424,17 +422,17 @@ void subghz_read_raw_set_status(
                 return true;
                 return true;
             });
             });
         break;
         break;
-    case SubghzReadRAWStatusIDLE:
+    case SubGhzReadRAWStatusIDLE:
         with_view_model(
         with_view_model(
-            instance->view, (SubghzReadRAWModel * model) {
-                model->satus = SubghzReadRAWStatusIDLE;
+            instance->view, (SubGhzReadRAWModel * model) {
+                model->satus = SubGhzReadRAWStatusIDLE;
                 return true;
                 return true;
             });
             });
         break;
         break;
-    case SubghzReadRAWStatusLoadKeyTX:
+    case SubGhzReadRAWStatusLoadKeyTX:
         with_view_model(
         with_view_model(
-            instance->view, (SubghzReadRAWModel * model) {
-                model->satus = SubghzReadRAWStatusLoadKeyIDLE;
+            instance->view, (SubGhzReadRAWModel * model) {
+                model->satus = SubGhzReadRAWStatusLoadKeyIDLE;
                 model->rssi_history_end = false;
                 model->rssi_history_end = false;
                 model->ind_write = 0;
                 model->ind_write = 0;
                 string_set(model->file_name, file_name);
                 string_set(model->file_name, file_name);
@@ -442,10 +440,10 @@ void subghz_read_raw_set_status(
                 return true;
                 return true;
             });
             });
         break;
         break;
-    case SubghzReadRAWStatusSaveKey:
+    case SubGhzReadRAWStatusSaveKey:
         with_view_model(
         with_view_model(
-            instance->view, (SubghzReadRAWModel * model) {
-                model->satus = SubghzReadRAWStatusLoadKeyIDLE;
+            instance->view, (SubGhzReadRAWModel * model) {
+                model->satus = SubGhzReadRAWStatusLoadKeyIDLE;
                 if(!model->ind_write) {
                 if(!model->ind_write) {
                     string_set(model->file_name, file_name);
                     string_set(model->file_name, file_name);
                     string_set(model->sample_write, "RAW");
                     string_set(model->sample_write, "RAW");
@@ -464,31 +462,31 @@ void subghz_read_raw_set_status(
 
 
 void subghz_read_raw_enter(void* context) {
 void subghz_read_raw_enter(void* context) {
     furi_assert(context);
     furi_assert(context);
-    //SubghzReadRAW* instance = context;
+    //SubGhzReadRAW* instance = context;
 }
 }
 
 
 void subghz_read_raw_exit(void* context) {
 void subghz_read_raw_exit(void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzReadRAW* instance = context;
+    SubGhzReadRAW* instance = context;
 
 
     with_view_model(
     with_view_model(
-        instance->view, (SubghzReadRAWModel * model) {
-            if(model->satus != SubghzReadRAWStatusIDLE &&
-               model->satus != SubghzReadRAWStatusStart &&
-               model->satus != SubghzReadRAWStatusLoadKeyIDLE) {
-                instance->callback(SubghzCustomEventViewReadRAWIDLE, instance->context);
-                model->satus = SubghzReadRAWStatusStart;
+        instance->view, (SubGhzReadRAWModel * model) {
+            if(model->satus != SubGhzReadRAWStatusIDLE &&
+               model->satus != SubGhzReadRAWStatusStart &&
+               model->satus != SubGhzReadRAWStatusLoadKeyIDLE) {
+                instance->callback(SubGhzCustomEventViewReadRAWIDLE, instance->context);
+                model->satus = SubGhzReadRAWStatusStart;
             }
             }
             return true;
             return true;
         });
         });
 }
 }
 
 
-SubghzReadRAW* subghz_read_raw_alloc() {
-    SubghzReadRAW* instance = malloc(sizeof(SubghzReadRAW));
+SubGhzReadRAW* subghz_read_raw_alloc() {
+    SubGhzReadRAW* instance = malloc(sizeof(SubGhzReadRAW));
 
 
     // View allocation and configuration
     // View allocation and configuration
     instance->view = view_alloc();
     instance->view = view_alloc();
-    view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubghzReadRAWModel));
+    view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubGhzReadRAWModel));
     view_set_context(instance->view, instance);
     view_set_context(instance->view, instance);
     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_read_raw_draw);
     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_read_raw_draw);
     view_set_input_callback(instance->view, subghz_read_raw_input);
     view_set_input_callback(instance->view, subghz_read_raw_input);
@@ -496,7 +494,7 @@ SubghzReadRAW* subghz_read_raw_alloc() {
     view_set_exit_callback(instance->view, subghz_read_raw_exit);
     view_set_exit_callback(instance->view, subghz_read_raw_exit);
 
 
     with_view_model(
     with_view_model(
-        instance->view, (SubghzReadRAWModel * model) {
+        instance->view, (SubGhzReadRAWModel * model) {
             string_init(model->frequency_str);
             string_init(model->frequency_str);
             string_init(model->preset_str);
             string_init(model->preset_str);
             string_init(model->sample_write);
             string_init(model->sample_write);
@@ -508,11 +506,11 @@ SubghzReadRAW* subghz_read_raw_alloc() {
     return instance;
     return instance;
 }
 }
 
 
-void subghz_read_raw_free(SubghzReadRAW* instance) {
+void subghz_read_raw_free(SubGhzReadRAW* instance) {
     furi_assert(instance);
     furi_assert(instance);
 
 
     with_view_model(
     with_view_model(
-        instance->view, (SubghzReadRAWModel * model) {
+        instance->view, (SubGhzReadRAWModel * model) {
             string_clear(model->frequency_str);
             string_clear(model->frequency_str);
             string_clear(model->preset_str);
             string_clear(model->preset_str);
             string_clear(model->sample_write);
             string_clear(model->sample_write);
@@ -524,7 +522,7 @@ void subghz_read_raw_free(SubghzReadRAW* instance) {
     free(instance);
     free(instance);
 }
 }
 
 
-View* subghz_read_raw_get_view(SubghzReadRAW* instance) {
+View* subghz_read_raw_get_view(SubGhzReadRAW* instance) {
     furi_assert(instance);
     furi_assert(instance);
     return instance->view;
     return instance->view;
 }
 }

+ 25 - 25
applications/subghz/views/subghz_read_raw.h

@@ -3,48 +3,48 @@
 #include <gui/view.h>
 #include <gui/view.h>
 #include "../helpers/subghz_custom_event.h"
 #include "../helpers/subghz_custom_event.h"
 
 
-typedef struct SubghzReadRAW SubghzReadRAW;
+typedef struct SubGhzReadRAW SubGhzReadRAW;
 
 
-typedef void (*SubghzReadRAWCallback)(SubghzCustomEvent event, void* context);
+typedef void (*SubGhzReadRAWCallback)(SubGhzCustomEvent event, void* context);
 
 
 typedef enum {
 typedef enum {
-    SubghzReadRAWStatusStart,
-    SubghzReadRAWStatusIDLE,
-    SubghzReadRAWStatusREC,
-    SubghzReadRAWStatusTX,
-    SubghzReadRAWStatusTXRepeat,
-
-    SubghzReadRAWStatusLoadKeyIDLE,
-    SubghzReadRAWStatusLoadKeyTX,
-    SubghzReadRAWStatusLoadKeyTXRepeat,
-    SubghzReadRAWStatusSaveKey,
-} SubghzReadRAWStatus;
+    SubGhzReadRAWStatusStart,
+    SubGhzReadRAWStatusIDLE,
+    SubGhzReadRAWStatusREC,
+    SubGhzReadRAWStatusTX,
+    SubGhzReadRAWStatusTXRepeat,
+
+    SubGhzReadRAWStatusLoadKeyIDLE,
+    SubGhzReadRAWStatusLoadKeyTX,
+    SubGhzReadRAWStatusLoadKeyTXRepeat,
+    SubGhzReadRAWStatusSaveKey,
+} SubGhzReadRAWStatus;
 
 
 void subghz_read_raw_set_callback(
 void subghz_read_raw_set_callback(
-    SubghzReadRAW* subghz_read_raw,
-    SubghzReadRAWCallback callback,
+    SubGhzReadRAW* subghz_read_raw,
+    SubGhzReadRAWCallback callback,
     void* context);
     void* context);
 
 
-SubghzReadRAW* subghz_read_raw_alloc();
+SubGhzReadRAW* subghz_read_raw_alloc();
 
 
-void subghz_read_raw_free(SubghzReadRAW* subghz_static);
+void subghz_read_raw_free(SubGhzReadRAW* subghz_static);
 
 
 void subghz_read_raw_add_data_statusbar(
 void subghz_read_raw_add_data_statusbar(
-    SubghzReadRAW* instance,
+    SubGhzReadRAW* instance,
     const char* frequency_str,
     const char* frequency_str,
     const char* preset_str);
     const char* preset_str);
 
 
-void subghz_read_raw_update_sample_write(SubghzReadRAW* instance, size_t sample);
+void subghz_read_raw_update_sample_write(SubGhzReadRAW* instance, size_t sample);
 
 
-void subghz_read_raw_stop_send(SubghzReadRAW* instance);
+void subghz_read_raw_stop_send(SubGhzReadRAW* instance);
 
 
-void subghz_read_raw_update_sin(SubghzReadRAW* instance);
+void subghz_read_raw_update_sin(SubGhzReadRAW* instance);
 
 
-void subghz_read_raw_add_data_rssi(SubghzReadRAW* instance, float rssi);
+void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi);
 
 
 void subghz_read_raw_set_status(
 void subghz_read_raw_set_status(
-    SubghzReadRAW* instance,
-    SubghzReadRAWStatus satus,
+    SubGhzReadRAW* instance,
+    SubGhzReadRAWStatus satus,
     const char* file_name);
     const char* file_name);
 
 
-View* subghz_read_raw_get_view(SubghzReadRAW* subghz_static);
+View* subghz_read_raw_get_view(SubGhzReadRAW* subghz_static);

+ 0 - 36
applications/subghz/views/subghz_receiver.h

@@ -1,36 +0,0 @@
-#pragma once
-
-#include <gui/view.h>
-#include "../helpers/subghz_custom_event.h"
-
-typedef struct SubghzReceiver SubghzReceiver;
-
-typedef void (*SubghzReceiverCallback)(SubghzCustomEvent event, void* context);
-
-void subghz_receiver_set_callback(
-    SubghzReceiver* subghz_receiver,
-    SubghzReceiverCallback callback,
-    void* context);
-
-SubghzReceiver* subghz_receiver_alloc();
-
-void subghz_receiver_free(SubghzReceiver* subghz_receiver);
-
-View* subghz_receiver_get_view(SubghzReceiver* subghz_receiver);
-
-void subghz_receiver_add_data_statusbar(
-    SubghzReceiver* subghz_receiver,
-    const char* frequency_str,
-    const char* preset_str,
-    const char* history_stat_str);
-
-void subghz_receiver_add_item_to_menu(
-    SubghzReceiver* subghz_receiver,
-    const char* name,
-    uint8_t type);
-
-uint16_t subghz_receiver_get_idx_menu(SubghzReceiver* subghz_receiver);
-
-void subghz_receiver_set_idx_menu(SubghzReceiver* subghz_receiver, uint16_t idx);
-
-void subghz_receiver_exit(void* context);

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

@@ -7,29 +7,29 @@
 #include <furi_hal.h>
 #include <furi_hal.h>
 #include <input/input.h>
 #include <input/input.h>
 
 
-struct SubghzTestCarrier {
+struct SubGhzTestCarrier {
     View* view;
     View* view;
     osTimerId_t timer;
     osTimerId_t timer;
-    SubghzTestCarrierCallback callback;
+    SubGhzTestCarrierCallback callback;
     void* context;
     void* context;
 };
 };
 
 
 typedef enum {
 typedef enum {
-    SubghzTestCarrierModelStatusRx,
-    SubghzTestCarrierModelStatusTx,
-} SubghzTestCarrierModelStatus;
+    SubGhzTestCarrierModelStatusRx,
+    SubGhzTestCarrierModelStatusTx,
+} SubGhzTestCarrierModelStatus;
 
 
 typedef struct {
 typedef struct {
     uint8_t frequency;
     uint8_t frequency;
     uint32_t real_frequency;
     uint32_t real_frequency;
     FuriHalSubGhzPath path;
     FuriHalSubGhzPath path;
     float rssi;
     float rssi;
-    SubghzTestCarrierModelStatus status;
-} SubghzTestCarrierModel;
+    SubGhzTestCarrierModelStatus status;
+} SubGhzTestCarrierModel;
 
 
 void subghz_test_carrier_set_callback(
 void subghz_test_carrier_set_callback(
-    SubghzTestCarrier* subghz_test_carrier,
-    SubghzTestCarrierCallback callback,
+    SubGhzTestCarrier* subghz_test_carrier,
+    SubGhzTestCarrierCallback callback,
     void* context) {
     void* context) {
     furi_assert(subghz_test_carrier);
     furi_assert(subghz_test_carrier);
     furi_assert(callback);
     furi_assert(callback);
@@ -37,7 +37,7 @@ void subghz_test_carrier_set_callback(
     subghz_test_carrier->context = context;
     subghz_test_carrier->context = context;
 }
 }
 
 
-void subghz_test_carrier_draw(Canvas* canvas, SubghzTestCarrierModel* model) {
+void subghz_test_carrier_draw(Canvas* canvas, SubGhzTestCarrierModel* model) {
     char buffer[64];
     char buffer[64];
 
 
     canvas_set_color(canvas, ColorBlack);
     canvas_set_color(canvas, ColorBlack);
@@ -67,7 +67,7 @@ void subghz_test_carrier_draw(Canvas* canvas, SubghzTestCarrierModel* model) {
     }
     }
     snprintf(buffer, sizeof(buffer), "Path: %d - %s", model->path, path_name);
     snprintf(buffer, sizeof(buffer), "Path: %d - %s", model->path, path_name);
     canvas_draw_str(canvas, 0, 31, buffer);
     canvas_draw_str(canvas, 0, 31, buffer);
-    if(model->status == SubghzTestCarrierModelStatusRx) {
+    if(model->status == SubGhzTestCarrierModelStatusRx) {
         snprintf(
         snprintf(
             buffer,
             buffer,
             sizeof(buffer),
             sizeof(buffer),
@@ -82,14 +82,14 @@ void subghz_test_carrier_draw(Canvas* canvas, SubghzTestCarrierModel* model) {
 
 
 bool subghz_test_carrier_input(InputEvent* event, void* context) {
 bool subghz_test_carrier_input(InputEvent* event, void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzTestCarrier* subghz_test_carrier = context;
+    SubGhzTestCarrier* subghz_test_carrier = context;
 
 
     if(event->key == InputKeyBack || event->type != InputTypeShort) {
     if(event->key == InputKeyBack || event->type != InputTypeShort) {
         return false;
         return false;
     }
     }
 
 
     with_view_model(
     with_view_model(
-        subghz_test_carrier->view, (SubghzTestCarrierModel * model) {
+        subghz_test_carrier->view, (SubGhzTestCarrierModel * model) {
             furi_hal_subghz_idle();
             furi_hal_subghz_idle();
 
 
             if(event->key == InputKeyLeft) {
             if(event->key == InputKeyLeft) {
@@ -101,10 +101,10 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) {
             } else if(event->key == InputKeyUp) {
             } else if(event->key == InputKeyUp) {
                 if(model->path < FuriHalSubGhzPath868) model->path++;
                 if(model->path < FuriHalSubGhzPath868) model->path++;
             } else if(event->key == InputKeyOk) {
             } else if(event->key == InputKeyOk) {
-                if(model->status == SubghzTestCarrierModelStatusTx) {
-                    model->status = SubghzTestCarrierModelStatusRx;
+                if(model->status == SubGhzTestCarrierModelStatusTx) {
+                    model->status = SubGhzTestCarrierModelStatusRx;
                 } else {
                 } else {
-                    model->status = SubghzTestCarrierModelStatusTx;
+                    model->status = SubGhzTestCarrierModelStatusTx;
                 }
                 }
             }
             }
 
 
@@ -112,7 +112,7 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) {
                 furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]);
                 furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]);
             furi_hal_subghz_set_path(model->path);
             furi_hal_subghz_set_path(model->path);
 
 
-            if(model->status == SubghzTestCarrierModelStatusRx) {
+            if(model->status == SubGhzTestCarrierModelStatusRx) {
                 hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
                 hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
                 furi_hal_subghz_rx();
                 furi_hal_subghz_rx();
             } else {
             } else {
@@ -121,7 +121,7 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) {
                 if(!furi_hal_subghz_tx()) {
                 if(!furi_hal_subghz_tx()) {
                     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
                     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
                     subghz_test_carrier->callback(
                     subghz_test_carrier->callback(
-                        SubghzTestCarrierEventOnlyRx, subghz_test_carrier->context);
+                        SubGhzTestCarrierEventOnlyRx, subghz_test_carrier->context);
                 }
                 }
             }
             }
 
 
@@ -133,7 +133,7 @@ bool subghz_test_carrier_input(InputEvent* event, void* context) {
 
 
 void subghz_test_carrier_enter(void* context) {
 void subghz_test_carrier_enter(void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzTestCarrier* subghz_test_carrier = context;
+    SubGhzTestCarrier* subghz_test_carrier = context;
 
 
     furi_hal_subghz_reset();
     furi_hal_subghz_reset();
     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
@@ -141,13 +141,13 @@ void subghz_test_carrier_enter(void* context) {
     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
 
 
     with_view_model(
     with_view_model(
-        subghz_test_carrier->view, (SubghzTestCarrierModel * model) {
+        subghz_test_carrier->view, (SubGhzTestCarrierModel * model) {
             model->frequency = subghz_frequencies_433_92_testing; // 433
             model->frequency = subghz_frequencies_433_92_testing; // 433
             model->real_frequency =
             model->real_frequency =
                 furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]);
                 furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]);
             model->path = FuriHalSubGhzPathIsolate; // isolate
             model->path = FuriHalSubGhzPathIsolate; // isolate
             model->rssi = 0.0f;
             model->rssi = 0.0f;
-            model->status = SubghzTestCarrierModelStatusRx;
+            model->status = SubGhzTestCarrierModelStatusRx;
             return true;
             return true;
         });
         });
 
 
@@ -158,7 +158,7 @@ void subghz_test_carrier_enter(void* context) {
 
 
 void subghz_test_carrier_exit(void* context) {
 void subghz_test_carrier_exit(void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzTestCarrier* subghz_test_carrier = context;
+    SubGhzTestCarrier* subghz_test_carrier = context;
 
 
     osTimerStop(subghz_test_carrier->timer);
     osTimerStop(subghz_test_carrier->timer);
 
 
@@ -168,11 +168,11 @@ void subghz_test_carrier_exit(void* context) {
 
 
 void subghz_test_carrier_rssi_timer_callback(void* context) {
 void subghz_test_carrier_rssi_timer_callback(void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzTestCarrier* subghz_test_carrier = context;
+    SubGhzTestCarrier* subghz_test_carrier = context;
 
 
     with_view_model(
     with_view_model(
-        subghz_test_carrier->view, (SubghzTestCarrierModel * model) {
-            if(model->status == SubghzTestCarrierModelStatusRx) {
+        subghz_test_carrier->view, (SubGhzTestCarrierModel * model) {
+            if(model->status == SubGhzTestCarrierModelStatusRx) {
                 model->rssi = furi_hal_subghz_get_rssi();
                 model->rssi = furi_hal_subghz_get_rssi();
                 return true;
                 return true;
             }
             }
@@ -180,13 +180,13 @@ void subghz_test_carrier_rssi_timer_callback(void* context) {
         });
         });
 }
 }
 
 
-SubghzTestCarrier* subghz_test_carrier_alloc() {
-    SubghzTestCarrier* subghz_test_carrier = malloc(sizeof(SubghzTestCarrier));
+SubGhzTestCarrier* subghz_test_carrier_alloc() {
+    SubGhzTestCarrier* subghz_test_carrier = malloc(sizeof(SubGhzTestCarrier));
 
 
     // View allocation and configuration
     // View allocation and configuration
     subghz_test_carrier->view = view_alloc();
     subghz_test_carrier->view = view_alloc();
     view_allocate_model(
     view_allocate_model(
-        subghz_test_carrier->view, ViewModelTypeLocking, sizeof(SubghzTestCarrierModel));
+        subghz_test_carrier->view, ViewModelTypeLocking, sizeof(SubGhzTestCarrierModel));
     view_set_context(subghz_test_carrier->view, subghz_test_carrier);
     view_set_context(subghz_test_carrier->view, subghz_test_carrier);
     view_set_draw_callback(subghz_test_carrier->view, (ViewDrawCallback)subghz_test_carrier_draw);
     view_set_draw_callback(subghz_test_carrier->view, (ViewDrawCallback)subghz_test_carrier_draw);
     view_set_input_callback(subghz_test_carrier->view, subghz_test_carrier_input);
     view_set_input_callback(subghz_test_carrier->view, subghz_test_carrier_input);
@@ -199,14 +199,14 @@ SubghzTestCarrier* subghz_test_carrier_alloc() {
     return subghz_test_carrier;
     return subghz_test_carrier;
 }
 }
 
 
-void subghz_test_carrier_free(SubghzTestCarrier* subghz_test_carrier) {
+void subghz_test_carrier_free(SubGhzTestCarrier* subghz_test_carrier) {
     furi_assert(subghz_test_carrier);
     furi_assert(subghz_test_carrier);
     osTimerDelete(subghz_test_carrier->timer);
     osTimerDelete(subghz_test_carrier->timer);
     view_free(subghz_test_carrier->view);
     view_free(subghz_test_carrier->view);
     free(subghz_test_carrier);
     free(subghz_test_carrier);
 }
 }
 
 
-View* subghz_test_carrier_get_view(SubghzTestCarrier* subghz_test_carrier) {
+View* subghz_test_carrier_get_view(SubGhzTestCarrier* subghz_test_carrier) {
     furi_assert(subghz_test_carrier);
     furi_assert(subghz_test_carrier);
     return subghz_test_carrier->view;
     return subghz_test_carrier->view;
 }
 }

+ 9 - 9
applications/subghz/views/subghz_test_carrier.h

@@ -3,20 +3,20 @@
 #include <gui/view.h>
 #include <gui/view.h>
 
 
 typedef enum {
 typedef enum {
-    SubghzTestCarrierEventOnlyRx,
-} SubghzTestCarrierEvent;
+    SubGhzTestCarrierEventOnlyRx,
+} SubGhzTestCarrierEvent;
 
 
-typedef struct SubghzTestCarrier SubghzTestCarrier;
+typedef struct SubGhzTestCarrier SubGhzTestCarrier;
 
 
-typedef void (*SubghzTestCarrierCallback)(SubghzTestCarrierEvent event, void* context);
+typedef void (*SubGhzTestCarrierCallback)(SubGhzTestCarrierEvent event, void* context);
 
 
 void subghz_test_carrier_set_callback(
 void subghz_test_carrier_set_callback(
-    SubghzTestCarrier* subghz_test_carrier,
-    SubghzTestCarrierCallback callback,
+    SubGhzTestCarrier* subghz_test_carrier,
+    SubGhzTestCarrierCallback callback,
     void* context);
     void* context);
 
 
-SubghzTestCarrier* subghz_test_carrier_alloc();
+SubGhzTestCarrier* subghz_test_carrier_alloc();
 
 
-void subghz_test_carrier_free(SubghzTestCarrier* subghz_test_carrier);
+void subghz_test_carrier_free(SubGhzTestCarrier* subghz_test_carrier);
 
 
-View* subghz_test_carrier_get_view(SubghzTestCarrier* subghz_test_carrier);
+View* subghz_test_carrier_get_view(SubGhzTestCarrier* subghz_test_carrier);

+ 57 - 55
applications/subghz/views/subghz_test_packet.c

@@ -7,26 +7,26 @@
 #include <furi_hal.h>
 #include <furi_hal.h>
 #include <input/input.h>
 #include <input/input.h>
 #include <toolbox/level_duration.h>
 #include <toolbox/level_duration.h>
-#include <lib/subghz/protocols/subghz_protocol_princeton.h>
+#include <lib/subghz/protocols/princeton_for_testing.h>
 
 
 #define SUBGHZ_TEST_PACKET_COUNT 500
 #define SUBGHZ_TEST_PACKET_COUNT 500
 
 
-struct SubghzTestPacket {
+struct SubGhzTestPacket {
     View* view;
     View* view;
     osTimerId_t timer;
     osTimerId_t timer;
 
 
     SubGhzDecoderPrinceton* decoder;
     SubGhzDecoderPrinceton* decoder;
     SubGhzEncoderPrinceton* encoder;
     SubGhzEncoderPrinceton* encoder;
     volatile size_t packet_rx;
     volatile size_t packet_rx;
-    SubghzTestPacketCallback callback;
+    SubGhzTestPacketCallback callback;
     void* context;
     void* context;
 };
 };
 
 
 typedef enum {
 typedef enum {
-    SubghzTestPacketModelStatusRx,
-    SubghzTestPacketModelStatusOnlyRx,
-    SubghzTestPacketModelStatusTx,
-} SubghzTestPacketModelStatus;
+    SubGhzTestPacketModelStatusRx,
+    SubGhzTestPacketModelStatusOnlyRx,
+    SubGhzTestPacketModelStatusTx,
+} SubGhzTestPacketModelStatus;
 
 
 typedef struct {
 typedef struct {
     uint8_t frequency;
     uint8_t frequency;
@@ -34,14 +34,14 @@ typedef struct {
     FuriHalSubGhzPath path;
     FuriHalSubGhzPath path;
     float rssi;
     float rssi;
     size_t packets;
     size_t packets;
-    SubghzTestPacketModelStatus status;
-} SubghzTestPacketModel;
+    SubGhzTestPacketModelStatus status;
+} SubGhzTestPacketModel;
 
 
 volatile bool subghz_test_packet_overrun = false;
 volatile bool subghz_test_packet_overrun = false;
 
 
 void subghz_test_packet_set_callback(
 void subghz_test_packet_set_callback(
-    SubghzTestPacket* subghz_test_packet,
-    SubghzTestPacketCallback callback,
+    SubGhzTestPacket* subghz_test_packet,
+    SubGhzTestPacketCallback callback,
     void* context) {
     void* context) {
     furi_assert(subghz_test_packet);
     furi_assert(subghz_test_packet);
     furi_assert(callback);
     furi_assert(callback);
@@ -51,34 +51,36 @@ void subghz_test_packet_set_callback(
 
 
 static void subghz_test_packet_rx_callback(bool level, uint32_t duration, void* context) {
 static void subghz_test_packet_rx_callback(bool level, uint32_t duration, void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzTestPacket* instance = context;
-    subghz_decoder_princeton_parse(instance->decoder, level, duration);
+    SubGhzTestPacket* instance = context;
+    subghz_decoder_princeton_for_testing_parse(instance->decoder, level, duration);
 }
 }
 
 
-static void subghz_test_packet_rx_pt_callback(SubGhzProtocolCommon* parser, void* context) {
+//todo
+static void subghz_test_packet_rx_pt_callback(SubGhzDecoderPrinceton* parser, void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzTestPacket* instance = context;
+    SubGhzTestPacket* instance = context;
     instance->packet_rx++;
     instance->packet_rx++;
 }
 }
 
 
 static void subghz_test_packet_rssi_timer_callback(void* context) {
 static void subghz_test_packet_rssi_timer_callback(void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzTestPacket* instance = context;
+    SubGhzTestPacket* instance = context;
 
 
     with_view_model(
     with_view_model(
-        instance->view, (SubghzTestPacketModel * model) {
-            if(model->status == SubghzTestPacketModelStatusRx) {
+        instance->view, (SubGhzTestPacketModel * model) {
+            if(model->status == SubGhzTestPacketModelStatusRx) {
                 model->rssi = furi_hal_subghz_get_rssi();
                 model->rssi = furi_hal_subghz_get_rssi();
                 model->packets = instance->packet_rx;
                 model->packets = instance->packet_rx;
-            } else if(model->status == SubghzTestPacketModelStatusTx) {
-                model->packets = SUBGHZ_TEST_PACKET_COUNT -
-                                 subghz_encoder_princeton_get_repeat_left(instance->encoder);
+            } else if(model->status == SubGhzTestPacketModelStatusTx) {
+                model->packets =
+                    SUBGHZ_TEST_PACKET_COUNT -
+                    subghz_encoder_princeton_for_testing_get_repeat_left(instance->encoder);
             }
             }
             return true;
             return true;
         });
         });
 }
 }
 
 
-static void subghz_test_packet_draw(Canvas* canvas, SubghzTestPacketModel* model) {
+static void subghz_test_packet_draw(Canvas* canvas, SubGhzTestPacketModel* model) {
     char buffer[64];
     char buffer[64];
 
 
     canvas_set_color(canvas, ColorBlack);
     canvas_set_color(canvas, ColorBlack);
@@ -112,7 +114,7 @@ static void subghz_test_packet_draw(Canvas* canvas, SubghzTestPacketModel* model
     snprintf(buffer, sizeof(buffer), "Packets: %d", model->packets);
     snprintf(buffer, sizeof(buffer), "Packets: %d", model->packets);
     canvas_draw_str(canvas, 0, 42, buffer);
     canvas_draw_str(canvas, 0, 42, buffer);
 
 
-    if(model->status == SubghzTestPacketModelStatusRx) {
+    if(model->status == SubGhzTestPacketModelStatusRx) {
         snprintf(
         snprintf(
             buffer,
             buffer,
             sizeof(buffer),
             sizeof(buffer),
@@ -127,18 +129,18 @@ static void subghz_test_packet_draw(Canvas* canvas, SubghzTestPacketModel* model
 
 
 static bool subghz_test_packet_input(InputEvent* event, void* context) {
 static bool subghz_test_packet_input(InputEvent* event, void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzTestPacket* instance = context;
+    SubGhzTestPacket* instance = context;
 
 
     if(event->key == InputKeyBack || event->type != InputTypeShort) {
     if(event->key == InputKeyBack || event->type != InputTypeShort) {
         return false;
         return false;
     }
     }
 
 
     with_view_model(
     with_view_model(
-        instance->view, (SubghzTestPacketModel * model) {
-            if(model->status == SubghzTestPacketModelStatusRx) {
+        instance->view, (SubGhzTestPacketModel * model) {
+            if(model->status == SubGhzTestPacketModelStatusRx) {
                 furi_hal_subghz_stop_async_rx();
                 furi_hal_subghz_stop_async_rx();
-            } else if(model->status == SubghzTestPacketModelStatusTx) {
-                subghz_encoder_princeton_stop(instance->encoder, millis());
+            } else if(model->status == SubGhzTestPacketModelStatusTx) {
+                subghz_encoder_princeton_for_testing_stop(instance->encoder, millis());
                 furi_hal_subghz_stop_async_tx();
                 furi_hal_subghz_stop_async_tx();
             }
             }
 
 
@@ -151,10 +153,10 @@ static bool subghz_test_packet_input(InputEvent* event, void* context) {
             } else if(event->key == InputKeyUp) {
             } else if(event->key == InputKeyUp) {
                 if(model->path < FuriHalSubGhzPath868) model->path++;
                 if(model->path < FuriHalSubGhzPath868) model->path++;
             } else if(event->key == InputKeyOk) {
             } else if(event->key == InputKeyOk) {
-                if(model->status == SubghzTestPacketModelStatusRx) {
-                    model->status = SubghzTestPacketModelStatusTx;
+                if(model->status == SubGhzTestPacketModelStatusRx) {
+                    model->status = SubGhzTestPacketModelStatusTx;
                 } else {
                 } else {
-                    model->status = SubghzTestPacketModelStatusRx;
+                    model->status = SubGhzTestPacketModelStatusRx;
                 }
                 }
             }
             }
 
 
@@ -162,18 +164,18 @@ static bool subghz_test_packet_input(InputEvent* event, void* context) {
                 furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]);
                 furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]);
             furi_hal_subghz_set_path(model->path);
             furi_hal_subghz_set_path(model->path);
 
 
-            if(model->status == SubghzTestPacketModelStatusRx) {
+            if(model->status == SubGhzTestPacketModelStatusRx) {
                 furi_hal_subghz_start_async_rx(subghz_test_packet_rx_callback, instance);
                 furi_hal_subghz_start_async_rx(subghz_test_packet_rx_callback, instance);
             } else {
             } else {
-                subghz_encoder_princeton_set(
+                subghz_encoder_princeton_for_testing_set(
                     instance->encoder,
                     instance->encoder,
                     0x00AABBCC,
                     0x00AABBCC,
                     SUBGHZ_TEST_PACKET_COUNT,
                     SUBGHZ_TEST_PACKET_COUNT,
                     subghz_frequencies_testing[model->frequency]);
                     subghz_frequencies_testing[model->frequency]);
                 if(!furi_hal_subghz_start_async_tx(
                 if(!furi_hal_subghz_start_async_tx(
-                       subghz_encoder_princeton_yield, instance->encoder)) {
-                    model->status = SubghzTestPacketModelStatusOnlyRx;
-                    instance->callback(SubghzTestPacketEventOnlyRx, instance->context);
+                       subghz_encoder_princeton_for_testing_yield, instance->encoder)) {
+                    model->status = SubGhzTestPacketModelStatusOnlyRx;
+                    instance->callback(SubGhzTestPacketEventOnlyRx, instance->context);
                 }
                 }
             }
             }
 
 
@@ -185,19 +187,19 @@ static bool subghz_test_packet_input(InputEvent* event, void* context) {
 
 
 void subghz_test_packet_enter(void* context) {
 void subghz_test_packet_enter(void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzTestPacket* instance = context;
+    SubGhzTestPacket* instance = context;
 
 
     furi_hal_subghz_reset();
     furi_hal_subghz_reset();
     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
 
 
     with_view_model(
     with_view_model(
-        instance->view, (SubghzTestPacketModel * model) {
+        instance->view, (SubGhzTestPacketModel * model) {
             model->frequency = subghz_frequencies_433_92_testing;
             model->frequency = subghz_frequencies_433_92_testing;
             model->real_frequency =
             model->real_frequency =
                 furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]);
                 furi_hal_subghz_set_frequency(subghz_frequencies_testing[model->frequency]);
             model->path = FuriHalSubGhzPathIsolate; // isolate
             model->path = FuriHalSubGhzPathIsolate; // isolate
             model->rssi = 0.0f;
             model->rssi = 0.0f;
-            model->status = SubghzTestPacketModelStatusRx;
+            model->status = SubGhzTestPacketModelStatusRx;
             return true;
             return true;
         });
         });
 
 
@@ -208,17 +210,17 @@ void subghz_test_packet_enter(void* context) {
 
 
 void subghz_test_packet_exit(void* context) {
 void subghz_test_packet_exit(void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzTestPacket* instance = context;
+    SubGhzTestPacket* instance = context;
 
 
     osTimerStop(instance->timer);
     osTimerStop(instance->timer);
 
 
     // Reinitialize IC to default state
     // Reinitialize IC to default state
     with_view_model(
     with_view_model(
-        instance->view, (SubghzTestPacketModel * model) {
-            if(model->status == SubghzTestPacketModelStatusRx) {
+        instance->view, (SubGhzTestPacketModel * model) {
+            if(model->status == SubGhzTestPacketModelStatusRx) {
                 furi_hal_subghz_stop_async_rx();
                 furi_hal_subghz_stop_async_rx();
-            } else if(model->status == SubghzTestPacketModelStatusTx) {
-                subghz_encoder_princeton_stop(instance->encoder, millis());
+            } else if(model->status == SubGhzTestPacketModelStatusTx) {
+                subghz_encoder_princeton_for_testing_stop(instance->encoder, millis());
                 furi_hal_subghz_stop_async_tx();
                 furi_hal_subghz_stop_async_tx();
             }
             }
             return true;
             return true;
@@ -226,12 +228,12 @@ void subghz_test_packet_exit(void* context) {
     furi_hal_subghz_sleep();
     furi_hal_subghz_sleep();
 }
 }
 
 
-SubghzTestPacket* subghz_test_packet_alloc() {
-    SubghzTestPacket* instance = malloc(sizeof(SubghzTestPacket));
+SubGhzTestPacket* subghz_test_packet_alloc() {
+    SubGhzTestPacket* instance = malloc(sizeof(SubGhzTestPacket));
 
 
     // View allocation and configuration
     // View allocation and configuration
     instance->view = view_alloc();
     instance->view = view_alloc();
-    view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubghzTestPacketModel));
+    view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubGhzTestPacketModel));
     view_set_context(instance->view, instance);
     view_set_context(instance->view, instance);
     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_test_packet_draw);
     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_test_packet_draw);
     view_set_input_callback(instance->view, subghz_test_packet_input);
     view_set_input_callback(instance->view, subghz_test_packet_input);
@@ -241,26 +243,26 @@ SubghzTestPacket* subghz_test_packet_alloc() {
     instance->timer =
     instance->timer =
         osTimerNew(subghz_test_packet_rssi_timer_callback, osTimerPeriodic, instance, NULL);
         osTimerNew(subghz_test_packet_rssi_timer_callback, osTimerPeriodic, instance, NULL);
 
 
-    instance->decoder = subghz_decoder_princeton_alloc();
-    subghz_protocol_common_set_callback(
-        (SubGhzProtocolCommon*)instance->decoder, subghz_test_packet_rx_pt_callback, instance);
-    instance->encoder = subghz_encoder_princeton_alloc();
+    instance->decoder = subghz_decoder_princeton_for_testing_alloc();
+    subghz_decoder_princeton_for_testing_set_callback(
+        instance->decoder, subghz_test_packet_rx_pt_callback, instance);
+    instance->encoder = subghz_encoder_princeton_for_testing_alloc();
 
 
     return instance;
     return instance;
 }
 }
 
 
-void subghz_test_packet_free(SubghzTestPacket* instance) {
+void subghz_test_packet_free(SubGhzTestPacket* instance) {
     furi_assert(instance);
     furi_assert(instance);
 
 
-    subghz_decoder_princeton_free(instance->decoder);
-    subghz_encoder_princeton_free(instance->encoder);
+    subghz_decoder_princeton_for_testing_free(instance->decoder);
+    subghz_encoder_princeton_for_testing_free(instance->encoder);
 
 
     osTimerDelete(instance->timer);
     osTimerDelete(instance->timer);
     view_free(instance->view);
     view_free(instance->view);
     free(instance);
     free(instance);
 }
 }
 
 
-View* subghz_test_packet_get_view(SubghzTestPacket* instance) {
+View* subghz_test_packet_get_view(SubGhzTestPacket* instance) {
     furi_assert(instance);
     furi_assert(instance);
     return instance->view;
     return instance->view;
 }
 }

+ 9 - 9
applications/subghz/views/subghz_test_packet.h

@@ -3,20 +3,20 @@
 #include <gui/view.h>
 #include <gui/view.h>
 
 
 typedef enum {
 typedef enum {
-    SubghzTestPacketEventOnlyRx,
-} SubghzTestPacketEvent;
+    SubGhzTestPacketEventOnlyRx,
+} SubGhzTestPacketEvent;
 
 
-typedef struct SubghzTestPacket SubghzTestPacket;
+typedef struct SubGhzTestPacket SubGhzTestPacket;
 
 
-typedef void (*SubghzTestPacketCallback)(SubghzTestPacketEvent event, void* context);
+typedef void (*SubGhzTestPacketCallback)(SubGhzTestPacketEvent event, void* context);
 
 
 void subghz_test_packet_set_callback(
 void subghz_test_packet_set_callback(
-    SubghzTestPacket* subghz_test_packet,
-    SubghzTestPacketCallback callback,
+    SubGhzTestPacket* subghz_test_packet,
+    SubGhzTestPacketCallback callback,
     void* context);
     void* context);
 
 
-SubghzTestPacket* subghz_test_packet_alloc();
+SubGhzTestPacket* subghz_test_packet_alloc();
 
 
-void subghz_test_packet_free(SubghzTestPacket* subghz_test_packet);
+void subghz_test_packet_free(SubGhzTestPacket* subghz_test_packet);
 
 
-View* subghz_test_packet_get_view(SubghzTestPacket* subghz_test_packet);
+View* subghz_test_packet_get_view(SubGhzTestPacket* subghz_test_packet);

+ 31 - 31
applications/subghz/views/subghz_test_static.c

@@ -7,14 +7,14 @@
 #include <furi_hal.h>
 #include <furi_hal.h>
 #include <input/input.h>
 #include <input/input.h>
 #include <notification/notification_messages.h>
 #include <notification/notification_messages.h>
-#include <lib/subghz/protocols/subghz_protocol_princeton.h>
+#include <lib/subghz/protocols/princeton_for_testing.h>
 
 
 #define TAG "SubGhzTestStatic"
 #define TAG "SubGhzTestStatic"
 
 
 typedef enum {
 typedef enum {
-    SubghzTestStaticStatusIDLE,
-    SubghzTestStaticStatusTX,
-} SubghzTestStaticStatus;
+    SubGhzTestStaticStatusIDLE,
+    SubGhzTestStaticStatusTX,
+} SubGhzTestStaticStatus;
 
 
 static const uint32_t subghz_test_static_keys[] = {
 static const uint32_t subghz_test_static_keys[] = {
     0x0074BADE,
     0x0074BADE,
@@ -23,11 +23,11 @@ static const uint32_t subghz_test_static_keys[] = {
     0x00E34A4E,
     0x00E34A4E,
 };
 };
 
 
-struct SubghzTestStatic {
+struct SubGhzTestStatic {
     View* view;
     View* view;
-    SubghzTestStaticStatus satus_tx;
+    SubGhzTestStaticStatus satus_tx;
     SubGhzEncoderPrinceton* encoder;
     SubGhzEncoderPrinceton* encoder;
-    SubghzTestStaticCallback callback;
+    SubGhzTestStaticCallback callback;
     void* context;
     void* context;
 };
 };
 
 
@@ -35,11 +35,11 @@ typedef struct {
     uint8_t frequency;
     uint8_t frequency;
     uint32_t real_frequency;
     uint32_t real_frequency;
     uint8_t button;
     uint8_t button;
-} SubghzTestStaticModel;
+} SubGhzTestStaticModel;
 
 
 void subghz_test_static_set_callback(
 void subghz_test_static_set_callback(
-    SubghzTestStatic* subghz_test_static,
-    SubghzTestStaticCallback callback,
+    SubGhzTestStatic* subghz_test_static,
+    SubGhzTestStaticCallback callback,
     void* context) {
     void* context) {
     furi_assert(subghz_test_static);
     furi_assert(subghz_test_static);
     furi_assert(callback);
     furi_assert(callback);
@@ -47,7 +47,7 @@ void subghz_test_static_set_callback(
     subghz_test_static->context = context;
     subghz_test_static->context = context;
 }
 }
 
 
-void subghz_test_static_draw(Canvas* canvas, SubghzTestStaticModel* model) {
+void subghz_test_static_draw(Canvas* canvas, SubGhzTestStaticModel* model) {
     char buffer[64];
     char buffer[64];
 
 
     canvas_set_color(canvas, ColorBlack);
     canvas_set_color(canvas, ColorBlack);
@@ -70,14 +70,14 @@ void subghz_test_static_draw(Canvas* canvas, SubghzTestStaticModel* model) {
 
 
 bool subghz_test_static_input(InputEvent* event, void* context) {
 bool subghz_test_static_input(InputEvent* event, void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzTestStatic* instance = context;
+    SubGhzTestStatic* instance = context;
 
 
     if(event->key == InputKeyBack) {
     if(event->key == InputKeyBack) {
         return false;
         return false;
     }
     }
 
 
     with_view_model(
     with_view_model(
-        instance->view, (SubghzTestStaticModel * model) {
+        instance->view, (SubGhzTestStaticModel * model) {
             if(event->type == InputTypeShort) {
             if(event->type == InputTypeShort) {
                 if(event->key == InputKeyLeft) {
                 if(event->key == InputKeyLeft) {
                     if(model->frequency > 0) model->frequency--;
                     if(model->frequency > 0) model->frequency--;
@@ -99,31 +99,31 @@ bool subghz_test_static_input(InputEvent* event, void* context) {
                     furi_hal_subghz_set_frequency_and_path(
                     furi_hal_subghz_set_frequency_and_path(
                         subghz_frequencies_testing[model->frequency]);
                         subghz_frequencies_testing[model->frequency]);
                     if(!furi_hal_subghz_tx()) {
                     if(!furi_hal_subghz_tx()) {
-                        instance->callback(SubghzTestStaticEventOnlyRx, instance->context);
+                        instance->callback(SubGhzTestStaticEventOnlyRx, instance->context);
                     } else {
                     } else {
                         notification_message_block(notification, &sequence_set_red_255);
                         notification_message_block(notification, &sequence_set_red_255);
 
 
                         FURI_LOG_I(TAG, "TX Start");
                         FURI_LOG_I(TAG, "TX Start");
 
 
-                        subghz_encoder_princeton_set(
+                        subghz_encoder_princeton_for_testing_set(
                             instance->encoder,
                             instance->encoder,
                             subghz_test_static_keys[model->button],
                             subghz_test_static_keys[model->button],
                             10000,
                             10000,
                             subghz_frequencies_testing[model->frequency]);
                             subghz_frequencies_testing[model->frequency]);
 
 
                         furi_hal_subghz_start_async_tx(
                         furi_hal_subghz_start_async_tx(
-                            subghz_encoder_princeton_yield, instance->encoder);
-                        instance->satus_tx = SubghzTestStaticStatusTX;
+                            subghz_encoder_princeton_for_testing_yield, instance->encoder);
+                        instance->satus_tx = SubGhzTestStaticStatusTX;
                     }
                     }
                 } else if(event->type == InputTypeRelease) {
                 } else if(event->type == InputTypeRelease) {
-                    if(instance->satus_tx == SubghzTestStaticStatusTX) {
+                    if(instance->satus_tx == SubGhzTestStaticStatusTX) {
                         FURI_LOG_I(TAG, "TX Stop");
                         FURI_LOG_I(TAG, "TX Stop");
-                        subghz_encoder_princeton_stop(instance->encoder, millis());
-                        subghz_encoder_princeton_print_log(instance->encoder);
+                        subghz_encoder_princeton_for_testing_stop(instance->encoder, millis());
+                        subghz_encoder_princeton_for_testing_print_log(instance->encoder);
                         furi_hal_subghz_stop_async_tx();
                         furi_hal_subghz_stop_async_tx();
                         notification_message(notification, &sequence_reset_red);
                         notification_message(notification, &sequence_reset_red);
                     }
                     }
-                    instance->satus_tx = SubghzTestStaticStatusIDLE;
+                    instance->satus_tx = SubGhzTestStaticStatusIDLE;
                 }
                 }
                 furi_record_close("notification");
                 furi_record_close("notification");
             }
             }
@@ -136,17 +136,17 @@ bool subghz_test_static_input(InputEvent* event, void* context) {
 
 
 void subghz_test_static_enter(void* context) {
 void subghz_test_static_enter(void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzTestStatic* instance = context;
+    SubGhzTestStatic* instance = context;
 
 
     furi_hal_subghz_reset();
     furi_hal_subghz_reset();
     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
     furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
 
 
     hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
     hal_gpio_init(&gpio_cc1101_g0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
     hal_gpio_write(&gpio_cc1101_g0, false);
     hal_gpio_write(&gpio_cc1101_g0, false);
-    instance->satus_tx = SubghzTestStaticStatusIDLE;
+    instance->satus_tx = SubGhzTestStaticStatusIDLE;
 
 
     with_view_model(
     with_view_model(
-        instance->view, (SubghzTestStaticModel * model) {
+        instance->view, (SubGhzTestStaticModel * model) {
             model->frequency = subghz_frequencies_433_92_testing;
             model->frequency = subghz_frequencies_433_92_testing;
             model->real_frequency = subghz_frequencies_testing[model->frequency];
             model->real_frequency = subghz_frequencies_testing[model->frequency];
             model->button = 0;
             model->button = 0;
@@ -160,31 +160,31 @@ void subghz_test_static_exit(void* context) {
     furi_hal_subghz_sleep();
     furi_hal_subghz_sleep();
 }
 }
 
 
-SubghzTestStatic* subghz_test_static_alloc() {
-    SubghzTestStatic* instance = malloc(sizeof(SubghzTestStatic));
+SubGhzTestStatic* subghz_test_static_alloc() {
+    SubGhzTestStatic* instance = malloc(sizeof(SubGhzTestStatic));
 
 
     // View allocation and configuration
     // View allocation and configuration
     instance->view = view_alloc();
     instance->view = view_alloc();
-    view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubghzTestStaticModel));
+    view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(SubGhzTestStaticModel));
     view_set_context(instance->view, instance);
     view_set_context(instance->view, instance);
     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_test_static_draw);
     view_set_draw_callback(instance->view, (ViewDrawCallback)subghz_test_static_draw);
     view_set_input_callback(instance->view, subghz_test_static_input);
     view_set_input_callback(instance->view, subghz_test_static_input);
     view_set_enter_callback(instance->view, subghz_test_static_enter);
     view_set_enter_callback(instance->view, subghz_test_static_enter);
     view_set_exit_callback(instance->view, subghz_test_static_exit);
     view_set_exit_callback(instance->view, subghz_test_static_exit);
 
 
-    instance->encoder = subghz_encoder_princeton_alloc();
+    instance->encoder = subghz_encoder_princeton_for_testing_alloc();
 
 
     return instance;
     return instance;
 }
 }
 
 
-void subghz_test_static_free(SubghzTestStatic* instance) {
+void subghz_test_static_free(SubGhzTestStatic* instance) {
     furi_assert(instance);
     furi_assert(instance);
-    subghz_encoder_princeton_free(instance->encoder);
+    subghz_encoder_princeton_for_testing_free(instance->encoder);
     view_free(instance->view);
     view_free(instance->view);
     free(instance);
     free(instance);
 }
 }
 
 
-View* subghz_test_static_get_view(SubghzTestStatic* instance) {
+View* subghz_test_static_get_view(SubGhzTestStatic* instance) {
     furi_assert(instance);
     furi_assert(instance);
     return instance->view;
     return instance->view;
 }
 }

+ 9 - 9
applications/subghz/views/subghz_test_static.h

@@ -3,20 +3,20 @@
 #include <gui/view.h>
 #include <gui/view.h>
 
 
 typedef enum {
 typedef enum {
-    SubghzTestStaticEventOnlyRx,
-} SubghzTestStaticEvent;
+    SubGhzTestStaticEventOnlyRx,
+} SubGhzTestStaticEvent;
 
 
-typedef struct SubghzTestStatic SubghzTestStatic;
+typedef struct SubGhzTestStatic SubGhzTestStatic;
 
 
-typedef void (*SubghzTestStaticCallback)(SubghzTestStaticEvent event, void* context);
+typedef void (*SubGhzTestStaticCallback)(SubGhzTestStaticEvent event, void* context);
 
 
 void subghz_test_static_set_callback(
 void subghz_test_static_set_callback(
-    SubghzTestStatic* subghz_test_static,
-    SubghzTestStaticCallback callback,
+    SubGhzTestStatic* subghz_test_static,
+    SubGhzTestStaticCallback callback,
     void* context);
     void* context);
 
 
-SubghzTestStatic* subghz_test_static_alloc();
+SubGhzTestStatic* subghz_test_static_alloc();
 
 
-void subghz_test_static_free(SubghzTestStatic* subghz_static);
+void subghz_test_static_free(SubGhzTestStatic* subghz_static);
 
 
-View* subghz_test_static_get_view(SubghzTestStatic* subghz_static);
+View* subghz_test_static_get_view(SubGhzTestStatic* subghz_static);

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

@@ -1,26 +0,0 @@
-#pragma once
-
-#include <gui/view.h>
-#include "../helpers/subghz_custom_event.h"
-
-typedef struct SubghzTransmitter SubghzTransmitter;
-
-typedef void (*SubghzTransmitterCallback)(SubghzCustomEvent event, void* context);
-
-void subghz_transmitter_set_callback(
-    SubghzTransmitter* subghz_transmitter,
-    SubghzTransmitterCallback callback,
-    void* context);
-
-SubghzTransmitter* subghz_transmitter_alloc();
-
-void subghz_transmitter_free(SubghzTransmitter* subghz_transmitter);
-
-View* subghz_transmitter_get_view(SubghzTransmitter* subghz_transmitter);
-
-void subghz_transmitter_add_data_to_show(
-    SubghzTransmitter* subghz_transmitter,
-    const char* key_str,
-    const char* frequency_str,
-    const char* preset_str,
-    uint8_t show_button);

+ 33 - 34
applications/subghz/views/subghz_transmitter.c → applications/subghz/views/transmitter.c

@@ -1,12 +1,12 @@
-#include "subghz_transmitter.h"
+#include "transmitter.h"
 #include "../subghz_i.h"
 #include "../subghz_i.h"
 
 
 #include <input/input.h>
 #include <input/input.h>
 #include <gui/elements.h>
 #include <gui/elements.h>
 
 
-struct SubghzTransmitter {
+struct SubGhzViewTransmitter {
     View* view;
     View* view;
-    SubghzTransmitterCallback callback;
+    SubGhzViewTransmitterCallback callback;
     void* context;
     void* context;
 };
 };
 
 
@@ -15,11 +15,11 @@ typedef struct {
     string_t preset_str;
     string_t preset_str;
     string_t key_str;
     string_t key_str;
     uint8_t show_button;
     uint8_t show_button;
-} SubghzTransmitterModel;
+} SubGhzViewTransmitterModel;
 
 
-void subghz_transmitter_set_callback(
-    SubghzTransmitter* subghz_transmitter,
-    SubghzTransmitterCallback callback,
+void subghz_view_transmitter_set_callback(
+    SubGhzViewTransmitter* subghz_transmitter,
+    SubGhzViewTransmitterCallback callback,
     void* context) {
     void* context) {
     furi_assert(subghz_transmitter);
     furi_assert(subghz_transmitter);
 
 
@@ -27,15 +27,15 @@ void subghz_transmitter_set_callback(
     subghz_transmitter->context = context;
     subghz_transmitter->context = context;
 }
 }
 
 
-void subghz_transmitter_add_data_to_show(
-    SubghzTransmitter* subghz_transmitter,
+void subghz_view_transmitter_add_data_to_show(
+    SubGhzViewTransmitter* subghz_transmitter,
     const char* key_str,
     const char* key_str,
     const char* frequency_str,
     const char* frequency_str,
     const char* preset_str,
     const char* preset_str,
     uint8_t show_button) {
     uint8_t show_button) {
     furi_assert(subghz_transmitter);
     furi_assert(subghz_transmitter);
     with_view_model(
     with_view_model(
-        subghz_transmitter->view, (SubghzTransmitterModel * model) {
+        subghz_transmitter->view, (SubGhzViewTransmitterModel * model) {
             string_set(model->key_str, key_str);
             string_set(model->key_str, key_str);
             string_set(model->frequency_str, frequency_str);
             string_set(model->frequency_str, frequency_str);
             string_set(model->preset_str, preset_str);
             string_set(model->preset_str, preset_str);
@@ -44,7 +44,7 @@ void subghz_transmitter_add_data_to_show(
         });
         });
 }
 }
 
 
-static void subghz_transmitter_button_right(Canvas* canvas, const char* str) {
+static void subghz_view_transmitter_button_right(Canvas* canvas, const char* str) {
     const uint8_t button_height = 13;
     const uint8_t button_height = 13;
     const uint8_t vertical_offset = 3;
     const uint8_t vertical_offset = 3;
     const uint8_t horizontal_offset = 1;
     const uint8_t horizontal_offset = 1;
@@ -75,24 +75,24 @@ static void subghz_transmitter_button_right(Canvas* canvas, const char* str) {
     canvas_invert_color(canvas);
     canvas_invert_color(canvas);
 }
 }
 
 
-void subghz_transmitter_draw(Canvas* canvas, SubghzTransmitterModel* model) {
+void subghz_view_transmitter_draw(Canvas* canvas, SubGhzViewTransmitterModel* model) {
     canvas_clear(canvas);
     canvas_clear(canvas);
     canvas_set_color(canvas, ColorBlack);
     canvas_set_color(canvas, ColorBlack);
     canvas_set_font(canvas, FontSecondary);
     canvas_set_font(canvas, FontSecondary);
     elements_multiline_text(canvas, 0, 8, string_get_cstr(model->key_str));
     elements_multiline_text(canvas, 0, 8, string_get_cstr(model->key_str));
     canvas_draw_str(canvas, 78, 8, string_get_cstr(model->frequency_str));
     canvas_draw_str(canvas, 78, 8, string_get_cstr(model->frequency_str));
     canvas_draw_str(canvas, 113, 8, string_get_cstr(model->preset_str));
     canvas_draw_str(canvas, 113, 8, string_get_cstr(model->preset_str));
-    if(model->show_button) subghz_transmitter_button_right(canvas, "Send");
+    if(model->show_button) subghz_view_transmitter_button_right(canvas, "Send");
 }
 }
 
 
-bool subghz_transmitter_input(InputEvent* event, void* context) {
+bool subghz_view_transmitter_input(InputEvent* event, void* context) {
     furi_assert(context);
     furi_assert(context);
-    SubghzTransmitter* subghz_transmitter = context;
+    SubGhzViewTransmitter* subghz_transmitter = context;
     bool can_be_sent = false;
     bool can_be_sent = false;
 
 
     if(event->key == InputKeyBack && event->type == InputTypeShort) {
     if(event->key == InputKeyBack && event->type == InputTypeShort) {
         with_view_model(
         with_view_model(
-            subghz_transmitter->view, (SubghzTransmitterModel * model) {
+            subghz_transmitter->view, (SubGhzViewTransmitterModel * model) {
                 string_reset(model->frequency_str);
                 string_reset(model->frequency_str);
                 string_reset(model->preset_str);
                 string_reset(model->preset_str);
                 string_reset(model->key_str);
                 string_reset(model->key_str);
@@ -103,7 +103,7 @@ bool subghz_transmitter_input(InputEvent* event, void* context) {
     }
     }
 
 
     with_view_model(
     with_view_model(
-        subghz_transmitter->view, (SubghzTransmitterModel * model) {
+        subghz_transmitter->view, (SubGhzViewTransmitterModel * model) {
             if(model->show_button) {
             if(model->show_button) {
                 can_be_sent = true;
                 can_be_sent = true;
             }
             }
@@ -112,42 +112,41 @@ bool subghz_transmitter_input(InputEvent* event, void* context) {
 
 
     if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) {
     if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) {
         subghz_transmitter->callback(
         subghz_transmitter->callback(
-            SubghzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
+            SubGhzCustomEventViewTransmitterSendStart, subghz_transmitter->context);
         return true;
         return true;
     } else if(can_be_sent && event->key == InputKeyOk && event->type == InputTypeRelease) {
     } else if(can_be_sent && event->key == InputKeyOk && event->type == InputTypeRelease) {
         subghz_transmitter->callback(
         subghz_transmitter->callback(
-            SubghzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
+            SubGhzCustomEventViewTransmitterSendStop, subghz_transmitter->context);
         return true;
         return true;
     }
     }
 
 
     return true;
     return true;
 }
 }
 
 
-void subghz_transmitter_enter(void* context) {
+void subghz_view_transmitter_enter(void* context) {
     furi_assert(context);
     furi_assert(context);
-    // SubghzTransmitter* subghz_transmitter = context;
 }
 }
 
 
-void subghz_transmitter_exit(void* context) {
+void subghz_view_transmitter_exit(void* context) {
     furi_assert(context);
     furi_assert(context);
-    // SubghzTransmitter* subghz_transmitter = context;
 }
 }
 
 
-SubghzTransmitter* subghz_transmitter_alloc() {
-    SubghzTransmitter* subghz_transmitter = malloc(sizeof(SubghzTransmitter));
+SubGhzViewTransmitter* subghz_view_transmitter_alloc() {
+    SubGhzViewTransmitter* subghz_transmitter = malloc(sizeof(SubGhzViewTransmitter));
 
 
     // View allocation and configuration
     // View allocation and configuration
     subghz_transmitter->view = view_alloc();
     subghz_transmitter->view = view_alloc();
     view_allocate_model(
     view_allocate_model(
-        subghz_transmitter->view, ViewModelTypeLocking, sizeof(SubghzTransmitterModel));
+        subghz_transmitter->view, ViewModelTypeLocking, sizeof(SubGhzViewTransmitterModel));
     view_set_context(subghz_transmitter->view, subghz_transmitter);
     view_set_context(subghz_transmitter->view, subghz_transmitter);
-    view_set_draw_callback(subghz_transmitter->view, (ViewDrawCallback)subghz_transmitter_draw);
-    view_set_input_callback(subghz_transmitter->view, subghz_transmitter_input);
-    view_set_enter_callback(subghz_transmitter->view, subghz_transmitter_enter);
-    view_set_exit_callback(subghz_transmitter->view, subghz_transmitter_exit);
+    view_set_draw_callback(
+        subghz_transmitter->view, (ViewDrawCallback)subghz_view_transmitter_draw);
+    view_set_input_callback(subghz_transmitter->view, subghz_view_transmitter_input);
+    view_set_enter_callback(subghz_transmitter->view, subghz_view_transmitter_enter);
+    view_set_exit_callback(subghz_transmitter->view, subghz_view_transmitter_exit);
 
 
     with_view_model(
     with_view_model(
-        subghz_transmitter->view, (SubghzTransmitterModel * model) {
+        subghz_transmitter->view, (SubGhzViewTransmitterModel * model) {
             string_init(model->frequency_str);
             string_init(model->frequency_str);
             string_init(model->preset_str);
             string_init(model->preset_str);
             string_init(model->key_str);
             string_init(model->key_str);
@@ -156,11 +155,11 @@ SubghzTransmitter* subghz_transmitter_alloc() {
     return subghz_transmitter;
     return subghz_transmitter;
 }
 }
 
 
-void subghz_transmitter_free(SubghzTransmitter* subghz_transmitter) {
+void subghz_view_transmitter_free(SubGhzViewTransmitter* subghz_transmitter) {
     furi_assert(subghz_transmitter);
     furi_assert(subghz_transmitter);
 
 
     with_view_model(
     with_view_model(
-        subghz_transmitter->view, (SubghzTransmitterModel * model) {
+        subghz_transmitter->view, (SubGhzViewTransmitterModel * model) {
             string_clear(model->frequency_str);
             string_clear(model->frequency_str);
             string_clear(model->preset_str);
             string_clear(model->preset_str);
             string_clear(model->key_str);
             string_clear(model->key_str);
@@ -170,7 +169,7 @@ void subghz_transmitter_free(SubghzTransmitter* subghz_transmitter) {
     free(subghz_transmitter);
     free(subghz_transmitter);
 }
 }
 
 
-View* subghz_transmitter_get_view(SubghzTransmitter* subghz_transmitter) {
+View* subghz_view_transmitter_get_view(SubGhzViewTransmitter* subghz_transmitter) {
     furi_assert(subghz_transmitter);
     furi_assert(subghz_transmitter);
     return subghz_transmitter->view;
     return subghz_transmitter->view;
 }
 }

+ 26 - 0
applications/subghz/views/transmitter.h

@@ -0,0 +1,26 @@
+#pragma once
+
+#include <gui/view.h>
+#include "../helpers/subghz_custom_event.h"
+
+typedef struct SubGhzViewTransmitter SubGhzViewTransmitter;
+
+typedef void (*SubGhzViewTransmitterCallback)(SubGhzCustomEvent event, void* context);
+
+void subghz_view_transmitter_set_callback(
+    SubGhzViewTransmitter* subghz_transmitter,
+    SubGhzViewTransmitterCallback callback,
+    void* context);
+
+SubGhzViewTransmitter* subghz_view_transmitter_alloc();
+
+void subghz_view_transmitter_free(SubGhzViewTransmitter* subghz_transmitter);
+
+View* subghz_view_transmitter_get_view(SubGhzViewTransmitter* subghz_transmitter);
+
+void subghz_view_transmitter_add_data_to_show(
+    SubGhzViewTransmitter* subghz_transmitter,
+    const char* key_str,
+    const char* frequency_str,
+    const char* preset_str,
+    uint8_t show_button);

Разлика између датотеке није приказан због своје велике величине
+ 0 - 5
assets/resources/subghz/assets/nice_flor_s_rx


Разлика између датотеке није приказан због своје велике величине
+ 0 - 5
assets/resources/subghz/assets/nice_flor_s_tx


+ 6 - 0
assets/resources/subghz/nice_flor_s

@@ -0,0 +1,6 @@
+Filetype: Flipper SubGhz Keystore RAW File
+Version: 0
+Encryption: 1
+IV: 33 69 62 1D AD 20 1B B8 A1 6C CF 6F 6B 6F D5 18
+Encrypt_data: RAW
+9C1D6E6733912B28AC0FF1A191660810BDFF00D19BF7839AFF5B2AAFBBC91A38

+ 3 - 2
bootloader/Makefile

@@ -1,5 +1,6 @@
-PROJECT_ROOT	= $(abspath $(dir $(abspath $(firstword $(MAKEFILE_LIST))))..)
-PROJECT			= bootloader
+MAKEFILE_DIR	:= $(dir $(abspath $(firstword $(MAKEFILE_LIST))))
+PROJECT_ROOT	:= $(abspath $(MAKEFILE_DIR)/..)
+PROJECT			:= bootloader
 
 
 include 		$(PROJECT_ROOT)/make/base.mk
 include 		$(PROJECT_ROOT)/make/base.mk
 
 

+ 3 - 2
firmware/Makefile

@@ -1,5 +1,6 @@
-PROJECT_ROOT	= $(abspath $(dir $(abspath $(firstword $(MAKEFILE_LIST))))..)
-PROJECT			= firmware
+MAKEFILE_DIR	:= $(dir $(abspath $(firstword $(MAKEFILE_LIST))))
+PROJECT_ROOT	:= $(abspath $(MAKEFILE_DIR)/..)
+PROJECT			:= firmware
 
 
 include 		$(PROJECT_ROOT)/make/base.mk
 include 		$(PROJECT_ROOT)/make/base.mk
 include 		$(PROJECT_ROOT)/make/freertos-heap.mk
 include 		$(PROJECT_ROOT)/make/freertos-heap.mk

+ 1 - 1
lib/ReadMe.md

@@ -20,6 +20,6 @@
 - `qrcode`              - Qr code generator library
 - `qrcode`              - Qr code generator library
 - `ST25RFAL002`         - ST253916 driver and NFC hal
 - `ST25RFAL002`         - ST253916 driver and NFC hal
 - `STM32CubeWB`         - STM32WB series cube package
 - `STM32CubeWB`         - STM32WB series cube package
-- `subghz`              - Subghz library
+- `subghz`              - SubGhz library
 - `toolbox`             - Toolbox of things that we are using but don't place in core
 - `toolbox`             - Toolbox of things that we are using but don't place in core
 - `u8g2`                - Graphics library that we use to draw GUI
 - `u8g2`                - Graphics library that we use to draw GUI

+ 1 - 0
lib/subghz/blocks/const.c

@@ -0,0 +1 @@
+#include "const.h"

+ 12 - 0
lib/subghz/blocks/const.h

@@ -0,0 +1,12 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+
+typedef struct {
+    const uint16_t te_long;
+    const uint16_t te_short;
+    const uint16_t te_delta;
+    const uint8_t min_count_bit_for_found;
+} SubGhzBlockConst;

+ 17 - 0
lib/subghz/blocks/decoder.c

@@ -0,0 +1,17 @@
+#include "decoder.h"
+
+#define TAG "SubGhzBlockDecoder"
+
+void subghz_protocol_blocks_add_bit(SubGhzBlockDecoder* decoder, uint8_t bit) {
+    decoder->decode_data = decoder->decode_data << 1 | bit;
+    decoder->decode_count_bit++;
+}
+
+uint8_t subghz_protocol_blocks_get_hash_data(SubGhzBlockDecoder* decoder, size_t len) {
+    uint8_t hash = 0;
+    uint8_t* p = (uint8_t*)&decoder->decode_data;
+    for(size_t i = 0; i < len; i++) {
+        hash ^= p[i];
+    }
+    return hash;
+}

+ 17 - 0
lib/subghz/blocks/decoder.h

@@ -0,0 +1,17 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+
+typedef struct SubGhzBlockDecoder SubGhzBlockDecoder;
+
+struct SubGhzBlockDecoder {
+    uint32_t parser_step;
+    uint32_t te_last;
+    uint64_t decode_data;
+    uint8_t decode_count_bit;
+};
+
+void subghz_protocol_blocks_add_bit(SubGhzBlockDecoder* decoder, uint8_t bit);
+uint8_t subghz_protocol_blocks_get_hash_data(SubGhzBlockDecoder* decoder, size_t len);

+ 3 - 0
lib/subghz/blocks/encoder.c

@@ -0,0 +1,3 @@
+#include "encoder.h"
+
+#define TAG "SubGhzBlockEncoder"

+ 16 - 0
lib/subghz/blocks/encoder.h

@@ -0,0 +1,16 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#include <lib/toolbox/level_duration.h>
+
+typedef struct {
+    bool is_runing;
+    size_t repeat;
+    size_t front;
+    size_t size_upload;
+    LevelDuration* upload;
+
+} SubGhzProtocolBlockEncoder;

+ 118 - 0
lib/subghz/blocks/generic.c

@@ -0,0 +1,118 @@
+#include "generic.h"
+#include "../types.h"
+#include <lib/toolbox/stream/stream.h>
+#include <lib/flipper_format/flipper_format_i.h>
+
+#define TAG "SubGhzBlockGeneric"
+
+bool subghz_block_generic_get_preset_name(FuriHalSubGhzPreset preset, string_t preset_str) {
+    const char* preset_name;
+    switch(preset) {
+    case FuriHalSubGhzPresetOok270Async:
+        preset_name = "FuriHalSubGhzPresetOok270Async";
+        break;
+    case FuriHalSubGhzPresetOok650Async:
+        preset_name = "FuriHalSubGhzPresetOok650Async";
+        break;
+    case FuriHalSubGhzPreset2FSKDev238Async:
+        preset_name = "FuriHalSubGhzPreset2FSKDev238Async";
+        break;
+    case FuriHalSubGhzPreset2FSKDev476Async:
+        preset_name = "FuriHalSubGhzPreset2FSKDev476Async";
+        break;
+    default:
+        FURI_LOG_E(TAG, "Unknown preset");
+        return false;
+        break;
+    }
+    string_set(preset_str, preset_name);
+    return true;
+}
+
+bool subghz_block_generic_serialize(
+    SubGhzBlockGeneric* instance,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    furi_assert(instance);
+    bool res = false;
+    string_t temp_str;
+    string_init(temp_str);
+    do {
+        stream_clean(flipper_format_get_raw_stream(flipper_format));
+        if(!flipper_format_write_header_cstr(
+               flipper_format, SUBGHZ_KEY_FILE_TYPE, SUBGHZ_KEY_FILE_VERSION)) {
+            FURI_LOG_E(TAG, "Unable to add header");
+            break;
+        }
+
+        if(!flipper_format_write_uint32(flipper_format, "Frequency", &frequency, 1)) {
+            FURI_LOG_E(TAG, "Unable to add Frequency");
+            break;
+        }
+        if(!subghz_block_generic_get_preset_name(preset, temp_str)) {
+            break;
+        }
+        if(!flipper_format_write_string_cstr(flipper_format, "Preset", string_get_cstr(temp_str))) {
+            FURI_LOG_E(TAG, "Unable to add Preset");
+            break;
+        }
+        if(!flipper_format_write_string_cstr(flipper_format, "Protocol", instance->protocol_name)) {
+            FURI_LOG_E(TAG, "Unable to add Protocol");
+            break;
+        }
+        uint32_t temp = instance->data_count_bit;
+        if(!flipper_format_write_uint32(flipper_format, "Bit", &temp, 1)) {
+            FURI_LOG_E(TAG, "Unable to add Bit");
+            break;
+        }
+
+        uint8_t key_data[sizeof(uint64_t)] = {0};
+        for(size_t i = 0; i < sizeof(uint64_t); i++) {
+            key_data[sizeof(uint64_t) - i - 1] = (instance->data >> i * 8) & 0xFF;
+        }
+
+        if(!flipper_format_write_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) {
+            FURI_LOG_E(TAG, "Unable to add Key");
+            break;
+        }
+        res = true;
+    } while(false);
+    string_clear(temp_str);
+    return res;
+}
+
+bool subghz_block_generic_deserialize(SubGhzBlockGeneric* instance, FlipperFormat* flipper_format) {
+    furi_assert(instance);
+    bool res = false;
+    string_t temp_str;
+    string_init(temp_str);
+    uint32_t temp_data = 0;
+
+    do {
+        if(!flipper_format_rewind(flipper_format)) {
+            FURI_LOG_E(TAG, "Rewind error");
+            break;
+        }
+        if(!flipper_format_read_uint32(flipper_format, "Bit", (uint32_t*)&temp_data, 1)) {
+            FURI_LOG_E(TAG, "Missing Bit");
+            break;
+        }
+        instance->data_count_bit = (uint8_t)temp_data;
+
+        uint8_t key_data[sizeof(uint64_t)] = {0};
+        if(!flipper_format_read_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) {
+            FURI_LOG_E(TAG, "Missing Key");
+            break;
+        }
+        for(uint8_t i = 0; i < sizeof(uint64_t); i++) {
+            instance->data = instance->data << 8 | key_data[i];
+        }
+
+        res = true;
+    } while(0);
+
+    string_clear(temp_str);
+
+    return res;
+}

+ 30 - 0
lib/subghz/blocks/generic.h

@@ -0,0 +1,30 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#include <lib/flipper_format/flipper_format.h>
+#include "furi.h"
+#include "furi_hal.h"
+
+typedef struct SubGhzBlockGeneric SubGhzBlockGeneric;
+
+struct SubGhzBlockGeneric {
+    const char* protocol_name;
+    uint64_t data;
+    uint32_t serial;
+    uint8_t data_count_bit;
+    uint8_t btn;
+    uint16_t cnt;
+};
+
+bool subghz_block_generic_get_preset_name(FuriHalSubGhzPreset preset, string_t preset_str);
+
+bool subghz_block_generic_serialize(
+    SubGhzBlockGeneric* instance,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset);
+
+bool subghz_block_generic_deserialize(SubGhzBlockGeneric* instance, FlipperFormat* flipper_format);

+ 9 - 0
lib/subghz/blocks/math.c

@@ -0,0 +1,9 @@
+#include "math.h"
+
+uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t count_bit) {
+    uint64_t key_reverse = 0;
+    for(uint8_t i = 0; i < count_bit; i++) {
+        key_reverse = key_reverse << 1 | bit_read(key, i);
+    }
+    return key_reverse;
+}

+ 13 - 0
lib/subghz/blocks/math.h

@@ -0,0 +1,13 @@
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#define bit_read(value, bit) (((value) >> (bit)) & 0x01)
+#define bit_set(value, bit) ((value) |= (1UL << (bit)))
+#define bit_clear(value, bit) ((value) &= ~(1UL << (bit)))
+#define bit_write(value, bit, bitvalue) (bitvalue ? bit_set(value, bit) : bit_clear(value, bit))
+#define DURATION_DIFF(x, y) ((x < y) ? (y - x) : (x - y))
+
+uint64_t subghz_protocol_blocks_reverse_key(uint64_t key, uint8_t count_bit);

+ 67 - 0
lib/subghz/environment.c

@@ -0,0 +1,67 @@
+#include "environment.h"
+
+struct SubGhzEnvironment {
+    SubGhzKeystore* keystore;
+    const char* came_atomo_rainbow_table_file_name;
+    const char* nice_flor_s_rainbow_table_file_name;
+};
+
+SubGhzEnvironment* subghz_environment_alloc() {
+    SubGhzEnvironment* instance = malloc(sizeof(SubGhzEnvironment));
+
+    instance->keystore = subghz_keystore_alloc();
+    instance->came_atomo_rainbow_table_file_name = NULL;
+    instance->nice_flor_s_rainbow_table_file_name = NULL;
+
+    return instance;
+}
+
+void subghz_environment_free(SubGhzEnvironment* instance) {
+    furi_assert(instance);
+
+    subghz_keystore_free(instance->keystore);
+
+    free(instance);
+}
+
+bool subghz_environment_load_keystore(SubGhzEnvironment* instance, const char* filename) {
+    furi_assert(instance);
+
+    return subghz_keystore_load(instance->keystore, filename);
+}
+
+SubGhzKeystore* subghz_environment_get_keystore(SubGhzEnvironment* instance) {
+    furi_assert(instance);
+
+    return instance->keystore;
+}
+
+void subghz_environment_set_came_atomo_rainbow_table_file_name(
+    SubGhzEnvironment* instance,
+    const char* filename) {
+    furi_assert(instance);
+
+    instance->came_atomo_rainbow_table_file_name = filename;
+}
+
+const char*
+    subghz_environment_get_came_atomo_rainbow_table_file_name(SubGhzEnvironment* instance) {
+    furi_assert(instance);
+
+    return instance->came_atomo_rainbow_table_file_name;
+}
+
+void subghz_environment_set_nice_flor_s_rainbow_table_file_name(
+    SubGhzEnvironment* instance,
+    const char* filename) {
+    furi_assert(instance);
+
+    instance->nice_flor_s_rainbow_table_file_name = filename;
+}
+
+const char*
+    subghz_environment_get_nice_flor_s_rainbow_table_file_name(SubGhzEnvironment* instance) {
+    furi_assert(instance);
+
+    return instance->nice_flor_s_rainbow_table_file_name;
+}

+ 28 - 0
lib/subghz/environment.h

@@ -0,0 +1,28 @@
+#pragma once
+
+#include <furi.h>
+
+#include "subghz_keystore.h"
+
+typedef struct SubGhzEnvironment SubGhzEnvironment;
+
+SubGhzEnvironment* subghz_environment_alloc();
+
+void subghz_environment_free(SubGhzEnvironment* instance);
+
+bool subghz_environment_load_keystore(SubGhzEnvironment* instance, const char* filename);
+
+SubGhzKeystore* subghz_environment_get_keystore(SubGhzEnvironment* instance);
+
+void subghz_environment_set_came_atomo_rainbow_table_file_name(
+    SubGhzEnvironment* instance,
+    const char* filename);
+
+const char* subghz_environment_get_came_atomo_rainbow_table_file_name(SubGhzEnvironment* instance);
+
+void subghz_environment_set_nice_flor_s_rainbow_table_file_name(
+    SubGhzEnvironment* instance,
+    const char* filename);
+
+const char*
+    subghz_environment_get_nice_flor_s_rainbow_table_file_name(SubGhzEnvironment* instance);

+ 64 - 0
lib/subghz/protocols/base.c

@@ -0,0 +1,64 @@
+#include "base.h"
+#include "registry.h"
+
+void subghz_protocol_decoder_base_set_decoder_callback(
+    SubGhzProtocolDecoderBase* decoder_base,
+    SubGhzProtocolDecoderBaseRxCallback callback,
+    void* context) {
+    decoder_base->callback = callback;
+    decoder_base->context = context;
+}
+
+bool subghz_protocol_decoder_base_get_string(
+    SubGhzProtocolDecoderBase* decoder_base,
+    string_t output) {
+    bool status = false;
+
+    if(decoder_base->protocol && decoder_base->protocol->decoder &&
+       decoder_base->protocol->decoder->get_string) {
+        decoder_base->protocol->decoder->get_string(decoder_base, output);
+        status = true;
+    }
+
+    return status;
+}
+
+bool subghz_protocol_decoder_base_serialize(
+    SubGhzProtocolDecoderBase* decoder_base,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    bool status = false;
+
+    if(decoder_base->protocol && decoder_base->protocol->decoder &&
+       decoder_base->protocol->decoder->serialize) {
+        status = decoder_base->protocol->decoder->serialize(
+            decoder_base, flipper_format, frequency, preset);
+    }
+
+    return status;
+}
+
+bool subghz_protocol_decoder_base_deserialize(
+    SubGhzProtocolDecoderBase* decoder_base,
+    FlipperFormat* flipper_format) {
+    bool status = false;
+
+    if(decoder_base->protocol && decoder_base->protocol->decoder &&
+       decoder_base->protocol->decoder->deserialize) {
+        status = decoder_base->protocol->decoder->deserialize(decoder_base, flipper_format);
+    }
+
+    return status;
+}
+
+uint8_t subghz_protocol_decoder_base_get_hash_data(SubGhzProtocolDecoderBase* decoder_base) {
+    uint8_t hash = 0;
+
+    if(decoder_base->protocol && decoder_base->protocol->decoder &&
+       decoder_base->protocol->decoder->get_hash_data) {
+        hash = decoder_base->protocol->decoder->get_hash_data(decoder_base);
+    }
+
+    return hash;
+}

+ 51 - 0
lib/subghz/protocols/base.h

@@ -0,0 +1,51 @@
+#pragma once
+
+#include "../types.h"
+
+typedef struct SubGhzProtocolDecoderBase SubGhzProtocolDecoderBase;
+
+typedef void (
+    *SubGhzProtocolDecoderBaseRxCallback)(SubGhzProtocolDecoderBase* instance, void* context);
+
+typedef void (
+    *SubGhzProtocolDecoderBaseSerialize)(SubGhzProtocolDecoderBase* decoder_base, string_t output);
+
+struct SubGhzProtocolDecoderBase {
+    // Decoder general section
+    const SubGhzProtocol* protocol;
+
+    // Callback section
+    SubGhzProtocolDecoderBaseRxCallback callback;
+    void* context;
+};
+
+void subghz_protocol_decoder_base_set_decoder_callback(
+    SubGhzProtocolDecoderBase* decoder_base,
+    SubGhzProtocolDecoderBaseRxCallback callback,
+    void* context);
+
+bool subghz_protocol_decoder_base_get_string(
+    SubGhzProtocolDecoderBase* decoder_base,
+    string_t output);
+
+bool subghz_protocol_decoder_base_serialize(
+    SubGhzProtocolDecoderBase* decoder_base,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset);
+
+bool subghz_protocol_decoder_base_deserialize(
+    SubGhzProtocolDecoderBase* decoder_base,
+    FlipperFormat* flipper_format);
+
+uint8_t subghz_protocol_decoder_base_get_hash_data(SubGhzProtocolDecoderBase* decoder_base);
+
+// Encoder Base
+typedef struct SubGhzProtocolEncoderBase SubGhzProtocolEncoderBase;
+
+struct SubGhzProtocolEncoderBase {
+    // Decoder general section
+    const SubGhzProtocol* protocol;
+
+    // Callback section
+};

+ 313 - 0
lib/subghz/protocols/came.c

@@ -0,0 +1,313 @@
+#include "came.h"
+
+#include "../blocks/const.h"
+#include "../blocks/decoder.h"
+#include "../blocks/encoder.h"
+#include "../blocks/generic.h"
+#include "../blocks/math.h"
+
+/*
+ * Help
+ * https://phreakerclub.com/447
+ *
+ */
+
+#define TAG "SubGhzProtocolCAME"
+
+static const SubGhzBlockConst subghz_protocol_came_const = {
+    .te_short = 320,
+    .te_long = 640,
+    .te_delta = 150,
+    .min_count_bit_for_found = 12,
+};
+
+struct SubGhzProtocolDecoderCame {
+    SubGhzProtocolDecoderBase base;
+
+    SubGhzBlockDecoder decoder;
+    SubGhzBlockGeneric generic;
+};
+
+struct SubGhzProtocolEncoderCame {
+    SubGhzProtocolEncoderBase base;
+
+    SubGhzProtocolBlockEncoder encoder;
+    SubGhzBlockGeneric generic;
+};
+
+typedef enum {
+    CameDecoderStepReset = 0,
+    CameDecoderStepFoundStartBit,
+    CameDecoderStepSaveDuration,
+    CameDecoderStepCheckDuration,
+} CameDecoderStep;
+
+const SubGhzProtocolDecoder subghz_protocol_came_decoder = {
+    .alloc = subghz_protocol_decoder_came_alloc,
+    .free = subghz_protocol_decoder_came_free,
+
+    .feed = subghz_protocol_decoder_came_feed,
+    .reset = subghz_protocol_decoder_came_reset,
+
+    .get_hash_data = subghz_protocol_decoder_came_get_hash_data,
+    .serialize = subghz_protocol_decoder_came_serialize,
+    .deserialize = subghz_protocol_decoder_came_deserialize,
+    .get_string = subghz_protocol_decoder_came_get_string,
+};
+
+const SubGhzProtocolEncoder subghz_protocol_came_encoder = {
+    .alloc = subghz_protocol_encoder_came_alloc,
+    .free = subghz_protocol_encoder_came_free,
+
+    .deserialize = subghz_protocol_encoder_came_deserialize,
+    .stop = subghz_protocol_encoder_came_stop,
+    .yield = subghz_protocol_encoder_came_yield,
+};
+
+const SubGhzProtocol subghz_protocol_came = {
+    .name = SUBGHZ_PROTOCOL_CAME_NAME,
+    .type = SubGhzProtocolTypeStatic,
+    .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_AM |
+            SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save |
+            SubGhzProtocolFlag_Send,
+
+    .decoder = &subghz_protocol_came_decoder,
+    .encoder = &subghz_protocol_came_encoder,
+};
+
+void* subghz_protocol_encoder_came_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolEncoderCame* instance = malloc(sizeof(SubGhzProtocolEncoderCame));
+
+    instance->base.protocol = &subghz_protocol_came;
+    instance->generic.protocol_name = instance->base.protocol->name;
+
+    instance->encoder.repeat = 10;
+    instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop)
+    instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
+    instance->encoder.is_runing = false;
+    return instance;
+}
+
+void subghz_protocol_encoder_came_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolEncoderCame* instance = context;
+    free(instance->encoder.upload);
+    free(instance);
+}
+
+static bool subghz_protocol_encoder_came_get_upload(SubGhzProtocolEncoderCame* instance) {
+    furi_assert(instance);
+    size_t index = 0;
+    size_t size_upload = (instance->generic.data_count_bit * 2) + 2;
+    if(size_upload > instance->encoder.size_upload) {
+        FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
+        return false;
+    } else {
+        instance->encoder.size_upload = size_upload;
+    }
+    //Send header
+    instance->encoder.upload[index++] =
+        level_duration_make(false, (uint32_t)subghz_protocol_came_const.te_short * 36);
+    //Send start bit
+    instance->encoder.upload[index++] =
+        level_duration_make(true, (uint32_t)subghz_protocol_came_const.te_short);
+    //Send key data
+    for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
+        if(bit_read(instance->generic.data, i - 1)) {
+            //send bit 1
+            instance->encoder.upload[index++] =
+                level_duration_make(false, (uint32_t)subghz_protocol_came_const.te_long);
+            instance->encoder.upload[index++] =
+                level_duration_make(true, (uint32_t)subghz_protocol_came_const.te_short);
+        } else {
+            //send bit 0
+            instance->encoder.upload[index++] =
+                level_duration_make(false, (uint32_t)subghz_protocol_came_const.te_short);
+            instance->encoder.upload[index++] =
+                level_duration_make(true, (uint32_t)subghz_protocol_came_const.te_long);
+        }
+    }
+    return true;
+}
+
+bool subghz_protocol_encoder_came_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolEncoderCame* instance = context;
+    bool res = false;
+    do {
+        if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
+            FURI_LOG_E(TAG, "Deserialize error");
+            break;
+        }
+
+        //optional parameter parameter
+        flipper_format_read_uint32(
+            flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
+
+        subghz_protocol_encoder_came_get_upload(instance);
+        instance->encoder.is_runing = true;
+
+        res = true;
+    } while(false);
+
+    return res;
+}
+
+void subghz_protocol_encoder_came_stop(void* context) {
+    SubGhzProtocolEncoderCame* instance = context;
+    instance->encoder.is_runing = false;
+}
+
+LevelDuration subghz_protocol_encoder_came_yield(void* context) {
+    SubGhzProtocolEncoderCame* instance = context;
+
+    if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) {
+        instance->encoder.is_runing = false;
+        return level_duration_reset();
+    }
+
+    LevelDuration ret = instance->encoder.upload[instance->encoder.front];
+
+    if(++instance->encoder.front == instance->encoder.size_upload) {
+        instance->encoder.repeat--;
+        instance->encoder.front = 0;
+    }
+
+    return ret;
+}
+
+void* subghz_protocol_decoder_came_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolDecoderCame* instance = malloc(sizeof(SubGhzProtocolDecoderCame));
+    instance->base.protocol = &subghz_protocol_came;
+    instance->generic.protocol_name = instance->base.protocol->name;
+    return instance;
+}
+
+void subghz_protocol_decoder_came_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCame* instance = context;
+    free(instance);
+}
+
+void subghz_protocol_decoder_came_reset(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCame* instance = context;
+    instance->decoder.parser_step = CameDecoderStepReset;
+}
+
+void subghz_protocol_decoder_came_feed(void* context, bool level, uint32_t duration) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCame* instance = context;
+    switch(instance->decoder.parser_step) {
+    case CameDecoderStepReset:
+        if((!level) && (DURATION_DIFF(duration, subghz_protocol_came_const.te_short * 51) <
+                        subghz_protocol_came_const.te_delta * 51)) { //Need protocol 36 te_short
+            //Found header CAME
+            instance->decoder.parser_step = CameDecoderStepFoundStartBit;
+        }
+        break;
+    case CameDecoderStepFoundStartBit:
+        if(!level) {
+            break;
+        } else if(
+            DURATION_DIFF(duration, subghz_protocol_came_const.te_short) <
+            subghz_protocol_came_const.te_delta) {
+            //Found start bit CAME
+            instance->decoder.parser_step = CameDecoderStepSaveDuration;
+            instance->decoder.decode_data = 0;
+            instance->decoder.decode_count_bit = 0;
+        } else {
+            instance->decoder.parser_step = CameDecoderStepReset;
+        }
+        break;
+    case CameDecoderStepSaveDuration:
+        if(!level) { //save interval
+            if(duration >= (subghz_protocol_came_const.te_short * 4)) {
+                instance->decoder.parser_step = CameDecoderStepFoundStartBit;
+                if(instance->decoder.decode_count_bit >=
+                   subghz_protocol_came_const.min_count_bit_for_found) {
+                    instance->generic.serial = 0x0;
+                    instance->generic.btn = 0x0;
+
+                    instance->generic.data = instance->decoder.decode_data;
+                    instance->generic.data_count_bit = instance->decoder.decode_count_bit;
+
+                    if(instance->base.callback)
+                        instance->base.callback(&instance->base, instance->base.context);
+                }
+                break;
+            }
+            instance->decoder.te_last = duration;
+            instance->decoder.parser_step = CameDecoderStepCheckDuration;
+        } else {
+            instance->decoder.parser_step = CameDecoderStepReset;
+        }
+        break;
+    case CameDecoderStepCheckDuration:
+        if(level) {
+            if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_came_const.te_short) <
+                subghz_protocol_came_const.te_delta) &&
+               (DURATION_DIFF(duration, subghz_protocol_came_const.te_long) <
+                subghz_protocol_came_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 0);
+                instance->decoder.parser_step = CameDecoderStepSaveDuration;
+            } else if(
+                (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_came_const.te_long) <
+                 subghz_protocol_came_const.te_delta) &&
+                (DURATION_DIFF(duration, subghz_protocol_came_const.te_short) <
+                 subghz_protocol_came_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 1);
+                instance->decoder.parser_step = CameDecoderStepSaveDuration;
+            } else
+                instance->decoder.parser_step = CameDecoderStepReset;
+        } else {
+            instance->decoder.parser_step = CameDecoderStepReset;
+        }
+        break;
+    }
+}
+
+uint8_t subghz_protocol_decoder_came_get_hash_data(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCame* instance = context;
+    return subghz_protocol_blocks_get_hash_data(
+        &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
+}
+
+bool subghz_protocol_decoder_came_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCame* instance = context;
+    return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
+}
+
+bool subghz_protocol_decoder_came_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCame* instance = context;
+    return subghz_block_generic_deserialize(&instance->generic, flipper_format);
+}
+
+void subghz_protocol_decoder_came_get_string(void* context, string_t output) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCame* instance = context;
+
+    uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
+
+    uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key(
+        instance->generic.data, instance->generic.data_count_bit);
+
+    uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
+
+    string_cat_printf(
+        output,
+        "%s %dbit\r\n"
+        "Key:0x%08lX\r\n"
+        "Yek:0x%08lX\r\n",
+        instance->generic.protocol_name,
+        instance->generic.data_count_bit,
+        code_found_lo,
+        code_found_reverse_lo);
+}

+ 63 - 0
lib/subghz/protocols/came.h

@@ -0,0 +1,63 @@
+#pragma once
+
+#include "base.h"
+
+#define SUBGHZ_PROTOCOL_CAME_NAME "CAME"
+
+typedef struct SubGhzProtocolDecoderCame SubGhzProtocolDecoderCame;
+typedef struct SubGhzProtocolEncoderCame SubGhzProtocolEncoderCame;
+
+extern const SubGhzProtocolDecoder subghz_protocol_came_decoder;
+extern const SubGhzProtocolEncoder subghz_protocol_came_encoder;
+extern const SubGhzProtocol subghz_protocol_came;
+
+void* subghz_protocol_encoder_came_alloc(SubGhzEnvironment* environment);
+
+void subghz_protocol_encoder_came_free(void* context);
+
+bool subghz_protocol_encoder_came_deserialize(void* context, FlipperFormat* flipper_format);
+
+void subghz_protocol_encoder_came_stop(void* context);
+
+LevelDuration subghz_protocol_encoder_came_yield(void* context);
+
+/** Allocate SubGhzProtocolCame
+ * 
+ * @return SubGhzProtocolCame* 
+ */
+void* subghz_protocol_decoder_came_alloc(SubGhzEnvironment* environment);
+
+/** Free SubGhzProtocolCame
+ * 
+ * @param instance 
+ */
+void subghz_protocol_decoder_came_free(void* context);
+
+/** Reset internal state
+ * @param instance - SubGhzProtocolCame instance
+ */
+void subghz_protocol_decoder_came_reset(void* context);
+
+/** Parse accepted duration
+ * 
+ * @param instance - SubGhzProtocolCame instance
+ * @param data - LevelDuration level_duration
+ */
+void subghz_protocol_decoder_came_feed(void* context, bool level, uint32_t duration);
+
+uint8_t subghz_protocol_decoder_came_get_hash_data(void* context);
+
+/** Outputting information from the parser
+ * 
+ * @param instance - SubGhzProtocolCame* instance
+ * @param output   - output string
+ */
+bool subghz_protocol_decoder_came_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset);
+
+bool subghz_protocol_decoder_came_deserialize(void* context, FlipperFormat* flipper_format);
+
+void subghz_protocol_decoder_came_get_string(void* context, string_t output);

+ 338 - 0
lib/subghz/protocols/came_atomo.c

@@ -0,0 +1,338 @@
+#include "came_atomo.h"
+#include <lib/toolbox/manchester_decoder.h>
+#include "../blocks/const.h"
+#include "../blocks/decoder.h"
+#include "../blocks/encoder.h"
+#include "../blocks/generic.h"
+#include "../blocks/math.h"
+
+#define TAG "SubGhzProtocoCameAtomo"
+
+#define SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE 0xFFFFFFFFFFFFFFFF
+
+static const SubGhzBlockConst subghz_protocol_came_atomo_const = {
+    .te_short = 600,
+    .te_long = 1200,
+    .te_delta = 250,
+    .min_count_bit_for_found = 62,
+};
+
+struct SubGhzProtocolDecoderCameAtomo {
+    SubGhzProtocolDecoderBase base;
+
+    SubGhzBlockDecoder decoder;
+    SubGhzBlockGeneric generic;
+
+    ManchesterState manchester_saved_state;
+    const char* came_atomo_rainbow_table_file_name;
+};
+
+struct SubGhzProtocolEncoderCameAtomo {
+    SubGhzProtocolEncoderBase base;
+
+    SubGhzProtocolBlockEncoder encoder;
+    SubGhzBlockGeneric generic;
+};
+
+typedef enum {
+    CameAtomoDecoderStepReset = 0,
+    CameAtomoDecoderStepDecoderData,
+} CameAtomoDecoderStep;
+
+const SubGhzProtocolDecoder subghz_protocol_came_atomo_decoder = {
+    .alloc = subghz_protocol_decoder_came_atomo_alloc,
+    .free = subghz_protocol_decoder_came_atomo_free,
+
+    .feed = subghz_protocol_decoder_came_atomo_feed,
+    .reset = subghz_protocol_decoder_came_atomo_reset,
+
+    .get_hash_data = subghz_protocol_decoder_came_atomo_get_hash_data,
+    .serialize = subghz_protocol_decoder_came_atomo_serialize,
+    .deserialize = subghz_protocol_decoder_came_atomo_deserialize,
+    .get_string = subghz_protocol_decoder_came_atomo_get_string,
+};
+
+const SubGhzProtocolEncoder subghz_protocol_came_atomo_encoder = {
+    .alloc = NULL,
+    .free = NULL,
+
+    .deserialize = NULL,
+    .stop = NULL,
+    .yield = NULL,
+};
+
+const SubGhzProtocol subghz_protocol_came_atomo = {
+    .name = SUBGHZ_PROTOCOL_CAME_ATOMO_NAME,
+    .type = SubGhzProtocolTypeDynamic,
+    .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
+
+    .decoder = &subghz_protocol_came_atomo_decoder,
+    .encoder = &subghz_protocol_came_atomo_encoder,
+};
+
+void* subghz_protocol_decoder_came_atomo_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolDecoderCameAtomo* instance = malloc(sizeof(SubGhzProtocolDecoderCameAtomo));
+    instance->base.protocol = &subghz_protocol_came_atomo;
+    instance->generic.protocol_name = instance->base.protocol->name;
+    instance->came_atomo_rainbow_table_file_name =
+        subghz_environment_get_came_atomo_rainbow_table_file_name(environment);
+    if(instance->came_atomo_rainbow_table_file_name) {
+        FURI_LOG_I(
+            TAG, "Loading rainbow table from %s", instance->came_atomo_rainbow_table_file_name);
+    }
+    return instance;
+}
+
+void subghz_protocol_decoder_came_atomo_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCameAtomo* instance = context;
+    instance->came_atomo_rainbow_table_file_name = NULL;
+    free(instance);
+}
+
+void subghz_protocol_decoder_came_atomo_reset(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCameAtomo* instance = context;
+    instance->decoder.parser_step = CameAtomoDecoderStepReset;
+    manchester_advance(
+        instance->manchester_saved_state,
+        ManchesterEventReset,
+        &instance->manchester_saved_state,
+        NULL);
+}
+
+void subghz_protocol_decoder_came_atomo_feed(void* context, bool level, uint32_t duration) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCameAtomo* instance = context;
+
+    ManchesterEvent event = ManchesterEventReset;
+    switch(instance->decoder.parser_step) {
+    case CameAtomoDecoderStepReset:
+        if((!level) && (DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_long * 65) <
+                        subghz_protocol_came_atomo_const.te_delta * 20)) {
+            //Found header CAME
+            instance->decoder.parser_step = CameAtomoDecoderStepDecoderData;
+            instance->decoder.decode_data = 0;
+            instance->decoder.decode_count_bit = 1;
+            manchester_advance(
+                instance->manchester_saved_state,
+                ManchesterEventReset,
+                &instance->manchester_saved_state,
+                NULL);
+            manchester_advance(
+                instance->manchester_saved_state,
+                ManchesterEventShortLow,
+                &instance->manchester_saved_state,
+                NULL);
+        }
+        break;
+    case CameAtomoDecoderStepDecoderData:
+        if(!level) {
+            if(DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_short) <
+               subghz_protocol_came_atomo_const.te_delta) {
+                event = ManchesterEventShortLow;
+            } else if(
+                DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_long) <
+                subghz_protocol_came_atomo_const.te_delta) {
+                event = ManchesterEventLongLow;
+            } else if(
+                duration >= (subghz_protocol_came_atomo_const.te_long * 2 +
+                             subghz_protocol_came_atomo_const.te_delta)) {
+                if(instance->decoder.decode_count_bit ==
+                   subghz_protocol_came_atomo_const.min_count_bit_for_found) {
+                    instance->generic.data = instance->decoder.decode_data;
+                    instance->generic.data_count_bit = instance->decoder.decode_count_bit;
+                    if(instance->base.callback)
+                        instance->base.callback(&instance->base, instance->base.context);
+                }
+                instance->decoder.decode_data = 0;
+                instance->decoder.decode_count_bit = 1;
+                manchester_advance(
+                    instance->manchester_saved_state,
+                    ManchesterEventReset,
+                    &instance->manchester_saved_state,
+                    NULL);
+                manchester_advance(
+                    instance->manchester_saved_state,
+                    ManchesterEventShortLow,
+                    &instance->manchester_saved_state,
+                    NULL);
+            } else {
+                instance->decoder.parser_step = CameAtomoDecoderStepReset;
+            }
+        } else {
+            if(DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_short) <
+               subghz_protocol_came_atomo_const.te_delta) {
+                event = ManchesterEventShortHigh;
+            } else if(
+                DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_long) <
+                subghz_protocol_came_atomo_const.te_delta) {
+                event = ManchesterEventLongHigh;
+            } else {
+                instance->decoder.parser_step = CameAtomoDecoderStepReset;
+            }
+        }
+        if(event != ManchesterEventReset) {
+            bool data;
+            bool data_ok = manchester_advance(
+                instance->manchester_saved_state, event, &instance->manchester_saved_state, &data);
+
+            if(data_ok) {
+                instance->decoder.decode_data = (instance->decoder.decode_data << 1) | !data;
+                instance->decoder.decode_count_bit++;
+            }
+        }
+        break;
+    }
+}
+
+/** Read bytes from rainbow table
+ *
+ * @param file_name - file name rainbow table
+ * @param number_atomo_magic_xor
+ * @return atomo_magic_xor
+ */
+static uint64_t subghz_protocol_came_atomo_get_magic_xor_in_file(
+    const char* file_name,
+    uint8_t number_atomo_magic_xor) {
+    if(!strcmp(file_name, "")) return SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE;
+
+    uint8_t buffer[sizeof(uint64_t)] = {0};
+    uint32_t address = number_atomo_magic_xor * sizeof(uint64_t);
+    uint64_t atomo_magic_xor = 0;
+
+    if(subghz_keystore_raw_get_data(file_name, address, buffer, sizeof(uint64_t))) {
+        for(size_t i = 0; i < sizeof(uint64_t); i++) {
+            atomo_magic_xor = (atomo_magic_xor << 8) | buffer[i];
+        }
+    } else {
+        atomo_magic_xor = SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE;
+    }
+    return atomo_magic_xor;
+}
+
+/** Analysis of received data
+ * 
+ * @param instance SubGhzBlockGeneric instance
+ */
+static void subghz_protocol_came_atomo_remote_controller(
+    SubGhzBlockGeneric* instance,
+    const char* file_name) {
+    /* 
+    * 0x1fafef3ed0f7d9ef
+    * 0x185fcc1531ee86e7
+    * 0x184fa96912c567ff
+    * 0x187f8a42f3dc38f7
+    * 0x186f63915492a5cd
+    * 0x181f40bab58bfac5
+    * 0x180f25c696a01bdd
+    * 0x183f06ed77b944d5
+    * 0x182ef661d83d21a9
+    * 0x18ded54a39247ea1
+    * 0x18ceb0361a0f9fb9
+    * 0x18fe931dfb16c0b1
+    * 0x18ee7ace5c585d8b
+    * ........ 
+    * transmission consists of 99 parcels with increasing counter while holding down the button
+    * with each new press, the counter in the encrypted part increases
+    * 
+    * 0x1FAFF13ED0F7D9EF
+    * 0x1FAFF11ED0F7D9EF
+    * 0x1FAFF10ED0F7D9EF
+    * 0x1FAFF0FED0F7D9EF
+    * 0x1FAFF0EED0F7D9EF
+    * 0x1FAFF0DED0F7D9EF
+    * 0x1FAFF0CED0F7D9EF
+    * 0x1FAFF0BED0F7D9EF
+    * 0x1FAFF0AED0F7D9EF 
+    * 
+    *                   where     0x1FAF - parcel counter, 0хF0A - button press counter,
+    *                           0xED0F7D9E - serial number, 0хF -  key
+    * 0x1FAF parcel counter - 1 in the parcel queue ^ 0x185F =  0x07F0
+    * 0x185f ^ 0x185F = 0x0000
+    * 0x184f ^ 0x185F = 0x0010
+    * 0x187f ^ 0x185F = 0x0020
+    * .....
+    * 0x182e ^ 0x185F = 0x0071 
+    * 0x18de ^ 0x185F = 0x0081
+    * .....
+    * 0x1e43 ^ 0x185F = 0x061C
+    *                           where the last nibble is incremented every 8 samples
+    * 
+    * Decode
+    * 
+    * 0x1cf6931dfb16c0b1 => 0x1cf6
+    * 0x1cf6 ^ 0x185F = 0x04A9
+    * 0x04A9 => 0x04A = 74 (dec)
+    * 74+1 % 32(atomo_magic_xor) = 11
+    * GET atomo_magic_xor[11] = 0xXXXXXXXXXXXXXXXX
+    * 0x931dfb16c0b1 ^ 0xXXXXXXXXXXXXXXXX =  0xEF3ED0F7D9EF
+    * 0xEF3 ED0F7D9E F  => 0xEF3 - CNT, 0xED0F7D9E - SN, 0xF - key
+    * 
+    * */
+
+    uint16_t parcel_counter = instance->data >> 48;
+    parcel_counter = parcel_counter ^ 0x185F;
+    parcel_counter >>= 4;
+    uint8_t ind = (parcel_counter + 1) % 32;
+    uint64_t temp_data = instance->data & 0x0000FFFFFFFFFFFF;
+    uint64_t atomo_magic_xor = subghz_protocol_came_atomo_get_magic_xor_in_file(file_name, ind);
+
+    if(atomo_magic_xor != SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE) {
+        temp_data = temp_data ^ atomo_magic_xor;
+        instance->cnt = temp_data >> 36;
+        instance->serial = (temp_data >> 4) & 0x000FFFFFFFF;
+        instance->btn = temp_data & 0xF;
+    } else {
+        instance->cnt = 0;
+        instance->serial = 0;
+        instance->btn = 0;
+    }
+}
+
+uint8_t subghz_protocol_decoder_came_atomo_get_hash_data(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCameAtomo* instance = context;
+    return subghz_protocol_blocks_get_hash_data(
+        &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
+}
+
+bool subghz_protocol_decoder_came_atomo_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCameAtomo* instance = context;
+    return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
+}
+
+bool subghz_protocol_decoder_came_atomo_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCameAtomo* instance = context;
+    return subghz_block_generic_deserialize(&instance->generic, flipper_format);
+}
+
+void subghz_protocol_decoder_came_atomo_get_string(void* context, string_t output) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCameAtomo* instance = context;
+    subghz_protocol_came_atomo_remote_controller(
+        &instance->generic, instance->came_atomo_rainbow_table_file_name);
+    uint32_t code_found_hi = instance->generic.data >> 32;
+    uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
+
+    string_cat_printf(
+        output,
+        "%s %db\r\n"
+        "Key:0x%lX%08lX\r\n"
+        "Sn:0x%08lX  Btn:0x%01X\r\n"
+        "Cnt:0x%03X\r\n",
+
+        instance->generic.protocol_name,
+        instance->generic.data_count_bit,
+        code_found_hi,
+        code_found_lo,
+        instance->generic.serial,
+        instance->generic.btn,
+        instance->generic.cnt);
+}

+ 24 - 0
lib/subghz/protocols/came_atomo.h

@@ -0,0 +1,24 @@
+#pragma once
+#include "base.h"
+
+#define SUBGHZ_PROTOCOL_CAME_ATOMO_NAME "CAME Atomo"
+
+typedef struct SubGhzProtocolDecoderCameAtomo SubGhzProtocolDecoderCameAtomo;
+typedef struct SubGhzProtocolEncoderCameAtomo SubGhzProtocolEncoderCameAtomo;
+
+extern const SubGhzProtocolDecoder subghz_protocol_came_atomo_decoder;
+extern const SubGhzProtocolEncoder subghz_protocol_came_atomo_encoder;
+extern const SubGhzProtocol subghz_protocol_came_atomo;
+
+void* subghz_protocol_decoder_came_atomo_alloc(SubGhzEnvironment* environment);
+void subghz_protocol_decoder_came_atomo_free(void* context);
+void subghz_protocol_decoder_came_atomo_reset(void* context);
+void subghz_protocol_decoder_came_atomo_feed(void* context, bool level, uint32_t duration);
+uint8_t subghz_protocol_decoder_came_atomo_get_hash_data(void* context);
+bool subghz_protocol_decoder_came_atomo_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset);
+bool subghz_protocol_decoder_came_atomo_deserialize(void* context, FlipperFormat* flipper_format);
+void subghz_protocol_decoder_came_atomo_get_string(void* context, string_t output);

+ 445 - 0
lib/subghz/protocols/came_twee.c

@@ -0,0 +1,445 @@
+#include "came_twee.h"
+#include <lib/toolbox/manchester_decoder.h>
+#include <lib/toolbox/manchester_encoder.h>
+#include "../blocks/const.h"
+#include "../blocks/decoder.h"
+#include "../blocks/encoder.h"
+#include "../blocks/generic.h"
+#include "../blocks/math.h"
+
+/*
+ * Help
+ * https://phreakerclub.com/forum/showthread.php?t=635&highlight=came+twin
+ *
+ */
+
+#define TAG "SubGhzProtocolCAME_Twee"
+
+#define DIP_PATTERN "%c%c%c%c%c%c%c%c%c%c"
+#define CNT_TO_DIP(dip)                                                                     \
+    (dip & 0x0200 ? '1' : '0'), (dip & 0x0100 ? '1' : '0'), (dip & 0x0080 ? '1' : '0'),     \
+        (dip & 0x0040 ? '1' : '0'), (dip & 0x0020 ? '1' : '0'), (dip & 0x0010 ? '1' : '0'), \
+        (dip & 0x0008 ? '1' : '0'), (dip & 0x0004 ? '1' : '0'), (dip & 0x0002 ? '1' : '0'), \
+        (dip & 0x0001 ? '1' : '0')
+
+static const uint32_t came_twee_magic_numbers_xor[15] = {
+    0x0E0E0E00,
+    0x1D1D1D11,
+    0x2C2C2C22,
+    0x3B3B3B33,
+    0x4A4A4A44,
+    0x59595955,
+    0x68686866,
+    0x77777777,
+    0x86868688,
+    0x95959599,
+    0xA4A4A4AA,
+    0xB3B3B3BB,
+    0xC2C2C2CC,
+    0xD1D1D1DD,
+    0xE0E0E0EE,
+};
+
+static const SubGhzBlockConst subghz_protocol_came_twee_const = {
+    .te_short = 500,
+    .te_long = 1000,
+    .te_delta = 250,
+    .min_count_bit_for_found = 54,
+};
+
+struct SubGhzProtocolDecoderCameTwee {
+    SubGhzProtocolDecoderBase base;
+
+    SubGhzBlockDecoder decoder;
+    SubGhzBlockGeneric generic;
+    ManchesterState manchester_saved_state;
+};
+
+struct SubGhzProtocolEncoderCameTwee {
+    SubGhzProtocolEncoderBase base;
+
+    SubGhzProtocolBlockEncoder encoder;
+    SubGhzBlockGeneric generic;
+};
+
+typedef enum {
+    CameTweeDecoderStepReset = 0,
+    CameTweeDecoderStepDecoderData,
+} CameTweeDecoderStep;
+
+const SubGhzProtocolDecoder subghz_protocol_came_twee_decoder = {
+    .alloc = subghz_protocol_decoder_came_twee_alloc,
+    .free = subghz_protocol_decoder_came_twee_free,
+
+    .feed = subghz_protocol_decoder_came_twee_feed,
+    .reset = subghz_protocol_decoder_came_twee_reset,
+
+    .get_hash_data = subghz_protocol_decoder_came_twee_get_hash_data,
+    .serialize = subghz_protocol_decoder_came_twee_serialize,
+    .deserialize = subghz_protocol_decoder_came_twee_deserialize,
+    .get_string = subghz_protocol_decoder_came_twee_get_string,
+};
+
+const SubGhzProtocolEncoder subghz_protocol_came_twee_encoder = {
+    .alloc = subghz_protocol_encoder_came_twee_alloc,
+    .free = subghz_protocol_encoder_came_twee_free,
+
+    .deserialize = subghz_protocol_encoder_came_twee_deserialize,
+    .stop = subghz_protocol_encoder_came_twee_stop,
+    .yield = subghz_protocol_encoder_came_twee_yield,
+};
+
+const SubGhzProtocol subghz_protocol_came_twee = {
+    .name = SUBGHZ_PROTOCOL_CAME_TWEE_NAME,
+    .type = SubGhzProtocolTypeStatic,
+    .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
+            SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
+
+    .decoder = &subghz_protocol_came_twee_decoder,
+    .encoder = &subghz_protocol_came_twee_encoder,
+};
+
+void* subghz_protocol_encoder_came_twee_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolEncoderCameTwee* instance = malloc(sizeof(SubGhzProtocolEncoderCameTwee));
+
+    instance->base.protocol = &subghz_protocol_came_twee;
+    instance->generic.protocol_name = instance->base.protocol->name;
+
+    instance->encoder.repeat = 10;
+    instance->encoder.size_upload = 1536; //max upload 92*14 = 1288 !!!!
+    instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
+    instance->encoder.is_runing = false;
+    return instance;
+}
+
+void subghz_protocol_encoder_came_twee_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolEncoderCameTwee* instance = context;
+    free(instance->encoder.upload);
+    free(instance);
+}
+
+static LevelDuration
+    subghz_protocol_encoder_came_twee_add_duration_to_upload(ManchesterEncoderResult result) {
+    LevelDuration data = {.duration = 0, .level = 0};
+    switch(result) {
+    case ManchesterEncoderResultShortLow:
+        data.duration = subghz_protocol_came_twee_const.te_short;
+        data.level = false;
+        break;
+    case ManchesterEncoderResultLongLow:
+        data.duration = subghz_protocol_came_twee_const.te_long;
+        data.level = false;
+        break;
+    case ManchesterEncoderResultLongHigh:
+        data.duration = subghz_protocol_came_twee_const.te_long;
+        data.level = true;
+        break;
+    case ManchesterEncoderResultShortHigh:
+        data.duration = subghz_protocol_came_twee_const.te_short;
+        data.level = true;
+        break;
+
+    default:
+        FURI_LOG_E(TAG, "DO CRASH HERE.");
+        furi_crash(NULL);
+        break;
+    }
+    return level_duration_make(data.level, data.duration);
+}
+
+static void subghz_protocol_encoder_came_twee_get_upload(SubGhzProtocolEncoderCameTwee* instance) {
+    furi_assert(instance);
+    size_t index = 0;
+
+    ManchesterEncoderState enc_state;
+    manchester_encoder_reset(&enc_state);
+    ManchesterEncoderResult result;
+
+    uint64_t temp_parcel = 0x003FFF7200000000; //parcel mask
+
+    for(int i = 14; i >= 0; i--) {
+        temp_parcel = (temp_parcel & 0xFFFFFFFF00000000) |
+                      (instance->generic.serial ^ came_twee_magic_numbers_xor[i]);
+
+        for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
+            if(!manchester_encoder_advance(&enc_state, !bit_read(temp_parcel, i - 1), &result)) {
+                instance->encoder.upload[index++] =
+                    subghz_protocol_encoder_came_twee_add_duration_to_upload(result);
+                manchester_encoder_advance(&enc_state, !bit_read(temp_parcel, i - 1), &result);
+            }
+            instance->encoder.upload[index++] =
+                subghz_protocol_encoder_came_twee_add_duration_to_upload(result);
+        }
+        instance->encoder.upload[index] = subghz_protocol_encoder_came_twee_add_duration_to_upload(
+            manchester_encoder_finish(&enc_state));
+        if(level_duration_get_level(instance->encoder.upload[index])) {
+            index++;
+        }
+        instance->encoder.upload[index++] =
+            level_duration_make(false, (uint32_t)subghz_protocol_came_twee_const.te_long * 51);
+    }
+    instance->encoder.size_upload = index;
+}
+
+/** Analysis of received data
+ * 
+ * @param instance SubGhzProtocolCameTwee instance
+ */
+static void subghz_protocol_came_twee_remote_controller(SubGhzBlockGeneric* instance) {
+    /*      Came Twee 54 bit, rolling code 15 parcels with
+    *       a decreasing counter from 0xE to 0x0
+    *       with originally coded dip switches on the console 10 bit code
+    * 
+    *  0x003FFF72E04A6FEE
+    *  0x003FFF72D17B5EDD
+    *  0x003FFF72C2684DCC
+    *  0x003FFF72B3193CBB
+    *  0x003FFF72A40E2BAA
+    *  0x003FFF72953F1A99
+    *  0x003FFF72862C0988
+    *  0x003FFF7277DDF877
+    *  0x003FFF7268C2E766
+    *  0x003FFF7259F3D655
+    *  0x003FFF724AE0C544
+    *  0x003FFF723B91B433
+    *  0x003FFF722C86A322
+    *  0x003FFF721DB79211
+    *  0x003FFF720EA48100
+    * 
+    *   decryption
+    * the last 32 bits, do XOR by the desired number, divide the result by 4,
+    * convert the first 16 bits of the resulting 32-bit number to bin and do
+    * bit-by-bit mirroring, adding up to 10 bits
+    * 
+    * Example
+    * Step 1. 0x003FFF721DB79211        => 0x1DB79211
+    * Step 4. 0x1DB79211 xor 0x1D1D1D11 => 0x00AA8F00
+    * Step 4. 0x00AA8F00 / 4            => 0x002AA3C0
+    * Step 5. 0x002AA3C0                => 0x002A
+    * Step 6. 0x002A    bin             => b101010
+    * Step 7. b101010                   => b0101010000
+    * Step 8. b0101010000               => (Dip) Off ON Off ON Off ON Off Off Off Off
+    */
+
+    uint8_t cnt_parcel = (uint8_t)(instance->data & 0xF);
+    uint32_t data = (uint32_t)(instance->data & 0x0FFFFFFFF);
+
+    data = (data ^ came_twee_magic_numbers_xor[cnt_parcel]);
+    instance->serial = data;
+    data /= 4;
+    instance->btn = (data >> 4) & 0x0F;
+    data >>= 16;
+    data = (uint16_t)subghz_protocol_blocks_reverse_key(data, 16);
+    instance->cnt = data >> 6;
+}
+
+bool subghz_protocol_encoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolEncoderCameTwee* instance = context;
+    bool res = false;
+    do {
+        if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
+            FURI_LOG_E(TAG, "Deserialize error");
+            break;
+        }
+
+        //optional parameter parameter
+        flipper_format_read_uint32(
+            flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
+
+        subghz_protocol_came_twee_remote_controller(&instance->generic);
+        subghz_protocol_encoder_came_twee_get_upload(instance);
+        instance->encoder.is_runing = true;
+
+        res = true;
+    } while(false);
+
+    return res;
+}
+
+void subghz_protocol_encoder_came_twee_stop(void* context) {
+    SubGhzProtocolEncoderCameTwee* instance = context;
+    instance->encoder.is_runing = false;
+}
+
+LevelDuration subghz_protocol_encoder_came_twee_yield(void* context) {
+    SubGhzProtocolEncoderCameTwee* instance = context;
+
+    if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) {
+        instance->encoder.is_runing = false;
+        return level_duration_reset();
+    }
+
+    LevelDuration ret = instance->encoder.upload[instance->encoder.front];
+
+    if(++instance->encoder.front == instance->encoder.size_upload) {
+        instance->encoder.repeat--;
+        instance->encoder.front = 0;
+    }
+
+    return ret;
+}
+
+void* subghz_protocol_decoder_came_twee_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolDecoderCameTwee* instance = malloc(sizeof(SubGhzProtocolDecoderCameTwee));
+    instance->base.protocol = &subghz_protocol_came_twee;
+    instance->generic.protocol_name = instance->base.protocol->name;
+    return instance;
+}
+
+void subghz_protocol_decoder_came_twee_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCameTwee* instance = context;
+    free(instance);
+}
+
+void subghz_protocol_decoder_came_twee_reset(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCameTwee* instance = context;
+    instance->decoder.parser_step = CameTweeDecoderStepReset;
+    manchester_advance(
+        instance->manchester_saved_state,
+        ManchesterEventReset,
+        &instance->manchester_saved_state,
+        NULL);
+}
+
+void subghz_protocol_decoder_came_twee_feed(void* context, bool level, uint32_t duration) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCameTwee* instance = context;
+    ManchesterEvent event = ManchesterEventReset;
+    switch(instance->decoder.parser_step) {
+    case CameTweeDecoderStepReset:
+        if((!level) && (DURATION_DIFF(duration, subghz_protocol_came_twee_const.te_long * 51) <
+                        subghz_protocol_came_twee_const.te_delta * 20)) {
+            //Found header CAME
+            instance->decoder.parser_step = CameTweeDecoderStepDecoderData;
+            instance->decoder.decode_data = 0;
+            instance->decoder.decode_count_bit = 0;
+            manchester_advance(
+                instance->manchester_saved_state,
+                ManchesterEventLongLow,
+                &instance->manchester_saved_state,
+                NULL);
+            manchester_advance(
+                instance->manchester_saved_state,
+                ManchesterEventLongHigh,
+                &instance->manchester_saved_state,
+                NULL);
+            manchester_advance(
+                instance->manchester_saved_state,
+                ManchesterEventShortLow,
+                &instance->manchester_saved_state,
+                NULL);
+        }
+        break;
+    case CameTweeDecoderStepDecoderData:
+        if(!level) {
+            if(DURATION_DIFF(duration, subghz_protocol_came_twee_const.te_short) <
+               subghz_protocol_came_twee_const.te_delta) {
+                event = ManchesterEventShortLow;
+            } else if(
+                DURATION_DIFF(duration, subghz_protocol_came_twee_const.te_long) <
+                subghz_protocol_came_twee_const.te_delta) {
+                event = ManchesterEventLongLow;
+            } else if(
+                duration >= (subghz_protocol_came_twee_const.te_long * 2 +
+                             subghz_protocol_came_twee_const.te_delta)) {
+                if(instance->decoder.decode_count_bit >=
+                   subghz_protocol_came_twee_const.min_count_bit_for_found) {
+                    instance->generic.data = instance->decoder.decode_data;
+                    instance->generic.data_count_bit = instance->decoder.decode_count_bit;
+
+                    if(instance->base.callback)
+                        instance->base.callback(&instance->base, instance->base.context);
+                }
+                instance->decoder.decode_data = 0;
+                instance->decoder.decode_count_bit = 0;
+                manchester_advance(
+                    instance->manchester_saved_state,
+                    ManchesterEventLongLow,
+                    &instance->manchester_saved_state,
+                    NULL);
+                manchester_advance(
+                    instance->manchester_saved_state,
+                    ManchesterEventLongHigh,
+                    &instance->manchester_saved_state,
+                    NULL);
+                manchester_advance(
+                    instance->manchester_saved_state,
+                    ManchesterEventShortLow,
+                    &instance->manchester_saved_state,
+                    NULL);
+            } else {
+                instance->decoder.parser_step = CameTweeDecoderStepReset;
+            }
+        } else {
+            if(DURATION_DIFF(duration, subghz_protocol_came_twee_const.te_short) <
+               subghz_protocol_came_twee_const.te_delta) {
+                event = ManchesterEventShortHigh;
+            } else if(
+                DURATION_DIFF(duration, subghz_protocol_came_twee_const.te_long) <
+                subghz_protocol_came_twee_const.te_delta) {
+                event = ManchesterEventLongHigh;
+            } else {
+                instance->decoder.parser_step = CameTweeDecoderStepReset;
+            }
+        }
+        if(event != ManchesterEventReset) {
+            bool data;
+            bool data_ok = manchester_advance(
+                instance->manchester_saved_state, event, &instance->manchester_saved_state, &data);
+
+            if(data_ok) {
+                instance->decoder.decode_data = (instance->decoder.decode_data << 1) | !data;
+                instance->decoder.decode_count_bit++;
+            }
+        }
+        break;
+    }
+}
+
+uint8_t subghz_protocol_decoder_came_twee_get_hash_data(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCameTwee* instance = context;
+    return subghz_protocol_blocks_get_hash_data(
+        &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
+}
+
+bool subghz_protocol_decoder_came_twee_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCameTwee* instance = context;
+    return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
+}
+
+bool subghz_protocol_decoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCameTwee* instance = context;
+    return subghz_block_generic_deserialize(&instance->generic, flipper_format);
+}
+
+void subghz_protocol_decoder_came_twee_get_string(void* context, string_t output) {
+    furi_assert(context);
+    SubGhzProtocolDecoderCameTwee* instance = context;
+    subghz_protocol_came_twee_remote_controller(&instance->generic);
+    uint32_t code_found_hi = instance->generic.data >> 32;
+    uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
+
+    string_cat_printf(
+        output,
+        "%s %dbit\r\n"
+        "Key:0x%lX%08lX\r\n"
+        "Btn:%lX\r\n"
+        "DIP:" DIP_PATTERN "\r\n",
+        instance->generic.protocol_name,
+        instance->generic.data_count_bit,
+        code_found_hi,
+        code_found_lo,
+        instance->generic.btn,
+        CNT_TO_DIP(instance->generic.cnt));
+}

+ 30 - 0
lib/subghz/protocols/came_twee.h

@@ -0,0 +1,30 @@
+#pragma once
+
+#include "base.h"
+
+#define SUBGHZ_PROTOCOL_CAME_TWEE_NAME "CAME TWEE"
+
+typedef struct SubGhzProtocolDecoderCameTwee SubGhzProtocolDecoderCameTwee;
+typedef struct SubGhzProtocolEncoderCameTwee SubGhzProtocolEncoderCameTwee;
+
+extern const SubGhzProtocolDecoder subghz_protocol_came_twee_decoder;
+extern const SubGhzProtocolEncoder subghz_protocol_came_twee_encoder;
+extern const SubGhzProtocol subghz_protocol_came_twee;
+
+void* subghz_protocol_encoder_came_twee_alloc(SubGhzEnvironment* environment);
+void subghz_protocol_encoder_came_twee_free(void* context);
+bool subghz_protocol_encoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format);
+void subghz_protocol_encoder_came_twee_stop(void* context);
+LevelDuration subghz_protocol_encoder_came_twee_yield(void* context);
+void* subghz_protocol_decoder_came_twee_alloc(SubGhzEnvironment* environment);
+void subghz_protocol_decoder_came_twee_free(void* context);
+void subghz_protocol_decoder_came_twee_reset(void* context);
+void subghz_protocol_decoder_came_twee_feed(void* context, bool level, uint32_t duration);
+uint8_t subghz_protocol_decoder_came_twee_get_hash_data(void* context);
+bool subghz_protocol_decoder_came_twee_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset);
+bool subghz_protocol_decoder_came_twee_deserialize(void* context, FlipperFormat* flipper_format);
+void subghz_protocol_decoder_came_twee_get_string(void* context, string_t output);

+ 218 - 0
lib/subghz/protocols/faac_slh.c

@@ -0,0 +1,218 @@
+#include "faac_slh.h"
+
+#include "../blocks/const.h"
+#include "../blocks/decoder.h"
+#include "../blocks/encoder.h"
+#include "../blocks/generic.h"
+#include "../blocks/math.h"
+
+#define TAG "SubGhzProtocolFaacSHL"
+
+static const SubGhzBlockConst subghz_protocol_faac_slh_const = {
+    .te_short = 255,
+    .te_long = 595,
+    .te_delta = 100,
+    .min_count_bit_for_found = 64,
+};
+
+struct SubGhzProtocolDecoderFaacSLH {
+    SubGhzProtocolDecoderBase base;
+
+    SubGhzBlockDecoder decoder;
+    SubGhzBlockGeneric generic;
+};
+
+struct SubGhzProtocolEncoderFaacSLH {
+    SubGhzProtocolEncoderBase base;
+
+    SubGhzProtocolBlockEncoder encoder;
+    SubGhzBlockGeneric generic;
+};
+
+typedef enum {
+    FaacSLHDecoderStepReset = 0,
+    FaacSLHDecoderStepFoundPreambula,
+    FaacSLHDecoderStepSaveDuration,
+    FaacSLHDecoderStepCheckDuration,
+} FaacSLHDecoderStep;
+
+const SubGhzProtocolDecoder subghz_protocol_faac_slh_decoder = {
+    .alloc = subghz_protocol_decoder_faac_slh_alloc,
+    .free = subghz_protocol_decoder_faac_slh_free,
+
+    .feed = subghz_protocol_decoder_faac_slh_feed,
+    .reset = subghz_protocol_decoder_faac_slh_reset,
+
+    .get_hash_data = subghz_protocol_decoder_faac_slh_get_hash_data,
+    .serialize = subghz_protocol_decoder_faac_slh_serialize,
+    .deserialize = subghz_protocol_decoder_faac_slh_deserialize,
+    .get_string = subghz_protocol_decoder_faac_slh_get_string,
+};
+
+const SubGhzProtocolEncoder subghz_protocol_faac_slh_encoder = {
+    .alloc = NULL,
+    .free = NULL,
+
+    .deserialize = NULL,
+    .stop = NULL,
+    .yield = NULL,
+};
+
+const SubGhzProtocol subghz_protocol_faac_slh = {
+    .name = SUBGHZ_PROTOCOL_FAAC_SLH_NAME,
+    .type = SubGhzProtocolTypeDynamic,
+    .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_AM |
+            SubGhzProtocolFlag_Decodable,
+
+    .decoder = &subghz_protocol_faac_slh_decoder,
+    .encoder = &subghz_protocol_faac_slh_encoder,
+};
+
+void* subghz_protocol_decoder_faac_slh_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolDecoderFaacSLH* instance = malloc(sizeof(SubGhzProtocolDecoderFaacSLH));
+    instance->base.protocol = &subghz_protocol_faac_slh;
+    instance->generic.protocol_name = instance->base.protocol->name;
+    return instance;
+}
+
+void subghz_protocol_decoder_faac_slh_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderFaacSLH* instance = context;
+    free(instance);
+}
+
+void subghz_protocol_decoder_faac_slh_reset(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderFaacSLH* instance = context;
+    instance->decoder.parser_step = FaacSLHDecoderStepReset;
+}
+
+void subghz_protocol_decoder_faac_slh_feed(void* context, bool level, uint32_t duration) {
+    furi_assert(context);
+    SubGhzProtocolDecoderFaacSLH* instance = context;
+
+    switch(instance->decoder.parser_step) {
+    case FaacSLHDecoderStepReset:
+        if((level) && (DURATION_DIFF(duration, subghz_protocol_faac_slh_const.te_long * 2) <
+                       subghz_protocol_faac_slh_const.te_delta * 3)) {
+            instance->decoder.parser_step = FaacSLHDecoderStepFoundPreambula;
+        }
+        break;
+    case FaacSLHDecoderStepFoundPreambula:
+        if((!level) && (DURATION_DIFF(duration, subghz_protocol_faac_slh_const.te_long * 2) <
+                        subghz_protocol_faac_slh_const.te_delta * 3)) {
+            //Found Preambula
+            instance->decoder.parser_step = FaacSLHDecoderStepSaveDuration;
+            instance->decoder.decode_data = 0;
+            instance->decoder.decode_count_bit = 0;
+        } else {
+            instance->decoder.parser_step = FaacSLHDecoderStepReset;
+        }
+        break;
+    case FaacSLHDecoderStepSaveDuration:
+        if(level) {
+            if(duration >= (subghz_protocol_faac_slh_const.te_short * 3 +
+                            subghz_protocol_faac_slh_const.te_delta)) {
+                instance->decoder.parser_step = FaacSLHDecoderStepFoundPreambula;
+                if(instance->decoder.decode_count_bit >=
+                   subghz_protocol_faac_slh_const.min_count_bit_for_found) {
+                    instance->generic.data = instance->decoder.decode_data;
+                    instance->generic.data_count_bit = instance->decoder.decode_count_bit;
+
+                    if(instance->base.callback)
+                        instance->base.callback(&instance->base, instance->base.context);
+                }
+                instance->decoder.decode_data = 0;
+                instance->decoder.decode_count_bit = 0;
+                break;
+            } else {
+                instance->decoder.te_last = duration;
+                instance->decoder.parser_step = FaacSLHDecoderStepCheckDuration;
+            }
+
+        } else {
+            instance->decoder.parser_step = FaacSLHDecoderStepReset;
+        }
+        break;
+    case FaacSLHDecoderStepCheckDuration:
+        if(!level) {
+            if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_faac_slh_const.te_short) <
+                subghz_protocol_faac_slh_const.te_delta) &&
+               (DURATION_DIFF(duration, subghz_protocol_faac_slh_const.te_long) <
+                subghz_protocol_faac_slh_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 0);
+                instance->decoder.parser_step = FaacSLHDecoderStepSaveDuration;
+            } else if(
+                (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_faac_slh_const.te_long) <
+                 subghz_protocol_faac_slh_const.te_delta) &&
+                (DURATION_DIFF(duration, subghz_protocol_faac_slh_const.te_short) <
+                 subghz_protocol_faac_slh_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 1);
+                instance->decoder.parser_step = FaacSLHDecoderStepSaveDuration;
+            } else {
+                instance->decoder.parser_step = FaacSLHDecoderStepReset;
+            }
+        } else {
+            instance->decoder.parser_step = FaacSLHDecoderStepReset;
+        }
+        break;
+    }
+}
+
+static void subghz_protocol_faac_slh_check_remote_controller(SubGhzBlockGeneric* instance) {
+    uint64_t code_found_reverse =
+        subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit);
+    uint32_t code_fix = code_found_reverse & 0xFFFFFFFF;
+
+    instance->serial = code_fix & 0xFFFFFFF;
+    instance->btn = (code_fix >> 28) & 0x0F;
+}
+
+uint8_t subghz_protocol_decoder_faac_slh_get_hash_data(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderFaacSLH* instance = context;
+    return subghz_protocol_blocks_get_hash_data(
+        &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
+}
+
+bool subghz_protocol_decoder_faac_slh_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    furi_assert(context);
+    SubGhzProtocolDecoderFaacSLH* instance = context;
+    return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
+}
+
+bool subghz_protocol_decoder_faac_slh_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolDecoderFaacSLH* instance = context;
+    return subghz_block_generic_deserialize(&instance->generic, flipper_format);
+}
+
+void subghz_protocol_decoder_faac_slh_get_string(void* context, string_t output) {
+    furi_assert(context);
+    SubGhzProtocolDecoderFaacSLH* instance = context;
+    subghz_protocol_faac_slh_check_remote_controller(&instance->generic);
+    uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key(
+        instance->generic.data, instance->generic.data_count_bit);
+    uint32_t code_fix = code_found_reverse & 0xFFFFFFFF;
+    uint32_t code_hop = (code_found_reverse >> 32) & 0xFFFFFFFF;
+
+    string_cat_printf(
+        output,
+        "%s %dbit\r\n"
+        "Key:%lX%08lX\r\n"
+        "Fix:%08lX \r\n"
+        "Hop:%08lX \r\n"
+        "Sn:%07lX Btn:%lX\r\n",
+        instance->generic.protocol_name,
+        instance->generic.data_count_bit,
+        (uint32_t)(instance->generic.data >> 32),
+        (uint32_t)instance->generic.data,
+        code_fix,
+        code_hop,
+        instance->generic.serial,
+        instance->generic.btn);
+}

+ 25 - 0
lib/subghz/protocols/faac_slh.h

@@ -0,0 +1,25 @@
+#pragma once
+
+#include "base.h"
+
+#define SUBGHZ_PROTOCOL_FAAC_SLH_NAME "Faac SLH"
+
+typedef struct SubGhzProtocolDecoderFaacSLH SubGhzProtocolDecoderFaacSLH;
+typedef struct SubGhzProtocolEncoderFaacSLH SubGhzProtocolEncoderFaacSLH;
+
+extern const SubGhzProtocolDecoder subghz_protocol_faac_slh_decoder;
+extern const SubGhzProtocolEncoder subghz_protocol_faac_slh_encoder;
+extern const SubGhzProtocol subghz_protocol_faac_slh;
+
+void* subghz_protocol_decoder_faac_slh_alloc(SubGhzEnvironment* environment);
+void subghz_protocol_decoder_faac_slh_free(void* context);
+void subghz_protocol_decoder_faac_slh_reset(void* context);
+void subghz_protocol_decoder_faac_slh_feed(void* context, bool level, uint32_t duration);
+uint8_t subghz_protocol_decoder_faac_slh_get_hash_data(void* context);
+bool subghz_protocol_decoder_faac_slh_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset);
+bool subghz_protocol_decoder_faac_slh_deserialize(void* context, FlipperFormat* flipper_format);
+void subghz_protocol_decoder_faac_slh_get_string(void* context, string_t output);

+ 308 - 0
lib/subghz/protocols/gate_tx.c

@@ -0,0 +1,308 @@
+#include "gate_tx.h"
+
+#include "../blocks/const.h"
+#include "../blocks/decoder.h"
+#include "../blocks/encoder.h"
+#include "../blocks/generic.h"
+#include "../blocks/math.h"
+
+#define TAG "SubGhzProtocolGateTx"
+
+static const SubGhzBlockConst subghz_protocol_gate_tx_const = {
+    .te_short = 350,
+    .te_long = 700,
+    .te_delta = 100,
+    .min_count_bit_for_found = 24,
+};
+
+struct SubGhzProtocolDecoderGateTx {
+    SubGhzProtocolDecoderBase base;
+
+    SubGhzBlockDecoder decoder;
+    SubGhzBlockGeneric generic;
+};
+
+struct SubGhzProtocolEncoderGateTx {
+    SubGhzProtocolEncoderBase base;
+
+    SubGhzProtocolBlockEncoder encoder;
+    SubGhzBlockGeneric generic;
+};
+
+typedef enum {
+    GateTXDecoderStepReset = 0,
+    GateTXDecoderStepFoundStartBit,
+    GateTXDecoderStepSaveDuration,
+    GateTXDecoderStepCheckDuration,
+} GateTXDecoderStep;
+
+const SubGhzProtocolDecoder subghz_protocol_gate_tx_decoder = {
+    .alloc = subghz_protocol_decoder_gate_tx_alloc,
+    .free = subghz_protocol_decoder_gate_tx_free,
+
+    .feed = subghz_protocol_decoder_gate_tx_feed,
+    .reset = subghz_protocol_decoder_gate_tx_reset,
+
+    .get_hash_data = subghz_protocol_decoder_gate_tx_get_hash_data,
+    .serialize = subghz_protocol_decoder_gate_tx_serialize,
+    .deserialize = subghz_protocol_decoder_gate_tx_deserialize,
+    .get_string = subghz_protocol_decoder_gate_tx_get_string,
+};
+
+const SubGhzProtocolEncoder subghz_protocol_gate_tx_encoder = {
+    .alloc = subghz_protocol_encoder_gate_tx_alloc,
+    .free = subghz_protocol_encoder_gate_tx_free,
+
+    .deserialize = subghz_protocol_encoder_gate_tx_deserialize,
+    .stop = subghz_protocol_encoder_gate_tx_stop,
+    .yield = subghz_protocol_encoder_gate_tx_yield,
+};
+
+const SubGhzProtocol subghz_protocol_gate_tx = {
+    .name = SUBGHZ_PROTOCOL_GATE_TX_NAME,
+    .type = SubGhzProtocolTypeStatic,
+    .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
+            SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
+
+    .decoder = &subghz_protocol_gate_tx_decoder,
+    .encoder = &subghz_protocol_gate_tx_encoder,
+};
+
+void* subghz_protocol_encoder_gate_tx_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolEncoderGateTx* instance = malloc(sizeof(SubGhzProtocolEncoderGateTx));
+
+    instance->base.protocol = &subghz_protocol_gate_tx;
+    instance->generic.protocol_name = instance->base.protocol->name;
+
+    instance->encoder.repeat = 10;
+    instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop)
+    instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
+    instance->encoder.is_runing = false;
+    return instance;
+}
+
+void subghz_protocol_encoder_gate_tx_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolEncoderGateTx* instance = context;
+    free(instance->encoder.upload);
+    free(instance);
+}
+
+static bool subghz_protocol_encoder_gate_tx_get_upload(SubGhzProtocolEncoderGateTx* instance) {
+    furi_assert(instance);
+    size_t index = 0;
+    size_t size_upload = (instance->generic.data_count_bit * 2) + 2;
+    if(size_upload > instance->encoder.size_upload) {
+        FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
+        return false;
+    } else {
+        instance->encoder.size_upload = size_upload;
+    }
+    //Send header
+    instance->encoder.upload[index++] =
+        level_duration_make(false, (uint32_t)subghz_protocol_gate_tx_const.te_short * 49);
+    //Send start bit
+    instance->encoder.upload[index++] =
+        level_duration_make(true, (uint32_t)subghz_protocol_gate_tx_const.te_long);
+    //Send key data
+    for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
+        if(bit_read(instance->generic.data, i - 1)) {
+            //send bit 1
+            instance->encoder.upload[index++] =
+                level_duration_make(false, (uint32_t)subghz_protocol_gate_tx_const.te_long);
+            instance->encoder.upload[index++] =
+                level_duration_make(true, (uint32_t)subghz_protocol_gate_tx_const.te_short);
+        } else {
+            //send bit 0
+            instance->encoder.upload[index++] =
+                level_duration_make(false, (uint32_t)subghz_protocol_gate_tx_const.te_short);
+            instance->encoder.upload[index++] =
+                level_duration_make(true, (uint32_t)subghz_protocol_gate_tx_const.te_long);
+        }
+    }
+    return true;
+}
+
+bool subghz_protocol_encoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolEncoderGateTx* instance = context;
+    bool res = false;
+    do {
+        if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
+            FURI_LOG_E(TAG, "Deserialize error");
+            break;
+        }
+
+        //optional parameter parameter
+        flipper_format_read_uint32(
+            flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
+
+        subghz_protocol_encoder_gate_tx_get_upload(instance);
+        instance->encoder.is_runing = true;
+
+        res = true;
+    } while(false);
+
+    return res;
+}
+
+void subghz_protocol_encoder_gate_tx_stop(void* context) {
+    SubGhzProtocolEncoderGateTx* instance = context;
+    instance->encoder.is_runing = false;
+}
+
+LevelDuration subghz_protocol_encoder_gate_tx_yield(void* context) {
+    SubGhzProtocolEncoderGateTx* instance = context;
+
+    if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) {
+        instance->encoder.is_runing = false;
+        return level_duration_reset();
+    }
+
+    LevelDuration ret = instance->encoder.upload[instance->encoder.front];
+
+    if(++instance->encoder.front == instance->encoder.size_upload) {
+        instance->encoder.repeat--;
+        instance->encoder.front = 0;
+    }
+
+    return ret;
+}
+
+void* subghz_protocol_decoder_gate_tx_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolDecoderGateTx* instance = malloc(sizeof(SubGhzProtocolDecoderGateTx));
+    instance->base.protocol = &subghz_protocol_gate_tx;
+    instance->generic.protocol_name = instance->base.protocol->name;
+    return instance;
+}
+
+void subghz_protocol_decoder_gate_tx_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderGateTx* instance = context;
+    free(instance);
+}
+
+void subghz_protocol_decoder_gate_tx_reset(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderGateTx* instance = context;
+    instance->decoder.parser_step = GateTXDecoderStepReset;
+}
+
+void subghz_protocol_decoder_gate_tx_feed(void* context, bool level, uint32_t duration) {
+    furi_assert(context);
+    SubGhzProtocolDecoderGateTx* instance = context;
+
+    switch(instance->decoder.parser_step) {
+    case GateTXDecoderStepReset:
+        if((!level) && (DURATION_DIFF(duration, subghz_protocol_gate_tx_const.te_short * 47) <
+                        subghz_protocol_gate_tx_const.te_delta * 47)) {
+            //Found Preambula
+            instance->decoder.parser_step = GateTXDecoderStepFoundStartBit;
+        }
+        break;
+    case GateTXDecoderStepFoundStartBit:
+        if(level && ((DURATION_DIFF(duration, subghz_protocol_gate_tx_const.te_long) <
+                      subghz_protocol_gate_tx_const.te_delta * 3))) {
+            //Found start bit
+            instance->decoder.parser_step = GateTXDecoderStepSaveDuration;
+            instance->decoder.decode_data = 0;
+            instance->decoder.decode_count_bit = 0;
+        } else {
+            instance->decoder.parser_step = GateTXDecoderStepReset;
+        }
+        break;
+    case GateTXDecoderStepSaveDuration:
+        if(!level) {
+            if(duration >= (subghz_protocol_gate_tx_const.te_short * 10 +
+                            subghz_protocol_gate_tx_const.te_delta)) {
+                instance->decoder.parser_step = GateTXDecoderStepFoundStartBit;
+                if(instance->decoder.decode_count_bit >=
+                   subghz_protocol_gate_tx_const.min_count_bit_for_found) {
+                    instance->generic.data = instance->decoder.decode_data;
+                    instance->generic.data_count_bit = instance->decoder.decode_count_bit;
+
+                    if(instance->base.callback)
+                        instance->base.callback(&instance->base, instance->base.context);
+                }
+                instance->decoder.decode_data = 0;
+                instance->decoder.decode_count_bit = 0;
+                break;
+            } else {
+                instance->decoder.te_last = duration;
+                instance->decoder.parser_step = GateTXDecoderStepCheckDuration;
+            }
+        }
+        break;
+    case GateTXDecoderStepCheckDuration:
+        if(level) {
+            if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_gate_tx_const.te_short) <
+                subghz_protocol_gate_tx_const.te_delta) &&
+               (DURATION_DIFF(duration, subghz_protocol_gate_tx_const.te_long) <
+                subghz_protocol_gate_tx_const.te_delta * 3)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 0);
+                instance->decoder.parser_step = GateTXDecoderStepSaveDuration;
+            } else if(
+                (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_gate_tx_const.te_long) <
+                 subghz_protocol_gate_tx_const.te_delta * 3) &&
+                (DURATION_DIFF(duration, subghz_protocol_gate_tx_const.te_short) <
+                 subghz_protocol_gate_tx_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 1);
+                instance->decoder.parser_step = GateTXDecoderStepSaveDuration;
+            } else {
+                instance->decoder.parser_step = GateTXDecoderStepReset;
+            }
+        } else {
+            instance->decoder.parser_step = GateTXDecoderStepReset;
+        }
+        break;
+    }
+}
+
+static void subghz_protocol_gate_tx_check_remote_controller(SubGhzBlockGeneric* instance) {
+    uint32_t code_found_reverse =
+        subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit);
+
+    instance->serial = (code_found_reverse & 0xFF) << 12 |
+                       ((code_found_reverse >> 8) & 0xFF) << 4 |
+                       ((code_found_reverse >> 20) & 0x0F);
+    instance->btn = ((code_found_reverse >> 16) & 0x0F);
+}
+
+uint8_t subghz_protocol_decoder_gate_tx_get_hash_data(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderGateTx* instance = context;
+    return subghz_protocol_blocks_get_hash_data(
+        &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
+}
+
+bool subghz_protocol_decoder_gate_tx_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    furi_assert(context);
+    SubGhzProtocolDecoderGateTx* instance = context;
+    return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
+}
+
+bool subghz_protocol_decoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolDecoderGateTx* instance = context;
+    return subghz_block_generic_deserialize(&instance->generic, flipper_format);
+}
+
+void subghz_protocol_decoder_gate_tx_get_string(void* context, string_t output) {
+    furi_assert(context);
+    SubGhzProtocolDecoderGateTx* instance = context;
+    subghz_protocol_gate_tx_check_remote_controller(&instance->generic);
+    string_cat_printf(
+        output,
+        "%s %dbit\r\n"
+        "Key:%06lX\r\n"
+        "Sn:%05lX  Btn:%lX\r\n",
+        instance->generic.protocol_name,
+        instance->generic.data_count_bit,
+        (uint32_t)(instance->generic.data & 0xFFFFFF),
+        instance->generic.serial,
+        instance->generic.btn);
+}

+ 30 - 0
lib/subghz/protocols/gate_tx.h

@@ -0,0 +1,30 @@
+#pragma once
+
+#include "base.h"
+
+#define SUBGHZ_PROTOCOL_GATE_TX_NAME "GateTX"
+
+typedef struct SubGhzProtocolDecoderGateTx SubGhzProtocolDecoderGateTx;
+typedef struct SubGhzProtocolEncoderGateTx SubGhzProtocolEncoderGateTx;
+
+extern const SubGhzProtocolDecoder subghz_protocol_gate_tx_decoder;
+extern const SubGhzProtocolEncoder subghz_protocol_gate_tx_encoder;
+extern const SubGhzProtocol subghz_protocol_gate_tx;
+
+void* subghz_protocol_encoder_gate_tx_alloc(SubGhzEnvironment* environment);
+void subghz_protocol_encoder_gate_tx_free(void* context);
+bool subghz_protocol_encoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format);
+void subghz_protocol_encoder_gate_tx_stop(void* context);
+LevelDuration subghz_protocol_encoder_gate_tx_yield(void* context);
+void* subghz_protocol_decoder_gate_tx_alloc(SubGhzEnvironment* environment);
+void subghz_protocol_decoder_gate_tx_free(void* context);
+void subghz_protocol_decoder_gate_tx_reset(void* context);
+void subghz_protocol_decoder_gate_tx_feed(void* context, bool level, uint32_t duration);
+uint8_t subghz_protocol_decoder_gate_tx_get_hash_data(void* context);
+bool subghz_protocol_decoder_gate_tx_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset);
+bool subghz_protocol_decoder_gate_tx_deserialize(void* context, FlipperFormat* flipper_format);
+void subghz_protocol_decoder_gate_tx_get_string(void* context, string_t output);

+ 331 - 0
lib/subghz/protocols/hormann.c

@@ -0,0 +1,331 @@
+#include "hormann.h"
+
+#include "../blocks/const.h"
+#include "../blocks/decoder.h"
+#include "../blocks/encoder.h"
+#include "../blocks/generic.h"
+#include "../blocks/math.h"
+
+#define TAG "SubGhzProtocolHormannHSM"
+
+static const SubGhzBlockConst subghz_protocol_hormann_const = {
+    .te_short = 500,
+    .te_long = 1000,
+    .te_delta = 200,
+    .min_count_bit_for_found = 44,
+};
+
+struct SubGhzProtocolDecoderHormann {
+    SubGhzProtocolDecoderBase base;
+
+    SubGhzBlockDecoder decoder;
+    SubGhzBlockGeneric generic;
+};
+
+struct SubGhzProtocolEncoderHormann {
+    SubGhzProtocolEncoderBase base;
+
+    SubGhzProtocolBlockEncoder encoder;
+    SubGhzBlockGeneric generic;
+};
+
+typedef enum {
+    HormannDecoderStepReset = 0,
+    HormannDecoderStepFoundStartHeader,
+    HormannDecoderStepFoundHeader,
+    HormannDecoderStepFoundStartBit,
+    HormannDecoderStepSaveDuration,
+    HormannDecoderStepCheckDuration,
+} HormannDecoderStep;
+
+const SubGhzProtocolDecoder subghz_protocol_hormann_decoder = {
+    .alloc = subghz_protocol_decoder_hormann_alloc,
+    .free = subghz_protocol_decoder_hormann_free,
+
+    .feed = subghz_protocol_decoder_hormann_feed,
+    .reset = subghz_protocol_decoder_hormann_reset,
+
+    .get_hash_data = subghz_protocol_decoder_hormann_get_hash_data,
+    .serialize = subghz_protocol_decoder_hormann_serialize,
+    .deserialize = subghz_protocol_decoder_hormann_deserialize,
+    .get_string = subghz_protocol_decoder_hormann_get_string,
+};
+
+const SubGhzProtocolEncoder subghz_protocol_hormann_encoder = {
+    .alloc = subghz_protocol_encoder_hormann_alloc,
+    .free = subghz_protocol_encoder_hormann_free,
+
+    .deserialize = subghz_protocol_encoder_hormann_deserialize,
+    .stop = subghz_protocol_encoder_hormann_stop,
+    .yield = subghz_protocol_encoder_hormann_yield,
+};
+
+const SubGhzProtocol subghz_protocol_hormann = {
+    .name = SUBGHZ_PROTOCOL_HORMANN_HSM_NAME,
+    .type = SubGhzProtocolTypeStatic,
+    .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_AM |
+            SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save |
+            SubGhzProtocolFlag_Send,
+
+    .decoder = &subghz_protocol_hormann_decoder,
+    .encoder = &subghz_protocol_hormann_encoder,
+};
+
+void* subghz_protocol_encoder_hormann_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolEncoderHormann* instance = malloc(sizeof(SubGhzProtocolEncoderHormann));
+
+    instance->base.protocol = &subghz_protocol_hormann;
+    instance->generic.protocol_name = instance->base.protocol->name;
+
+    instance->encoder.repeat = 10;
+    instance->encoder.size_upload = 2048;
+    instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
+    instance->encoder.is_runing = false;
+    return instance;
+}
+
+void subghz_protocol_encoder_hormann_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolEncoderHormann* instance = context;
+    free(instance->encoder.upload);
+    free(instance);
+}
+
+static bool subghz_protocol_encoder_hormann_get_upload(SubGhzProtocolEncoderHormann* instance) {
+    furi_assert(instance);
+
+    size_t index = 0;
+    size_t size_upload = 3 + (instance->generic.data_count_bit * 2 + 2) * 20 + 1;
+    if(size_upload > instance->encoder.size_upload) {
+        FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
+        return false;
+    } else {
+        instance->encoder.size_upload = size_upload;
+    }
+    //Send header
+    instance->encoder.upload[index++] =
+        level_duration_make(false, (uint32_t)subghz_protocol_hormann_const.te_short * 64);
+    instance->encoder.upload[index++] =
+        level_duration_make(true, (uint32_t)subghz_protocol_hormann_const.te_short * 64);
+    instance->encoder.upload[index++] =
+        level_duration_make(false, (uint32_t)subghz_protocol_hormann_const.te_short * 64);
+    instance->encoder.repeat = 10; //original remote does 10 repeats
+
+    for(size_t repeat = 0; repeat < 20; repeat++) {
+        //Send start bit
+        instance->encoder.upload[index++] =
+            level_duration_make(true, (uint32_t)subghz_protocol_hormann_const.te_short * 24);
+        instance->encoder.upload[index++] =
+            level_duration_make(false, (uint32_t)subghz_protocol_hormann_const.te_short);
+        //Send key data
+        for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
+            if(bit_read(instance->generic.data, i - 1)) {
+                //send bit 1
+                instance->encoder.upload[index++] =
+                    level_duration_make(true, (uint32_t)subghz_protocol_hormann_const.te_long);
+                instance->encoder.upload[index++] =
+                    level_duration_make(false, (uint32_t)subghz_protocol_hormann_const.te_short);
+            } else {
+                //send bit 0
+                instance->encoder.upload[index++] =
+                    level_duration_make(true, (uint32_t)subghz_protocol_hormann_const.te_short);
+                instance->encoder.upload[index++] =
+                    level_duration_make(false, (uint32_t)subghz_protocol_hormann_const.te_long);
+            }
+        }
+    }
+    instance->encoder.upload[index++] =
+        level_duration_make(true, (uint32_t)subghz_protocol_hormann_const.te_short * 24);
+    return true;
+}
+
+bool subghz_protocol_encoder_hormann_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolEncoderHormann* instance = context;
+    bool res = false;
+    do {
+        if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
+            FURI_LOG_E(TAG, "Deserialize error");
+            break;
+        }
+
+        //optional parameter parameter
+        flipper_format_read_uint32(
+            flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
+
+        subghz_protocol_encoder_hormann_get_upload(instance);
+        instance->encoder.is_runing = true;
+
+        res = true;
+    } while(false);
+
+    return res;
+}
+
+void subghz_protocol_encoder_hormann_stop(void* context) {
+    SubGhzProtocolEncoderHormann* instance = context;
+    instance->encoder.is_runing = false;
+}
+
+LevelDuration subghz_protocol_encoder_hormann_yield(void* context) {
+    SubGhzProtocolEncoderHormann* instance = context;
+
+    if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) {
+        instance->encoder.is_runing = false;
+        return level_duration_reset();
+    }
+
+    LevelDuration ret = instance->encoder.upload[instance->encoder.front];
+
+    if(++instance->encoder.front == instance->encoder.size_upload) {
+        instance->encoder.repeat--;
+        instance->encoder.front = 0;
+    }
+
+    return ret;
+}
+
+void* subghz_protocol_decoder_hormann_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolDecoderHormann* instance = malloc(sizeof(SubGhzProtocolDecoderHormann));
+    instance->base.protocol = &subghz_protocol_hormann;
+    instance->generic.protocol_name = instance->base.protocol->name;
+    return instance;
+}
+
+void subghz_protocol_decoder_hormann_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderHormann* instance = context;
+    free(instance);
+}
+
+void subghz_protocol_decoder_hormann_reset(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderHormann* instance = context;
+    instance->decoder.parser_step = HormannDecoderStepReset;
+}
+
+void subghz_protocol_decoder_hormann_feed(void* context, bool level, uint32_t duration) {
+    furi_assert(context);
+    SubGhzProtocolDecoderHormann* instance = context;
+
+    switch(instance->decoder.parser_step) {
+    case HormannDecoderStepReset:
+        if((level) && (DURATION_DIFF(duration, subghz_protocol_hormann_const.te_short * 64) <
+                       subghz_protocol_hormann_const.te_delta * 64)) {
+            instance->decoder.parser_step = HormannDecoderStepFoundStartHeader;
+        }
+        break;
+    case HormannDecoderStepFoundStartHeader:
+        if((!level) && (DURATION_DIFF(duration, subghz_protocol_hormann_const.te_short * 64) <
+                        subghz_protocol_hormann_const.te_delta * 64)) {
+            instance->decoder.parser_step = HormannDecoderStepFoundHeader;
+        } else {
+            instance->decoder.parser_step = HormannDecoderStepReset;
+        }
+        break;
+    case HormannDecoderStepFoundHeader:
+        if((level) && (DURATION_DIFF(duration, subghz_protocol_hormann_const.te_short * 24) <
+                       subghz_protocol_hormann_const.te_delta * 24)) {
+            instance->decoder.parser_step = HormannDecoderStepFoundStartBit;
+        } else {
+            instance->decoder.parser_step = HormannDecoderStepReset;
+        }
+        break;
+    case HormannDecoderStepFoundStartBit:
+        if((!level) && (DURATION_DIFF(duration, subghz_protocol_hormann_const.te_short) <
+                        subghz_protocol_hormann_const.te_delta)) {
+            instance->decoder.parser_step = HormannDecoderStepSaveDuration;
+            instance->decoder.decode_data = 0;
+            instance->decoder.decode_count_bit = 0;
+        } else {
+            instance->decoder.parser_step = HormannDecoderStepReset;
+        }
+        break;
+    case HormannDecoderStepSaveDuration:
+        if(level) { //save interval
+            if(duration >= (subghz_protocol_hormann_const.te_short * 5)) {
+                instance->decoder.parser_step = HormannDecoderStepFoundStartBit;
+                if(instance->decoder.decode_count_bit >=
+                   subghz_protocol_hormann_const.min_count_bit_for_found) {
+                    instance->generic.data = instance->decoder.decode_data;
+                    instance->generic.data_count_bit = instance->decoder.decode_count_bit;
+
+                    if(instance->base.callback)
+                        instance->base.callback(&instance->base, instance->base.context);
+                }
+                break;
+            }
+            instance->decoder.te_last = duration;
+            instance->decoder.parser_step = HormannDecoderStepCheckDuration;
+        } else {
+            instance->decoder.parser_step = HormannDecoderStepReset;
+        }
+        break;
+    case HormannDecoderStepCheckDuration:
+        if(!level) {
+            if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_hormann_const.te_short) <
+                subghz_protocol_hormann_const.te_delta) &&
+               (DURATION_DIFF(duration, subghz_protocol_hormann_const.te_long) <
+                subghz_protocol_hormann_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 0);
+                instance->decoder.parser_step = HormannDecoderStepSaveDuration;
+            } else if(
+                (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_hormann_const.te_long) <
+                 subghz_protocol_hormann_const.te_delta) &&
+                (DURATION_DIFF(duration, subghz_protocol_hormann_const.te_short) <
+                 subghz_protocol_hormann_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 1);
+                instance->decoder.parser_step = HormannDecoderStepSaveDuration;
+            } else
+                instance->decoder.parser_step = HormannDecoderStepReset;
+        } else {
+            instance->decoder.parser_step = HormannDecoderStepReset;
+        }
+        break;
+    }
+}
+
+static void subghz_protocol_hormann_check_remote_controller(SubGhzBlockGeneric* instance) {
+    instance->btn = (instance->data >> 4) & 0xF;
+}
+
+uint8_t subghz_protocol_decoder_hormann_get_hash_data(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderHormann* instance = context;
+    return subghz_protocol_blocks_get_hash_data(
+        &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
+}
+
+bool subghz_protocol_decoder_hormann_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    furi_assert(context);
+    SubGhzProtocolDecoderHormann* instance = context;
+    return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
+}
+
+bool subghz_protocol_decoder_hormann_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolDecoderHormann* instance = context;
+    return subghz_block_generic_deserialize(&instance->generic, flipper_format);
+}
+
+void subghz_protocol_decoder_hormann_get_string(void* context, string_t output) {
+    furi_assert(context);
+    SubGhzProtocolDecoderHormann* instance = context;
+    subghz_protocol_hormann_check_remote_controller(&instance->generic);
+
+    string_cat_printf(
+        output,
+        "%s\r\n"
+        "%dbit\r\n"
+        "Key:0x%03lX%08lX\r\n"
+        "Btn:0x%01X\r\n",
+        instance->generic.protocol_name,
+        instance->generic.data_count_bit,
+        (uint32_t)(instance->generic.data >> 32),
+        (uint32_t)instance->generic.data,
+        instance->generic.btn);
+}

+ 30 - 0
lib/subghz/protocols/hormann.h

@@ -0,0 +1,30 @@
+#pragma once
+
+#include "base.h"
+
+#define SUBGHZ_PROTOCOL_HORMANN_HSM_NAME "Hormann HSM"
+
+typedef struct SubGhzProtocolDecoderHormann SubGhzProtocolDecoderHormann;
+typedef struct SubGhzProtocolEncoderHormann SubGhzProtocolEncoderHormann;
+
+extern const SubGhzProtocolDecoder subghz_protocol_hormann_decoder;
+extern const SubGhzProtocolEncoder subghz_protocol_hormann_encoder;
+extern const SubGhzProtocol subghz_protocol_hormann;
+
+void* subghz_protocol_encoder_hormann_alloc(SubGhzEnvironment* environment);
+void subghz_protocol_encoder_hormann_free(void* context);
+bool subghz_protocol_encoder_hormann_deserialize(void* context, FlipperFormat* flipper_format);
+void subghz_protocol_encoder_hormann_stop(void* context);
+LevelDuration subghz_protocol_encoder_hormann_yield(void* context);
+void* subghz_protocol_decoder_hormann_alloc(SubGhzEnvironment* environment);
+void subghz_protocol_decoder_hormann_free(void* context);
+void subghz_protocol_decoder_hormann_reset(void* context);
+void subghz_protocol_decoder_hormann_feed(void* context, bool level, uint32_t duration);
+uint8_t subghz_protocol_decoder_hormann_get_hash_data(void* context);
+bool subghz_protocol_decoder_hormann_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset);
+bool subghz_protocol_decoder_hormann_deserialize(void* context, FlipperFormat* flipper_format);
+void subghz_protocol_decoder_hormann_get_string(void* context, string_t output);

+ 218 - 0
lib/subghz/protocols/ido.c

@@ -0,0 +1,218 @@
+#include "ido.h"
+
+#include "../blocks/const.h"
+#include "../blocks/decoder.h"
+#include "../blocks/encoder.h"
+#include "../blocks/generic.h"
+#include "../blocks/math.h"
+
+#define TAG "SubGhzProtocol_iDo_117/111"
+
+static const SubGhzBlockConst subghz_protocol_ido_const = {
+    .te_short = 450,
+    .te_long = 1450,
+    .te_delta = 150,
+    .min_count_bit_for_found = 48,
+};
+
+struct SubGhzProtocolDecoderIDo {
+    SubGhzProtocolDecoderBase base;
+
+    SubGhzBlockDecoder decoder;
+    SubGhzBlockGeneric generic;
+};
+
+struct SubGhzProtocolEncoderIDo {
+    SubGhzProtocolEncoderBase base;
+
+    SubGhzProtocolBlockEncoder encoder;
+    SubGhzBlockGeneric generic;
+};
+
+typedef enum {
+    IDoDecoderStepReset = 0,
+    IDoDecoderStepFoundPreambula,
+    IDoDecoderStepSaveDuration,
+    IDoDecoderStepCheckDuration,
+} IDoDecoderStep;
+
+const SubGhzProtocolDecoder subghz_protocol_ido_decoder = {
+    .alloc = subghz_protocol_decoder_ido_alloc,
+    .free = subghz_protocol_decoder_ido_free,
+
+    .feed = subghz_protocol_decoder_ido_feed,
+    .reset = subghz_protocol_decoder_ido_reset,
+
+    .get_hash_data = subghz_protocol_decoder_ido_get_hash_data,
+    .deserialize = subghz_protocol_decoder_ido_deserialize,
+    .serialize = subghz_protocol_decoder_ido_serialize,
+    .get_string = subghz_protocol_decoder_ido_get_string,
+};
+
+const SubGhzProtocolEncoder subghz_protocol_ido_encoder = {
+    .alloc = NULL,
+    .free = NULL,
+
+    .deserialize = NULL,
+    .stop = NULL,
+    .yield = NULL,
+};
+
+const SubGhzProtocol subghz_protocol_ido = {
+    .name = SUBGHZ_PROTOCOL_IDO_NAME,
+    .type = SubGhzProtocolTypeDynamic,
+    .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
+
+    .decoder = &subghz_protocol_ido_decoder,
+    .encoder = &subghz_protocol_ido_encoder,
+};
+
+void* subghz_protocol_decoder_ido_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolDecoderIDo* instance = malloc(sizeof(SubGhzProtocolDecoderIDo));
+    instance->base.protocol = &subghz_protocol_ido;
+    instance->generic.protocol_name = instance->base.protocol->name;
+
+    return instance;
+}
+
+void subghz_protocol_decoder_ido_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderIDo* instance = context;
+    free(instance);
+}
+
+void subghz_protocol_decoder_ido_reset(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderIDo* instance = context;
+    instance->decoder.parser_step = IDoDecoderStepReset;
+}
+
+void subghz_protocol_decoder_ido_feed(void* context, bool level, uint32_t duration) {
+    furi_assert(context);
+    SubGhzProtocolDecoderIDo* instance = context;
+
+    switch(instance->decoder.parser_step) {
+    case IDoDecoderStepReset:
+        if((level) && (DURATION_DIFF(duration, subghz_protocol_ido_const.te_short * 10) <
+                       subghz_protocol_ido_const.te_delta * 5)) {
+            instance->decoder.parser_step = IDoDecoderStepFoundPreambula;
+        }
+        break;
+    case IDoDecoderStepFoundPreambula:
+        if((!level) && (DURATION_DIFF(duration, subghz_protocol_ido_const.te_short * 10) <
+                        subghz_protocol_ido_const.te_delta * 5)) {
+            //Found Preambula
+            instance->decoder.parser_step = IDoDecoderStepSaveDuration;
+            instance->decoder.decode_data = 0;
+            instance->decoder.decode_count_bit = 0;
+        } else {
+            instance->decoder.parser_step = IDoDecoderStepReset;
+        }
+        break;
+    case IDoDecoderStepSaveDuration:
+        if(level) {
+            if(duration >=
+               (subghz_protocol_ido_const.te_short * 5 + subghz_protocol_ido_const.te_delta)) {
+                instance->decoder.parser_step = IDoDecoderStepFoundPreambula;
+                if(instance->decoder.decode_count_bit >=
+                   subghz_protocol_ido_const.min_count_bit_for_found) {
+                    instance->generic.data = instance->decoder.decode_data;
+                    instance->generic.data_count_bit = instance->decoder.decode_count_bit;
+                    if(instance->base.callback)
+                        instance->base.callback(&instance->base, instance->base.context);
+                }
+                instance->decoder.decode_data = 0;
+                instance->decoder.decode_count_bit = 0;
+                break;
+            } else {
+                instance->decoder.te_last = duration;
+                instance->decoder.parser_step = IDoDecoderStepCheckDuration;
+            }
+
+        } else {
+            instance->decoder.parser_step = IDoDecoderStepReset;
+        }
+        break;
+    case IDoDecoderStepCheckDuration:
+        if(!level) {
+            if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_ido_const.te_short) <
+                subghz_protocol_ido_const.te_delta) &&
+               (DURATION_DIFF(duration, subghz_protocol_ido_const.te_long) <
+                subghz_protocol_ido_const.te_delta * 3)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 0);
+                instance->decoder.parser_step = IDoDecoderStepSaveDuration;
+            } else if(
+                (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_ido_const.te_short) <
+                 subghz_protocol_ido_const.te_delta * 3) &&
+                (DURATION_DIFF(duration, subghz_protocol_ido_const.te_short) <
+                 subghz_protocol_ido_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 1);
+                instance->decoder.parser_step = IDoDecoderStepSaveDuration;
+            } else {
+                instance->decoder.parser_step = IDoDecoderStepReset;
+            }
+        } else {
+            instance->decoder.parser_step = IDoDecoderStepReset;
+        }
+        break;
+    }
+}
+
+static void subghz_protocol_ido_check_remote_controller(SubGhzBlockGeneric* instance) {
+    uint64_t code_found_reverse =
+        subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit);
+    uint32_t code_fix = code_found_reverse & 0xFFFFFF;
+
+    instance->serial = code_fix & 0xFFFFF;
+    instance->btn = (code_fix >> 20) & 0x0F;
+}
+
+uint8_t subghz_protocol_decoder_ido_get_hash_data(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderIDo* instance = context;
+    return subghz_protocol_blocks_get_hash_data(
+        &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
+}
+
+bool subghz_protocol_decoder_ido_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    furi_assert(context);
+    SubGhzProtocolDecoderIDo* instance = context;
+    return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
+}
+
+bool subghz_protocol_decoder_ido_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolDecoderIDo* instance = context;
+    return subghz_block_generic_deserialize(&instance->generic, flipper_format);
+}
+
+void subghz_protocol_decoder_ido_get_string(void* context, string_t output) {
+    furi_assert(context);
+    SubGhzProtocolDecoderIDo* instance = context;
+
+    subghz_protocol_ido_check_remote_controller(&instance->generic);
+    uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key(
+        instance->generic.data, instance->generic.data_count_bit);
+    uint32_t code_fix = code_found_reverse & 0xFFFFFF;
+    uint32_t code_hop = (code_found_reverse >> 24) & 0xFFFFFF;
+
+    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->generic.protocol_name,
+        instance->generic.data_count_bit,
+        (uint32_t)(instance->generic.data >> 32),
+        (uint32_t)instance->generic.data,
+        code_fix,
+        code_hop,
+        instance->generic.serial,
+        instance->generic.btn);
+}

+ 25 - 0
lib/subghz/protocols/ido.h

@@ -0,0 +1,25 @@
+#pragma once
+
+#include "base.h"
+
+#define SUBGHZ_PROTOCOL_IDO_NAME "iDo 117/111"
+
+typedef struct SubGhzProtocolDecoderIDo SubGhzProtocolDecoderIDo;
+typedef struct SubGhzProtocolEncoderIDo SubGhzProtocolEncoderIDo;
+
+extern const SubGhzProtocolDecoder subghz_protocol_ido_decoder;
+extern const SubGhzProtocolEncoder subghz_protocol_ido_encoder;
+extern const SubGhzProtocol subghz_protocol_ido;
+
+void* subghz_protocol_decoder_ido_alloc(SubGhzEnvironment* environment);
+void subghz_protocol_decoder_ido_free(void* context);
+void subghz_protocol_decoder_ido_reset(void* context);
+void subghz_protocol_decoder_ido_feed(void* context, bool level, uint32_t duration);
+uint8_t subghz_protocol_decoder_ido_get_hash_data(void* context);
+bool subghz_protocol_decoder_ido_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset);
+bool subghz_protocol_decoder_ido_deserialize(void* context, FlipperFormat* flipper_format);
+void subghz_protocol_decoder_ido_get_string(void* context, string_t output);

+ 681 - 0
lib/subghz/protocols/keeloq.c

@@ -0,0 +1,681 @@
+#include "keeloq.h"
+#include "keeloq_common.h"
+
+#include "../subghz_keystore.h"
+#include <m-string.h>
+#include <m-array.h>
+
+#include "../blocks/const.h"
+#include "../blocks/decoder.h"
+#include "../blocks/encoder.h"
+#include "../blocks/generic.h"
+#include "../blocks/math.h"
+
+#define TAG "SubGhzProtocolkeeloq"
+
+static const SubGhzBlockConst subghz_protocol_keeloq_const = {
+    .te_short = 400,
+    .te_long = 800,
+    .te_delta = 140,
+    .min_count_bit_for_found = 64,
+};
+
+struct SubGhzProtocolDecoderKeeloq {
+    SubGhzProtocolDecoderBase base;
+
+    SubGhzBlockDecoder decoder;
+    SubGhzBlockGeneric generic;
+
+    uint16_t header_count;
+    SubGhzKeystore* keystore;
+    const char* manufacture_name;
+};
+
+struct SubGhzProtocolEncoderKeeloq {
+    SubGhzProtocolEncoderBase base;
+
+    SubGhzProtocolBlockEncoder encoder;
+    SubGhzBlockGeneric generic;
+
+    SubGhzKeystore* keystore;
+    const char* manufacture_name;
+};
+
+typedef enum {
+    KeeloqDecoderStepReset = 0,
+    KeeloqDecoderStepCheckPreambula,
+    KeeloqDecoderStepSaveDuration,
+    KeeloqDecoderStepCheckDuration,
+} KeeloqDecoderStep;
+
+const SubGhzProtocolDecoder subghz_protocol_keeloq_decoder = {
+    .alloc = subghz_protocol_decoder_keeloq_alloc,
+    .free = subghz_protocol_decoder_keeloq_free,
+
+    .feed = subghz_protocol_decoder_keeloq_feed,
+    .reset = subghz_protocol_decoder_keeloq_reset,
+
+    .get_hash_data = subghz_protocol_decoder_keeloq_get_hash_data,
+    .serialize = subghz_protocol_decoder_keeloq_serialize,
+    .deserialize = subghz_protocol_decoder_keeloq_deserialize,
+    .get_string = subghz_protocol_decoder_keeloq_get_string,
+};
+
+const SubGhzProtocolEncoder subghz_protocol_keeloq_encoder = {
+    .alloc = subghz_protocol_encoder_keeloq_alloc,
+    .free = subghz_protocol_encoder_keeloq_free,
+
+    .deserialize = subghz_protocol_encoder_keeloq_deserialize,
+    .stop = subghz_protocol_encoder_keeloq_stop,
+    .yield = subghz_protocol_encoder_keeloq_yield,
+};
+
+const SubGhzProtocol subghz_protocol_keeloq = {
+    .name = SUBGHZ_PROTOCOL_KEELOQ_NAME,
+    .type = SubGhzProtocolTypeDynamic,
+    .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_315 |
+            SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load |
+            SubGhzProtocolFlag_Send,
+
+    .decoder = &subghz_protocol_keeloq_decoder,
+    .encoder = &subghz_protocol_keeloq_encoder,
+};
+
+static void subghz_protocol_keeloq_check_remote_controller(
+    SubGhzBlockGeneric* instance,
+    SubGhzKeystore* keystore,
+    const char** manufacture_name);
+
+void* subghz_protocol_encoder_keeloq_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolEncoderKeeloq* instance = malloc(sizeof(SubGhzProtocolEncoderKeeloq));
+
+    instance->base.protocol = &subghz_protocol_keeloq;
+    instance->generic.protocol_name = instance->base.protocol->name;
+    instance->keystore = subghz_environment_get_keystore(environment);
+
+    instance->encoder.repeat = 10;
+    instance->encoder.size_upload = 256;
+    instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
+    instance->encoder.is_runing = false;
+    return instance;
+}
+
+void subghz_protocol_encoder_keeloq_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolEncoderKeeloq* instance = context;
+    free(instance->encoder.upload);
+    free(instance);
+}
+
+static bool subghz_protocol_keeloq_gen_data(SubGhzProtocolEncoderKeeloq* instance, uint8_t btn) {
+    instance->generic.cnt++;
+    uint32_t fix = btn << 28 | instance->generic.serial;
+    uint32_t decrypt = btn << 28 |
+                       (instance->generic.serial & 0x3FF)
+                           << 16 | //ToDo in some protocols the discriminator is 0
+                       instance->generic.cnt;
+    uint32_t hop = 0;
+    uint64_t man = 0;
+    int res = 0;
+
+    for
+        M_EACH(manufacture_code, *subghz_keystore_get_data(instance->keystore), SubGhzKeyArray_t) {
+            res = strcmp(string_get_cstr(manufacture_code->name), instance->manufacture_name);
+            if(res == 0) {
+                switch(manufacture_code->type) {
+                case KEELOQ_LEARNING_SIMPLE:
+                    //Simple Learning
+                    hop = subghz_protocol_keeloq_common_encrypt(decrypt, manufacture_code->key);
+                    break;
+                case KEELOQ_LEARNING_NORMAL:
+                    //Simple Learning
+                    man =
+                        subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
+                    hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
+                    break;
+                case KEELOQ_LEARNING_MAGIC_XOR_TYPE_1:
+                    man = subghz_protocol_keeloq_common_magic_xor_type1_learning(
+                        instance->generic.serial, manufacture_code->key);
+                    hop = subghz_protocol_keeloq_common_encrypt(decrypt, man);
+                    break;
+                case KEELOQ_LEARNING_UNKNOWN:
+                    hop = 0; //todo
+                    break;
+                }
+                break;
+            }
+        }
+    if(hop) {
+        uint64_t yek = (uint64_t)fix << 32 | hop;
+        instance->generic.data =
+            subghz_protocol_blocks_reverse_key(yek, instance->generic.data_count_bit);
+        return true;
+    } else {
+        instance->manufacture_name = "Unknown";
+        return false;
+    }
+}
+
+bool subghz_protocol_keeloq_create_data(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t serial,
+    uint8_t btn,
+    uint16_t cnt,
+    const char* manufacture_name,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    furi_assert(context);
+    SubGhzProtocolEncoderKeeloq* instance = context;
+    instance->generic.serial = serial;
+    instance->generic.cnt = cnt;
+    instance->manufacture_name = manufacture_name;
+    instance->generic.data_count_bit = 64;
+    bool res = subghz_protocol_keeloq_gen_data(instance, btn);
+    if(res) {
+        res =
+            subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
+    }
+    return res;
+}
+
+static bool
+    subghz_protocol_encoder_keeloq_get_upload(SubGhzProtocolEncoderKeeloq* instance, uint8_t btn) {
+    furi_assert(instance);
+
+    //gen new key
+    if(subghz_protocol_keeloq_gen_data(instance, btn)) {
+        //ToDo Update display data
+        // if(instance->common.callback)
+        //     instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context);
+    } else {
+        return false;
+    }
+
+    size_t index = 0;
+    size_t size_upload = 11 * 2 + 2 + (instance->generic.data_count_bit * 2) + 4;
+    if(size_upload > instance->encoder.size_upload) {
+        FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
+        return false;
+    } else {
+        instance->encoder.size_upload = size_upload;
+    }
+
+    //Send header
+    for(uint8_t i = 11; i > 0; i--) {
+        instance->encoder.upload[index++] =
+            level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short);
+        instance->encoder.upload[index++] =
+            level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_short);
+    }
+    instance->encoder.upload[index++] =
+        level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short);
+    instance->encoder.upload[index++] =
+        level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_short * 10);
+
+    //Send key data
+    for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
+        if(bit_read(instance->generic.data, i - 1)) {
+            //send bit 1
+            instance->encoder.upload[index++] =
+                level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short);
+            instance->encoder.upload[index++] =
+                level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_long);
+        } else {
+            //send bit 0
+            instance->encoder.upload[index++] =
+                level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_long);
+            instance->encoder.upload[index++] =
+                level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_short);
+        }
+    }
+    // +send 2 status bit
+    instance->encoder.upload[index++] =
+        level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short);
+    instance->encoder.upload[index++] =
+        level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_long);
+    // send end
+    instance->encoder.upload[index++] =
+        level_duration_make(true, (uint32_t)subghz_protocol_keeloq_const.te_short);
+    instance->encoder.upload[index++] =
+        level_duration_make(false, (uint32_t)subghz_protocol_keeloq_const.te_short * 40);
+
+    return true;
+}
+
+bool subghz_protocol_encoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolEncoderKeeloq* instance = context;
+    bool res = false;
+    do {
+        if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
+            FURI_LOG_E(TAG, "Deserialize error");
+            break;
+        }
+
+        subghz_protocol_keeloq_check_remote_controller(
+            &instance->generic, instance->keystore, &instance->manufacture_name);
+
+        if(strcmp(instance->manufacture_name, "DoorHan")) {
+            break;
+        }
+
+        //optional parameter parameter
+        flipper_format_read_uint32(
+            flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
+
+        subghz_protocol_encoder_keeloq_get_upload(instance, instance->generic.btn);
+
+        if(!flipper_format_rewind(flipper_format)) {
+            FURI_LOG_E(TAG, "Rewind error");
+            break;
+        }
+        uint8_t key_data[sizeof(uint64_t)] = {0};
+        for(size_t i = 0; i < sizeof(uint64_t); i++) {
+            key_data[sizeof(uint64_t) - i - 1] = (instance->generic.data >> i * 8) & 0xFF;
+        }
+        if(!flipper_format_update_hex(flipper_format, "Key", key_data, sizeof(uint64_t))) {
+            FURI_LOG_E(TAG, "Unable to add Key");
+            break;
+        }
+
+        instance->encoder.is_runing = true;
+
+        res = true;
+    } while(false);
+
+    return res;
+}
+
+void subghz_protocol_encoder_keeloq_stop(void* context) {
+    SubGhzProtocolEncoderKeeloq* instance = context;
+    instance->encoder.is_runing = false;
+}
+
+LevelDuration subghz_protocol_encoder_keeloq_yield(void* context) {
+    SubGhzProtocolEncoderKeeloq* instance = context;
+
+    if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) {
+        instance->encoder.is_runing = false;
+        return level_duration_reset();
+    }
+
+    LevelDuration ret = instance->encoder.upload[instance->encoder.front];
+
+    if(++instance->encoder.front == instance->encoder.size_upload) {
+        instance->encoder.repeat--;
+        instance->encoder.front = 0;
+    }
+
+    return ret;
+}
+
+void* subghz_protocol_decoder_keeloq_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolDecoderKeeloq* instance = malloc(sizeof(SubGhzProtocolDecoderKeeloq));
+    instance->base.protocol = &subghz_protocol_keeloq;
+    instance->generic.protocol_name = instance->base.protocol->name;
+    instance->keystore = subghz_environment_get_keystore(environment);
+
+    return instance;
+}
+
+void subghz_protocol_decoder_keeloq_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderKeeloq* instance = context;
+
+    free(instance);
+}
+
+void subghz_protocol_decoder_keeloq_reset(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderKeeloq* instance = context;
+    instance->decoder.parser_step = KeeloqDecoderStepReset;
+}
+
+void subghz_protocol_decoder_keeloq_feed(void* context, bool level, uint32_t duration) {
+    furi_assert(context);
+    SubGhzProtocolDecoderKeeloq* instance = context;
+
+    switch(instance->decoder.parser_step) {
+    case KeeloqDecoderStepReset:
+        if((level) && DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_short) <
+                          subghz_protocol_keeloq_const.te_delta) {
+            instance->decoder.parser_step = KeeloqDecoderStepCheckPreambula;
+            instance->header_count++;
+        }
+        break;
+    case KeeloqDecoderStepCheckPreambula:
+        if((!level) && (DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_short) <
+                        subghz_protocol_keeloq_const.te_delta)) {
+            instance->decoder.parser_step = KeeloqDecoderStepReset;
+            break;
+        }
+        if((instance->header_count > 2) &&
+           (DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_short * 10) <
+            subghz_protocol_keeloq_const.te_delta * 10)) {
+            // Found header
+            instance->decoder.parser_step = KeeloqDecoderStepSaveDuration;
+            instance->decoder.decode_data = 0;
+            instance->decoder.decode_count_bit = 0;
+        } else {
+            instance->decoder.parser_step = KeeloqDecoderStepReset;
+            instance->header_count = 0;
+        }
+        break;
+    case KeeloqDecoderStepSaveDuration:
+        if(level) {
+            instance->decoder.te_last = duration;
+            instance->decoder.parser_step = KeeloqDecoderStepCheckDuration;
+        }
+        break;
+    case KeeloqDecoderStepCheckDuration:
+        if(!level) {
+            if(duration >= (subghz_protocol_keeloq_const.te_short * 2 +
+                            subghz_protocol_keeloq_const.te_delta)) {
+                // Found end TX
+                instance->decoder.parser_step = KeeloqDecoderStepReset;
+                if(instance->decoder.decode_count_bit >=
+                   subghz_protocol_keeloq_const.min_count_bit_for_found) {
+                    if(instance->generic.data != instance->decoder.decode_data) {
+                        instance->generic.data = instance->decoder.decode_data;
+                        instance->generic.data_count_bit = instance->decoder.decode_count_bit;
+                        if(instance->base.callback)
+                            instance->base.callback(&instance->base, instance->base.context);
+                    }
+                    instance->decoder.decode_data = 0;
+                    instance->decoder.decode_count_bit = 0;
+                    instance->header_count = 0;
+                }
+                break;
+            } else if(
+                (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_keeloq_const.te_short) <
+                 subghz_protocol_keeloq_const.te_delta) &&
+                (DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_long) <
+                 subghz_protocol_keeloq_const.te_delta)) {
+                if(instance->decoder.decode_count_bit <
+                   subghz_protocol_keeloq_const.min_count_bit_for_found) {
+                    subghz_protocol_blocks_add_bit(&instance->decoder, 1);
+                }
+                instance->decoder.parser_step = KeeloqDecoderStepSaveDuration;
+            } else if(
+                (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_keeloq_const.te_long) <
+                 subghz_protocol_keeloq_const.te_delta) &&
+                (DURATION_DIFF(duration, subghz_protocol_keeloq_const.te_short) <
+                 subghz_protocol_keeloq_const.te_delta)) {
+                if(instance->decoder.decode_count_bit <
+                   subghz_protocol_keeloq_const.min_count_bit_for_found) {
+                    subghz_protocol_blocks_add_bit(&instance->decoder, 0);
+                }
+                instance->decoder.parser_step = KeeloqDecoderStepSaveDuration;
+            } else {
+                instance->decoder.parser_step = KeeloqDecoderStepReset;
+                instance->header_count = 0;
+            }
+        } else {
+            instance->decoder.parser_step = KeeloqDecoderStepReset;
+            instance->header_count = 0;
+        }
+        break;
+    }
+}
+
+static inline bool subghz_protocol_keeloq_check_decrypt(
+    SubGhzBlockGeneric* instance,
+    uint32_t decrypt,
+    uint8_t btn,
+    uint32_t end_serial) {
+    furi_assert(instance);
+    if((decrypt >> 28 == btn) && (((((uint16_t)(decrypt >> 16)) & 0xFF) == end_serial) ||
+                                  ((((uint16_t)(decrypt >> 16)) & 0xFF) == 0))) {
+        instance->cnt = decrypt & 0x0000FFFF;
+        return true;
+    }
+    return false;
+}
+
+/** Checking the accepted code against the database manafacture key
+ * 
+ * @param instance SubGhzProtocolKeeloq instance
+ * @param fix fix part of the parcel
+ * @param hop hop encrypted part of the parcel
+ * @return true on successful search
+ */
+static uint8_t subghz_protocol_keeloq_check_remote_controller_selector(
+    SubGhzBlockGeneric* instance,
+    uint32_t fix,
+    uint32_t hop,
+    SubGhzKeystore* keystore,
+    const char** manufacture_name) {
+    // protocol HCS300 uses 10 bits in discriminator, HCS200 uses 8 bits, for backward compatibility, we are looking for the 8-bit pattern
+    // HCS300 -> uint16_t end_serial = (uint16_t)(fix & 0x3FF);
+    // HCS200 -> uint16_t end_serial = (uint16_t)(fix & 0xFF);
+
+    uint16_t end_serial = (uint16_t)(fix & 0xFF);
+    uint8_t btn = (uint8_t)(fix >> 28);
+    uint32_t decrypt = 0;
+    uint64_t man;
+    uint32_t seed = 0;
+
+    for
+        M_EACH(manufacture_code, *subghz_keystore_get_data(keystore), SubGhzKeyArray_t) {
+            switch(manufacture_code->type) {
+            case KEELOQ_LEARNING_SIMPLE:
+                // Simple Learning
+                decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
+                if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
+                    *manufacture_name = string_get_cstr(manufacture_code->name);
+                    return 1;
+                }
+                break;
+            case KEELOQ_LEARNING_NORMAL:
+                // Normal Learning
+                // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
+                man = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
+                decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
+                if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
+                    *manufacture_name = string_get_cstr(manufacture_code->name);
+                    return 1;
+                }
+                break;
+            case KEELOQ_LEARNING_SECURE:
+                man = subghz_protocol_keeloq_common_secure_learning(
+                    fix, seed, manufacture_code->key);
+                decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
+                if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
+                    *manufacture_name = string_get_cstr(manufacture_code->name);
+                    return 1;
+                }
+                break;
+            case KEELOQ_LEARNING_MAGIC_XOR_TYPE_1:
+                man = subghz_protocol_keeloq_common_magic_xor_type1_learning(
+                    fix, manufacture_code->key);
+                decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
+                if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
+                    *manufacture_name = string_get_cstr(manufacture_code->name);
+                    return 1;
+                }
+                break;
+            case KEELOQ_LEARNING_UNKNOWN:
+                // Simple Learning
+                decrypt = subghz_protocol_keeloq_common_decrypt(hop, manufacture_code->key);
+                if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
+                    *manufacture_name = string_get_cstr(manufacture_code->name);
+                    return 1;
+                }
+                // Check for mirrored man
+                uint64_t man_rev = 0;
+                uint64_t man_rev_byte = 0;
+                for(uint8_t i = 0; i < 64; i += 8) {
+                    man_rev_byte = (uint8_t)(manufacture_code->key >> i);
+                    man_rev = man_rev | man_rev_byte << (56 - i);
+                }
+                decrypt = subghz_protocol_keeloq_common_decrypt(hop, man_rev);
+                if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
+                    *manufacture_name = string_get_cstr(manufacture_code->name);
+                    return 1;
+                }
+                //###########################
+                // Normal Learning
+                // https://phreakerclub.com/forum/showpost.php?p=43557&postcount=37
+                man = subghz_protocol_keeloq_common_normal_learning(fix, manufacture_code->key);
+                decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
+                if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
+                    *manufacture_name = string_get_cstr(manufacture_code->name);
+                    return 1;
+                }
+
+                // Check for mirrored man
+                man = subghz_protocol_keeloq_common_normal_learning(fix, man_rev);
+                decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
+                if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
+                    *manufacture_name = string_get_cstr(manufacture_code->name);
+                    return 1;
+                }
+
+                // Secure Learning
+                man = subghz_protocol_keeloq_common_secure_learning(
+                    fix, seed, manufacture_code->key);
+                decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
+                if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
+                    *manufacture_name = string_get_cstr(manufacture_code->name);
+                    return 1;
+                }
+
+                // Check for mirrored man
+                man = subghz_protocol_keeloq_common_secure_learning(fix, seed, man_rev);
+                decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
+                if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
+                    *manufacture_name = string_get_cstr(manufacture_code->name);
+                    return 1;
+                }
+
+                // Magic xor type1 learning
+                man = subghz_protocol_keeloq_common_magic_xor_type1_learning(
+                    fix, manufacture_code->key);
+                decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
+                if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
+                    *manufacture_name = string_get_cstr(manufacture_code->name);
+                    return 1;
+                }
+
+                // Check for mirrored man
+                man = subghz_protocol_keeloq_common_magic_xor_type1_learning(fix, man_rev);
+                decrypt = subghz_protocol_keeloq_common_decrypt(hop, man);
+                if(subghz_protocol_keeloq_check_decrypt(instance, decrypt, btn, end_serial)) {
+                    *manufacture_name = string_get_cstr(manufacture_code->name);
+                    return 1;
+                }
+                break;
+            }
+        }
+
+    *manufacture_name = "Unknown";
+    instance->cnt = 0;
+
+    return 0;
+}
+
+/** Analysis of received data
+ * 
+ * @param instance SubGhzProtocolKeeloq instance
+ */
+static void subghz_protocol_keeloq_check_remote_controller(
+    SubGhzBlockGeneric* instance,
+    SubGhzKeystore* keystore,
+    const char** manufacture_name) {
+    uint64_t key = subghz_protocol_blocks_reverse_key(instance->data, instance->data_count_bit);
+    uint32_t key_fix = key >> 32;
+    uint32_t key_hop = key & 0x00000000ffffffff;
+    // Check key AN-Motors
+    if((key_hop >> 24) == ((key_hop >> 16) & 0x00ff) &&
+       (key_fix >> 28) == ((key_hop >> 12) & 0x0f) && (key_hop & 0xFFF) == 0x404) {
+        *manufacture_name = "AN-Motors";
+        instance->cnt = key_hop >> 16;
+    } else if((key_hop & 0xFFF) == (0x000) && (key_fix >> 28) == ((key_hop >> 12) & 0x0f)) {
+        *manufacture_name = "HCS101";
+        instance->cnt = key_hop >> 16;
+    } else {
+        subghz_protocol_keeloq_check_remote_controller_selector(
+            instance, key_fix, key_hop, keystore, manufacture_name);
+    }
+
+    instance->serial = key_fix & 0x0FFFFFFF;
+    instance->btn = key_fix >> 28;
+}
+
+uint8_t subghz_protocol_decoder_keeloq_get_hash_data(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderKeeloq* instance = context;
+    return subghz_protocol_blocks_get_hash_data(
+        &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
+}
+
+bool subghz_protocol_decoder_keeloq_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    furi_assert(context);
+    SubGhzProtocolDecoderKeeloq* instance = context;
+    subghz_protocol_keeloq_check_remote_controller(
+        &instance->generic, instance->keystore, &instance->manufacture_name);
+
+    bool res =
+        subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
+
+    if(res && !flipper_format_write_string_cstr(
+                  flipper_format, "Manufacture", instance->manufacture_name)) {
+        FURI_LOG_E(TAG, "Unable to add manufacture name");
+        res = false;
+    }
+    return res;
+}
+
+bool subghz_protocol_decoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolDecoderKeeloq* instance = context;
+    bool res = false;
+    do {
+        if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
+            FURI_LOG_E(TAG, "Deserialize error");
+            break;
+        }
+        res = true;
+    } while(false);
+
+    return res;
+}
+
+void subghz_protocol_decoder_keeloq_get_string(void* context, string_t output) {
+    furi_assert(context);
+    SubGhzProtocolDecoderKeeloq* instance = context;
+    subghz_protocol_keeloq_check_remote_controller(
+        &instance->generic, instance->keystore, &instance->manufacture_name);
+
+    uint32_t code_found_hi = instance->generic.data >> 32;
+    uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
+
+    uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key(
+        instance->generic.data, instance->generic.data_count_bit);
+    uint32_t code_found_reverse_hi = code_found_reverse >> 32;
+    uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
+
+    string_cat_printf(
+        output,
+        "%s %dbit\r\n"
+        "Key:%08lX%08lX\r\n"
+        "Fix:0x%08lX    Cnt:%04X\r\n"
+        "Hop:0x%08lX    Btn:%01lX\r\n"
+        "MF:%s\r\n"
+        "Sn:0x%07lX \r\n",
+        instance->generic.protocol_name,
+        instance->generic.data_count_bit,
+        code_found_hi,
+        code_found_lo,
+        code_found_reverse_hi,
+        instance->generic.cnt,
+        code_found_reverse_lo,
+        instance->generic.btn,
+        instance->manufacture_name,
+        instance->generic.serial);
+}

+ 39 - 0
lib/subghz/protocols/keeloq.h

@@ -0,0 +1,39 @@
+#pragma once
+
+#include "base.h"
+
+#define SUBGHZ_PROTOCOL_KEELOQ_NAME "KeeLoq"
+
+typedef struct SubGhzProtocolDecoderKeeloq SubGhzProtocolDecoderKeeloq;
+typedef struct SubGhzProtocolEncoderKeeloq SubGhzProtocolEncoderKeeloq;
+
+extern const SubGhzProtocolDecoder subghz_protocol_keeloq_decoder;
+extern const SubGhzProtocolEncoder subghz_protocol_keeloq_encoder;
+extern const SubGhzProtocol subghz_protocol_keeloq;
+
+void* subghz_protocol_encoder_keeloq_alloc(SubGhzEnvironment* environment);
+void subghz_protocol_encoder_keeloq_free(void* context);
+bool subghz_protocol_keeloq_create_data(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t serial,
+    uint8_t btn,
+    uint16_t cnt,
+    const char* manufacture_name,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset);
+bool subghz_protocol_encoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format);
+void subghz_protocol_encoder_keeloq_stop(void* context);
+LevelDuration subghz_protocol_encoder_keeloq_yield(void* context);
+void* subghz_protocol_decoder_keeloq_alloc(SubGhzEnvironment* environment);
+void subghz_protocol_decoder_keeloq_free(void* context);
+void subghz_protocol_decoder_keeloq_reset(void* context);
+void subghz_protocol_decoder_keeloq_feed(void* context, bool level, uint32_t duration);
+uint8_t subghz_protocol_decoder_keeloq_get_hash_data(void* context);
+bool subghz_protocol_decoder_keeloq_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset);
+bool subghz_protocol_decoder_keeloq_deserialize(void* context, FlipperFormat* flipper_format);
+void subghz_protocol_decoder_keeloq_get_string(void* context, string_t output);

+ 2 - 2
lib/subghz/protocols/subghz_protocol_keeloq_common.c → lib/subghz/protocols/keeloq_common.c

@@ -1,4 +1,4 @@
-#include "subghz_protocol_keeloq_common.h"
+#include "keeloq_common.h"
 
 
 #include <furi.h>
 #include <furi.h>
 
 
@@ -8,7 +8,7 @@
 /** Simple Learning Encrypt
 /** Simple Learning Encrypt
  * @param data - 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter
  * @param data - 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter
  * @param key - manufacture (64bit)
  * @param key - manufacture (64bit)
- * @return keelog encrypt data
+ * @return keeloq encrypt data
  */
  */
 inline uint32_t subghz_protocol_keeloq_common_encrypt(const uint32_t data, const uint64_t key) {
 inline uint32_t subghz_protocol_keeloq_common_encrypt(const uint32_t data, const uint64_t key) {
     uint32_t x = data, r;
     uint32_t x = data, r;

+ 4 - 4
lib/subghz/protocols/subghz_protocol_keeloq_common.h → lib/subghz/protocols/keeloq_common.h

@@ -1,6 +1,6 @@
 #pragma once
 #pragma once
-#include "subghz_protocol_common.h"
-#include "file_worker.h"
+
+#include "base.h"
 
 
 #include <furi.h>
 #include <furi.h>
 
 
@@ -29,12 +29,12 @@
 /** Simple Learning Encrypt
 /** Simple Learning Encrypt
  * @param data - 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter
  * @param data - 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter
  * @param key - manufacture (64bit)
  * @param key - manufacture (64bit)
- * @return keelog encrypt data
+ * @return keeloq encrypt data
  */
  */
 uint32_t subghz_protocol_keeloq_common_encrypt(const uint32_t data, const uint64_t key);
 uint32_t subghz_protocol_keeloq_common_encrypt(const uint32_t data, const uint64_t key);
 
 
 /** Simple Learning Decrypt
 /** Simple Learning Decrypt
- * @param data - keelog encrypt data
+ * @param data - keeloq encrypt data
  * @param key - manufacture (64bit)
  * @param key - manufacture (64bit)
  * @return 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter
  * @return 0xBSSSCCCC, B(4bit) key, S(10bit) serial&0x3FF, C(16bit) counter
  */
  */

+ 268 - 0
lib/subghz/protocols/kia.c

@@ -0,0 +1,268 @@
+#include "kia.h"
+
+#include "../blocks/const.h"
+#include "../blocks/decoder.h"
+#include "../blocks/encoder.h"
+#include "../blocks/generic.h"
+#include "../blocks/math.h"
+
+#define TAG "SubGhzProtocoKIA"
+
+static const SubGhzBlockConst subghz_protocol_kia_const = {
+    .te_short = 250,
+    .te_long = 500,
+    .te_delta = 100,
+    .min_count_bit_for_found = 60,
+};
+
+struct SubGhzProtocolDecoderKIA {
+    SubGhzProtocolDecoderBase base;
+
+    SubGhzBlockDecoder decoder;
+    SubGhzBlockGeneric generic;
+
+    uint16_t header_count;
+};
+
+struct SubGhzProtocolEncoderKIA {
+    SubGhzProtocolEncoderBase base;
+
+    SubGhzProtocolBlockEncoder encoder;
+    SubGhzBlockGeneric generic;
+};
+
+typedef enum {
+    KIADecoderStepReset = 0,
+    KIADecoderStepCheckPreambula,
+    KIADecoderStepSaveDuration,
+    KIADecoderStepCheckDuration,
+} KIADecoderStep;
+
+const SubGhzProtocolDecoder subghz_protocol_kia_decoder = {
+    .alloc = subghz_protocol_decoder_kia_alloc,
+    .free = subghz_protocol_decoder_kia_free,
+
+    .feed = subghz_protocol_decoder_kia_feed,
+    .reset = subghz_protocol_decoder_kia_reset,
+
+    .get_hash_data = subghz_protocol_decoder_kia_get_hash_data,
+    .serialize = subghz_protocol_decoder_kia_serialize,
+    .deserialize = subghz_protocol_decoder_kia_deserialize,
+    .get_string = subghz_protocol_decoder_kia_get_string,
+};
+
+const SubGhzProtocolEncoder subghz_protocol_kia_encoder = {
+    .alloc = NULL,
+    .free = NULL,
+
+    .deserialize = NULL,
+    .stop = NULL,
+    .yield = NULL,
+};
+
+const SubGhzProtocol subghz_protocol_kia = {
+    .name = SUBGHZ_PROTOCOL_KIA_NAME,
+    .type = SubGhzProtocolTypeDynamic,
+    .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable,
+
+    .decoder = &subghz_protocol_kia_decoder,
+    .encoder = &subghz_protocol_kia_encoder,
+};
+
+void* subghz_protocol_decoder_kia_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolDecoderKIA* instance = malloc(sizeof(SubGhzProtocolDecoderKIA));
+    instance->base.protocol = &subghz_protocol_kia;
+    instance->generic.protocol_name = instance->base.protocol->name;
+
+    return instance;
+}
+
+void subghz_protocol_decoder_kia_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderKIA* instance = context;
+    free(instance);
+}
+
+void subghz_protocol_decoder_kia_reset(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderKIA* instance = context;
+    instance->decoder.parser_step = KIADecoderStepReset;
+}
+
+void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t duration) {
+    furi_assert(context);
+    SubGhzProtocolDecoderKIA* instance = context;
+
+    switch(instance->decoder.parser_step) {
+    case KIADecoderStepReset:
+        if((!level) && (DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) <
+                        subghz_protocol_kia_const.te_delta)) {
+            instance->decoder.parser_step = KIADecoderStepCheckPreambula;
+            instance->decoder.te_last = duration;
+            instance->header_count = 0;
+        }
+        break;
+    case KIADecoderStepCheckPreambula:
+        if(!level) {
+            if((DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) <
+                subghz_protocol_kia_const.te_delta) ||
+               (DURATION_DIFF(duration, subghz_protocol_kia_const.te_long) <
+                subghz_protocol_kia_const.te_delta)) {
+                instance->decoder.te_last = duration;
+            } else {
+                instance->decoder.parser_step = KIADecoderStepReset;
+            }
+        } else if(
+            (DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) <
+             subghz_protocol_kia_const.te_delta) &&
+            (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_short) <
+             subghz_protocol_kia_const.te_delta)) {
+            // Found header
+            instance->header_count++;
+            break;
+        } else if(
+            (DURATION_DIFF(duration, subghz_protocol_kia_const.te_long) <
+             subghz_protocol_kia_const.te_delta) &&
+            (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_long) <
+             subghz_protocol_kia_const.te_delta)) {
+            // Found start bit
+            if(instance->header_count > 15) {
+                instance->decoder.parser_step = KIADecoderStepSaveDuration;
+                instance->decoder.decode_data = 0;
+                instance->decoder.decode_count_bit = 1;
+                subghz_protocol_blocks_add_bit(&instance->decoder, 1);
+            } else {
+                instance->decoder.parser_step = KIADecoderStepReset;
+            }
+        } else {
+            instance->decoder.parser_step = KIADecoderStepReset;
+        }
+        break;
+    case KIADecoderStepSaveDuration:
+        if(!level) {
+            if(duration >=
+               (subghz_protocol_kia_const.te_long + subghz_protocol_kia_const.te_delta * 2)) {
+                //Found stop bit
+                instance->decoder.parser_step = KIADecoderStepReset;
+                if(instance->decoder.decode_count_bit >=
+                   subghz_protocol_kia_const.min_count_bit_for_found) {
+                    instance->generic.data = instance->decoder.decode_data;
+                    instance->generic.data_count_bit = instance->decoder.decode_count_bit;
+                    if(instance->base.callback)
+                        instance->base.callback(&instance->base, instance->base.context);
+                }
+                instance->decoder.decode_data = 0;
+                instance->decoder.decode_count_bit = 0;
+                break;
+            } else {
+                instance->decoder.te_last = duration;
+                instance->decoder.parser_step = KIADecoderStepCheckDuration;
+            }
+
+        } else {
+            instance->decoder.parser_step = KIADecoderStepReset;
+        }
+        break;
+    case KIADecoderStepCheckDuration:
+        if(level) {
+            if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_short) <
+                subghz_protocol_kia_const.te_delta) &&
+               (DURATION_DIFF(duration, subghz_protocol_kia_const.te_short) <
+                subghz_protocol_kia_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 0);
+                instance->decoder.parser_step = KIADecoderStepSaveDuration;
+            } else if(
+                (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_kia_const.te_long) <
+                 subghz_protocol_kia_const.te_delta) &&
+                (DURATION_DIFF(duration, subghz_protocol_kia_const.te_long) <
+                 subghz_protocol_kia_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 1);
+                instance->decoder.parser_step = KIADecoderStepSaveDuration;
+            } else {
+                instance->decoder.parser_step = KIADecoderStepReset;
+            }
+        } else {
+            instance->decoder.parser_step = KIADecoderStepReset;
+        }
+        break;
+    }
+}
+
+uint8_t subghz_protocol_kia_crc8(uint8_t* data, size_t len) {
+    uint8_t crc = 0x08;
+    size_t i, j;
+    for(i = 0; i < len; i++) {
+        crc ^= data[i];
+        for(j = 0; j < 8; j++) {
+            if((crc & 0x80) != 0)
+                crc = (uint8_t)((crc << 1) ^ 0x7F);
+            else
+                crc <<= 1;
+        }
+    }
+    return crc;
+}
+
+/** Analysis of received data
+ * 
+ * @param instance SubGhzProtocolKIA instance
+ */
+static void subghz_protocol_kia_check_remote_controller(SubGhzBlockGeneric* instance) {
+    /*
+    *   0x0F 0112 43B04EC 1 7D
+    *   0x0F 0113 43B04EC 1 DF
+    *   0x0F 0114 43B04EC 1 30
+    *   0x0F 0115 43B04EC 2 13
+    *   0x0F 0116 43B04EC 3 F5
+    *         CNT  Serial K CRC8 Kia (CRC8, poly 0x7f, start_crc 0x08)
+    */
+
+    instance->serial = (uint32_t)((instance->data >> 12) & 0x0FFFFFFF);
+    instance->btn = (instance->data >> 8) & 0x0F;
+    instance->cnt = (instance->data >> 40) & 0xFFFF;
+}
+
+uint8_t subghz_protocol_decoder_kia_get_hash_data(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderKIA* instance = context;
+    return subghz_protocol_blocks_get_hash_data(
+        &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
+}
+
+bool subghz_protocol_decoder_kia_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    furi_assert(context);
+    SubGhzProtocolDecoderKIA* instance = context;
+    return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
+}
+
+bool subghz_protocol_decoder_kia_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolDecoderKIA* instance = context;
+    return subghz_block_generic_deserialize(&instance->generic, flipper_format);
+}
+
+void subghz_protocol_decoder_kia_get_string(void* context, string_t output) {
+    furi_assert(context);
+    SubGhzProtocolDecoderKIA* instance = context;
+
+    subghz_protocol_kia_check_remote_controller(&instance->generic);
+    uint32_t code_found_hi = instance->generic.data >> 32;
+    uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
+
+    string_cat_printf(
+        output,
+        "%s %dbit\r\n"
+        "Key:%08lX%08lX\r\n"
+        "Sn:%07lX Btn:%lX Cnt:%04X\r\n",
+        instance->generic.protocol_name,
+        instance->generic.data_count_bit,
+        code_found_hi,
+        code_found_lo,
+        instance->generic.serial,
+        instance->generic.btn,
+        instance->generic.cnt);
+}

+ 25 - 0
lib/subghz/protocols/kia.h

@@ -0,0 +1,25 @@
+#pragma once
+
+#include "base.h"
+
+#define SUBGHZ_PROTOCOL_KIA_NAME "KIA Seed"
+
+typedef struct SubGhzProtocolDecoderKIA SubGhzProtocolDecoderKIA;
+typedef struct SubGhzProtocolEncoderKIA SubGhzProtocolEncoderKIA;
+
+extern const SubGhzProtocolDecoder subghz_protocol_kia_decoder;
+extern const SubGhzProtocolEncoder subghz_protocol_kia_encoder;
+extern const SubGhzProtocol subghz_protocol_kia;
+
+void* subghz_protocol_decoder_kia_alloc(SubGhzEnvironment* environment);
+void subghz_protocol_decoder_kia_free(void* context);
+void subghz_protocol_decoder_kia_reset(void* context);
+void subghz_protocol_decoder_kia_feed(void* context, bool level, uint32_t duration);
+uint8_t subghz_protocol_decoder_kia_get_hash_data(void* context);
+bool subghz_protocol_decoder_kia_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset);
+bool subghz_protocol_decoder_kia_deserialize(void* context, FlipperFormat* flipper_format);
+void subghz_protocol_decoder_kia_get_string(void* context, string_t output);

+ 375 - 0
lib/subghz/protocols/nero_radio.c

@@ -0,0 +1,375 @@
+#include "nero_radio.h"
+
+#include "../blocks/const.h"
+#include "../blocks/decoder.h"
+#include "../blocks/encoder.h"
+#include "../blocks/generic.h"
+#include "../blocks/math.h"
+
+#define TAG "SubGhzProtocolNeroRadio"
+
+static const SubGhzBlockConst subghz_protocol_nero_radio_const = {
+    .te_short = 200,
+    .te_long = 400,
+    .te_delta = 80,
+    .min_count_bit_for_found = 56,
+};
+
+struct SubGhzProtocolDecoderNeroRadio {
+    SubGhzProtocolDecoderBase base;
+
+    SubGhzBlockDecoder decoder;
+    SubGhzBlockGeneric generic;
+
+    uint16_t header_count;
+};
+
+struct SubGhzProtocolEncoderNeroRadio {
+    SubGhzProtocolEncoderBase base;
+
+    SubGhzProtocolBlockEncoder encoder;
+    SubGhzBlockGeneric generic;
+};
+
+typedef enum {
+    NeroRadioDecoderStepReset = 0,
+    NeroRadioDecoderStepCheckPreambula,
+    NeroRadioDecoderStepSaveDuration,
+    NeroRadioDecoderStepCheckDuration,
+} NeroRadioDecoderStep;
+
+const SubGhzProtocolDecoder subghz_protocol_nero_radio_decoder = {
+    .alloc = subghz_protocol_decoder_nero_radio_alloc,
+    .free = subghz_protocol_decoder_nero_radio_free,
+
+    .feed = subghz_protocol_decoder_nero_radio_feed,
+    .reset = subghz_protocol_decoder_nero_radio_reset,
+
+    .get_hash_data = subghz_protocol_decoder_nero_radio_get_hash_data,
+    .serialize = subghz_protocol_decoder_nero_radio_serialize,
+    .deserialize = subghz_protocol_decoder_nero_radio_deserialize,
+    .get_string = subghz_protocol_decoder_nero_radio_get_string,
+};
+
+const SubGhzProtocolEncoder subghz_protocol_nero_radio_encoder = {
+    .alloc = subghz_protocol_encoder_nero_radio_alloc,
+    .free = subghz_protocol_encoder_nero_radio_free,
+
+    .deserialize = subghz_protocol_encoder_nero_radio_deserialize,
+    .stop = subghz_protocol_encoder_nero_radio_stop,
+    .yield = subghz_protocol_encoder_nero_radio_yield,
+};
+
+const SubGhzProtocol subghz_protocol_nero_radio = {
+    .name = SUBGHZ_PROTOCOL_NERO_RADIO_NAME,
+    .type = SubGhzProtocolTypeStatic,
+    .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
+            SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
+
+    .decoder = &subghz_protocol_nero_radio_decoder,
+    .encoder = &subghz_protocol_nero_radio_encoder,
+};
+
+void* subghz_protocol_encoder_nero_radio_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolEncoderNeroRadio* instance = malloc(sizeof(SubGhzProtocolEncoderNeroRadio));
+
+    instance->base.protocol = &subghz_protocol_nero_radio;
+    instance->generic.protocol_name = instance->base.protocol->name;
+
+    instance->encoder.repeat = 10;
+    instance->encoder.size_upload = 256;
+    instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
+    instance->encoder.is_runing = false;
+    return instance;
+}
+
+void subghz_protocol_encoder_nero_radio_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolEncoderNeroRadio* instance = context;
+    free(instance->encoder.upload);
+    free(instance);
+}
+
+static bool
+    subghz_protocol_encoder_nero_radio_get_upload(SubGhzProtocolEncoderNeroRadio* instance) {
+    furi_assert(instance);
+    size_t index = 0;
+    size_t size_upload = 49 * 2 + 2 + (instance->generic.data_count_bit * 2);
+    if(size_upload > instance->encoder.size_upload) {
+        FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
+        return false;
+    } else {
+        instance->encoder.size_upload = size_upload;
+    }
+
+    //Send header
+    for(uint8_t i = 0; i < 49; i++) {
+        instance->encoder.upload[index++] =
+            level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_short);
+        instance->encoder.upload[index++] =
+            level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_short);
+    }
+
+    //Send start bit
+    instance->encoder.upload[index++] =
+        level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_short * 4);
+    instance->encoder.upload[index++] =
+        level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_short);
+
+    //Send key data
+    for(uint8_t i = instance->generic.data_count_bit; i > 1; i--) {
+        if(bit_read(instance->generic.data, i - 1)) {
+            //send bit 1
+            instance->encoder.upload[index++] =
+                level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_long);
+            instance->encoder.upload[index++] =
+                level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_short);
+        } else {
+            //send bit 0
+            instance->encoder.upload[index++] =
+                level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_short);
+            instance->encoder.upload[index++] =
+                level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_long);
+        }
+    }
+    if(bit_read(instance->generic.data, 0)) {
+        //send bit 1
+        instance->encoder.upload[index++] =
+            level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_long);
+        instance->encoder.upload[index++] =
+            level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_short * 37);
+    } else {
+        //send bit 0
+        instance->encoder.upload[index++] =
+            level_duration_make(true, (uint32_t)subghz_protocol_nero_radio_const.te_short);
+        instance->encoder.upload[index++] =
+            level_duration_make(false, (uint32_t)subghz_protocol_nero_radio_const.te_short * 37);
+    }
+    return true;
+}
+
+bool subghz_protocol_encoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolEncoderNeroRadio* instance = context;
+    bool res = false;
+    do {
+        if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
+            FURI_LOG_E(TAG, "Deserialize error");
+            break;
+        }
+
+        //optional parameter parameter
+        flipper_format_read_uint32(
+            flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
+
+        subghz_protocol_encoder_nero_radio_get_upload(instance);
+        instance->encoder.is_runing = true;
+
+        res = true;
+    } while(false);
+
+    return res;
+}
+
+void subghz_protocol_encoder_nero_radio_stop(void* context) {
+    SubGhzProtocolEncoderNeroRadio* instance = context;
+    instance->encoder.is_runing = false;
+}
+
+LevelDuration subghz_protocol_encoder_nero_radio_yield(void* context) {
+    SubGhzProtocolEncoderNeroRadio* instance = context;
+
+    if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) {
+        instance->encoder.is_runing = false;
+        return level_duration_reset();
+    }
+
+    LevelDuration ret = instance->encoder.upload[instance->encoder.front];
+
+    if(++instance->encoder.front == instance->encoder.size_upload) {
+        instance->encoder.repeat--;
+        instance->encoder.front = 0;
+    }
+
+    return ret;
+}
+
+void* subghz_protocol_decoder_nero_radio_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolDecoderNeroRadio* instance = malloc(sizeof(SubGhzProtocolDecoderNeroRadio));
+    instance->base.protocol = &subghz_protocol_nero_radio;
+    instance->generic.protocol_name = instance->base.protocol->name;
+    return instance;
+}
+
+void subghz_protocol_decoder_nero_radio_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNeroRadio* instance = context;
+    free(instance);
+}
+
+void subghz_protocol_decoder_nero_radio_reset(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNeroRadio* instance = context;
+    instance->decoder.parser_step = NeroRadioDecoderStepReset;
+}
+
+void subghz_protocol_decoder_nero_radio_feed(void* context, bool level, uint32_t duration) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNeroRadio* instance = context;
+
+    switch(instance->decoder.parser_step) {
+    case NeroRadioDecoderStepReset:
+        if((level) && (DURATION_DIFF(duration, subghz_protocol_nero_radio_const.te_short) <
+                       subghz_protocol_nero_radio_const.te_delta)) {
+            instance->decoder.parser_step = NeroRadioDecoderStepCheckPreambula;
+            instance->decoder.te_last = duration;
+            instance->header_count = 0;
+        }
+        break;
+    case NeroRadioDecoderStepCheckPreambula:
+        if(level) {
+            if((DURATION_DIFF(duration, subghz_protocol_nero_radio_const.te_short) <
+                subghz_protocol_nero_radio_const.te_delta) ||
+               (DURATION_DIFF(duration, subghz_protocol_nero_radio_const.te_short * 4) <
+                subghz_protocol_nero_radio_const.te_delta)) {
+                instance->decoder.te_last = duration;
+            } else {
+                instance->decoder.parser_step = NeroRadioDecoderStepReset;
+            }
+        } else if(
+            DURATION_DIFF(duration, subghz_protocol_nero_radio_const.te_short) <
+            subghz_protocol_nero_radio_const.te_delta) {
+            if(DURATION_DIFF(instance->decoder.te_last, subghz_protocol_nero_radio_const.te_short) <
+               subghz_protocol_nero_radio_const.te_delta) {
+                // Found header
+                instance->header_count++;
+                break;
+            } else if(
+                DURATION_DIFF(
+                    instance->decoder.te_last, subghz_protocol_nero_radio_const.te_short * 4) <
+                subghz_protocol_nero_radio_const.te_delta) {
+                // Found start bit
+                if(instance->header_count > 40) {
+                    instance->decoder.parser_step = NeroRadioDecoderStepSaveDuration;
+                    instance->decoder.decode_data = 0;
+                    instance->decoder.decode_count_bit = 0;
+                } else {
+                    instance->decoder.parser_step = NeroRadioDecoderStepReset;
+                }
+            } else {
+                instance->decoder.parser_step = NeroRadioDecoderStepReset;
+            }
+        } else {
+            instance->decoder.parser_step = NeroRadioDecoderStepReset;
+        }
+        break;
+    case NeroRadioDecoderStepSaveDuration:
+        if(level) {
+            instance->decoder.te_last = duration;
+            instance->decoder.parser_step = NeroRadioDecoderStepCheckDuration;
+        } else {
+            instance->decoder.parser_step = NeroRadioDecoderStepReset;
+        }
+        break;
+    case NeroRadioDecoderStepCheckDuration:
+        if(!level) {
+            if(duration >= (subghz_protocol_nero_radio_const.te_short * 10 +
+                            subghz_protocol_nero_radio_const.te_delta * 2)) {
+                //Found stop bit
+                if(DURATION_DIFF(
+                       instance->decoder.te_last, subghz_protocol_nero_radio_const.te_short) <
+                   subghz_protocol_nero_radio_const.te_delta) {
+                    subghz_protocol_blocks_add_bit(&instance->decoder, 0);
+                } else if(
+                    DURATION_DIFF(
+                        instance->decoder.te_last, subghz_protocol_nero_radio_const.te_long) <
+                    subghz_protocol_nero_radio_const.te_delta) {
+                    subghz_protocol_blocks_add_bit(&instance->decoder, 1);
+                }
+                instance->decoder.parser_step = NeroRadioDecoderStepReset;
+                if(instance->decoder.decode_count_bit >=
+                   subghz_protocol_nero_radio_const.min_count_bit_for_found) {
+                    instance->generic.data = instance->decoder.decode_data;
+                    instance->generic.data_count_bit = instance->decoder.decode_count_bit;
+
+                    if(instance->base.callback)
+                        instance->base.callback(&instance->base, instance->base.context);
+                }
+                instance->decoder.decode_data = 0;
+                instance->decoder.decode_count_bit = 0;
+                instance->decoder.parser_step = NeroRadioDecoderStepReset;
+                break;
+            } else if(
+                (DURATION_DIFF(
+                     instance->decoder.te_last, subghz_protocol_nero_radio_const.te_short) <
+                 subghz_protocol_nero_radio_const.te_delta) &&
+                (DURATION_DIFF(duration, subghz_protocol_nero_radio_const.te_long) <
+                 subghz_protocol_nero_radio_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 0);
+                instance->decoder.parser_step = NeroRadioDecoderStepSaveDuration;
+            } else if(
+                (DURATION_DIFF(
+                     instance->decoder.te_last, subghz_protocol_nero_radio_const.te_long) <
+                 subghz_protocol_nero_radio_const.te_delta) &&
+                (DURATION_DIFF(duration, subghz_protocol_nero_radio_const.te_short) <
+                 subghz_protocol_nero_radio_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 1);
+                instance->decoder.parser_step = NeroRadioDecoderStepSaveDuration;
+            } else {
+                instance->decoder.parser_step = NeroRadioDecoderStepReset;
+            }
+        } else {
+            instance->decoder.parser_step = NeroRadioDecoderStepReset;
+        }
+        break;
+    }
+}
+
+uint8_t subghz_protocol_decoder_nero_radio_get_hash_data(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNeroRadio* instance = context;
+    return subghz_protocol_blocks_get_hash_data(
+        &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
+}
+
+bool subghz_protocol_decoder_nero_radio_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNeroRadio* instance = context;
+    return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
+}
+
+bool subghz_protocol_decoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNeroRadio* instance = context;
+    return subghz_block_generic_deserialize(&instance->generic, flipper_format);
+}
+
+void subghz_protocol_decoder_nero_radio_get_string(void* context, string_t output) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNeroRadio* instance = context;
+
+    uint32_t code_found_hi = instance->generic.data >> 32;
+    uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
+
+    uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key(
+        instance->generic.data, instance->generic.data_count_bit);
+
+    uint32_t code_found_reverse_hi = code_found_reverse >> 32;
+    uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
+
+    string_cat_printf(
+        output,
+        "%s %dbit\r\n"
+        "Key:0x%lX%08lX\r\n"
+        "Yek:0x%lX%08lX\r\n",
+        instance->generic.protocol_name,
+        instance->generic.data_count_bit,
+        code_found_hi,
+        code_found_lo,
+        code_found_reverse_hi,
+        code_found_reverse_lo);
+}

+ 30 - 0
lib/subghz/protocols/nero_radio.h

@@ -0,0 +1,30 @@
+#pragma once
+
+#include "base.h"
+
+#define SUBGHZ_PROTOCOL_NERO_RADIO_NAME "Nero Radio"
+
+typedef struct SubGhzProtocolDecoderNeroRadio SubGhzProtocolDecoderNeroRadio;
+typedef struct SubGhzProtocolEncoderNeroRadio SubGhzProtocolEncoderNeroRadio;
+
+extern const SubGhzProtocolDecoder subghz_protocol_nero_radio_decoder;
+extern const SubGhzProtocolEncoder subghz_protocol_nero_radio_encoder;
+extern const SubGhzProtocol subghz_protocol_nero_radio;
+
+void* subghz_protocol_encoder_nero_radio_alloc(SubGhzEnvironment* environment);
+void subghz_protocol_encoder_nero_radio_free(void* context);
+bool subghz_protocol_encoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format);
+void subghz_protocol_encoder_nero_radio_stop(void* context);
+LevelDuration subghz_protocol_encoder_nero_radio_yield(void* context);
+void* subghz_protocol_decoder_nero_radio_alloc(SubGhzEnvironment* environment);
+void subghz_protocol_decoder_nero_radio_free(void* context);
+void subghz_protocol_decoder_nero_radio_reset(void* context);
+void subghz_protocol_decoder_nero_radio_feed(void* context, bool level, uint32_t duration);
+uint8_t subghz_protocol_decoder_nero_radio_get_hash_data(void* context);
+bool subghz_protocol_decoder_nero_radio_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset);
+bool subghz_protocol_decoder_nero_radio_deserialize(void* context, FlipperFormat* flipper_format);
+void subghz_protocol_decoder_nero_radio_get_string(void* context, string_t output);

+ 366 - 0
lib/subghz/protocols/nero_sketch.c

@@ -0,0 +1,366 @@
+#include "nero_sketch.h"
+
+#include "../blocks/const.h"
+#include "../blocks/decoder.h"
+#include "../blocks/encoder.h"
+#include "../blocks/generic.h"
+#include "../blocks/math.h"
+
+/*
+ * Help
+ * https://phreakerclub.com/447
+ *
+ */
+
+#define TAG "SubGhzProtocolNeroSketch"
+
+static const SubGhzBlockConst subghz_protocol_nero_sketch_const = {
+    .te_short = 330,
+    .te_long = 660,
+    .te_delta = 150,
+    .min_count_bit_for_found = 40,
+};
+
+struct SubGhzProtocolDecoderNeroSketch {
+    SubGhzProtocolDecoderBase base;
+
+    SubGhzBlockDecoder decoder;
+    SubGhzBlockGeneric generic;
+    uint16_t header_count;
+};
+
+struct SubGhzProtocolEncoderNeroSketch {
+    SubGhzProtocolEncoderBase base;
+
+    SubGhzProtocolBlockEncoder encoder;
+    SubGhzBlockGeneric generic;
+};
+
+typedef enum {
+    NeroSketchDecoderStepReset = 0,
+    NeroSketchDecoderStepCheckPreambula,
+    NeroSketchDecoderStepSaveDuration,
+    NeroSketchDecoderStepCheckDuration,
+} NeroSketchDecoderStep;
+
+const SubGhzProtocolDecoder subghz_protocol_nero_sketch_decoder = {
+    .alloc = subghz_protocol_decoder_nero_sketch_alloc,
+    .free = subghz_protocol_decoder_nero_sketch_free,
+
+    .feed = subghz_protocol_decoder_nero_sketch_feed,
+    .reset = subghz_protocol_decoder_nero_sketch_reset,
+
+    .get_hash_data = subghz_protocol_decoder_nero_sketch_get_hash_data,
+    .serialize = subghz_protocol_decoder_nero_sketch_serialize,
+    .deserialize = subghz_protocol_decoder_nero_sketch_deserialize,
+    .get_string = subghz_protocol_decoder_nero_sketch_get_string,
+};
+
+const SubGhzProtocolEncoder subghz_protocol_nero_sketch_encoder = {
+    .alloc = subghz_protocol_encoder_nero_sketch_alloc,
+    .free = subghz_protocol_encoder_nero_sketch_free,
+
+    .deserialize = subghz_protocol_encoder_nero_sketch_deserialize,
+    .stop = subghz_protocol_encoder_nero_sketch_stop,
+    .yield = subghz_protocol_encoder_nero_sketch_yield,
+};
+
+const SubGhzProtocol subghz_protocol_nero_sketch = {
+    .name = SUBGHZ_PROTOCOL_NERO_SKETCH_NAME,
+    .type = SubGhzProtocolTypeStatic,
+    .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable |
+            SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
+
+    .decoder = &subghz_protocol_nero_sketch_decoder,
+    .encoder = &subghz_protocol_nero_sketch_encoder,
+};
+
+void* subghz_protocol_encoder_nero_sketch_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolEncoderNeroSketch* instance = malloc(sizeof(SubGhzProtocolEncoderNeroSketch));
+
+    instance->base.protocol = &subghz_protocol_nero_sketch;
+    instance->generic.protocol_name = instance->base.protocol->name;
+
+    instance->encoder.repeat = 10;
+    instance->encoder.size_upload = 256;
+    instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
+    instance->encoder.is_runing = false;
+    return instance;
+}
+
+void subghz_protocol_encoder_nero_sketch_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolEncoderNeroSketch* instance = context;
+    free(instance->encoder.upload);
+    free(instance);
+}
+
+static bool
+    subghz_protocol_encoder_nero_sketch_get_upload(SubGhzProtocolEncoderNeroSketch* instance) {
+    furi_assert(instance);
+
+    size_t index = 0;
+    size_t size_upload = 47 * 2 + 2 + (instance->generic.data_count_bit * 2) + 2;
+    if(size_upload > instance->encoder.size_upload) {
+        FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
+        return false;
+    } else {
+        instance->encoder.size_upload = size_upload;
+    }
+
+    //Send header
+    for(uint8_t i = 0; i < 47; i++) {
+        instance->encoder.upload[index++] =
+            level_duration_make(true, (uint32_t)subghz_protocol_nero_sketch_const.te_short);
+        instance->encoder.upload[index++] =
+            level_duration_make(false, (uint32_t)subghz_protocol_nero_sketch_const.te_short);
+    }
+
+    //Send start bit
+    instance->encoder.upload[index++] =
+        level_duration_make(true, (uint32_t)subghz_protocol_nero_sketch_const.te_short * 4);
+    instance->encoder.upload[index++] =
+        level_duration_make(false, (uint32_t)subghz_protocol_nero_sketch_const.te_short);
+
+    //Send key data
+    for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
+        if(bit_read(instance->generic.data, i - 1)) {
+            //send bit 1
+            instance->encoder.upload[index++] =
+                level_duration_make(true, (uint32_t)subghz_protocol_nero_sketch_const.te_long);
+            instance->encoder.upload[index++] =
+                level_duration_make(false, (uint32_t)subghz_protocol_nero_sketch_const.te_short);
+        } else {
+            //send bit 0
+            instance->encoder.upload[index++] =
+                level_duration_make(true, (uint32_t)subghz_protocol_nero_sketch_const.te_short);
+            instance->encoder.upload[index++] =
+                level_duration_make(false, (uint32_t)subghz_protocol_nero_sketch_const.te_long);
+        }
+    }
+
+    //Send stop bit
+    instance->encoder.upload[index++] =
+        level_duration_make(true, (uint32_t)subghz_protocol_nero_sketch_const.te_short * 3);
+    instance->encoder.upload[index++] =
+        level_duration_make(false, (uint32_t)subghz_protocol_nero_sketch_const.te_short);
+
+    return true;
+}
+
+bool subghz_protocol_encoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolEncoderNeroSketch* instance = context;
+    bool res = false;
+    do {
+        if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
+            FURI_LOG_E(TAG, "Deserialize error");
+            break;
+        }
+
+        //optional parameter parameter
+        flipper_format_read_uint32(
+            flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
+
+        subghz_protocol_encoder_nero_sketch_get_upload(instance);
+        instance->encoder.is_runing = true;
+
+        res = true;
+    } while(false);
+
+    return res;
+}
+
+void subghz_protocol_encoder_nero_sketch_stop(void* context) {
+    SubGhzProtocolEncoderNeroSketch* instance = context;
+    instance->encoder.is_runing = false;
+}
+
+LevelDuration subghz_protocol_encoder_nero_sketch_yield(void* context) {
+    SubGhzProtocolEncoderNeroSketch* instance = context;
+
+    if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) {
+        instance->encoder.is_runing = false;
+        return level_duration_reset();
+    }
+
+    LevelDuration ret = instance->encoder.upload[instance->encoder.front];
+
+    if(++instance->encoder.front == instance->encoder.size_upload) {
+        instance->encoder.repeat--;
+        instance->encoder.front = 0;
+    }
+
+    return ret;
+}
+
+void* subghz_protocol_decoder_nero_sketch_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolDecoderNeroSketch* instance = malloc(sizeof(SubGhzProtocolDecoderNeroSketch));
+    instance->base.protocol = &subghz_protocol_nero_sketch;
+    instance->generic.protocol_name = instance->base.protocol->name;
+    return instance;
+}
+
+void subghz_protocol_decoder_nero_sketch_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNeroSketch* instance = context;
+    free(instance);
+}
+
+void subghz_protocol_decoder_nero_sketch_reset(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNeroSketch* instance = context;
+    instance->decoder.parser_step = NeroSketchDecoderStepReset;
+}
+
+void subghz_protocol_decoder_nero_sketch_feed(void* context, bool level, uint32_t duration) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNeroSketch* instance = context;
+
+    switch(instance->decoder.parser_step) {
+    case NeroSketchDecoderStepReset:
+        if((level) && (DURATION_DIFF(duration, subghz_protocol_nero_sketch_const.te_short) <
+                       subghz_protocol_nero_sketch_const.te_delta)) {
+            instance->decoder.parser_step = NeroSketchDecoderStepCheckPreambula;
+            instance->decoder.te_last = duration;
+            instance->header_count = 0;
+        }
+        break;
+    case NeroSketchDecoderStepCheckPreambula:
+        if(level) {
+            if((DURATION_DIFF(duration, subghz_protocol_nero_sketch_const.te_short) <
+                subghz_protocol_nero_sketch_const.te_delta) ||
+               (DURATION_DIFF(duration, subghz_protocol_nero_sketch_const.te_short * 4) <
+                subghz_protocol_nero_sketch_const.te_delta)) {
+                instance->decoder.te_last = duration;
+            } else {
+                instance->decoder.parser_step = NeroSketchDecoderStepReset;
+            }
+        } else if(
+            DURATION_DIFF(duration, subghz_protocol_nero_sketch_const.te_short) <
+            subghz_protocol_nero_sketch_const.te_delta) {
+            if(DURATION_DIFF(
+                   instance->decoder.te_last, subghz_protocol_nero_sketch_const.te_short) <
+               subghz_protocol_nero_sketch_const.te_delta) {
+                // Found header
+                instance->header_count++;
+                break;
+            } else if(
+                DURATION_DIFF(
+                    instance->decoder.te_last, subghz_protocol_nero_sketch_const.te_short * 4) <
+                subghz_protocol_nero_sketch_const.te_delta) {
+                // Found start bit
+                if(instance->header_count > 40) {
+                    instance->decoder.parser_step = NeroSketchDecoderStepSaveDuration;
+                    instance->decoder.decode_data = 0;
+                    instance->decoder.decode_count_bit = 0;
+                } else {
+                    instance->decoder.parser_step = NeroSketchDecoderStepReset;
+                }
+            } else {
+                instance->decoder.parser_step = NeroSketchDecoderStepReset;
+            }
+        } else {
+            instance->decoder.parser_step = NeroSketchDecoderStepReset;
+        }
+        break;
+    case NeroSketchDecoderStepSaveDuration:
+        if(level) {
+            if(duration >= (subghz_protocol_nero_sketch_const.te_short * 2 +
+                            subghz_protocol_nero_sketch_const.te_delta * 2)) {
+                //Found stop bit
+                instance->decoder.parser_step = NeroSketchDecoderStepReset;
+                if(instance->decoder.decode_count_bit >=
+                   subghz_protocol_nero_sketch_const.min_count_bit_for_found) {
+                    instance->generic.data = instance->decoder.decode_data;
+                    instance->generic.data_count_bit = instance->decoder.decode_count_bit;
+                    if(instance->base.callback)
+                        instance->base.callback(&instance->base, instance->base.context);
+                }
+                instance->decoder.decode_data = 0;
+                instance->decoder.decode_count_bit = 0;
+                break;
+            } else {
+                instance->decoder.te_last = duration;
+                instance->decoder.parser_step = NeroSketchDecoderStepCheckDuration;
+            }
+
+        } else {
+            instance->decoder.parser_step = NeroSketchDecoderStepReset;
+        }
+        break;
+    case NeroSketchDecoderStepCheckDuration:
+        if(!level) {
+            if((DURATION_DIFF(
+                    instance->decoder.te_last, subghz_protocol_nero_sketch_const.te_short) <
+                subghz_protocol_nero_sketch_const.te_delta) &&
+               (DURATION_DIFF(duration, subghz_protocol_nero_sketch_const.te_long) <
+                subghz_protocol_nero_sketch_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 0);
+                instance->decoder.parser_step = NeroSketchDecoderStepSaveDuration;
+            } else if(
+                (DURATION_DIFF(
+                     instance->decoder.te_last, subghz_protocol_nero_sketch_const.te_long) <
+                 subghz_protocol_nero_sketch_const.te_delta) &&
+                (DURATION_DIFF(duration, subghz_protocol_nero_sketch_const.te_short) <
+                 subghz_protocol_nero_sketch_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 1);
+                instance->decoder.parser_step = NeroSketchDecoderStepSaveDuration;
+            } else {
+                instance->decoder.parser_step = NeroSketchDecoderStepReset;
+            }
+        } else {
+            instance->decoder.parser_step = NeroSketchDecoderStepReset;
+        }
+        break;
+    }
+}
+
+uint8_t subghz_protocol_decoder_nero_sketch_get_hash_data(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNeroSketch* instance = context;
+    return subghz_protocol_blocks_get_hash_data(
+        &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
+}
+
+bool subghz_protocol_decoder_nero_sketch_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNeroSketch* instance = context;
+    return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
+}
+
+bool subghz_protocol_decoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNeroSketch* instance = context;
+    return subghz_block_generic_deserialize(&instance->generic, flipper_format);
+}
+
+void subghz_protocol_decoder_nero_sketch_get_string(void* context, string_t output) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNeroSketch* instance = context;
+
+    uint32_t code_found_hi = instance->generic.data >> 32;
+    uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
+
+    uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key(
+        instance->generic.data, instance->generic.data_count_bit);
+
+    uint32_t code_found_reverse_hi = code_found_reverse >> 32;
+    uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
+
+    string_cat_printf(
+        output,
+        "%s %dbit\r\n"
+        "Key:0x%lX%08lX\r\n"
+        "Yek:0x%lX%08lX\r\n",
+        instance->generic.protocol_name,
+        instance->generic.data_count_bit,
+        code_found_hi,
+        code_found_lo,
+        code_found_reverse_hi,
+        code_found_reverse_lo);
+}

+ 30 - 0
lib/subghz/protocols/nero_sketch.h

@@ -0,0 +1,30 @@
+#pragma once
+
+#include "base.h"
+
+#define SUBGHZ_PROTOCOL_NERO_SKETCH_NAME "Nero Sketch"
+
+typedef struct SubGhzProtocolDecoderNeroSketch SubGhzProtocolDecoderNeroSketch;
+typedef struct SubGhzProtocolEncoderNeroSketch SubGhzProtocolEncoderNeroSketch;
+
+extern const SubGhzProtocolDecoder subghz_protocol_nero_sketch_decoder;
+extern const SubGhzProtocolEncoder subghz_protocol_nero_sketch_encoder;
+extern const SubGhzProtocol subghz_protocol_nero_sketch;
+
+void* subghz_protocol_encoder_nero_sketch_alloc(SubGhzEnvironment* environment);
+void subghz_protocol_encoder_nero_sketch_free(void* context);
+bool subghz_protocol_encoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format);
+void subghz_protocol_encoder_nero_sketch_stop(void* context);
+LevelDuration subghz_protocol_encoder_nero_sketch_yield(void* context);
+void* subghz_protocol_decoder_nero_sketch_alloc(SubGhzEnvironment* environment);
+void subghz_protocol_decoder_nero_sketch_free(void* context);
+void subghz_protocol_decoder_nero_sketch_reset(void* context);
+void subghz_protocol_decoder_nero_sketch_feed(void* context, bool level, uint32_t duration);
+uint8_t subghz_protocol_decoder_nero_sketch_get_hash_data(void* context);
+bool subghz_protocol_decoder_nero_sketch_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset);
+bool subghz_protocol_decoder_nero_sketch_deserialize(void* context, FlipperFormat* flipper_format);
+void subghz_protocol_decoder_nero_sketch_get_string(void* context, string_t output);

+ 310 - 0
lib/subghz/protocols/nice_flo.c

@@ -0,0 +1,310 @@
+#include "nice_flo.h"
+#include "../blocks/const.h"
+#include "../blocks/decoder.h"
+#include "../blocks/encoder.h"
+#include "../blocks/generic.h"
+#include "../blocks/math.h"
+
+/*
+ * Help
+ * https://phreakerclub.com/447
+ *
+ */
+
+#define TAG "SubGhzProtocolNiceFLO"
+
+static const SubGhzBlockConst subghz_protocol_nice_flo_const = {
+    .te_short = 700,
+    .te_long = 1400,
+    .te_delta = 200,
+    .min_count_bit_for_found = 12,
+};
+
+struct SubGhzProtocolDecoderNiceFlo {
+    SubGhzProtocolDecoderBase base;
+
+    SubGhzBlockDecoder decoder;
+    SubGhzBlockGeneric generic;
+};
+
+struct SubGhzProtocolEncoderNiceFlo {
+    SubGhzProtocolEncoderBase base;
+
+    SubGhzProtocolBlockEncoder encoder;
+    SubGhzBlockGeneric generic;
+};
+
+typedef enum {
+    NiceFloDecoderStepReset = 0,
+    NiceFloDecoderStepFoundStartBit,
+    NiceFloDecoderStepSaveDuration,
+    NiceFloDecoderStepCheckDuration,
+} NiceFloDecoderStep;
+
+const SubGhzProtocolDecoder subghz_protocol_nice_flo_decoder = {
+    .alloc = subghz_protocol_decoder_nice_flo_alloc,
+    .free = subghz_protocol_decoder_nice_flo_free,
+
+    .feed = subghz_protocol_decoder_nice_flo_feed,
+    .reset = subghz_protocol_decoder_nice_flo_reset,
+
+    .get_hash_data = subghz_protocol_decoder_nice_flo_get_hash_data,
+    .serialize = subghz_protocol_decoder_nice_flo_serialize,
+    .deserialize = subghz_protocol_decoder_nice_flo_deserialize,
+    .get_string = subghz_protocol_decoder_nice_flo_get_string,
+};
+
+const SubGhzProtocolEncoder subghz_protocol_nice_flo_encoder = {
+    .alloc = subghz_protocol_encoder_nice_flo_alloc,
+    .free = subghz_protocol_encoder_nice_flo_free,
+
+    .deserialize = subghz_protocol_encoder_nice_flo_deserialize,
+    .stop = subghz_protocol_encoder_nice_flo_stop,
+    .yield = subghz_protocol_encoder_nice_flo_yield,
+};
+
+const SubGhzProtocol subghz_protocol_nice_flo = {
+    .name = SUBGHZ_PROTOCOL_NICE_FLO_NAME,
+    .type = SubGhzProtocolTypeStatic,
+    .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_AM |
+            SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save |
+            SubGhzProtocolFlag_Send,
+
+    .decoder = &subghz_protocol_nice_flo_decoder,
+    .encoder = &subghz_protocol_nice_flo_encoder,
+};
+
+void* subghz_protocol_encoder_nice_flo_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolEncoderNiceFlo* instance = malloc(sizeof(SubGhzProtocolEncoderNiceFlo));
+
+    instance->base.protocol = &subghz_protocol_nice_flo;
+    instance->generic.protocol_name = instance->base.protocol->name;
+
+    instance->encoder.repeat = 10;
+    instance->encoder.size_upload = 52; //max 24bit*2 + 2 (start, stop)
+    instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
+    instance->encoder.is_runing = false;
+    return instance;
+}
+
+void subghz_protocol_encoder_nice_flo_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolEncoderNiceFlo* instance = context;
+    free(instance->encoder.upload);
+    free(instance);
+}
+
+static bool subghz_protocol_encoder_nice_flo_get_upload(SubGhzProtocolEncoderNiceFlo* instance) {
+    furi_assert(instance);
+    size_t index = 0;
+    size_t size_upload = (instance->generic.data_count_bit * 2) + 2;
+    if(size_upload > instance->encoder.size_upload) {
+        FURI_LOG_E(TAG, "Size upload exceeds allocated encoder buffer.");
+        return false;
+    } else {
+        instance->encoder.size_upload = size_upload;
+    }
+    //Send header
+    instance->encoder.upload[index++] =
+        level_duration_make(false, (uint32_t)subghz_protocol_nice_flo_const.te_short * 36);
+    //Send start bit
+    instance->encoder.upload[index++] =
+        level_duration_make(true, (uint32_t)subghz_protocol_nice_flo_const.te_short);
+    //Send key data
+    for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
+        if(bit_read(instance->generic.data, i - 1)) {
+            //send bit 1
+            instance->encoder.upload[index++] =
+                level_duration_make(false, (uint32_t)subghz_protocol_nice_flo_const.te_long);
+            instance->encoder.upload[index++] =
+                level_duration_make(true, (uint32_t)subghz_protocol_nice_flo_const.te_short);
+        } else {
+            //send bit 0
+            instance->encoder.upload[index++] =
+                level_duration_make(false, (uint32_t)subghz_protocol_nice_flo_const.te_short);
+            instance->encoder.upload[index++] =
+                level_duration_make(true, (uint32_t)subghz_protocol_nice_flo_const.te_long);
+        }
+    }
+    return true;
+}
+
+bool subghz_protocol_encoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolEncoderNiceFlo* instance = context;
+    bool res = false;
+    do {
+        if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
+            FURI_LOG_E(TAG, "Deserialize error");
+            break;
+        }
+
+        //optional parameter parameter
+        flipper_format_read_uint32(
+            flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
+
+        subghz_protocol_encoder_nice_flo_get_upload(instance);
+        instance->encoder.is_runing = true;
+
+        res = true;
+    } while(false);
+
+    return res;
+}
+
+void subghz_protocol_encoder_nice_flo_stop(void* context) {
+    SubGhzProtocolEncoderNiceFlo* instance = context;
+    instance->encoder.is_runing = false;
+}
+
+LevelDuration subghz_protocol_encoder_nice_flo_yield(void* context) {
+    SubGhzProtocolEncoderNiceFlo* instance = context;
+
+    if(instance->encoder.repeat == 0 || !instance->encoder.is_runing) {
+        instance->encoder.is_runing = false;
+        return level_duration_reset();
+    }
+
+    LevelDuration ret = instance->encoder.upload[instance->encoder.front];
+
+    if(++instance->encoder.front == instance->encoder.size_upload) {
+        instance->encoder.repeat--;
+        instance->encoder.front = 0;
+    }
+
+    return ret;
+}
+
+void* subghz_protocol_decoder_nice_flo_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolDecoderNiceFlo* instance = malloc(sizeof(SubGhzProtocolDecoderNiceFlo));
+    instance->base.protocol = &subghz_protocol_nice_flo;
+    instance->generic.protocol_name = instance->base.protocol->name;
+    return instance;
+}
+
+void subghz_protocol_decoder_nice_flo_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNiceFlo* instance = context;
+    free(instance);
+}
+
+void subghz_protocol_decoder_nice_flo_reset(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNiceFlo* instance = context;
+    instance->decoder.parser_step = NiceFloDecoderStepReset;
+}
+
+void subghz_protocol_decoder_nice_flo_feed(void* context, bool level, uint32_t duration) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNiceFlo* instance = context;
+
+    switch(instance->decoder.parser_step) {
+    case NiceFloDecoderStepReset:
+        if((!level) && (DURATION_DIFF(duration, subghz_protocol_nice_flo_const.te_short * 36) <
+                        subghz_protocol_nice_flo_const.te_delta * 36)) {
+            //Found header Nice Flo
+            instance->decoder.parser_step = NiceFloDecoderStepFoundStartBit;
+        }
+        break;
+    case NiceFloDecoderStepFoundStartBit:
+        if(!level) {
+            break;
+        } else if(
+            DURATION_DIFF(duration, subghz_protocol_nice_flo_const.te_short) <
+            subghz_protocol_nice_flo_const.te_delta) {
+            //Found start bit Nice Flo
+            instance->decoder.parser_step = NiceFloDecoderStepSaveDuration;
+            instance->decoder.decode_data = 0;
+            instance->decoder.decode_count_bit = 0;
+        } else {
+            instance->decoder.parser_step = NiceFloDecoderStepReset;
+        }
+        break;
+    case NiceFloDecoderStepSaveDuration:
+        if(!level) { //save interval
+            if(duration >= (subghz_protocol_nice_flo_const.te_short * 4)) {
+                instance->decoder.parser_step = NiceFloDecoderStepFoundStartBit;
+                if(instance->decoder.decode_count_bit >=
+                   subghz_protocol_nice_flo_const.min_count_bit_for_found) {
+                    instance->generic.serial = 0x0;
+                    instance->generic.btn = 0x0;
+
+                    instance->generic.data = instance->decoder.decode_data;
+                    instance->generic.data_count_bit = instance->decoder.decode_count_bit;
+                    if(instance->base.callback)
+                        instance->base.callback(&instance->base, instance->base.context);
+                }
+                break;
+            }
+            instance->decoder.te_last = duration;
+            instance->decoder.parser_step = NiceFloDecoderStepCheckDuration;
+        } else {
+            instance->decoder.parser_step = NiceFloDecoderStepReset;
+        }
+        break;
+    case NiceFloDecoderStepCheckDuration:
+        if(level) {
+            if((DURATION_DIFF(instance->decoder.te_last, subghz_protocol_nice_flo_const.te_short) <
+                subghz_protocol_nice_flo_const.te_delta) &&
+               (DURATION_DIFF(duration, subghz_protocol_nice_flo_const.te_long) <
+                subghz_protocol_nice_flo_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 0);
+                instance->decoder.parser_step = NiceFloDecoderStepSaveDuration;
+            } else if(
+                (DURATION_DIFF(instance->decoder.te_last, subghz_protocol_nice_flo_const.te_long) <
+                 subghz_protocol_nice_flo_const.te_delta) &&
+                (DURATION_DIFF(duration, subghz_protocol_nice_flo_const.te_short) <
+                 subghz_protocol_nice_flo_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 1);
+                instance->decoder.parser_step = NiceFloDecoderStepSaveDuration;
+            } else
+                instance->decoder.parser_step = NiceFloDecoderStepReset;
+        } else {
+            instance->decoder.parser_step = NiceFloDecoderStepReset;
+        }
+        break;
+    }
+}
+
+uint8_t subghz_protocol_decoder_nice_flo_get_hash_data(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNiceFlo* instance = context;
+    return subghz_protocol_blocks_get_hash_data(
+        &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
+}
+
+bool subghz_protocol_decoder_nice_flo_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNiceFlo* instance = context;
+    return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
+}
+
+bool subghz_protocol_decoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNiceFlo* instance = context;
+    return subghz_block_generic_deserialize(&instance->generic, flipper_format);
+}
+
+void subghz_protocol_decoder_nice_flo_get_string(void* context, string_t output) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNiceFlo* instance = context;
+
+    uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
+    uint64_t code_found_reverse = subghz_protocol_blocks_reverse_key(
+        instance->generic.data, instance->generic.data_count_bit);
+    uint32_t code_found_reverse_lo = code_found_reverse & 0x00000000ffffffff;
+
+    string_cat_printf(
+        output,
+        "%s %dbit\r\n"
+        "Key:0x%08lX\r\n"
+        "Yek:0x%08lX\r\n",
+        instance->generic.protocol_name,
+        instance->generic.data_count_bit,
+        code_found_lo,
+        code_found_reverse_lo);
+}

+ 30 - 0
lib/subghz/protocols/nice_flo.h

@@ -0,0 +1,30 @@
+#pragma once
+
+#include "base.h"
+
+#define SUBGHZ_PROTOCOL_NICE_FLO_NAME "Nice FLO"
+
+typedef struct SubGhzProtocolDecoderNiceFlo SubGhzProtocolDecoderNiceFlo;
+typedef struct SubGhzProtocolEncoderNiceFlo SubGhzProtocolEncoderNiceFlo;
+
+extern const SubGhzProtocolDecoder subghz_protocol_nice_flo_decoder;
+extern const SubGhzProtocolEncoder subghz_protocol_nice_flo_encoder;
+extern const SubGhzProtocol subghz_protocol_nice_flo;
+
+void* subghz_protocol_encoder_nice_flo_alloc(SubGhzEnvironment* environment);
+void subghz_protocol_encoder_nice_flo_free(void* context);
+bool subghz_protocol_encoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format);
+void subghz_protocol_encoder_nice_flo_stop(void* context);
+LevelDuration subghz_protocol_encoder_nice_flo_yield(void* context);
+void* subghz_protocol_decoder_nice_flo_alloc(SubGhzEnvironment* environment);
+void subghz_protocol_decoder_nice_flo_free(void* context);
+void subghz_protocol_decoder_nice_flo_reset(void* context);
+void subghz_protocol_decoder_nice_flo_feed(void* context, bool level, uint32_t duration);
+uint8_t subghz_protocol_decoder_nice_flo_get_hash_data(void* context);
+void subghz_protocol_decoder_nice_flo_get_string(void* context, string_t output);
+bool subghz_protocol_decoder_nice_flo_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset);
+bool subghz_protocol_decoder_nice_flo_deserialize(void* context, FlipperFormat* flipper_format);

+ 366 - 0
lib/subghz/protocols/nice_flor_s.c

@@ -0,0 +1,366 @@
+#include "nice_flor_s.h"
+
+#include "../blocks/const.h"
+#include "../blocks/decoder.h"
+#include "../blocks/encoder.h"
+#include "../blocks/generic.h"
+#include "../blocks/math.h"
+/*
+ * https://phreakerclub.com/1615
+ * https://phreakerclub.com/forum/showthread.php?t=2360
+ * https://vrtp.ru/index.php?showtopic=27867
+ */
+
+#define TAG "SubGhzProtocoNiceFlorS"
+
+static const SubGhzBlockConst subghz_protocol_nice_flor_s_const = {
+    .te_short = 500,
+    .te_long = 1000,
+    .te_delta = 300,
+    .min_count_bit_for_found = 52,
+};
+
+struct SubGhzProtocolDecoderNiceFlorS {
+    SubGhzProtocolDecoderBase base;
+
+    SubGhzBlockDecoder decoder;
+    SubGhzBlockGeneric generic;
+
+    const char* nice_flor_s_rainbow_table_file_name;
+};
+
+struct SubGhzProtocolEncoderNiceFlorS {
+    SubGhzProtocolEncoderBase base;
+
+    SubGhzProtocolBlockEncoder encoder;
+    SubGhzBlockGeneric generic;
+};
+
+typedef enum {
+    NiceFlorSDecoderStepReset = 0,
+    NiceFlorSDecoderStepCheckHeader,
+    NiceFlorSDecoderStepFoundHeader,
+    NiceFlorSDecoderStepSaveDuration,
+    NiceFlorSDecoderStepCheckDuration,
+} NiceFlorSDecoderStep;
+
+const SubGhzProtocolDecoder subghz_protocol_nice_flor_s_decoder = {
+    .alloc = subghz_protocol_decoder_nice_flor_s_alloc,
+    .free = subghz_protocol_decoder_nice_flor_s_free,
+
+    .feed = subghz_protocol_decoder_nice_flor_s_feed,
+    .reset = subghz_protocol_decoder_nice_flor_s_reset,
+
+    .get_hash_data = subghz_protocol_decoder_nice_flor_s_get_hash_data,
+    .serialize = subghz_protocol_decoder_nice_flor_s_serialize,
+    .deserialize = subghz_protocol_decoder_nice_flor_s_deserialize,
+    .get_string = subghz_protocol_decoder_nice_flor_s_get_string,
+};
+
+const SubGhzProtocolEncoder subghz_protocol_nice_flor_s_encoder = {
+    .alloc = NULL,
+    .free = NULL,
+
+    .deserialize = NULL,
+    .stop = NULL,
+    .yield = NULL,
+};
+
+const SubGhzProtocol subghz_protocol_nice_flor_s = {
+    .name = SUBGHZ_PROTOCOL_NICE_FLOR_S_NAME,
+    .type = SubGhzProtocolTypeDynamic,
+    .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_868 | SubGhzProtocolFlag_AM |
+            SubGhzProtocolFlag_Decodable,
+
+    .decoder = &subghz_protocol_nice_flor_s_decoder,
+    .encoder = &subghz_protocol_nice_flor_s_encoder,
+};
+
+/** Read bytes from rainbow table
+ * 
+ * @param instance - SubGhzProtocolNiceFlorS* instance
+ * @param address  - address byte
+ * @return byte data
+ */
+static uint8_t
+    subghz_protocol_nice_flor_s_get_byte_in_file(const char* file_name, uint32_t address) {
+    if(!file_name) return 0;
+
+    uint8_t buffer[1] = {0};
+    if(subghz_keystore_raw_get_data(file_name, address, buffer, sizeof(uint8_t))) {
+        return buffer[0];
+    } else {
+        return 0;
+    }
+}
+
+static inline void subghz_protocol_decoder_nice_flor_s_magic_xor(uint8_t* p, uint8_t k) {
+    for(uint8_t i = 1; i < 6; i++) {
+        p[i] ^= k;
+    }
+}
+
+uint64_t subghz_protocol_nice_flor_s_encrypt(uint64_t data, const char* file_name) {
+    uint8_t* p = (uint8_t*)&data;
+
+    uint8_t k = 0;
+    for(uint8_t y = 0; y < 2; y++) {
+        k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] & 0x1f);
+        subghz_protocol_decoder_nice_flor_s_magic_xor(p, k);
+
+        p[5] &= 0x0f;
+        p[0] ^= k & 0xe0;
+        k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] >> 3) + 0x25;
+        subghz_protocol_decoder_nice_flor_s_magic_xor(p, k);
+
+        p[5] &= 0x0f;
+        p[0] ^= k & 0x7;
+        if(y == 0) {
+            k = p[0];
+            p[0] = p[1];
+            p[1] = k;
+        }
+    }
+
+    p[5] = ~p[5] & 0x0f;
+    k = ~p[4];
+    p[4] = ~p[0];
+    p[0] = ~p[2];
+    p[2] = k;
+    k = ~p[3];
+    p[3] = ~p[1];
+    p[1] = k;
+
+    return data;
+}
+
+static uint64_t
+    subghz_protocol_nice_flor_s_decrypt(SubGhzBlockGeneric* instance, const char* file_name) {
+    furi_assert(instance);
+    uint64_t data = instance->data;
+    uint8_t* p = (uint8_t*)&data;
+
+    uint8_t k = 0;
+
+    k = ~p[4];
+    p[5] = ~p[5];
+    p[4] = ~p[2];
+    p[2] = ~p[0];
+    p[0] = k;
+    k = ~p[3];
+    p[3] = ~p[1];
+    p[1] = k;
+
+    for(uint8_t y = 0; y < 2; y++) {
+        k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] >> 3) + 0x25;
+        subghz_protocol_decoder_nice_flor_s_magic_xor(p, k);
+
+        p[5] &= 0x0f;
+        p[0] ^= k & 0x7;
+        k = subghz_protocol_nice_flor_s_get_byte_in_file(file_name, p[0] & 0x1f);
+        subghz_protocol_decoder_nice_flor_s_magic_xor(p, k);
+
+        p[5] &= 0x0f;
+        p[0] ^= k & 0xe0;
+
+        if(y == 0) {
+            k = p[0];
+            p[0] = p[1];
+            p[1] = k;
+        }
+    }
+    return data;
+}
+
+void* subghz_protocol_decoder_nice_flor_s_alloc(SubGhzEnvironment* environment) {
+    SubGhzProtocolDecoderNiceFlorS* instance = malloc(sizeof(SubGhzProtocolDecoderNiceFlorS));
+    instance->base.protocol = &subghz_protocol_nice_flor_s;
+    instance->generic.protocol_name = instance->base.protocol->name;
+    instance->nice_flor_s_rainbow_table_file_name =
+        subghz_environment_get_nice_flor_s_rainbow_table_file_name(environment);
+    if(instance->nice_flor_s_rainbow_table_file_name) {
+        FURI_LOG_I(
+            TAG, "Loading rainbow table from %s", instance->nice_flor_s_rainbow_table_file_name);
+    }
+    return instance;
+}
+
+void subghz_protocol_decoder_nice_flor_s_free(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNiceFlorS* instance = context;
+    instance->nice_flor_s_rainbow_table_file_name = NULL;
+    free(instance);
+}
+
+void subghz_protocol_decoder_nice_flor_s_reset(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNiceFlorS* instance = context;
+    instance->decoder.parser_step = NiceFlorSDecoderStepReset;
+}
+
+void subghz_protocol_decoder_nice_flor_s_feed(void* context, bool level, uint32_t duration) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNiceFlorS* instance = context;
+
+    switch(instance->decoder.parser_step) {
+    case NiceFlorSDecoderStepReset:
+        if((!level) && (DURATION_DIFF(duration, subghz_protocol_nice_flor_s_const.te_short * 38) <
+                        subghz_protocol_nice_flor_s_const.te_delta * 38)) {
+            //Found start header Nice Flor-S
+            instance->decoder.parser_step = NiceFlorSDecoderStepCheckHeader;
+        }
+        break;
+    case NiceFlorSDecoderStepCheckHeader:
+        if((level) && (DURATION_DIFF(duration, subghz_protocol_nice_flor_s_const.te_short * 3) <
+                       subghz_protocol_nice_flor_s_const.te_delta * 3)) {
+            //Found next header Nice Flor-S
+            instance->decoder.parser_step = NiceFlorSDecoderStepFoundHeader;
+        } else {
+            instance->decoder.parser_step = NiceFlorSDecoderStepReset;
+        }
+        break;
+    case NiceFlorSDecoderStepFoundHeader:
+        if((!level) && (DURATION_DIFF(duration, subghz_protocol_nice_flor_s_const.te_short * 3) <
+                        subghz_protocol_nice_flor_s_const.te_delta * 3)) {
+            //Found header Nice Flor-S
+            instance->decoder.parser_step = NiceFlorSDecoderStepSaveDuration;
+            instance->decoder.decode_data = 0;
+            instance->decoder.decode_count_bit = 0;
+        } else {
+            instance->decoder.parser_step = NiceFlorSDecoderStepReset;
+        }
+        break;
+    case NiceFlorSDecoderStepSaveDuration:
+        if(level) {
+            if(DURATION_DIFF(duration, subghz_protocol_nice_flor_s_const.te_short * 3) <
+               subghz_protocol_nice_flor_s_const.te_delta) {
+                //Found STOP bit
+                instance->decoder.parser_step = NiceFlorSDecoderStepReset;
+                if(instance->decoder.decode_count_bit >=
+                   subghz_protocol_nice_flor_s_const.min_count_bit_for_found) {
+                    instance->generic.data = instance->decoder.decode_data;
+                    instance->generic.data_count_bit = instance->decoder.decode_count_bit;
+                    if(instance->base.callback)
+                        instance->base.callback(&instance->base, instance->base.context);
+                }
+                break;
+            } else {
+                //save interval
+                instance->decoder.te_last = duration;
+                instance->decoder.parser_step = NiceFlorSDecoderStepCheckDuration;
+            }
+        }
+        break;
+    case NiceFlorSDecoderStepCheckDuration:
+        if(!level) {
+            if((DURATION_DIFF(
+                    instance->decoder.te_last, subghz_protocol_nice_flor_s_const.te_short) <
+                subghz_protocol_nice_flor_s_const.te_delta) &&
+               (DURATION_DIFF(duration, subghz_protocol_nice_flor_s_const.te_long) <
+                subghz_protocol_nice_flor_s_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 0);
+                instance->decoder.parser_step = NiceFlorSDecoderStepSaveDuration;
+            } else if(
+                (DURATION_DIFF(
+                     instance->decoder.te_last, subghz_protocol_nice_flor_s_const.te_long) <
+                 subghz_protocol_nice_flor_s_const.te_delta) &&
+                (DURATION_DIFF(duration, subghz_protocol_nice_flor_s_const.te_short) <
+                 subghz_protocol_nice_flor_s_const.te_delta)) {
+                subghz_protocol_blocks_add_bit(&instance->decoder, 1);
+                instance->decoder.parser_step = NiceFlorSDecoderStepSaveDuration;
+            } else
+                instance->decoder.parser_step = NiceFlorSDecoderStepReset;
+        } else {
+            instance->decoder.parser_step = NiceFlorSDecoderStepReset;
+        }
+        break;
+    }
+}
+
+/** Decrypt protocol Nice Flor S
+ * 
+ * @param instance - SubGhzProtocolNiceFlorS* instance
+ */
+static void subghz_protocol_nice_flor_s_remote_controller(
+    SubGhzBlockGeneric* instance,
+    const char* file_name) {
+    /*
+    * Packet format Nice Flor-s: START-P0-P1-P2-P3-P4-P5-P6-P7-STOP
+    * P0 (4-bit)    - button positional code - 1:0x1, 2:0x2, 3:0x4, 4:0x8;
+    * P1 (4-bit)    - batch repetition number, calculated by the formula:
+    * P1 = 0xF ^ P0 ^ n; where n changes from 1 to 15, then 0, and then in a circle
+    * key 1: {0xE,0xF,0xC,0xD,0xA,0xB,0x8,0x9,0x6,0x7,0x4,0x5,0x2,0x3,0x0,0x1};
+    * key 2: {0xD,0xC,0xF,0xE,0x9,0x8,0xB,0xA,0x5,0x4,0x7,0x6,0x1,0x0,0x3,0x2};
+    * key 3: {0xB,0xA,0x9,0x8,0xF,0xE,0xD,0xC,0x3,0x2,0x1,0x0,0x7,0x6,0x5,0x4};
+    * key 4: {0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0,0xF,0xE,0xD,0xC,0xB,0xA,0x9,0x8};
+    * P2 (4-bit)    - part of the serial number, P2 = (K ^ S3) & 0xF;
+    * P3 (byte)     - the major part of the encrypted index
+    * P4 (byte)     - the low-order part of the encrypted index
+    * P5 (byte)     - part of the serial number, P5 = K ^ S2;
+    * P6 (byte)     - part of the serial number, P6 = K ^ S1;
+    * P7 (byte)     - part of the serial number, P7 = K ^ S0;
+    * K (byte)      - depends on P3 and P4, K = Fk(P3, P4);
+    * S3,S2,S1,S0   - serial number of the console 28 bit.
+    *
+    * data    => 0x1c5783607f7b3     key  serial  cnt
+    * decrypt => 0x10436c6820444 => 0x1  0436c682 0444
+    * 
+    */
+    if(!file_name) {
+        instance->cnt = 0;
+        instance->serial = 0;
+        instance->btn = 0;
+    } else {
+        uint64_t decrypt = subghz_protocol_nice_flor_s_decrypt(instance, file_name);
+        instance->cnt = decrypt & 0xFFFF;
+        instance->serial = (decrypt >> 16) & 0xFFFFFFF;
+        instance->btn = (decrypt >> 48) & 0xF;
+    }
+}
+
+uint8_t subghz_protocol_decoder_nice_flor_s_get_hash_data(void* context) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNiceFlorS* instance = context;
+    return subghz_protocol_blocks_get_hash_data(
+        &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
+}
+
+bool subghz_protocol_decoder_nice_flor_s_serialize(
+    void* context,
+    FlipperFormat* flipper_format,
+    uint32_t frequency,
+    FuriHalSubGhzPreset preset) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNiceFlorS* instance = context;
+    return subghz_block_generic_serialize(&instance->generic, flipper_format, frequency, preset);
+}
+
+bool subghz_protocol_decoder_nice_flor_s_deserialize(void* context, FlipperFormat* flipper_format) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNiceFlorS* instance = context;
+    return subghz_block_generic_deserialize(&instance->generic, flipper_format);
+}
+
+void subghz_protocol_decoder_nice_flor_s_get_string(void* context, string_t output) {
+    furi_assert(context);
+    SubGhzProtocolDecoderNiceFlorS* instance = context;
+
+    subghz_protocol_nice_flor_s_remote_controller(
+        &instance->generic, instance->nice_flor_s_rainbow_table_file_name);
+    uint32_t code_found_hi = instance->generic.data >> 32;
+    uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
+
+    string_cat_printf(
+        output,
+        "%s %dbit\r\n"
+        "Key:0x%lX%08lX\r\n"
+        "Sn:%05lX\r\n"
+        "Cnt:%04X Btn:%02lX\r\n",
+        instance->generic.protocol_name,
+        instance->generic.data_count_bit,
+        code_found_hi,
+        code_found_lo,
+        instance->generic.serial,
+        instance->generic.cnt,
+        instance->generic.btn);
+}

Неке датотеке нису приказане због велике количине промена