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

[FL-1756, FL-1769, FL-1776, FL-1759] Gui: input events complementary V3, refactoring. SubGhz: read/emulate fixes. Cleanup. (#684)

* Gui: move rotation logic to ViewPort, replace delayed View switch in ViewDispatcher with event filtering and redirection to previous view.
* SubGhz: add function description
* Gui, Input: add event id to input events.
* SubGhz: fix "crashing on ?"
* SubGhz: add icon scanning
* SubGhz: updated interface read scene,  updated interface config scene
* Assets: update subghz assets
* SubGhz:  replaced the picture in the read scene, changed the paths to additional files
* SubGhz: fix deadlock in timer callback
* SubGhz: fix icon read scene
* SubGhz: fix icon read scene
* SubGhz: fix duble text transmitter scene
* SubGhz: correct spelling. Gui: bigger queue for ViewDispatcher.
* SubGhz: fix creation and transmission of dynamic code without the presence of a manufactory key
* SubGhz: fix keelog, setting a name in the absence of a manufactory key
* SubGhz: fix load bad keelog key
* Format sources
* Furi: remove garbage from core. GpioTester: fix memory leak and cleanup
* Accessor: remove obsolete notification code
* MusicPlayer: remove input event injection
* Input: rename id to sequence

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
Skorpionm 4 лет назад
Родитель
Сommit
e17336498d
47 измененных файлов с 740 добавлено и 447 удалено
  1. 0 12
      applications/accessor/accessor-app.cpp
  2. 0 2
      applications/accessor/accessor-app.h
  3. 85 94
      applications/gpio-tester/gpio-tester.c
  4. 6 3
      applications/gui/canvas.c
  5. 30 53
      applications/gui/gui.c
  6. 44 32
      applications/gui/view_dispatcher.c
  7. 1 1
      applications/gui/view_dispatcher_i.h
  8. 31 0
      applications/gui/view_port.c
  9. 5 0
      applications/input/input.c
  10. 1 0
      applications/input/input.h
  11. 2 0
      applications/input/input_i.h
  12. 11 16
      applications/music-player/music-player.c
  13. 1 0
      applications/subghz/scenes/subghz_scene_config.h
  14. 48 0
      applications/subghz/scenes/subghz_scene_no_man.c
  15. 4 0
      applications/subghz/scenes/subghz_scene_receiver.c
  16. 9 5
      applications/subghz/scenes/subghz_scene_set_type.c
  17. 5 0
      applications/subghz/scenes/subghz_scene_transmitter.c
  18. 2 2
      applications/subghz/subghz.c
  19. 2 2
      applications/subghz/subghz_cli.c
  20. 10 4
      applications/subghz/subghz_history.c
  21. 84 1
      applications/subghz/subghz_history.h
  22. 76 47
      applications/subghz/views/subghz_receiver.c
  23. 2 1
      applications/subghz/views/subghz_receiver.h
  24. 23 6
      applications/subghz/views/subghz_transmitter.c
  25. 1 0
      applications/subghz/views/subghz_transmitter.h
  26. 0 2
      assets/compiled/assets_icons.c
  27. 4 6
      assets/compiled/assets_icons.h
  28. BIN
      assets/icons/GubGHz/Broadcast_dolph_67-61.png
  29. BIN
      assets/icons/GubGHz/Scanning_123x52.png
  30. BIN
      assets/icons/GubGHz/Scanning_dolph_67-61.png
  31. BIN
      assets/icons/GubGHz/Top-frame_128-13.png
  32. 0 144
      core/furi-hal/api-spi.h
  33. 9 0
      core/furi/common_defines.h
  34. 24 2
      lib/subghz/protocols/subghz_protocol_came.h
  35. 28 0
      lib/subghz/protocols/subghz_protocol_common.h
  36. 5 0
      lib/subghz/protocols/subghz_protocol_faac_slh.h
  37. 18 0
      lib/subghz/protocols/subghz_protocol_gate_tx.h
  38. 6 0
      lib/subghz/protocols/subghz_protocol_ido.h
  39. 24 7
      lib/subghz/protocols/subghz_protocol_keeloq.c
  40. 32 1
      lib/subghz/protocols/subghz_protocol_keeloq.h
  41. 18 0
      lib/subghz/protocols/subghz_protocol_nero_sketch.h
  42. 18 0
      lib/subghz/protocols/subghz_protocol_nice_flo.h
  43. 6 0
      lib/subghz/protocols/subghz_protocol_nice_flor_s.h
  44. 23 3
      lib/subghz/protocols/subghz_protocol_princeton.h
  45. 6 1
      lib/subghz/protocols/subghz_protocol_star_line.c
  46. 18 0
      lib/subghz/protocols/subghz_protocol_star_line.h
  47. 18 0
      lib/subghz/subghz_keystore.h

+ 0 - 12
applications/accessor/accessor-app.cpp

@@ -35,7 +35,6 @@ AccessorApp::AccessorApp()
     : onewire_master{&ibutton_gpio} {
     furi_hal_power_insomnia_enter();
     notification = static_cast<NotificationApp*>(furi_record_open("notification"));
-    notify_init();
     furi_hal_power_enable_otg();
 }
 
@@ -104,17 +103,6 @@ AccessorApp::Scene AccessorApp::get_previous_scene() {
 
 /***************************** NOTIFY *******************************/
 
-void AccessorApp::notify_init() {
-    GPIO_InitTypeDef GPIO_InitStruct = {0};
-
-    GPIO_InitStruct.Pin = PB3_Pin;
-    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
-    GPIO_InitStruct.Pull = GPIO_NOPULL;
-    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
-    GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
-    HAL_GPIO_Init(PB3_GPIO_Port, &GPIO_InitStruct);
-}
-
 void AccessorApp::notify_green_blink() {
     notification_message(notification, &sequence_blink_green_10);
 }

+ 0 - 2
applications/accessor/accessor-app.h

@@ -29,9 +29,7 @@ public:
     bool switch_to_previous_scene(uint8_t count = 1);
     Scene get_previous_scene();
 
-    void notify_init();
     void notify_green_blink();
-
     void notify_success();
 
     char* get_text_store();

+ 85 - 94
applications/gpio-tester/gpio-tester.c

@@ -2,143 +2,134 @@
 #include <furi-hal.h>
 
 #include <gui/gui.h>
-#include <input/input.h>
 #include <notification/notification-messages.h>
 
 typedef struct {
     const char* name;
-    GpioPin pin;
+    const GpioPin* pin;
 } GpioItem;
 
-const GpioItem GPIO_PINS[] = {
-    {"1.2: PA7", {GPIOA, GPIO_PIN_7}},
-    {"1.3: PA6", {GPIOA, GPIO_PIN_6}},
-    {"1.4: PA4", {GPIOA, GPIO_PIN_4}},
-    {"1.5: PB3", {GPIOB, GPIO_PIN_3}},
-    {"1.6: PB2", {GPIOB, GPIO_PIN_2}},
-    {"1.7: PC3", {GPIOC, GPIO_PIN_3}},
-
-    {"2.7: PC1", {GPIOC, GPIO_PIN_1}},
-    {"2.8: PC0", {GPIOC, GPIO_PIN_0}},
+static const GpioItem GPIO_PINS[] = {
+    {"1.2: PA7", &gpio_ext_pa7},
+    {"1.3: PA6", &gpio_ext_pa6},
+    {"1.4: PA4", &gpio_ext_pa4},
+    {"1.5: PB3", &gpio_ext_pb3},
+    {"1.6: PB2", &gpio_ext_pb2},
+    {"1.7: PC3", &gpio_ext_pc3},
+    {"2.7: PC1", &gpio_ext_pc1},
+    {"2.8: PC0", &gpio_ext_pc0},
 };
 
-typedef enum {
-    EventTypeTick,
-    EventTypeKey,
-} EventType;
-
-typedef struct {
-    union {
-        InputEvent input;
-    } value;
-    EventType type;
-} AppEvent;
+static const size_t GPIO_PINS_COUNT = sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]);
 
 typedef struct {
+    osMessageQueueId_t input_queue;
     uint8_t gpio_index;
-} State;
+    ViewPort* view_port;
+    Gui* gui;
+    NotificationApp* notification;
+} GpioTest;
 
-static void render_callback(Canvas* canvas, void* ctx) {
-    State* state = (State*)acquire_mutex((ValueMutex*)ctx, 25);
+static void gpio_test_render_callback(Canvas* canvas, void* ctx) {
+    GpioTest* gpio_test = ctx;
 
     canvas_clear(canvas);
     canvas_set_color(canvas, ColorBlack);
     canvas_set_font(canvas, FontPrimary);
     canvas_draw_str(canvas, 2, 10, "GPIO Control");
     canvas_set_font(canvas, FontSecondary);
-    canvas_draw_str(canvas, 2, 25, GPIO_PINS[state->gpio_index].name);
-
-    release_mutex((ValueMutex*)ctx, state);
+    canvas_draw_str(canvas, 2, 25, GPIO_PINS[gpio_test->gpio_index].name);
 }
 
-static void input_callback(InputEvent* input_event, void* ctx) {
-    osMessageQueueId_t event_queue = ctx;
+static void gpio_test_input_callback(InputEvent* input_event, void* ctx) {
+    GpioTest* gpio_test = ctx;
 
-    AppEvent event;
-    event.type = EventTypeKey;
-    event.value.input = *input_event;
-    osMessageQueuePut(event_queue, &event, 0, 0);
+    osMessageQueuePut(gpio_test->input_queue, input_event, 0, 0);
 }
 
-int32_t gpio_test_app(void* p) {
-    osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(AppEvent), NULL);
-    furi_check(event_queue);
+static void gpio_test_configure_pins(GpioMode mode) {
+    for(size_t i = 0; i < GPIO_PINS_COUNT; i++) {
+        hal_gpio_write(GPIO_PINS[i].pin, false);
+        hal_gpio_init(GPIO_PINS[i].pin, mode, GpioPullNo, GpioSpeedLow);
+    }
+}
 
-    State _state;
-    _state.gpio_index = 0;
+GpioTest* gpio_test_alloc() {
+    GpioTest* instance = furi_alloc(sizeof(GpioTest));
 
-    ValueMutex state_mutex;
-    if(!init_mutex(&state_mutex, &_state, sizeof(State))) {
-        printf("[gpio-tester] cannot create mutex\r\n");
-        return 255;
-    }
+    gpio_test_configure_pins(GpioModeOutputPushPull);
 
-    ViewPort* view_port = view_port_alloc();
+    instance->input_queue = osMessageQueueNew(8, sizeof(InputEvent), NULL);
+    furi_check(instance->input_queue);
 
-    view_port_draw_callback_set(view_port, render_callback, &state_mutex);
-    view_port_input_callback_set(view_port, input_callback, event_queue);
+    instance->view_port = view_port_alloc();
+    view_port_draw_callback_set(instance->view_port, gpio_test_render_callback, instance);
+    view_port_input_callback_set(instance->view_port, gpio_test_input_callback, instance);
 
-    // Open GUI and register view_port
-    Gui* gui = furi_record_open("gui");
-    gui_add_view_port(gui, view_port, GuiLayerFullscreen);
+    instance->gui = furi_record_open("gui");
+    gui_add_view_port(instance->gui, instance->view_port, GuiLayerFullscreen);
 
-    NotificationApp* notification = furi_record_open("notification");
+    instance->notification = furi_record_open("notification");
 
-    // configure pin
-    for(uint8_t i = 0; i < sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]); i++) {
-        hal_gpio_init(
-            (GpioPin*)&GPIO_PINS[i].pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
-    }
+    return instance;
+}
 
-    AppEvent event;
-    while(1) {
-        osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, osWaitForever);
-        State* state = (State*)acquire_mutex_block(&state_mutex);
+void gpio_test_free(GpioTest* instance) {
+    furi_assert(instance);
 
-        if(event_status == osOK) {
-            if(event.type == EventTypeKey) {
-                if(event.value.input.type == InputTypeShort &&
-                   event.value.input.key == InputKeyBack) {
-                    printf("[gpio-tester] bye!\r\n");
-                    notification_message(notification, &sequence_reset_green);
-                    furi_record_close("notification");
+    furi_record_close("notification");
 
-                    view_port_enabled_set(view_port, false);
-                    gui_remove_view_port(gui, view_port);
-                    view_port_free(view_port);
+    view_port_enabled_set(instance->view_port, false);
+    gui_remove_view_port(instance->gui, instance->view_port);
+    furi_record_close("gui");
 
-                    return 0;
-                }
+    view_port_free(instance->view_port);
 
-                if(event.value.input.type == InputTypeShort &&
-                   event.value.input.key == InputKeyRight) {
-                    if(state->gpio_index < (sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]) - 1)) {
-                        state->gpio_index++;
-                    }
-                }
+    osMessageQueueDelete(instance->input_queue);
+
+    gpio_test_configure_pins(GpioModeAnalog);
+
+    free(instance);
+}
 
-                if(event.value.input.type == InputTypeShort &&
-                   event.value.input.key == InputKeyLeft) {
-                    if(state->gpio_index > 0) {
-                        state->gpio_index--;
-                    }
+int32_t gpio_test_app(void* p) {
+    GpioTest* gpio_test = gpio_test_alloc();
+
+    InputEvent event;
+    while(osMessageQueueGet(gpio_test->input_queue, &event, NULL, osWaitForever) == osOK) {
+        if(event.type == InputTypeShort) {
+            if(event.key == InputKeyBack) {
+                notification_message(gpio_test->notification, &sequence_reset_green);
+                break;
+            }
+
+            if(event.key == InputKeyRight) {
+                if(gpio_test->gpio_index < (GPIO_PINS_COUNT - 1)) {
+                    gpio_test->gpio_index++;
                 }
+            }
 
-                if(event.value.input.key == InputKeyOk) {
-                    if(event.value.input.type == InputTypePress) {
-                        hal_gpio_write((GpioPin*)&GPIO_PINS[state->gpio_index].pin, true);
-                        notification_message(notification, &sequence_set_green_255);
-                    } else if(event.value.input.type == InputTypeRelease) {
-                        hal_gpio_write((GpioPin*)&GPIO_PINS[state->gpio_index].pin, false);
-                        notification_message(notification, &sequence_reset_green);
-                    }
+            if(event.key == InputKeyLeft) {
+                if(gpio_test->gpio_index > 0) {
+                    gpio_test->gpio_index--;
+                }
+            }
+        } else {
+            if(event.key == InputKeyOk) {
+                if(event.type == InputTypePress) {
+                    hal_gpio_write(GPIO_PINS[gpio_test->gpio_index].pin, true);
+                    notification_message(gpio_test->notification, &sequence_set_green_255);
+                } else if(event.type == InputTypeRelease) {
+                    hal_gpio_write(GPIO_PINS[gpio_test->gpio_index].pin, false);
+                    notification_message(gpio_test->notification, &sequence_reset_green);
                 }
             }
         }
 
-        release_mutex(&state_mutex, state);
-        view_port_update(view_port);
+        view_port_update(gpio_test->view_port);
     }
 
+    gpio_test_free(gpio_test);
+
     return 0;
 }

+ 6 - 3
applications/gui/canvas.c

@@ -309,12 +309,15 @@ void canvas_set_orientation(Canvas* canvas, CanvasOrientation orientation) {
     furi_assert(canvas);
     if(canvas->orientation != orientation) {
         canvas->orientation = orientation;
-        if(canvas->orientation == CanvasOrientationHorizontal)
+        if(canvas->orientation == CanvasOrientationHorizontal) {
+            FURI_SWAP(canvas->width, canvas->height);
             u8g2_SetDisplayRotation(&canvas->fb, U8G2_R0);
-        else if(canvas->orientation == CanvasOrientationVertical)
+        } else if(canvas->orientation == CanvasOrientationVertical) {
+            FURI_SWAP(canvas->width, canvas->height);
             u8g2_SetDisplayRotation(&canvas->fb, U8G2_R3);
-        else
+        } else {
             furi_assert(0);
+        }
     }
 }
 

+ 30 - 53
applications/gui/gui.c

@@ -1,40 +1,5 @@
 #include "gui_i.h"
 
-static void gui_rotate_buttons(InputEvent* event) {
-    switch(event->key) {
-    case InputKeyUp:
-        event->key = InputKeyRight;
-        break;
-    case InputKeyDown:
-        event->key = InputKeyLeft;
-        break;
-    case InputKeyRight:
-        event->key = InputKeyDown;
-        break;
-    case InputKeyLeft:
-        event->key = InputKeyUp;
-        break;
-    default:
-        break;
-    }
-}
-
-static void gui_setup_fs_orientation(const ViewPort* view_port, Canvas* canvas) {
-    ViewPortOrientation view_port_orientation = view_port_get_orientation(view_port);
-    CanvasOrientation canvas_orientation = canvas_get_orientation(canvas);
-    if(view_port_orientation == ViewPortOrientationHorizontal) {
-        canvas_frame_set(canvas, 0, 0, GUI_DISPLAY_WIDTH, GUI_DISPLAY_HEIGHT);
-        if(canvas_orientation != CanvasOrientationHorizontal) {
-            canvas_set_orientation(canvas, CanvasOrientationHorizontal);
-        }
-    } else if(view_port_orientation == ViewPortOrientationVertical) {
-        canvas_frame_set(canvas, 0, 0, GUI_DISPLAY_HEIGHT, GUI_DISPLAY_WIDTH);
-        if(canvas_orientation != CanvasOrientationVertical) {
-            canvas_set_orientation(canvas, CanvasOrientationVertical);
-        }
-    }
-}
-
 ViewPort* gui_view_port_find_enabled(ViewPortArray_t array) {
     // Iterating backward
     ViewPortArray_it_t it;
@@ -66,9 +31,10 @@ void gui_input_events_callback(const void* value, void* ctx) {
 
 // Only Fullscreen supports vertical display for now
 bool gui_redraw_fs(Gui* gui) {
+    canvas_set_orientation(gui->canvas, CanvasOrientationHorizontal);
+    canvas_frame_set(gui->canvas, 0, 0, GUI_DISPLAY_WIDTH, GUI_DISPLAY_HEIGHT);
     ViewPort* view_port = gui_view_port_find_enabled(gui->layers[GuiLayerFullscreen]);
     if(view_port) {
-        gui_setup_fs_orientation(view_port, gui->canvas);
         view_port_draw(view_port, gui->canvas);
         return true;
     } else {
@@ -225,9 +191,10 @@ void gui_input(Gui* gui, InputEvent* input_event) {
     } else if(!(gui->ongoing_input & key_bit)) {
         FURI_LOG_W(
             "Gui",
-            "non-complementary input, discarding key %s type %s",
+            "non-complementary input, discarding key: %s type: %s, sequence: %p",
             input_get_key_name(input_event->key),
-            input_get_type_name(input_event->type));
+            input_get_type_name(input_event->type),
+            input_event->sequence);
         return;
     }
 
@@ -241,21 +208,27 @@ void gui_input(Gui* gui, InputEvent* input_event) {
         gui->ongoing_input_view_port = view_port;
     }
 
-    if(view_port) {
-        if(view_port == gui->ongoing_input_view_port) {
-            if(view_port_get_orientation(view_port) == ViewPortOrientationVertical) {
-                gui_rotate_buttons(input_event);
-            }
-            view_port_input(view_port, input_event);
-        } else {
-            FURI_LOG_W(
-                "Gui",
-                "ViewPort change while key press %x -> %x. Discarding key: %s, type: %s",
-                gui->ongoing_input_view_port,
-                view_port,
-                input_get_key_name(input_event->key),
-                input_get_type_name(input_event->type));
-        }
+    if(view_port && view_port == gui->ongoing_input_view_port) {
+        view_port_input(view_port, input_event);
+    } else if(gui->ongoing_input_view_port && input_event->type == InputTypeRelease) {
+        FURI_LOG_W(
+            "Gui",
+            "ViewPort changed while key press %p -> %p. Sending key: %s, type: %s, sequence: %p to previous view port",
+            gui->ongoing_input_view_port,
+            view_port,
+            input_get_key_name(input_event->key),
+            input_get_type_name(input_event->type),
+            input_event->sequence);
+        view_port_input(gui->ongoing_input_view_port, input_event);
+    } else {
+        FURI_LOG_W(
+            "Gui",
+            "ViewPort changed while key press %p -> %p. Discarding key: %s, type: %s, sequence: %p",
+            gui->ongoing_input_view_port,
+            view_port,
+            input_get_key_name(input_event->key),
+            input_get_type_name(input_event->type),
+            input_event->sequence);
     }
 
     gui_unlock(gui);
@@ -355,6 +328,10 @@ void gui_remove_view_port(Gui* gui, ViewPort* view_port) {
         }
     }
 
+    if(gui->ongoing_input_view_port == view_port) {
+        gui->ongoing_input_view_port = NULL;
+    }
+
     gui_unlock(gui);
 }
 

+ 44 - 32
applications/gui/view_dispatcher.c

@@ -37,7 +37,7 @@ void view_dispatcher_free(ViewDispatcher* view_dispatcher) {
 void view_dispatcher_enable_queue(ViewDispatcher* view_dispatcher) {
     furi_assert(view_dispatcher);
     furi_assert(view_dispatcher->queue == NULL);
-    view_dispatcher->queue = osMessageQueueNew(8, sizeof(ViewDispatcherMessage), NULL);
+    view_dispatcher->queue = osMessageQueueNew(16, sizeof(ViewDispatcherMessage), NULL);
 }
 
 void view_dispatcher_set_event_callback_context(ViewDispatcher* view_dispatcher, void* context) {
@@ -149,6 +149,10 @@ void view_dispatcher_remove_view(ViewDispatcher* view_dispatcher, uint32_t view_
     if(view_dispatcher->current_view == view) {
         view_dispatcher_set_current_view(view_dispatcher, NULL);
     }
+    // Check if view is recieving input
+    if(view_dispatcher->ongoing_input_view == view) {
+        view_dispatcher->ongoing_input_view = NULL;
+    }
     // Remove view
     ViewDict_erase(view_dispatcher->views, view_id);
 
@@ -169,12 +173,7 @@ void view_dispatcher_switch_to_view(ViewDispatcher* view_dispatcher, uint32_t vi
     } else {
         View** view_pp = ViewDict_get(view_dispatcher->views, view_id);
         furi_check(view_pp != NULL);
-        if(view_dispatcher->ongoing_input) {
-            view_dispatcher->delayed_next_view = *view_pp;
-        } else {
-            view_dispatcher->delayed_next_view = NULL;
-            view_dispatcher_set_current_view(view_dispatcher, *view_pp);
-        }
+        view_dispatcher_set_current_view(view_dispatcher, *view_pp);
     }
 }
 
@@ -227,39 +226,52 @@ void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* e
     } else if(!(view_dispatcher->ongoing_input & key_bit)) {
         FURI_LOG_W(
             "ViewDispatcher",
-            "non-complementary input, discarding key: %s, type: %s",
+            "non-complementary input, discarding key: %s, type: %s, sequence: %p",
             input_get_key_name(event->key),
-            input_get_type_name(event->type));
+            input_get_type_name(event->type),
+            event->sequence);
         return;
     }
 
-    bool is_consumed = false;
-    if(view_dispatcher->current_view) {
-        is_consumed = view_input(view_dispatcher->current_view, event);
+    // Set ongoing input view if this is event is first press event
+    if(!(view_dispatcher->ongoing_input & ~key_bit) && event->type == InputTypePress) {
+        view_dispatcher->ongoing_input_view = view_dispatcher->current_view;
     }
-    if(!is_consumed && event->type == InputTypeShort) {
-        // TODO remove view navigation handlers
-        uint32_t view_id = VIEW_IGNORE;
-        if(event->key == InputKeyBack) {
-            view_id = view_previous(view_dispatcher->current_view);
-            if((view_id == VIEW_IGNORE) && (view_dispatcher->navigation_event_callback)) {
-                is_consumed =
-                    view_dispatcher->navigation_event_callback(view_dispatcher->event_context);
-                if(!is_consumed) {
-                    view_dispatcher_stop(view_dispatcher);
-                    return;
+
+    // Deliver event
+    if(view_dispatcher->ongoing_input_view == view_dispatcher->current_view) {
+        bool is_consumed = false;
+        if(view_dispatcher->current_view) {
+            is_consumed = view_input(view_dispatcher->current_view, event);
+        }
+        if(!is_consumed && event->type == InputTypeShort) {
+            // TODO remove view navigation handlers
+            uint32_t view_id = VIEW_IGNORE;
+            if(event->key == InputKeyBack) {
+                view_id = view_previous(view_dispatcher->current_view);
+                if((view_id == VIEW_IGNORE) && (view_dispatcher->navigation_event_callback)) {
+                    is_consumed =
+                        view_dispatcher->navigation_event_callback(view_dispatcher->event_context);
+                    if(!is_consumed) {
+                        view_dispatcher_stop(view_dispatcher);
+                        return;
+                    }
                 }
             }
+            if(!is_consumed) {
+                view_dispatcher_switch_to_view(view_dispatcher, view_id);
+            }
         }
-        if(!is_consumed) {
-            view_dispatcher_switch_to_view(view_dispatcher, view_id);
-        }
-    }
-
-    // Delayed view switch
-    if(view_dispatcher->delayed_next_view && !(view_dispatcher->ongoing_input)) {
-        view_dispatcher_set_current_view(view_dispatcher, view_dispatcher->delayed_next_view);
-        view_dispatcher->delayed_next_view = NULL;
+    } else if(view_dispatcher->ongoing_input_view && event->type == InputTypeRelease) {
+        FURI_LOG_W(
+            "ViewDispatcher",
+            "View changed while key press %p -> %p. Sending key: %s, type: %s, sequence: %p to previous view port",
+            view_dispatcher->ongoing_input_view,
+            view_dispatcher->current_view,
+            input_get_key_name(event->key),
+            input_get_type_name(event->type),
+            event->sequence);
+        view_input(view_dispatcher->ongoing_input_view, event);
     }
 }
 

+ 1 - 1
applications/gui/view_dispatcher_i.h

@@ -17,7 +17,7 @@ struct ViewDispatcher {
 
     View* current_view;
 
-    View* delayed_next_view;
+    View* ongoing_input_view;
     uint8_t ongoing_input;
 
     ViewDispatcherCustomEventCallback custom_event_callback;

+ 31 - 0
applications/gui/view_port.c

@@ -7,6 +7,33 @@
 
 // TODO add mutex to view_port ops
 
+static void view_port_rotate_buttons(InputEvent* event) {
+    switch(event->key) {
+    case InputKeyUp:
+        event->key = InputKeyRight;
+        break;
+    case InputKeyDown:
+        event->key = InputKeyLeft;
+        break;
+    case InputKeyRight:
+        event->key = InputKeyDown;
+        break;
+    case InputKeyLeft:
+        event->key = InputKeyUp;
+        break;
+    default:
+        break;
+    }
+}
+
+static void view_port_setup_canvas_orientation(const ViewPort* view_port, Canvas* canvas) {
+    if(view_port->orientation == ViewPortOrientationHorizontal) {
+        canvas_set_orientation(canvas, CanvasOrientationHorizontal);
+    } else if(view_port->orientation == ViewPortOrientationVertical) {
+        canvas_set_orientation(canvas, CanvasOrientationVertical);
+    }
+}
+
 ViewPort* view_port_alloc() {
     ViewPort* view_port = furi_alloc(sizeof(ViewPort));
     view_port->orientation = ViewPortOrientationHorizontal;
@@ -84,6 +111,7 @@ void view_port_draw(ViewPort* view_port, Canvas* canvas) {
     furi_check(view_port->gui);
 
     if(view_port->draw_callback) {
+        view_port_setup_canvas_orientation(view_port, canvas);
         view_port->draw_callback(canvas, view_port->draw_callback_context);
     }
 }
@@ -94,6 +122,9 @@ void view_port_input(ViewPort* view_port, InputEvent* event) {
     furi_check(view_port->gui);
 
     if(view_port->input_callback) {
+        if(view_port_get_orientation(view_port) == ViewPortOrientationVertical) {
+            view_port_rotate_buttons(event);
+        }
         view_port->input_callback(event, view_port->input_callback_context);
     }
 }

+ 5 - 0
applications/input/input.c

@@ -23,6 +23,7 @@ inline static void input_timer_stop(osTimerId_t timer_id) {
 void input_press_timer_callback(void* arg) {
     InputPinState* input_pin = arg;
     InputEvent event;
+    event.sequence = input_pin->counter;
     event.key = input_pin->pin->key;
     input_pin->press_counter++;
     if(input_pin->press_counter == INPUT_LONG_PRESS_COUNTS) {
@@ -158,8 +159,12 @@ int32_t input_srv() {
 
                 // Short / Long / Repeat timer routine
                 if(state) {
+                    input->counter++;
+                    input->pin_states[i].counter = input->counter;
+                    event.sequence = input->pin_states[i].counter;
                     input_timer_start(input->pin_states[i].press_timer, INPUT_PRESS_TICKS);
                 } else {
+                    event.sequence = input->pin_states[i].counter;
                     input_timer_stop(input->pin_states[i].press_timer);
                     if(input->pin_states[i].press_counter < INPUT_LONG_PRESS_COUNTS) {
                         event.type = InputTypeShort;

+ 1 - 0
applications/input/input.h

@@ -15,6 +15,7 @@ typedef enum {
 
 /* Input Event, dispatches with PubSub */
 typedef struct {
+    uint32_t sequence;
     InputKey key;
     InputType type;
 } InputEvent;

+ 2 - 0
applications/input/input_i.h

@@ -24,6 +24,7 @@ typedef struct {
     volatile uint8_t debounce;
     volatile osTimerId_t press_timer;
     volatile uint8_t press_counter;
+    volatile uint32_t counter;
 } InputPinState;
 
 /* Input state */
@@ -32,6 +33,7 @@ typedef struct {
     PubSub event_pubsub;
     InputPinState* pin_states;
     Cli* cli;
+    volatile uint32_t counter;
 } Input;
 
 /* Input press timer callback */

+ 11 - 16
applications/music-player/music-player.c

@@ -383,11 +383,6 @@ int32_t music_player_app(void* p) {
     Gui* gui = furi_record_open("gui");
     gui_add_view_port(gui, view_port, GuiLayerFullscreen);
 
-    // open input record
-    PubSub* input_events_record = furi_record_open("input_events");
-    // prepare "do nothing" event
-    InputEvent input_event = {InputKeyRight, true};
-
     // start player thread
     // TODO change to fuirac_start
     osThreadAttr_t player_attr = {.name = "music_player_thread", .stack_size = 512};
@@ -410,14 +405,8 @@ int32_t music_player_app(void* p) {
                 // press events
                 if(event.value.input.type == InputTypeShort &&
                    event.value.input.key == InputKeyBack) {
-                    osThreadTerminate(player);
-                    hal_pwm_stop(&SPEAKER_TIM, SPEAKER_CH);
-                    view_port_enabled_set(view_port, false);
-                    gui_remove_view_port(gui, view_port);
-                    view_port_free(view_port);
-                    osMessageQueueDelete(event_queue);
-
-                    return 0;
+                    release_mutex(&state_mutex, state);
+                    break;
                 }
 
                 if(event.value.input.type == InputTypePress &&
@@ -442,9 +431,6 @@ int32_t music_player_app(void* p) {
                 }
 
             } else if(event.type == EventTypeNote) {
-                // send "do nothing" event to prevent display backlight off
-                notify_pubsub(input_events_record, &input_event);
-
                 state->note_record = event.value.note_record;
 
                 for(size_t i = note_stack_size - 1; i > 0; i--) {
@@ -460,5 +446,14 @@ int32_t music_player_app(void* p) {
         release_mutex(&state_mutex, state);
     }
 
+    osThreadTerminate(player);
+    hal_pwm_stop(&SPEAKER_TIM, SPEAKER_CH);
+    view_port_enabled_set(view_port, false);
+    gui_remove_view_port(gui, view_port);
+    furi_record_close("gui");
+    view_port_free(view_port);
+    osMessageQueueDelete(event_queue);
+    delete_mutex(&state_mutex);
+
     return 0;
 }

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

@@ -4,6 +4,7 @@ ADD_SCENE(subghz, save_name, SaveName)
 ADD_SCENE(subghz, save_success, SaveSuccess)
 ADD_SCENE(subghz, saved, Saved)
 ADD_SCENE(subghz, transmitter, Transmitter)
+ADD_SCENE(subghz, no_man, NoMan)
 ADD_SCENE(subghz, test, Test)
 ADD_SCENE(subghz, test_static, TestStatic)
 ADD_SCENE(subghz, test_carrier, TestCarrier)

+ 48 - 0
applications/subghz/scenes/subghz_scene_no_man.c

@@ -0,0 +1,48 @@
+#include "../subghz_i.h"
+
+#define SCENE_NO_MAN_CUSTOM_EVENT (11UL)
+
+void subghz_scene_no_man_popup_callback(void* context) {
+    SubGhz* subghz = context;
+    view_dispatcher_send_custom_event(subghz->view_dispatcher, SCENE_NO_MAN_CUSTOM_EVENT);
+}
+
+const void subghz_scene_no_man_on_enter(void* context) {
+    SubGhz* subghz = context;
+
+    // Setup view
+    Popup* popup = subghz->popup;
+    popup_set_icon(popup, 32, 12, &I_DolphinFirstStart7_61x51);
+    popup_set_header(popup, "No manufactory key", 13, 8, AlignLeft, AlignBottom);
+    popup_set_timeout(popup, 1500);
+    popup_set_context(popup, subghz);
+    popup_set_callback(popup, subghz_scene_no_man_popup_callback);
+    popup_enable_timeout(popup);
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewPopup);
+}
+
+const bool subghz_scene_no_man_on_event(void* context, SceneManagerEvent event) {
+    SubGhz* subghz = context;
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == SCENE_NO_MAN_CUSTOM_EVENT) {
+            scene_manager_search_and_switch_to_previous_scene(
+                subghz->scene_manager, SubGhzSceneStart);
+            return true;
+        }
+    }
+    return false;
+}
+
+const void subghz_scene_no_man_on_exit(void* context) {
+    SubGhz* subghz = context;
+
+    // Clear view
+    Popup* popup = subghz->popup;
+    popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
+    popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
+    popup_set_icon(popup, 0, 0, NULL);
+    popup_set_callback(popup, NULL);
+    popup_set_context(popup, NULL);
+    popup_set_timeout(popup, 0);
+    popup_disable_timeout(popup);
+}

+ 4 - 0
applications/subghz/scenes/subghz_scene_receiver.c

@@ -57,6 +57,10 @@ const bool subghz_scene_receiver_on_event(void* context, SceneManagerEvent event
             subghz->state_notifications = NOTIFICATION_IDLE_STATE;
             return true;
             break;
+        case SubghzReceverEventSendHistoryFull:
+            subghz->state_notifications = NOTIFICATION_IDLE_STATE;
+            return true;
+            break;
         default:
             break;
         }

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

@@ -146,11 +146,15 @@ const bool subghz_scene_set_type_on_event(void* context, SceneManagerEvent event
                 subghz->protocol_result->serial = key & 0x0FFFFFFF;
                 subghz->protocol_result->btn = 0x2; //btn 0x1, 0x2, 0x4, 0x8
                 subghz->protocol_result->cnt = 0x0003;
-                subghz_protocol_keeloq_set_manufacture_name(subghz->protocol_result, "DoorHan");
-                subghz->protocol_result->code_last_found =
-                    subghz_protocol_keeloq_gen_key(subghz->protocol_result);
-
-                generated_protocol = true;
+                if(subghz_protocol_keeloq_set_manufacture_name(
+                       subghz->protocol_result, "DoorHan")) {
+                    subghz->protocol_result->code_last_found =
+                        subghz_protocol_keeloq_gen_key(subghz->protocol_result);
+                    generated_protocol = true;
+                } else {
+                    generated_protocol = false;
+                    scene_manager_next_scene(subghz->scene_manager, SubGhzSceneNoMan);
+                }
             }
             break;
 

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

@@ -38,6 +38,11 @@ const bool subghz_scene_transmitter_on_event(void* context, SceneManagerEvent ev
             scene_manager_search_and_switch_to_previous_scene(
                 subghz->scene_manager, SubGhzSceneStart);
             return true;
+        } else if(event.event == SubghzTransmitterEventNoMan) {
+            subghz->state_notifications = NOTIFICATION_IDLE_STATE;
+            scene_manager_search_and_switch_to_previous_scene(
+                subghz->scene_manager, SubGhzSceneNoMan);
+            return true;
         }
     } else if(event.type == SceneManagerEventTypeTick) {
         if(subghz->state_notifications == NOTIFICATION_TX_STATE) {

+ 2 - 2
applications/subghz/subghz.c

@@ -129,8 +129,8 @@ SubGhz* subghz_alloc() {
         subghz->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse);
     subghz_worker_set_context(subghz->worker, subghz->protocol);
 
-    subghz_protocol_load_keeloq_file(subghz->protocol, "/ext/assets/subghz/keeloq_mfcodes");
-    subghz_protocol_load_nice_flor_s_file(subghz->protocol, "/ext/assets/subghz/nice_floor_s_rx");
+    subghz_protocol_load_keeloq_file(subghz->protocol, "/ext/subghz/keeloq_mfcodes");
+    subghz_protocol_load_nice_flor_s_file(subghz->protocol, "/ext/subghz/nice_floor_s_rx");
 
     //subghz_protocol_enable_dump_text(subghz->protocol, subghz_text_callback, subghz);
 

+ 2 - 2
applications/subghz/subghz_cli.c

@@ -206,8 +206,8 @@ void subghz_cli_command_rx(Cli* cli, string_t args, void* context) {
     furi_check(instance->stream);
 
     SubGhzProtocol* protocol = subghz_protocol_alloc();
-    subghz_protocol_load_keeloq_file(protocol, "/ext/assets/subghz/keeloq_mfcodes");
-    subghz_protocol_load_nice_flor_s_file(protocol, "/ext/assets/subghz/nice_floor_s_rx");
+    subghz_protocol_load_keeloq_file(protocol, "/ext/subghz/keeloq_mfcodes");
+    subghz_protocol_load_nice_flor_s_file(protocol, "/ext/subghz/nice_floor_s_rx");
     subghz_protocol_enable_dump_text(protocol, subghz_cli_command_rx_text_callback, instance);
 
     // Configure radio

+ 10 - 4
applications/subghz/subghz_history.c

@@ -88,9 +88,15 @@ SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, u
     instance->data.param1 = instance->history[idx].te;
     return &instance->data;
 }
-void 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);
-    string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX);
+    if(instance->last_index_write == SUBGHZ_HISTORY_MAX) {
+        if(output != NULL) string_printf(output, "Memory is FULL");
+        return true;
+    }
+    if(output != NULL)
+        string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX);
+    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) {
@@ -144,10 +150,10 @@ void subghz_history_add_to_history(SubGhzHistory* instance, void* context) {
     instance->history[instance->last_index_write].code_found = protocol->code_last_found;
     if(strcmp(protocol->name, "KeeLoq") == 0) {
         instance->history[instance->last_index_write].manufacture_name =
-            subghz_protocol_keeloq_get_manufacture_name(protocol);
+            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_get_manufacture_name(protocol);
+            subghz_protocol_star_line_find_and_get_manufacture_name(protocol);
     } else if(strcmp(protocol->name, "Princeton") == 0) {
         instance->history[instance->last_index_write].te =
             subghz_protocol_princeton_get_te(protocol);

+ 84 - 1
applications/subghz/subghz_history.h

@@ -4,20 +4,103 @@
 
 typedef struct SubGhzHistory SubGhzHistory;
 
+/** Allocate SubGhzHistory
+ * 
+ * @return SubGhzHistory* 
+ */
 SubGhzHistory* subghz_history_alloc(void);
+
+/** Free SubGhzHistory
+ * 
+ * @param instance - SubGhzHistory instance
+ */
 void subghz_history_free(SubGhzHistory* instance);
+
+/** Clear history
+ * 
+ * @param instance - SubGhzHistory instance
+ */
 void subghz_history_clean(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]
+ * 
+ * @param instance  - SubGhzHistory instance
+ * @param idx       - record index  
+ * @return frequency - frequency Hz
+ */
 uint32_t subghz_history_get_frequency(SubGhzHistory* instance, uint16_t idx);
+
+/** Get preset to history[idx]
+ * 
+ * @param instance  - SubGhzHistory instance
+ * @param idx       - record index  
+ * @return preset    - FuriHalSubGhzPreset preset
+ */
 FuriHalSubGhzPreset subghz_history_get_preset(SubGhzHistory* instance, uint16_t idx);
+
+/** Get history index write 
+ * 
+ * @param instance  - SubGhzHistory instance
+ * @return idx      - current record index  
+ */
 uint16_t subghz_history_get_item(SubGhzHistory* instance);
+
+/** Get type protocol to history[idx]
+ * 
+ * @param instance  - SubGhzHistory instance
+ * @param idx       - record index  
+ * @return type      - type protocol  
+ */
 uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx);
+
+/** Get name protocol to history[idx]
+ * 
+ * @param instance  - SubGhzHistory instance
+ * @param idx       - record index  
+ * @return name      - const char* name protocol  
+ */
 const char* subghz_history_get_name(SubGhzHistory* instance, uint16_t idx);
+
+/** Get string item menu to history[idx]
+ * 
+ * @param instance  - SubGhzHistory instance
+ * @param output    - string_t output
+ * @param idx       - record index
+ */
 void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output, uint16_t idx);
-void subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output);
+
+/** Get string the remaining number of records to history
+ * 
+ * @param instance  - SubGhzHistory instance
+ * @param output    - string_t output
+ * @return bool - is FUUL
+ */
+bool subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output);
+
+/** Add protocol to history
+ * 
+ * @param instance  - SubGhzHistory instance
+ * @param context    - SubGhzProtocolCommon context
+ */
 void subghz_history_add_to_history(SubGhzHistory* instance, void* context);
+
+/** Get SubGhzProtocolCommonLoad to load into the protocol decoder bin data
+ * 
+ * @param instance  - SubGhzHistory instance
+ * @param idx       - record index
+ * @return SubGhzProtocolCommonLoad*
+ */
 SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx);

+ 76 - 47
applications/subghz/views/subghz_receiver.c

@@ -39,9 +39,9 @@ typedef enum {
 } SubGhzHopperState;
 
 static const Icon* ReceiverItemIcons[] = {
-    [TYPE_PROTOCOL_UNKNOWN] = &I_quest_7x8,
-    [TYPE_PROTOCOL_STATIC] = &I_unlock_7x8,
-    [TYPE_PROTOCOL_DYNAMIC] = &I_lock_7x8,
+    [TYPE_PROTOCOL_UNKNOWN] = &I_Quest_7x8,
+    [TYPE_PROTOCOL_STATIC] = &I_Unlock_7x8,
+    [TYPE_PROTOCOL_DYNAMIC] = &I_Lock_7x8,
 };
 
 struct SubghzReceiver {
@@ -53,6 +53,7 @@ struct SubghzReceiver {
     osTimerId timer;
     SubGhzHopperState hopper_state;
     uint8_t hopper_timeout;
+    uint32_t event_key_sequence;
 };
 
 typedef struct {
@@ -172,44 +173,40 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
             string_clean(str_buff);
         }
         if(scrollbar) {
-            elements_scrollbar_pos(canvas, 126, 0, 49, model->idx, model->history_item);
+            elements_scrollbar_pos(canvas, 128, 0, 49, model->idx, model->history_item);
         }
         canvas_set_color(canvas, ColorBlack);
         canvas_set_font(canvas, FontSecondary);
 
-        elements_button_left(canvas, "Conf");
-        if((model->real_frequency / 1000 % 10) > 4) {
-            frequency = model->real_frequency + 10000;
+        elements_button_left(canvas, "Config");
+        canvas_draw_line(canvas, 46, 51, 125, 51);
+        if(subghz_history_get_text_space_left(model->history, str_buff)) {
+            canvas_draw_str(canvas, 54, 62, string_get_cstr(str_buff));
         } else {
-            frequency = model->real_frequency;
+            if((model->real_frequency / 1000 % 10) > 4) {
+                frequency = model->real_frequency + 10000;
+            } else {
+                frequency = model->real_frequency;
+            }
+            snprintf(
+                buffer,
+                sizeof(buffer),
+                "%03ld.%02ld",
+                frequency / 1000000 % 1000,
+                frequency / 10000 % 100);
+            canvas_draw_str(canvas, 44, 62, buffer);
+            canvas_draw_str(canvas, 79, 62, "AM");
+            canvas_draw_str(canvas, 96, 62, string_get_cstr(str_buff));
         }
-        snprintf(
-            buffer,
-            sizeof(buffer),
-            "%03ld.%02ld",
-            frequency / 1000000 % 1000,
-            frequency / 10000 % 100);
-        canvas_draw_str(canvas, 40, 62, buffer);
-        canvas_draw_str(canvas, 75, 62, "AM");
-        subghz_history_get_text_space_left(model->history, str_buff);
-        canvas_draw_str(canvas, 94, 62, string_get_cstr(str_buff));
-        canvas_draw_line(canvas, 38, 51, 125, 51);
         break;
 
     case ReceiverSceneStart:
-        canvas_draw_icon(canvas, 0, 0, &I_RFIDDolphinReceive_97x61);
-        canvas_invert_color(canvas);
-        canvas_draw_box(canvas, 80, 2, 20, 20);
-        canvas_invert_color(canvas);
-        canvas_draw_icon(canvas, 75, 8, &I_sub1_10px);
+        canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52);
         canvas_set_font(canvas, FontPrimary);
-        canvas_draw_str(canvas, 63, 40, "Scanning...");
+        canvas_draw_str(canvas, 63, 46, "Scanning...");
         canvas_set_color(canvas, ColorBlack);
         canvas_set_font(canvas, FontSecondary);
-        elements_button_left(canvas, "Conf");
-        canvas_invert_color(canvas);
-        canvas_draw_box(canvas, 38, 52, 10, 10);
-        canvas_invert_color(canvas);
+        elements_button_left(canvas, "Config");
         if((model->real_frequency / 1000 % 10) > 4) {
             frequency = model->real_frequency + 10000;
         } else {
@@ -221,11 +218,11 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
             "%03ld.%02ld",
             frequency / 1000000 % 1000,
             frequency / 10000 % 100);
-        canvas_draw_str(canvas, 40, 62, buffer);
-        canvas_draw_str(canvas, 75, 62, "AM");
+        canvas_draw_str(canvas, 44, 62, buffer);
+        canvas_draw_str(canvas, 79, 62, "AM");
         subghz_history_get_text_space_left(model->history, str_buff);
-        canvas_draw_str(canvas, 94, 62, string_get_cstr(str_buff));
-        canvas_draw_line(canvas, 48, 51, 125, 51);
+        canvas_draw_str(canvas, 96, 62, string_get_cstr(str_buff));
+        canvas_draw_line(canvas, 46, 51, 125, 51);
         break;
 
     case ReceiverSceneConfig:
@@ -237,9 +234,12 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
                 model->real_frequency / 1000000 % 1000,
                 model->real_frequency / 1000 % 1000);
             canvas_draw_str(canvas, 0, 8, buffer);
+            canvas_draw_str(canvas, 0, 18, "Frequency Hopping: <OFF>");
         } else {
-            canvas_draw_str(canvas, 0, 8, "Frequency: <auto>");
+            canvas_draw_str(canvas, 0, 8, "Frequency: < --- >");
+            canvas_draw_str(canvas, 0, 18, "Frequency Hopping: <ON>");
         }
+        canvas_draw_str(canvas, 0, 28, "Modulation: <AM>");
 
         elements_button_center(canvas, "Save");
         break;
@@ -269,6 +269,13 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
     string_clear(str_buff);
 }
 
+void subghz_receiver_history_full(void* context) {
+    furi_assert(context);
+    SubghzReceiver* subghz_receiver = context;
+    subghz_receiver->callback(SubghzReceverEventSendHistoryFull, subghz_receiver->context);
+    subghz_receiver->hopper_state = SubGhzHopperStateOFF;
+}
+
 bool subghz_receiver_input(InputEvent* event, void* context) {
     furi_assert(context);
 
@@ -280,13 +287,11 @@ bool subghz_receiver_input(InputEvent* event, void* context) {
             return false;
         });
 
-    if(scene != ReceiverSceneInfo && event->type != InputTypeShort) return false;
-
     bool can_be_saved = false;
 
     switch(scene) {
     case ReceiverSceneMain:
-        if(event->key == InputKeyBack) {
+        if(event->key == InputKeyBack && event->type == InputTypeShort) {
             with_view_model(
                 subghz_receiver->view, (SubghzReceiverModel * model) {
                     model->idx = 0;
@@ -296,19 +301,23 @@ bool subghz_receiver_input(InputEvent* event, void* context) {
                     return true;
                 });
             return false;
-        } else if(event->key == InputKeyUp) {
+        } else if(
+            event->key == InputKeyUp &&
+            (event->type == InputTypeShort || event->type == InputTypeRepeat)) {
             with_view_model(
                 subghz_receiver->view, (SubghzReceiverModel * model) {
                     if(model->idx != 0) model->idx--;
                     return true;
                 });
-        } else if(event->key == InputKeyDown) {
+        } else if(
+            event->key == InputKeyDown &&
+            (event->type == InputTypeShort || event->type == InputTypeRepeat)) {
             with_view_model(
                 subghz_receiver->view, (SubghzReceiverModel * model) {
                     if(model->idx != subghz_history_get_item(model->history) - 1) model->idx++;
                     return true;
                 });
-        } else if(event->key == InputKeyLeft) {
+        } else if(event->key == InputKeyLeft && event->type == InputTypeShort) {
             subghz_receiver->hopper_state = SubGhzHopperStatePause;
             with_view_model(
                 subghz_receiver->view, (SubghzReceiverModel * model) {
@@ -317,7 +326,8 @@ bool subghz_receiver_input(InputEvent* event, void* context) {
                     return true;
                 });
             subghz_receiver->callback(SubghzReceverEventConfig, subghz_receiver->context);
-        } else if(event->key == InputKeyOk) {
+        } else if(event->key == InputKeyOk && event->type == InputTypeShort) {
+            subghz_receiver->event_key_sequence = event->sequence;
             with_view_model(
                 subghz_receiver->view, (SubghzReceiverModel * model) {
                     string_clean(model->text);
@@ -358,18 +368,23 @@ bool subghz_receiver_input(InputEvent* event, void* context) {
         } else if(can_be_saved && event->key == InputKeyRight) {
             subghz_receiver->callback(SubghzReceverEventSave, subghz_receiver->context);
             return false;
-        } else if(can_be_saved && event->key == InputKeyOk && event->type == InputTypePress) {
+        } else if(
+            can_be_saved && event->key == InputKeyOk && event->type == InputTypePress &&
+            subghz_receiver->event_key_sequence != event->sequence) {
             subghz_receiver->hopper_state = SubGhzHopperStatePause;
             subghz_rx_end(subghz_receiver->worker);
             subghz_receiver->callback(SubghzReceverEventSendStart, subghz_receiver->context);
             return true;
-        } else if(can_be_saved && event->key == InputKeyOk && event->type == InputTypeRelease) {
+        } else if(
+            can_be_saved && event->key == InputKeyOk && event->type == InputTypeRelease &&
+            subghz_receiver->event_key_sequence != event->sequence) {
             subghz_receiver->callback(SubghzReceverEventSendStop, subghz_receiver->context);
             return true;
         }
         break;
 
     case ReceiverSceneConfig:
+        if(event->type != InputTypeShort) return false;
         if(event->key == InputKeyBack) {
             with_view_model(
                 subghz_receiver->view, (SubghzReceiverModel * model) {
@@ -396,7 +411,6 @@ bool subghz_receiver_input(InputEvent* event, void* context) {
                         osTimerStart(subghz_receiver->timer, 1024 / 10);
                         subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
                     }
-
                     if(subghz_history_get_item(model->history) == 0) {
                         model->scene = ReceiverSceneStart;
                     } else {
@@ -426,6 +440,7 @@ bool subghz_receiver_input(InputEvent* event, void* context) {
         break;
 
     case ReceiverSceneStart:
+        if(event->type != InputTypeShort) return false;
         if(event->key == InputKeyBack) {
             return false;
         } else if(event->key == InputKeyLeft) {
@@ -445,6 +460,16 @@ bool subghz_receiver_input(InputEvent* event, void* context) {
     }
 
     subghz_receiver_update_offset(subghz_receiver);
+    if(scene != ReceiverSceneInfo) {
+        with_view_model(
+            subghz_receiver->view, (SubghzReceiverModel * model) {
+                if(subghz_history_get_text_space_left(model->history, NULL)) {
+                    subghz_receiver_history_full(subghz_receiver);
+                }
+                return false;
+            });
+    }
+
     return true;
 }
 
@@ -476,6 +501,9 @@ void subghz_receiver_protocol_callback(SubGhzProtocolCommon* parser, void* conte
 
             model->history_item = subghz_history_get_item(model->history);
             model->scene = ReceiverSceneMain;
+            if(subghz_history_get_text_space_left(model->history, NULL)) {
+                subghz_receiver_history_full(subghz_receiver);
+            }
             return true;
         });
     subghz_protocol_reset(subghz_receiver->protocol);
@@ -528,10 +556,11 @@ static void subghz_receiver_timer_callback(void* context) {
             }
 
             // Restart radio
-            subghz_rx_end(subghz_receiver->worker);
+            furi_hal_subghz_idle();
             subghz_protocol_reset(subghz_receiver->protocol);
-            model->real_frequency =
-                subghz_rx(subghz_receiver->worker, subghz_frequencies_hopper[model->frequency]);
+            model->real_frequency = furi_hal_subghz_set_frequency_and_path(
+                subghz_frequencies_hopper[model->frequency]);
+            furi_hal_subghz_rx();
 
             return true;
         });

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

@@ -14,7 +14,8 @@ typedef enum {
     SubghzReceverEventBack,
     SubghzReceverEventMore,
     SubghzReceverEventSendStart,
-    SubghzReceverEventSendStop
+    SubghzReceverEventSendStop,
+    SubghzReceverEventSendHistoryFull,
 } SubghzReceverEvent;
 
 typedef struct SubghzReceiver SubghzReceiver;

+ 23 - 6
applications/subghz/views/subghz_transmitter.c

@@ -7,6 +7,7 @@
 #include <input/input.h>
 #include <gui/elements.h>
 #include <notification/notification-messages.h>
+#include <lib/subghz/protocols/subghz_protocol_keeloq.h>
 
 struct SubghzTransmitter {
     View* view;
@@ -100,6 +101,10 @@ void subghz_transmitter_draw(Canvas* canvas, SubghzTransmitterModel* model) {
     canvas_draw_str(canvas, 90, 8, buffer);
 
     if(model->protocol && model->protocol->get_upload_protocol) {
+        if((!strcmp(model->protocol->name, "KeeLoq")) &&
+           (!strcmp(subghz_protocol_keeloq_get_manufacture_name(model->protocol), "Unknown"))) {
+            return;
+        }
         subghz_transmitter_button_right(canvas, "Send");
     }
 }
@@ -107,22 +112,33 @@ void subghz_transmitter_draw(Canvas* canvas, SubghzTransmitterModel* model) {
 bool subghz_transmitter_input(InputEvent* event, void* context) {
     furi_assert(context);
     SubghzTransmitter* subghz_transmitter = context;
-    bool can_be_send = false;
+    bool can_be_sent = false;
+
+    if(event->key == InputKeyBack) {
+        return false;
+    }
+
     with_view_model(
         subghz_transmitter->view, (SubghzTransmitterModel * model) {
-            can_be_send = (model->protocol && model->protocol->get_upload_protocol);
+            if(model->protocol && model->protocol->get_upload_protocol) {
+                if((!strcmp(model->protocol->name, "KeeLoq")) &&
+                   (!strcmp(
+                       subghz_protocol_keeloq_get_manufacture_name(model->protocol), "Unknown"))) {
+                    return false;
+                }
+                can_be_sent = true;
+            }
+            //can_be_sent = (model->protocol && model->protocol->get_upload_protocol);
             string_clean(model->text);
             model->protocol->to_string(model->protocol, model->text);
             return true;
         });
     //if(event->type != InputTypeShort) return false;
 
-    if(event->key == InputKeyBack) {
-        return false;
-    } else if(can_be_send && event->key == InputKeyOk && event->type == InputTypePress) {
+    if(can_be_sent && event->key == InputKeyOk && event->type == InputTypePress) {
         subghz_transmitter->callback(SubghzTransmitterEventSendStart, subghz_transmitter->context);
         return true;
-    } else if(can_be_send && event->key == InputKeyOk && event->type == InputTypeRelease) {
+    } else if(can_be_sent && event->key == InputKeyOk && event->type == InputTypeRelease) {
         subghz_transmitter->callback(SubghzTransmitterEventSendStop, subghz_transmitter->context);
         return true;
     }
@@ -147,6 +163,7 @@ void subghz_transmitter_enter(void* context) {
     SubghzTransmitter* subghz_transmitter = context;
     with_view_model(
         subghz_transmitter->view, (SubghzTransmitterModel * model) {
+            string_clean(model->text);
             model->protocol->to_string(model->protocol, model->text);
             return true;
         });

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

@@ -7,6 +7,7 @@ typedef enum {
     SubghzTransmitterEventSendStart,
     SubghzTransmitterEventSendStop,
     SubghzTransmitterEventBack,
+    SubghzTransmitterEventNoMan,
 } SubghzTransmitterEvent;
 
 typedef struct SubghzTransmitter SubghzTransmitter;

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


+ 4 - 6
assets/compiled/assets_icons.h

@@ -29,12 +29,10 @@ extern const Icon I_DolphinFirstStart8_56x51;
 extern const Icon I_DolphinFirstStart7_61x51;
 extern const Icon I_Flipper_young_80x60;
 extern const Icon I_DolphinFirstStart3_57x48;
-extern const Icon I_quest_7x8;
-extern const Icon I_unlock_7x8;
-extern const Icon I_Scanning_dolph_67_61;
-extern const Icon I_Broadcast_dolph_67_61;
-extern const Icon I_lock_7x8;
-extern const Icon I_Top_frame_128_13;
+extern const Icon I_Scanning_123x52;
+extern const Icon I_Quest_7x8;
+extern const Icon I_Unlock_7x8;
+extern const Icon I_Lock_7x8;
 extern const Icon I_PassportBottom_128x17;
 extern const Icon I_DoorLeft_8x56;
 extern const Icon I_DoorLocked_10x56;

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


BIN
assets/icons/GubGHz/Scanning_123x52.png


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


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


+ 0 - 144
core/furi-hal/api-spi.h

@@ -1,144 +0,0 @@
-#include <furi.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
-struct used for handling SPI info.
-*/
-typedef struct {
-    SPI_HandleTypeDef* spi;
-    PubSubCallback cb;
-    void* ctx;
-} SpiHandle;
-
-/*
-For transmit/receive data use `spi_xfer` function.
-
-* `tx_data` and `rx_data` size must be equal (and equal `len`)
-* `cb` called after spi operation is completed, `(NULL, ctx)` passed to callback.
-*/
-bool spi_xfer(
-    SPI_HandleTypeDef* spi,
-    uint8_t* tx_data,
-    uint8_t* rx_data,
-    size_t len,
-    PubSubCallback cb,
-    void* ctx);
-
-/*
-Blocking verison:
-*/
-static inline bool
-    spi_xfer_block(SPI_HandleTypeDef* spi, uint8_t* tx_data, uint8_t* rx_data, size_t len) {
-    semaphoreInfo s;
-    osSemaphore block = createSemaphoreStatic(s);
-    if(!spi_xfer(spi, tx_data, rx_data, len, RELEASE_SEMAPHORE, (void*)block)) {
-        osReleaseSemaphore(block);
-        return false;
-    }
-    osWaitSemaphore(block);
-    return false;
-}
-
-/*
-Common implementation of SPI bus: serial interface + CS pin
-*/
-typedef struct {
-    GpioPin* cs; ///< CS pin
-    ValueMutex* spi; ///< <SpiHandle*>
-} SpiBus;
-
-/*
-For dedicated work with one device there is `SpiDevice` entity.
-It contains ValueMutex around SpiBus: after you acquire device
-you can acquire spi to work with it (don't forget SPI bus is shared
-around many device, release it after every transaction as quick as possible).
-*/
-typedef struct {
-    ValueMutex* bus; ///< <SpiBus*>
-} SpiDevice;
-
-##SPI IRQ device
-
-    /*
-Many devices (like CC1101 and NFC) present as SPI bus and IRQ line.
-For work with it there is special entity `SpiIrqDevice`.
-Use `subscribe_pubsub` for subscribinq to irq events.
-*/
-
-    typedef struct {
-    ValueMutex* bus; ///< <SpiBus*>
-    PubSub* irq;
-} SpiIrqDevice;
-
-/*
-Special implementation of SPI bus: serial interface + CS, Res, D/I lines.
-*/
-typedef struct {
-    GpioPin* cs; ///< CS pin
-    GpioPin* res; ///< reset pin
-    GpioPin* di; ///< D/I pin
-    ValueMutex* spi; ///< <SPI_HandleTypeDef*>
-} DisplayBus;
-
-typedef struct {
-    ValueMutex* bus; ///< <DisplayBus*>
-} DisplayDevice;
-
-/*
-# SPI devices (F2)
-
-* `/dev/sdcard` - SD card SPI, `SpiDevice`
-* `/dev/cc1101_bus` - Sub-GHz radio (CC1101), `SpiIrqDevice`
-* `/dev/nfc` - NFC (ST25R3916), `SpiIrqDevice`
-* `/dev/display` - `DisplayDevice`
-* `/dev/spiext` - External SPI (warning! Lock PA4, PA5, PA6, PA7)
-
-### Application example
-
-```C
-// Be careful, this function called from IRQ context
-void handle_irq(void* _arg, void* _ctx) {
-}
-
-void cc1101_example() {
-    SpiIrqDevice* cc1101_device = open_input("/dev/cc1101_bus");
-    if(cc1101_device == NULL) return; // bus not available, critical error
-
-    subscribe_pubsub(cc1101_device->irq, handle_irq, NULL);
-
-    {
-        // acquire device as device bus
-        SpiBus* spi_bus = acquire_mutex(cc1101_device->bus, 0);
-        if(spi_bus == NULL) {
-            printf("Device busy\n");
-            // wait for device
-            spi_bus = acquire_mutex_block(cc1101_device->bus);
-        }
-        
-        // make transaction
-        uint8_t request[4] = {0xDE, 0xAD, 0xBE, 0xEF};
-        uint8_t response[4];
-
-        {
-            SPI_HandleTypeDef* spi = acquire_mutex_block(spi_bus->spi);
-
-            gpio_write(spi_bus->cs, false);
-            spi_xfer_block(spi, request, response, 4);
-            gpio_write(spi_bus->cs, true);
-
-            release_mutex(cc1101_device->spi, spi);
-        }
-
-        // release device (device bus)
-        release_mutex(cc1101_device->bus, spi_bus);
-    }
-}
-```
-*/
-
-#ifdef __cplusplus
-}
-#endif

+ 9 - 0
core/furi/common_defines.h

@@ -31,3 +31,12 @@
 #ifndef COUNT_OF
 #define COUNT_OF(x) (sizeof(x) / sizeof(x[0]))
 #endif
+
+#ifndef FURI_SWAP
+#define FURI_SWAP(x, y)     \
+    do {                    \
+        typeof(x) SWAP = x; \
+        x = y;              \
+        y = SWAP;           \
+    } while(0)
+#endif

+ 24 - 2
lib/subghz/protocols/subghz_protocol_came.h

@@ -22,7 +22,9 @@ void subghz_protocol_came_free(SubGhzProtocolCame* instance);
  * @param encoder - SubGhzProtocolCommonEncoder encoder
  * @return bool
  */
-bool subghz_protocol_came_send_key(SubGhzProtocolCame* instance, SubGhzProtocolCommonEncoder* encoder);
+bool subghz_protocol_came_send_key(
+    SubGhzProtocolCame* instance,
+    SubGhzProtocolCommonEncoder* encoder);
 
 /** Reset internal state
  * @param instance - SubGhzProtocolCame instance
@@ -43,6 +45,26 @@ void subghz_protocol_came_parse(SubGhzProtocolCame* instance, bool level, uint32
  */
 void subghz_protocol_came_to_str(SubGhzProtocolCame* instance, string_t output);
 
+/** Get a string to save the protocol
+ * 
+ * @param instance  - SubGhzProtocolCame instance
+ * @param output    - the resulting string
+ */
 void subghz_protocol_came_to_save_str(SubGhzProtocolCame* instance, string_t output);
-bool subghz_protocol_came_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolCame* instance);
+
+/** Loading protocol from file
+ * 
+ * @param file_worker - FileWorker file_worker
+ * @param instance - SubGhzProtocolCame instance
+ * @return bool
+ */
+bool subghz_protocol_came_to_load_protocol_from_file(
+    FileWorker* file_worker,
+    SubGhzProtocolCame* instance);
+
+/** Loading protocol from bin data
+ * 
+ * @param instance - SubGhzProtocolCame instance
+ * @param context - SubGhzProtocolCommonLoad context
+ */
 void subghz_decoder_came_to_load_protocol(SubGhzProtocolCame* instance, void* context);

+ 28 - 0
lib/subghz/protocols/subghz_protocol_common.h

@@ -96,9 +96,30 @@ struct SubGhzProtocolCommonLoad{
     uint32_t param3;
 };
 
+/** Allocate SubGhzProtocolCommonEncoder
+ * 
+ * @return SubGhzProtocolCommonEncoder* 
+ */
 SubGhzProtocolCommonEncoder* subghz_protocol_encoder_common_alloc();
+
+/** Free SubGhzProtocolCommonEncoder
+ * 
+ * @param instance 
+ */
 void subghz_protocol_encoder_common_free(SubGhzProtocolCommonEncoder* instance);
+
+/** Get count repeat left
+ * 
+ * @param instance - SubGhzProtocolCommonEncoder instance
+ * @return count repeat left
+ */
 size_t subghz_encoder_common_get_repeat_left(SubGhzProtocolCommonEncoder* instance);
+
+/** Get LevelDuration this encoder step
+ * 
+ * @param context - SubGhzProtocolCommonEncoder context
+ * @return LevelDuration this step
+ */
 LevelDuration subghz_protocol_encoder_common_yield(void* context);
 
 /** Add data bit to code_found
@@ -146,4 +167,11 @@ void subghz_protocol_common_set_callback(
  */
 void subghz_protocol_common_to_str(SubGhzProtocolCommon* instance, string_t output);
 
+/** Converting a string to a HEX array
+ * 
+ * @param str - string data
+ * @param buff - uint8_t* buff
+ * @param len - size buff
+ * @return bool
+ */
 bool subghz_protocol_common_read_hex(string_t str, uint8_t* buff, uint16_t len);

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

@@ -50,4 +50,9 @@ void subghz_protocol_faac_slh_parse(SubGhzProtocolFaacSLH* instance, bool level,
  */
 void subghz_protocol_faac_slh_to_str(SubGhzProtocolFaacSLH* instance, string_t output);
 
+/** Loading protocol from bin data
+ * 
+ * @param instance - SubGhzProtocolFaacSLH instance
+ * @param context - SubGhzProtocolCommonLoad context
+ */
 void subghz_decoder_faac_slh_to_load_protocol(SubGhzProtocolFaacSLH* instance, void* context);

+ 18 - 0
lib/subghz/protocols/subghz_protocol_gate_tx.h

@@ -43,6 +43,24 @@ void subghz_protocol_gate_tx_parse(SubGhzProtocolGateTX* instance, bool level, u
  */
 void subghz_protocol_gate_tx_to_str(SubGhzProtocolGateTX* instance, string_t output);
 
+/** Get a string to save the protocol
+ * 
+ * @param instance  - SubGhzProtocolGateTX instance
+ * @param output    - the resulting string
+ */
 void subghz_protocol_gate_tx_to_save_str(SubGhzProtocolGateTX* instance, string_t output);
+
+/** Loading protocol from file
+ * 
+ * @param file_worker - FileWorker file_worker
+ * @param instance - SubGhzProtocolGateTX instance
+ * @return bool
+ */
 bool subghz_protocol_gate_tx_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolGateTX* instance);
+
+/** Loading protocol from bin data
+ * 
+ * @param instance - SubGhzProtocolGateTX instance
+ * @param context - SubGhzProtocolCommonLoad context
+ */
 void subghz_decoder_gate_tx_to_load_protocol(SubGhzProtocolGateTX* instance, void* context);

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

@@ -49,4 +49,10 @@ void subghz_protocol_ido_parse(SubGhzProtocolIDo* instance, bool level, uint32_t
  * @param output   - output string
  */
 void subghz_protocol_ido_to_str(SubGhzProtocolIDo* instance, string_t output);
+
+/** Loading protocol from bin data
+ * 
+ * @param instance - SubGhzProtocolIDo instance
+ * @param context - SubGhzProtocolCommonLoad context
+ */
 void subghz_decoder_ido_to_load_protocol(SubGhzProtocolIDo* instance, void* context);

+ 24 - 7
lib/subghz/protocols/subghz_protocol_keeloq.c

@@ -174,15 +174,31 @@ void subghz_protocol_keeloq_check_remote_controller(SubGhzProtocolKeeloq* instan
     instance->common.btn = key_fix >> 28;
 }
 
-const char* subghz_protocol_keeloq_get_manufacture_name(void* context) {
+const char* subghz_protocol_keeloq_find_and_get_manufacture_name(void* context) {
     SubGhzProtocolKeeloq* instance = context;
     subghz_protocol_keeloq_check_remote_controller(instance);
     return instance->manufacture_name;
 }
 
-void subghz_protocol_keeloq_set_manufacture_name(void* context, const char* manufacture_name) {
+const char* subghz_protocol_keeloq_get_manufacture_name(void* context) {
+    SubGhzProtocolKeeloq* instance = context;
+    return instance->manufacture_name;
+}
+
+bool subghz_protocol_keeloq_set_manufacture_name(void* context, const char* manufacture_name) {
     SubGhzProtocolKeeloq* instance = context;
     instance->manufacture_name = manufacture_name;
+    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) return true;
+            }
+        instance->manufacture_name = "Unknown";
+        return false;
 }
 
 uint64_t subghz_protocol_keeloq_gen_key(void* context) {
@@ -232,6 +248,10 @@ bool subghz_protocol_keeloq_send_key(
     if(instance->common.callback)
         instance->common.callback((SubGhzProtocolCommon*)instance, instance->common.context);
 
+    if(!strcmp(instance->manufacture_name, "Unknown")) {
+        return false;
+    }
+
     size_t index = 0;
     encoder->size_upload = 11 * 2 + 2 + (instance->common.code_last_count_bit * 2) + 4;
     if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
@@ -392,8 +412,7 @@ void subghz_protocol_keeloq_to_str(SubGhzProtocolKeeloq* instance, string_t outp
         code_found_reverse_lo,
         instance->common.btn,
         instance->manufacture_name,
-        instance->common.serial
-    );
+        instance->common.serial);
 }
 
 void subghz_protocol_keeloq_to_save_str(SubGhzProtocolKeeloq* instance, string_t output) {
@@ -450,9 +469,7 @@ bool subghz_protocol_keeloq_to_load_protocol_from_file(
     return loaded;
 }
 
-void subghz_decoder_keeloq_to_load_protocol(
-    SubGhzProtocolKeeloq* instance,
-    void* context) {
+void subghz_decoder_keeloq_to_load_protocol(SubGhzProtocolKeeloq* instance, void* context) {
     furi_assert(context);
     furi_assert(instance);
     SubGhzProtocolCommonLoad* data = context;

+ 32 - 1
lib/subghz/protocols/subghz_protocol_keeloq.h

@@ -18,14 +18,27 @@ SubGhzProtocolKeeloq* subghz_protocol_keeloq_alloc(SubGhzKeystore* keystore);
  */
 void subghz_protocol_keeloq_free(SubGhzProtocolKeeloq* instance);
 
+/** Find and get manufacture name
+ * 
+ * @param context - SubGhzProtocolKeeloq context
+ * @return name - char* manufacture name
+ */
+const char* subghz_protocol_keeloq_find_and_get_manufacture_name(void* context);
+
+/** Get manufacture name
+ * 
+ * @param context - SubGhzProtocolKeeloq context
+ * @return name - char* manufacture name
+ */
 const char* subghz_protocol_keeloq_get_manufacture_name(void* context);
 
 /** Set manufacture name
  * 
  * @param manufacture_name - manufacture name
  * @param context - SubGhzProtocolKeeloq context
+ * @return bool
  */
-void subghz_protocol_keeloq_set_manufacture_name(void* context, const char* manufacture_name);
+bool subghz_protocol_keeloq_set_manufacture_name(void* context, const char* manufacture_name);
 
 /** Get key keeloq
  * 
@@ -61,6 +74,24 @@ void subghz_protocol_keeloq_parse(SubGhzProtocolKeeloq* instance, bool level, ui
  */
 void subghz_protocol_keeloq_to_str(SubGhzProtocolKeeloq* instance, string_t output);
 
+/** Get a string to save the protocol
+ * 
+ * @param instance  - SubGhzProtocolKeeloq instance
+ * @param output    - the resulting string
+ */
 void subghz_protocol_keeloq_to_save_str(SubGhzProtocolKeeloq* instance, string_t output);
+
+/** Loading protocol from file
+ * 
+ * @param file_worker - FileWorker file_worker
+ * @param instance - SubGhzProtocolKeeloq instance
+ * @return bool
+ */
 bool subghz_protocol_keeloq_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolKeeloq* instance);
+
+/** Loading protocol from bin data
+ * 
+ * @param instance - SubGhzProtocolKeeloq instance
+ * @param context - SubGhzProtocolCommonLoad context
+ */
 void subghz_decoder_keeloq_to_load_protocol(SubGhzProtocolKeeloq* instance, void* context);

+ 18 - 0
lib/subghz/protocols/subghz_protocol_nero_sketch.h

@@ -49,6 +49,24 @@ void subghz_protocol_nero_sketch_parse(SubGhzProtocolNeroSketch* instance, bool
  */
 void subghz_protocol_nero_sketch_to_str(SubGhzProtocolNeroSketch* instance, string_t output);
 
+/** Get a string to save the protocol
+ * 
+ * @param instance  - SubGhzProtocolNeroSketch instance
+ * @param output    - the resulting string
+ */
 void subghz_protocol_nero_sketch_to_save_str(SubGhzProtocolNeroSketch* instance, string_t output);
+
+/** Loading protocol from file
+ * 
+ * @param file_worker - FileWorker file_worker
+ * @param instance - SubGhzProtocolNeroSketch instance
+ * @return bool
+ */
 bool subghz_protocol_nero_sketch_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolNeroSketch* instance);
+
+/** Loading protocol from bin data
+ * 
+ * @param instance - SubGhzProtocolNeroSketch instance
+ * @param context - SubGhzProtocolCommonLoad context
+ */
 void subghz_decoder_nero_sketch_to_load_protocol(SubGhzProtocolNeroSketch* instance, void* context);

+ 18 - 0
lib/subghz/protocols/subghz_protocol_nice_flo.h

@@ -43,6 +43,24 @@ void subghz_protocol_nice_flo_parse(SubGhzProtocolNiceFlo* instance, bool level,
  */
 void subghz_protocol_nice_flo_to_str(SubGhzProtocolNiceFlo* instance, string_t output);
 
+/** Get a string to save the protocol
+ * 
+ * @param instance  - SubGhzProtocolNiceFlo instance
+ * @param output    - the resulting string
+ */
 void subghz_protocol_nice_flo_to_save_str(SubGhzProtocolNiceFlo* instance, string_t output);
+
+/** Loading protocol from file
+ * 
+ * @param file_worker - FileWorker file_worker
+ * @param instance - SubGhzProtocolNiceFlo instance
+ * @return bool
+ */
 bool subghz_protocol_nice_flo_to_load_protocol_from_file(FileWorker* file_worker, SubGhzProtocolNiceFlo* instance);
+
+/** Loading protocol from bin data
+ * 
+ * @param instance - SubGhzProtocolNiceFlo instance
+ * @param context - SubGhzProtocolCommonLoad context
+ */
 void subghz_decoder_nice_flo_to_load_protocol(SubGhzProtocolNiceFlo* instance, void* context);

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

@@ -50,4 +50,10 @@ void subghz_protocol_nice_flor_s_parse(SubGhzProtocolNiceFlorS* instance, bool l
  * @param output   - output string
  */
 void subghz_protocol_nice_flor_s_to_str(SubGhzProtocolNiceFlorS* instance, string_t output);
+
+/** Loading protocol from bin data
+ * 
+ * @param instance - SubGhzProtocolNiceFlorS instance
+ * @param context - SubGhzProtocolCommonLoad context
+ */
 void subghz_decoder_nice_flor_s_to_load_protocol(SubGhzProtocolNiceFlorS* instance, void* context);

+ 23 - 3
lib/subghz/protocols/subghz_protocol_princeton.h

@@ -56,6 +56,11 @@ SubGhzDecoderPrinceton* subghz_decoder_princeton_alloc();
  */
 void subghz_decoder_princeton_free(SubGhzDecoderPrinceton* instance);
 
+/** Get Te interval protocol
+ * 
+ * @param context - SubGhzDecoderPrinceton context
+ * @return Te interval (us)
+ */
 uint16_t subghz_protocol_princeton_get_te(void* context);
 
 /** Get upload protocol
@@ -90,11 +95,26 @@ void subghz_decoder_princeton_parse(
  */
 void subghz_decoder_princeton_to_str(SubGhzDecoderPrinceton* instance, string_t output);
 
+/** Get a string to save the protocol
+ * 
+ * @param instance  - SubGhzDecoderPrinceton instance
+ * @param output    - the resulting string
+ */
 void subghz_decoder_princeton_to_save_str(SubGhzDecoderPrinceton* instance, string_t output);
-bool subghz_decoder_princeton_to_load_protocol_from_file(
-    FileWorker* file_worker,
-    SubGhzDecoderPrinceton* instance);
 
+/** Loading protocol from file
+ * 
+ * @param file_worker - FileWorker file_worker
+ * @param instance - SubGhzDecoderPrinceton instance
+ * @return bool
+ */
+bool subghz_decoder_princeton_to_load_protocol_from_file(FileWorker* file_worker, SubGhzDecoderPrinceton* instance);
+
+/** Loading protocol from bin data
+ * 
+ * @param instance - SubGhzDecoderPrinceton instance
+ * @param context - SubGhzProtocolCommonLoad context
+ */
 void subghz_decoder_princeton_to_load_protocol(
     SubGhzDecoderPrinceton* instance,
     void* context) ;

+ 6 - 1
lib/subghz/protocols/subghz_protocol_star_line.c

@@ -38,12 +38,17 @@ void subghz_protocol_star_line_free(SubGhzProtocolStarLine* instance) {
     free(instance);
 }
 
-const char* subghz_protocol_star_line_get_manufacture_name (void* context){
+const char* subghz_protocol_star_line_find_and_get_manufacture_name (void* context){
     SubGhzProtocolStarLine* instance = context;
     subghz_protocol_star_line_check_remote_controller(instance);
     return instance->manufacture_name;
 }
 
+const char* subghz_protocol_star_line_get_manufacture_name (void* context){
+    SubGhzProtocolStarLine* instance = context;
+    return instance->manufacture_name;
+}
+
 /** Send bit 
  * 
  * @param instance - SubGhzProtocolStarLine instance

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

@@ -18,6 +18,18 @@ SubGhzProtocolStarLine* subghz_protocol_star_line_alloc(SubGhzKeystore* keystore
  */
 void subghz_protocol_star_line_free(SubGhzProtocolStarLine* instance);
 
+/** Find and get manufacture name
+ * 
+ * @param context - SubGhzProtocolStarLine context
+ * @return name - char* manufacture name
+ */
+const char* subghz_protocol_star_line_find_and_get_manufacture_name(void* context);
+
+/** Get manufacture name
+ * 
+ * @param context - SubGhzProtocolStarLine context
+ * @return name - char* manufacture name
+ */
 const char* subghz_protocol_star_line_get_manufacture_name(void* context);
 
 /** Sends the key on the air
@@ -53,4 +65,10 @@ void subghz_protocol_star_line_parse(SubGhzProtocolStarLine* instance, bool leve
  * @param output   - output string
  */
 void subghz_protocol_star_line_to_str(SubGhzProtocolStarLine* instance, string_t output);
+
+/** Loading protocol from bin data
+ * 
+ * @param instance - SubGhzDecoderPrinceton instance
+ * @param context - SubGhzProtocolCommonLoad context
+ */
 void subghz_decoder_star_line_to_load_protocol(SubGhzProtocolStarLine* instance, void* context);

+ 18 - 0
lib/subghz/subghz_keystore.h

@@ -16,10 +16,28 @@ ARRAY_DEF(SubGhzKeyArray, SubGhzKey, M_POD_OPLIST)
 
 typedef struct SubGhzKeystore SubGhzKeystore;
 
+/** Allocate SubGhzKeystore
+ * 
+ * @return SubGhzKeystore* 
+ */
 SubGhzKeystore* subghz_keystore_alloc();
 
+/** Free SubGhzKeystore
+ * 
+ * @param instance 
+ */
 void subghz_keystore_free(SubGhzKeystore* instance);
 
+/** Loading manufacture key from file
+ * 
+ * @param instance - SubGhzKeystore instance
+ * @param filename - const char* full path to the file
+ */
 void subghz_keystore_load(SubGhzKeystore* instance, const char* filename);
 
+/** Get array of keys and names manufacture
+ * 
+ * @param instance - SubGhzKeystore instance
+ * @return SubGhzKeyArray_t*
+ */
 SubGhzKeyArray_t* subghz_keystore_get_data(SubGhzKeystore* instance);

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