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

[FL-1755, FL-1756] added LL_DeInit timers, removed Analyze scene, redesigned astomatic frequency change mechanism, updated subghz read scene interface (#677)

* SubGhz: Fix Timer hopping
* SubGhz: add display of received packages and their maximum number. redesigned interface, the maximum number of received packages increased to 50
* SubGhz: add clearing history on exit read scene, jump after saving the key into the history of received signals
* SubGhz: Fix honoring the width of the icon for transmitter scene
* RFID: Fix [FL-1755] freeze after key emulation
* SubGhz: drop analyze scene and views
* SubGhz: fix save scene
* Input, GUI: new event delivery scheme that groups event for complementarity.
* Gui: update View Dispatcher documentation
* Gui: remove dead code, wait till all input events are delivered in ViewDispatcher in queue mode.
* Gui: update comment in ViewDispatcher
* FuriHal: fix incorrect clock disable invocation
* FuriHal: proper include
* SubGhz: properly reset history in receiver view
* Gui: correct view switch order and non-complementary events discarding

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
Skorpionm 4 лет назад
Родитель
Сommit
6f7bcdf9a7

+ 13 - 0
applications/dialogs/view_holder.c

@@ -11,6 +11,8 @@ struct ViewHolder {
 
     BackCallback back_callback;
     void* back_context;
+
+    uint8_t ongoing_input_events_count;
 };
 
 static void view_holder_draw_callback(Canvas* canvas, void* context);
@@ -92,6 +94,7 @@ void view_holder_start(ViewHolder* view_holder) {
 }
 
 void view_holder_stop(ViewHolder* view_holder) {
+    while(view_holder->ongoing_input_events_count > 0) osDelay(1);
     view_port_enabled_set(view_holder->view_port, false);
 }
 
@@ -114,6 +117,16 @@ static void view_holder_draw_callback(Canvas* canvas, void* context) {
 
 static void view_holder_input_callback(InputEvent* event, void* context) {
     ViewHolder* view_holder = context;
+
+    if(event->type == InputTypeRelease && view_holder->ongoing_input_events_count > 0) {
+        view_holder->ongoing_input_events_count--;
+    } else if(event->type == InputTypePress) {
+        view_holder->ongoing_input_events_count++;
+    } else if(view_holder->ongoing_input_events_count == 0) {
+        FURI_LOG_E("ViewHolder", "non-complementary input, discarding");
+        return;
+    }
+
     bool is_consumed = false;
 
     if(view_holder->view) {

+ 0 - 14
applications/gui/view.c

@@ -35,11 +35,6 @@ void view_set_previous_callback(View* view, ViewNavigationCallback callback) {
     view->previous_callback = callback;
 }
 
-void view_set_next_callback(View* view, ViewNavigationCallback callback) {
-    furi_assert(view);
-    view->next_callback = callback;
-}
-
 void view_set_enter_callback(View* view, ViewCallback callback) {
     furi_assert(view);
     view->enter_callback = callback;
@@ -169,15 +164,6 @@ uint32_t view_previous(View* view) {
     }
 }
 
-uint32_t view_next(View* view) {
-    furi_assert(view);
-    if(view->next_callback) {
-        return view->next_callback(view->context);
-    } else {
-        return VIEW_IGNORE;
-    }
-}
-
 void view_enter(View* view) {
     furi_assert(view);
     if(view->enter_callback) view->enter_callback(view->context);

+ 0 - 11
applications/gui/view.h

@@ -14,11 +14,6 @@ extern "C" {
 #define VIEW_NONE 0xFFFFFFFF
 /* Ignore navigation event */
 #define VIEW_IGNORE 0xFFFFFFFE
-/* Deatch from gui, deallocate Views and ViewDispatcher
- * BE SUPER CAREFUL, deallocation happens automatically on GUI thread
- * You ARE NOT owning ViewDispatcher and Views instances
- */
-#define VIEW_DESTROY 0xFFFFFFFA
 
 typedef enum {
     ViewOrientationHorizontal,
@@ -119,12 +114,6 @@ void view_set_custom_callback(View* view, ViewCustomCallback callback);
  */
 void view_set_previous_callback(View* view, ViewNavigationCallback callback);
 
-/* Set Navigation Next callback
- * @param view, pointer to View
- * @param callback, input callback
- */
-void view_set_next_callback(View* view, ViewNavigationCallback callback);
-
 /* Set Enter callback
  * @param view, pointer to View
  * @param callback, callback

+ 34 - 5
applications/gui/view_dispatcher.c

@@ -91,6 +91,18 @@ void view_dispatcher_run(ViewDispatcher* view_dispatcher) {
             view_dispatcher_handle_custom_event(view_dispatcher, message.custom_event);
         }
     }
+
+    // Wait till all input events delivered
+    while(view_dispatcher->ongoing_input_events_count > 0) {
+        osMessageQueueGet(view_dispatcher->queue, &message, NULL, osWaitForever);
+        if(message.type == ViewDispatcherMessageTypeInput) {
+            if(message.input.type == InputTypePress) {
+                view_dispatcher->ongoing_input_events_count++;
+            } else if(message.input.type == InputTypeRelease) {
+                view_dispatcher->ongoing_input_events_count--;
+            }
+        }
+    }
 }
 
 void view_dispatcher_stop(ViewDispatcher* view_dispatcher) {
@@ -153,12 +165,15 @@ void view_dispatcher_switch_to_view(ViewDispatcher* view_dispatcher, uint32_t vi
     if(view_id == VIEW_NONE) {
         view_dispatcher_set_current_view(view_dispatcher, NULL);
     } else if(view_id == VIEW_IGNORE) {
-    } else if(view_id == VIEW_DESTROY) {
-        view_dispatcher_free(view_dispatcher);
     } else {
         View** view_pp = ViewDict_get(view_dispatcher->views, view_id);
         furi_check(view_pp != NULL);
-        view_dispatcher_set_current_view(view_dispatcher, *view_pp);
+        if(view_dispatcher->ongoing_input_events_count > 0) {
+            view_dispatcher->delayed_next_view = *view_pp;
+        } else {
+            view_dispatcher->delayed_next_view = NULL;
+            view_dispatcher_set_current_view(view_dispatcher, *view_pp);
+        }
     }
 }
 
@@ -202,6 +217,16 @@ void view_dispatcher_input_callback(InputEvent* event, void* context) {
 }
 
 void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* event) {
+    // Ongoing input events counting
+    if(event->type == InputTypeRelease && view_dispatcher->ongoing_input_events_count > 0) {
+        view_dispatcher->ongoing_input_events_count--;
+    } else if(event->type == InputTypePress) {
+        view_dispatcher->ongoing_input_events_count++;
+    } else if(view_dispatcher->ongoing_input_events_count == 0) {
+        FURI_LOG_E("ViewDispatcher", "non-complementary input, discarding");
+        return;
+    }
+
     bool is_consumed = false;
     if(view_dispatcher->current_view) {
         is_consumed = view_input(view_dispatcher->current_view, event);
@@ -219,13 +244,17 @@ void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* e
                     return;
                 }
             }
-        } else if(event->key == InputKeyOk) {
-            view_id = view_next(view_dispatcher->current_view);
         }
         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_events_count == 0) {
+        view_dispatcher_set_current_view(view_dispatcher, view_dispatcher->delayed_next_view);
+        view_dispatcher->delayed_next_view = NULL;
+    }
 }
 
 void view_dispatcher_handle_tick_event(ViewDispatcher* view_dispatcher) {

+ 1 - 0
applications/gui/view_dispatcher.h

@@ -113,6 +113,7 @@ void view_dispatcher_remove_view(ViewDispatcher* view_dispatcher, uint32_t view_
 /** Switch to View
  * @param view_dispatcher ViewDispatcher instance
  * @param view_id View id to register
+ * @warning switching may be delayed till input events complementarity reached
  */
 void view_dispatcher_switch_to_view(ViewDispatcher* view_dispatcher, uint32_t view_id);
 

+ 5 - 0
applications/gui/view_dispatcher_i.h

@@ -14,7 +14,12 @@ struct ViewDispatcher {
     Gui* gui;
     ViewPort* view_port;
     ViewDict_t views;
+
     View* current_view;
+
+    View* delayed_next_view;
+    uint8_t ongoing_input_events_count;
+
     ViewDispatcherCustomEventCallback custom_event_callback;
     ViewDispatcherNavigationEventCallback navigation_event_callback;
     ViewDispatcherTickEventCallback tick_event_callback;

+ 0 - 4
applications/gui/view_i.h

@@ -15,7 +15,6 @@ struct View {
 
     ViewModelType model_type;
     ViewNavigationCallback previous_callback;
-    ViewNavigationCallback next_callback;
     ViewCallback enter_callback;
     ViewCallback exit_callback;
     ViewOrientation orientation;
@@ -42,9 +41,6 @@ bool view_custom(View* view, uint32_t event);
 /* Previous Callback for View dispatcher */
 uint32_t view_previous(View* view);
 
-/* Next Callback for View dispatcher */
-uint32_t view_next(View* view);
-
 /* Enter Callback for View dispatcher */
 void view_enter(View* view);
 

+ 4 - 3
applications/input/input.c

@@ -131,9 +131,6 @@ int32_t input_srv() {
                 // Common state info
                 InputEvent event;
                 event.key = input->pin_states[i].pin->key;
-                event.type = input->pin_states[i].state ? InputTypePress : InputTypeRelease;
-                // Send Press/Release event
-                notify_pubsub(&input->event_pubsub, &event);
 
                 // Short / Long / Repeat timer routine
                 if(state) {
@@ -146,6 +143,10 @@ int32_t input_srv() {
                     }
                     input->pin_states[i].press_counter = 0;
                 }
+
+                // Send Press/Release event
+                event.type = input->pin_states[i].state ? InputTypePress : InputTypeRelease;
+                notify_pubsub(&input->event_pubsub, &event);
             }
         }
 

+ 0 - 19
applications/subghz/scenes/subghz_scene_analyze.c

@@ -1,19 +0,0 @@
-#include "../subghz_i.h"
-
-const void subghz_scene_analyze_on_enter(void* context) {
-    SubGhz* subghz = context;
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewAnalyze);
-}
-
-const bool subghz_scene_analyze_on_event(void* context, SceneManagerEvent event) {
-    SubGhz* subghz = context;
-    if(event.type == SceneManagerEventTypeTick) {
-        notification_message(subghz->notifications, &sequence_blink_blue_10);
-        return true;
-    }
-    return false;
-}
-
-const void subghz_scene_analyze_on_exit(void* context) {
-    // SubGhz* subghz = context;
-}

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

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

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

@@ -25,8 +25,12 @@ const bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent e
     SubGhz* subghz = context;
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == SCENE_SAVE_SUCCESS_CUSTOM_EVENT) {
-            return scene_manager_search_and_switch_to_previous_scene(
-                subghz->scene_manager, SubGhzSceneStart);
+            if(!scene_manager_search_and_switch_to_previous_scene(
+                   subghz->scene_manager, SubGhzSceneReceiver)) {
+                scene_manager_search_and_switch_to_previous_scene(
+                    subghz->scene_manager, SubGhzSceneStart);
+            }
+            return true;
         }
     }
     return false;

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

@@ -1,7 +1,6 @@
 #include "../subghz_i.h"
 
 enum SubmenuIndex {
-    SubmenuIndexAnalyze,
     SubmenuIndexRead,
     SubmenuIndexSaved,
     SubmenuIndexTest,
@@ -18,12 +17,6 @@ const void subghz_scene_start_on_enter(void* context) {
     if(subghz->state_notifications == NOTIFICATION_STARTING_STATE) {
         subghz->state_notifications = NOTIFICATION_IDLE_STATE;
     }
-    submenu_add_item(
-        subghz->submenu,
-        "Analyze",
-        SubmenuIndexAnalyze,
-        subghz_scene_start_submenu_callback,
-        subghz);
     submenu_add_item(
         subghz->submenu, "Read", SubmenuIndexRead, subghz_scene_start_submenu_callback, subghz);
     submenu_add_item(
@@ -47,12 +40,7 @@ const bool subghz_scene_start_on_event(void* context, SceneManagerEvent event) {
     SubGhz* subghz = context;
 
     if(event.type == SceneManagerEventTypeCustom) {
-        if(event.event == SubmenuIndexAnalyze) {
-            scene_manager_set_scene_state(
-                subghz->scene_manager, SubGhzSceneStart, SubmenuIndexAnalyze);
-            scene_manager_next_scene(subghz->scene_manager, SubGhzSceneAnalyze);
-            return true;
-        } else if(event.event == SubmenuIndexRead) {
+        if(event.event == SubmenuIndexRead) {
             scene_manager_set_scene_state(
                 subghz->scene_manager, SubGhzSceneStart, SubmenuIndexRead);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReceiver);

+ 0 - 11
applications/subghz/subghz.c

@@ -70,13 +70,6 @@ SubGhz* subghz_alloc() {
     view_dispatcher_add_view(
         subghz->view_dispatcher, SubGhzViewMenu, submenu_get_view(subghz->submenu));
 
-    // Analyze
-    subghz->subghz_analyze = subghz_analyze_alloc();
-    view_dispatcher_add_view(
-        subghz->view_dispatcher,
-        SubGhzViewAnalyze,
-        subghz_analyze_get_view(subghz->subghz_analyze));
-
     // Receiver
     subghz->subghz_receiver = subghz_receiver_alloc();
     view_dispatcher_add_view(
@@ -159,10 +152,6 @@ void subghz_free(SubGhz* subghz) {
     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewStatic);
     subghz_test_static_free(subghz->subghz_test_static);
 
-    // Analyze
-    view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewAnalyze);
-    subghz_analyze_free(subghz->subghz_analyze);
-
     // Receiver
     view_dispatcher_remove_view(subghz->view_dispatcher, SubGhzViewReceiver);
     subghz_receiver_free(subghz->subghz_receiver);

+ 5 - 2
applications/subghz/subghz_history.c

@@ -6,7 +6,7 @@
 #include <furi.h>
 #include <m-string.h>
 
-#define SUBGHZ_HISTORY_MAX 20
+#define SUBGHZ_HISTORY_MAX 50
 
 typedef struct SubGhzHistoryStruct SubGhzHistoryStruct;
 
@@ -88,7 +88,10 @@ 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) {
+    furi_assert(instance);
+    string_printf(output, "%02u/%02u", instance->last_index_write, SUBGHZ_HISTORY_MAX);
+}
 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(

+ 1 - 0
applications/subghz/subghz_history.h

@@ -18,5 +18,6 @@ uint16_t subghz_history_get_item(SubGhzHistory* instance);
 uint8_t subghz_history_get_type_protocol(SubGhzHistory* instance, uint16_t idx);
 const char* subghz_history_get_name(SubGhzHistory* instance, uint16_t idx);
 void subghz_history_get_text_item_menu(SubGhzHistory* instance, string_t output, uint16_t idx);
+void subghz_history_get_text_space_left(SubGhzHistory* instance, string_t output);
 void subghz_history_add_to_history(SubGhzHistory* instance, void* context);
 SubGhzProtocolCommonLoad* subghz_history_get_raw_data(SubGhzHistory* instance, uint16_t idx);

+ 0 - 3
applications/subghz/subghz_i.h

@@ -1,7 +1,6 @@
 #pragma once
 
 #include "subghz.h"
-#include "views/subghz_analyze.h"
 #include "views/subghz_receiver.h"
 #include "views/subghz_transmitter.h"
 
@@ -59,7 +58,6 @@ struct SubGhz {
     char text_store[SUBGHZ_TEXT_STORE_SIZE + 1];
     uint8_t state_notifications;
 
-    SubghzAnalyze* subghz_analyze;
     SubghzReceiver* subghz_receiver;
     SubghzTransmitter* subghz_transmitter;
 
@@ -71,7 +69,6 @@ struct SubGhz {
 typedef enum {
     SubGhzViewMenu,
 
-    SubGhzViewAnalyze,
     SubGhzViewDialogEx,
     SubGhzViewReceiver,
     SubGhzViewPopup,

+ 0 - 233
applications/subghz/views/subghz_analyze.c

@@ -1,233 +0,0 @@
-#include "subghz_analyze.h"
-#include "../subghz_i.h"
-
-#include <math.h>
-#include <furi.h>
-#include <furi-hal.h>
-#include <input/input.h>
-#include <gui/elements.h>
-#include <notification/notification-messages.h>
-
-#include <lib/subghz/subghz_worker.h>
-#include <lib/subghz/protocols/subghz_protocol.h>
-
-#include <assets_icons.h>
-
-struct SubghzAnalyze {
-    View* view;
-    SubGhzWorker* worker;
-    SubGhzProtocol* protocol;
-};
-
-typedef struct {
-    uint8_t frequency;
-    uint32_t real_frequency;
-    uint32_t counter;
-    string_t text;
-    uint16_t scene;
-    SubGhzProtocolCommon parser;
-} SubghzAnalyzeModel;
-
-static const char subghz_symbols[] = {'-', '\\', '|', '/'};
-
-void subghz_analyze_draw(Canvas* canvas, SubghzAnalyzeModel* model) {
-    char buffer[64];
-
-    canvas_set_color(canvas, ColorBlack);
-    canvas_set_font(canvas, FontPrimary);
-
-    snprintf(
-        buffer,
-        sizeof(buffer),
-        "Analyze: %03ld.%03ldMHz %c",
-        model->real_frequency / 1000000 % 1000,
-        model->real_frequency / 1000 % 1000,
-        subghz_symbols[model->counter % 4]);
-    canvas_draw_str(canvas, 0, 8, buffer);
-
-    switch(model->scene) {
-    case 1:
-        canvas_draw_icon(canvas, 0, 10, &I_RFIDDolphinReceive_97x61);
-        canvas_invert_color(canvas);
-        canvas_draw_box(canvas, 80, 12, 20, 20);
-        canvas_invert_color(canvas);
-        canvas_draw_icon(canvas, 75, 18, &I_sub1_10px);
-        elements_multiline_text_aligned(
-            canvas, 90, 38, AlignCenter, AlignTop, "Detecting\r\nSubGhz");
-        break;
-
-    default:
-        canvas_set_font(canvas, FontSecondary);
-        elements_multiline_text(canvas, 0, 18, string_get_cstr(model->text));
-        break;
-    }
-}
-
-bool subghz_analyze_input(InputEvent* event, void* context) {
-    furi_assert(context);
-    SubghzAnalyze* subghz_analyze = context;
-
-    if(event->type != InputTypeShort) return false;
-
-    if(event->key == InputKeyBack) {
-        return false;
-    }
-
-    with_view_model(
-        subghz_analyze->view, (SubghzAnalyzeModel * model) {
-            bool model_updated = false;
-
-            if(event->key == InputKeyLeft) {
-                if(model->frequency > 0) model->frequency--;
-                model_updated = true;
-            } else if(event->key == InputKeyRight) {
-                if(model->frequency < subghz_frequencies_count - 1) model->frequency++;
-                model_updated = true;
-            }
-
-            if(model_updated) {
-                furi_hal_subghz_idle();
-                model->real_frequency =
-                    furi_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]);
-                furi_hal_subghz_rx();
-            }
-
-            return model_updated;
-        });
-
-    return true;
-}
-
-void subghz_analyze_text_callback(string_t text, void* context) {
-    furi_assert(context);
-    SubghzAnalyze* subghz_analyze = context;
-
-    with_view_model(
-        subghz_analyze->view, (SubghzAnalyzeModel * model) {
-            model->counter++;
-            string_set(model->text, text);
-            model->scene = 0;
-            return true;
-        });
-}
-
-void subghz_analyze_protocol_callback(SubGhzProtocolCommon* parser, void* context) {
-    furi_assert(context);
-    SubghzAnalyze* subghz_analyze = context;
-    char buffer[64];
-    snprintf(
-        buffer,
-        sizeof(buffer),
-        "%s\r\n"
-        "K:%lX%lX\r\n"
-        "SN:%lX\r\n"
-        "BTN:%X",
-        parser->name,
-        (uint32_t)(parser->code_found >> 32),
-        (uint32_t)(parser->code_found & 0x00000000FFFFFFFF),
-        parser->serial,
-        parser->btn);
-
-    with_view_model(
-        subghz_analyze->view, (SubghzAnalyzeModel * model) {
-            model->counter++;
-            model->parser = *parser;
-            string_set(model->text, buffer);
-            model->scene = 0;
-            return true;
-        });
-}
-
-void subghz_analyze_enter(void* context) {
-    furi_assert(context);
-    SubghzAnalyze* subghz_analyze = context;
-
-    furi_hal_subghz_reset();
-    furi_hal_subghz_idle();
-    furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
-
-    with_view_model(
-        subghz_analyze->view, (SubghzAnalyzeModel * model) {
-            model->frequency = subghz_frequencies_433_92;
-            model->real_frequency =
-                furi_hal_subghz_set_frequency_and_path(subghz_frequencies[model->frequency]);
-            model->scene = 1;
-            return true;
-        });
-
-    hal_gpio_init(&gpio_cc1101_g0, GpioModeInput, GpioPullNo, GpioSpeedLow);
-
-    furi_hal_subghz_start_async_rx(subghz_worker_rx_callback, subghz_analyze->worker);
-
-    subghz_worker_start(subghz_analyze->worker);
-
-    furi_hal_subghz_flush_rx();
-    furi_hal_subghz_rx();
-}
-
-void subghz_analyze_exit(void* context) {
-    furi_assert(context);
-    SubghzAnalyze* subghz_analyze = context;
-
-    subghz_worker_stop(subghz_analyze->worker);
-
-    furi_hal_subghz_stop_async_rx();
-    furi_hal_subghz_sleep();
-}
-
-SubghzAnalyze* subghz_analyze_alloc() {
-    SubghzAnalyze* subghz_analyze = furi_alloc(sizeof(SubghzAnalyze));
-
-    // View allocation and configuration
-    subghz_analyze->view = view_alloc();
-    view_allocate_model(subghz_analyze->view, ViewModelTypeLocking, sizeof(SubghzAnalyzeModel));
-    view_set_context(subghz_analyze->view, subghz_analyze);
-    view_set_draw_callback(subghz_analyze->view, (ViewDrawCallback)subghz_analyze_draw);
-    view_set_input_callback(subghz_analyze->view, subghz_analyze_input);
-    view_set_enter_callback(subghz_analyze->view, subghz_analyze_enter);
-    view_set_exit_callback(subghz_analyze->view, subghz_analyze_exit);
-
-    with_view_model(
-        subghz_analyze->view, (SubghzAnalyzeModel * model) {
-            string_init(model->text);
-            return true;
-        });
-
-    subghz_analyze->worker = subghz_worker_alloc();
-    subghz_analyze->protocol = subghz_protocol_alloc();
-
-    subghz_worker_set_overrun_callback(
-        subghz_analyze->worker, (SubGhzWorkerOverrunCallback)subghz_protocol_reset);
-    subghz_worker_set_pair_callback(
-        subghz_analyze->worker, (SubGhzWorkerPairCallback)subghz_protocol_parse);
-    subghz_worker_set_context(subghz_analyze->worker, subghz_analyze->protocol);
-
-    subghz_protocol_load_keeloq_file(
-        subghz_analyze->protocol, "/ext/assets/subghz/keeloq_mfcodes");
-    subghz_protocol_load_nice_flor_s_file(
-        subghz_analyze->protocol, "/ext/assets/subghz/nice_floor_s_rx");
-    subghz_protocol_enable_dump_text(
-        subghz_analyze->protocol, subghz_analyze_text_callback, subghz_analyze);
-
-    return subghz_analyze;
-}
-
-void subghz_analyze_free(SubghzAnalyze* subghz_analyze) {
-    furi_assert(subghz_analyze);
-
-    subghz_protocol_free(subghz_analyze->protocol);
-    subghz_worker_free(subghz_analyze->worker);
-
-    with_view_model(
-        subghz_analyze->view, (SubghzAnalyzeModel * model) {
-            string_clear(model->text);
-            return true;
-        });
-    view_free(subghz_analyze->view);
-    free(subghz_analyze);
-}
-
-View* subghz_analyze_get_view(SubghzAnalyze* subghz_analyze) {
-    furi_assert(subghz_analyze);
-    return subghz_analyze->view;
-}

+ 0 - 11
applications/subghz/views/subghz_analyze.h

@@ -1,11 +0,0 @@
-#pragma once
-
-#include <gui/view.h>
-
-typedef struct SubghzAnalyze SubghzAnalyze;
-
-SubghzAnalyze* subghz_analyze_alloc();
-
-void subghz_analyze_free(SubghzAnalyze* subghz_analyze);
-
-View* subghz_analyze_get_view(SubghzAnalyze* subghz_analyze);

+ 70 - 30
applications/subghz/views/subghz_receiver.c

@@ -14,8 +14,8 @@
 #define MAX_LEN_PX 100
 #define MENU_ITEMS 4
 
-#define COUNT_FREQUNCY_SCANER 3
-const uint32_t subghz_frequencies_scanner[] = {
+#define COUNT_FREQUNCY_HOPPER 3
+const uint32_t subghz_frequencies_hopper[] = {
     /* 300 - 348 */
     315000000,
     /* 387 - 464 */
@@ -35,6 +35,7 @@ typedef enum {
     SubGhzHopperStateOFF,
     SubGhzHopperStatePause,
     SubGhzHopperStateRunnig,
+    SubGhzHopperStateRSSITimeOut,
 } SubGhzHopperState;
 
 static const Icon* ReceiverItemIcons[] = {
@@ -51,6 +52,7 @@ struct SubghzReceiver {
     SubGhzProtocol* protocol;
     osTimerId timer;
     SubGhzHopperState hopper_state;
+    uint8_t hopper_timeout;
 };
 
 typedef struct {
@@ -62,8 +64,6 @@ typedef struct {
     uint8_t temp_frequency;
     uint32_t real_frequency;
 
-    uint8_t tab_idx;
-    uint8_t menu_idx;
     uint16_t idx;
     uint16_t list_offset;
     uint16_t history_item;
@@ -146,6 +146,7 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
     bool scrollbar = model->history_item > 4;
     string_t str_buff;
     char buffer[64];
+    uint32_t frequency;
     string_init(str_buff);
 
     canvas_clear(canvas);
@@ -174,15 +175,25 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
             elements_scrollbar_pos(canvas, 126, 0, 49, model->idx, model->history_item);
         }
         canvas_set_color(canvas, ColorBlack);
-        canvas_set_font(canvas, FontPrimary);
+        canvas_set_font(canvas, FontSecondary);
+
+        elements_button_left(canvas, "Conf");
+        if((model->real_frequency / 1000 % 10) > 4) {
+            frequency = model->real_frequency + 10000;
+        } else {
+            frequency = model->real_frequency;
+        }
         snprintf(
             buffer,
             sizeof(buffer),
-            "%03ld.%03ld  OOK",
-            model->real_frequency / 1000000 % 1000,
-            model->real_frequency / 1000 % 1000);
-        canvas_draw_str(canvas, 60, 61, buffer);
-        elements_button_left(canvas, "Config");
+            "%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:
@@ -194,15 +205,27 @@ void subghz_receiver_draw(Canvas* canvas, SubghzReceiverModel* model) {
         canvas_set_font(canvas, FontPrimary);
         canvas_draw_str(canvas, 63, 40, "Scanning...");
         canvas_set_color(canvas, ColorBlack);
-        canvas_set_font(canvas, FontPrimary);
+        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);
+        if((model->real_frequency / 1000 % 10) > 4) {
+            frequency = model->real_frequency + 10000;
+        } else {
+            frequency = model->real_frequency;
+        }
         snprintf(
             buffer,
             sizeof(buffer),
-            "%03ld.%03ld  OOK",
-            model->real_frequency / 1000000 % 1000,
-            model->real_frequency / 1000 % 1000);
-        canvas_draw_str(canvas, 60, 61, buffer);
-        elements_button_left(canvas, "Config");
+            "%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, 48, 51, 125, 51);
         break;
 
     case ReceiverSceneConfig:
@@ -264,6 +287,14 @@ bool subghz_receiver_input(InputEvent* event, void* context) {
     switch(scene) {
     case ReceiverSceneMain:
         if(event->key == InputKeyBack) {
+            with_view_model(
+                subghz_receiver->view, (SubghzReceiverModel * model) {
+                    model->idx = 0;
+                    model->list_offset = 0;
+                    model->history_item = 0;
+                    subghz_history_clean(model->history);
+                    return true;
+                });
             return false;
         } else if(event->key == InputKeyUp) {
             with_view_model(
@@ -456,32 +487,41 @@ static void subghz_receiver_timer_callback(void* context) {
     SubghzReceiver* subghz_receiver = context;
 
     switch(subghz_receiver->hopper_state) {
-    case SubGhzHopperStateOFF:
+    case SubGhzHopperStatePause:
         return;
         break;
-    case SubGhzHopperStatePause:
-        osTimerStart(subghz_receiver->timer, 1024 / 10);
+    case SubGhzHopperStateOFF:
+        osTimerStop(subghz_receiver->timer);
         return;
         break;
+    case SubGhzHopperStateRSSITimeOut:
+        if(subghz_receiver->hopper_timeout != 0) {
+            subghz_receiver->hopper_timeout--;
+            return;
+        }
+        break;
     default:
         break;
     }
     float rssi = -127.0f;
     with_view_model(
         subghz_receiver->view, (SubghzReceiverModel * model) {
-            // See RSSI Calculation timings in CC1101 17.3 RSSI
-            rssi = furi_hal_subghz_get_rssi();
-
-            // Stay if RSSI is high enough
-            if(rssi > -90.0f) {
-                osTimerStart(subghz_receiver->timer, 1024 / 4);
-                return false;
+            if(subghz_receiver->hopper_state != SubGhzHopperStateRSSITimeOut) {
+                // See RSSI Calculation timings in CC1101 17.3 RSSI
+                rssi = furi_hal_subghz_get_rssi();
+
+                // Stay if RSSI is high enough
+                if(rssi > -90.0f) {
+                    subghz_receiver->hopper_timeout = 10;
+                    subghz_receiver->hopper_state = SubGhzHopperStateRSSITimeOut;
+                    return false;
+                }
             } else {
-                osTimerStart(subghz_receiver->timer, 1024 / 10);
+                subghz_receiver->hopper_state = SubGhzHopperStateRunnig;
             }
 
             // Select next frequency
-            if(model->frequency < COUNT_FREQUNCY_SCANER - 1) {
+            if(model->frequency < COUNT_FREQUNCY_HOPPER - 1) {
                 model->frequency++;
             } else {
                 model->frequency = 0;
@@ -491,7 +531,7 @@ static void subghz_receiver_timer_callback(void* context) {
             subghz_rx_end(subghz_receiver->worker);
             subghz_protocol_reset(subghz_receiver->protocol);
             model->real_frequency =
-                subghz_rx(subghz_receiver->worker, subghz_frequencies_scanner[model->frequency]);
+                subghz_rx(subghz_receiver->worker, subghz_frequencies_hopper[model->frequency]);
 
             return true;
         });
@@ -553,7 +593,7 @@ SubghzReceiver* subghz_receiver_alloc() {
         });
 
     subghz_receiver->timer =
-        osTimerNew(subghz_receiver_timer_callback, osTimerOnce, subghz_receiver, NULL);
+        osTimerNew(subghz_receiver_timer_callback, osTimerPeriodic, subghz_receiver, NULL);
     subghz_receiver->hopper_state = SubGhzHopperStateOFF;
     return subghz_receiver;
 }

+ 1 - 4
applications/subghz/views/subghz_transmitter.c

@@ -8,9 +8,6 @@
 #include <gui/elements.h>
 #include <notification/notification-messages.h>
 
-//#include <assets_icons.h>
-#include <gui/icon_i.h>
-
 struct SubghzTransmitter {
     View* view;
     SubghzTransmitterCallback callback;
@@ -64,7 +61,7 @@ static void subghz_transmitter_button_right(Canvas* canvas, const char* str) {
     const uint8_t string_width = canvas_string_width(canvas, str);
     const Icon* icon = &I_ButtonCenter_7x7;
     const uint8_t icon_offset = 3;
-    const uint8_t icon_width_with_offset = icon->width + icon_offset;
+    const uint8_t icon_width_with_offset = icon_get_width(icon) + icon_offset;
     const uint8_t button_width = string_width + horizontal_offset * 2 + icon_width_with_offset;
 
     const uint8_t x = (canvas_width(canvas) - button_width) / 2 + 40;

+ 7 - 1
firmware/targets/f6/furi-hal/furi-hal-rfid.c

@@ -2,6 +2,8 @@
 #include <furi-hal-ibutton.h>
 #include <furi-hal-resources.h>
 
+#include <stm32wbxx_ll_tim.h>
+
 #define LFRFID_READ_TIM htim1
 #define LFRFID_READ_CHANNEL TIM_CHANNEL_1
 #define LFRFID_EMULATE_TIM htim2
@@ -216,7 +218,11 @@ void furi_hal_rfid_tim_emulate_stop() {
 
 void furi_hal_rfid_tim_reset() {
     HAL_TIM_Base_DeInit(&LFRFID_READ_TIM);
+    LL_TIM_DeInit(TIM1);
+    LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_TIM1);
     HAL_TIM_Base_DeInit(&LFRFID_EMULATE_TIM);
+    LL_TIM_DeInit(TIM2);
+    LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_TIM2);
 }
 
 bool furi_hal_rfid_is_tim_emulate(TIM_HandleTypeDef* hw) {
@@ -275,4 +281,4 @@ void furi_hal_rfid_change_read_config(float freq, float duty_cycle) {
     uint32_t period = (uint32_t)((SystemCoreClock) / freq) - 1;
     furi_hal_rfid_set_read_period(period);
     furi_hal_rfid_set_read_pulse(period * duty_cycle);
-}
+}