Sfoglia il codice sorgente

RPC App: state message and GUI update (#1423)

* RPC App: state message and GUI update
* Protobuf submodule update

Co-authored-by: SG <who.just.the.doctor@gmail.com>
Co-authored-by: あく <alleteam@gmail.com>
Nikolay Minaylov 3 anni fa
parent
commit
d80edba891

+ 13 - 5
applications/ibutton/ibutton.c

@@ -118,6 +118,8 @@ static bool ibutton_rpc_command_callback(RpcAppSystemEvent event, const char* ar
             string_set_str(ibutton->file_path, arg);
             string_set_str(ibutton->file_path, arg);
             if(ibutton_load_key_data(ibutton, ibutton->file_path, false)) {
             if(ibutton_load_key_data(ibutton, ibutton->file_path, false)) {
                 ibutton_worker_emulate_start(ibutton->key_worker, ibutton->key);
                 ibutton_worker_emulate_start(ibutton->key_worker, ibutton->key);
+                view_dispatcher_send_custom_event(
+                    ibutton->view_dispatcher, iButtonCustomEventRpcLoad);
                 result = true;
                 result = true;
             }
             }
         }
         }
@@ -162,8 +164,6 @@ iButton* ibutton_alloc() {
         ibutton->view_dispatcher, ibutton_tick_event_callback, 100);
         ibutton->view_dispatcher, ibutton_tick_event_callback, 100);
 
 
     ibutton->gui = furi_record_open("gui");
     ibutton->gui = furi_record_open("gui");
-    view_dispatcher_attach_to_gui(
-        ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen);
 
 
     ibutton->storage = furi_record_open("storage");
     ibutton->storage = furi_record_open("storage");
     ibutton->dialogs = furi_record_open("dialogs");
     ibutton->dialogs = furi_record_open("dialogs");
@@ -373,6 +373,7 @@ int32_t ibutton_app(void* p) {
             ibutton->rpc_ctx = (void*)rpc_ctx;
             ibutton->rpc_ctx = (void*)rpc_ctx;
             rpc_mode = true;
             rpc_mode = true;
             rpc_system_app_set_callback(ibutton->rpc_ctx, ibutton_rpc_command_callback, ibutton);
             rpc_system_app_set_callback(ibutton->rpc_ctx, ibutton_rpc_command_callback, ibutton);
+            rpc_system_app_send_started(ibutton->rpc_ctx);
         } else {
         } else {
             string_set_str(ibutton->file_path, (const char*)p);
             string_set_str(ibutton->file_path, (const char*)p);
             if(ibutton_load_key_data(ibutton, ibutton->file_path, true)) {
             if(ibutton_load_key_data(ibutton, ibutton->file_path, true)) {
@@ -383,17 +384,24 @@ int32_t ibutton_app(void* p) {
     }
     }
 
 
     if(rpc_mode) {
     if(rpc_mode) {
+        view_dispatcher_attach_to_gui(
+            ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeDesktop);
         scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRpc);
         scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRpc);
-    } else if(key_loaded) {
-        scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate);
     } else {
     } else {
-        scene_manager_next_scene(ibutton->scene_manager, iButtonSceneStart);
+        view_dispatcher_attach_to_gui(
+            ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen);
+        if(key_loaded) {
+            scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate);
+        } else {
+            scene_manager_next_scene(ibutton->scene_manager, iButtonSceneStart);
+        }
     }
     }
 
 
     view_dispatcher_run(ibutton->view_dispatcher);
     view_dispatcher_run(ibutton->view_dispatcher);
 
 
     if(ibutton->rpc_ctx) {
     if(ibutton->rpc_ctx) {
         rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL);
         rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL);
+        rpc_system_app_send_exited(ibutton->rpc_ctx);
     }
     }
     ibutton_free(ibutton);
     ibutton_free(ibutton);
     return 0;
     return 0;

+ 1 - 0
applications/ibutton/ibutton_custom_event.h

@@ -10,5 +10,6 @@ enum iButtonCustomEvent {
     iButtonCustomEventWorkerEmulated,
     iButtonCustomEventWorkerEmulated,
     iButtonCustomEventWorkerRead,
     iButtonCustomEventWorkerRead,
 
 
+    iButtonCustomEventRpcLoad,
     iButtonCustomEventRpcExit,
     iButtonCustomEventRpcExit,
 };
 };

+ 33 - 6
applications/ibutton/scenes/ibutton_scene_rpc.c

@@ -3,12 +3,14 @@
 
 
 void ibutton_scene_rpc_on_enter(void* context) {
 void ibutton_scene_rpc_on_enter(void* context) {
     iButton* ibutton = context;
     iButton* ibutton = context;
-    Widget* widget = ibutton->widget;
+    Popup* popup = ibutton->popup;
 
 
-    widget_add_text_box_element(
-        widget, 0, 0, 128, 28, AlignCenter, AlignCenter, "RPC mode", false);
+    popup_set_header(popup, "iButton", 82, 28, AlignCenter, AlignBottom);
+    popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop);
 
 
-    view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
+    popup_set_icon(popup, 2, 14, &I_iButtonKey_49x44);
+
+    view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
 
 
     notification_message(ibutton->notifications, &sequence_display_backlight_on);
     notification_message(ibutton->notifications, &sequence_display_backlight_on);
 }
 }
@@ -17,12 +19,31 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
     UNUSED(context);
     UNUSED(context);
     UNUSED(event);
     UNUSED(event);
     iButton* ibutton = context;
     iButton* ibutton = context;
+    Popup* popup = ibutton->popup;
 
 
     bool consumed = false;
     bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         consumed = true;
         consumed = true;
-        if(event.event == iButtonCustomEventRpcExit) {
+        if(event.event == iButtonCustomEventRpcLoad) {
+            string_t key_name;
+            string_init(key_name);
+            if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) {
+                path_extract_filename(ibutton->file_path, key_name, true);
+            }
+
+            if(!string_empty_p(key_name)) {
+                ibutton_text_store_set(ibutton, "emulating\n%s", string_get_cstr(key_name));
+            } else {
+                ibutton_text_store_set(ibutton, "emulating");
+            }
+            popup_set_text(popup, ibutton->text_store, 82, 32, AlignCenter, AlignTop);
+
+            ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
+
+            string_clear(key_name);
+        } else if(event.event == iButtonCustomEventRpcExit) {
+            ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop);
             view_dispatcher_stop(ibutton->view_dispatcher);
             view_dispatcher_stop(ibutton->view_dispatcher);
         }
         }
     }
     }
@@ -32,5 +53,11 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
 
 
 void ibutton_scene_rpc_on_exit(void* context) {
 void ibutton_scene_rpc_on_exit(void* context) {
     iButton* ibutton = context;
     iButton* ibutton = context;
-    widget_reset(ibutton->widget);
+    Popup* popup = ibutton->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);
+
+    ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop);
 }
 }

+ 13 - 4
applications/infrared/infrared.c

@@ -65,6 +65,8 @@ static bool
                 infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared);
                 infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared);
             infrared_worker_tx_set_signal_sent_callback(
             infrared_worker_tx_set_signal_sent_callback(
                 infrared->worker, infrared_signal_sent_callback, infrared);
                 infrared->worker, infrared_signal_sent_callback, infrared);
+            view_dispatcher_send_custom_event(
+                infrared->view_dispatcher, InfraredCustomEventTypeRpcLoaded);
         }
         }
     } else if(event == RpcAppEventButtonPress) {
     } else if(event == RpcAppEventButtonPress) {
         if(arg) {
         if(arg) {
@@ -141,7 +143,6 @@ static Infrared* infrared_alloc() {
     infrared->gui = furi_record_open("gui");
     infrared->gui = furi_record_open("gui");
 
 
     ViewDispatcher* view_dispatcher = infrared->view_dispatcher;
     ViewDispatcher* view_dispatcher = infrared->view_dispatcher;
-    view_dispatcher_attach_to_gui(view_dispatcher, infrared->gui, ViewDispatcherTypeFullscreen);
     view_dispatcher_enable_queue(view_dispatcher);
     view_dispatcher_enable_queue(view_dispatcher);
     view_dispatcher_set_event_callback_context(view_dispatcher, infrared);
     view_dispatcher_set_event_callback_context(view_dispatcher, infrared);
     view_dispatcher_set_custom_event_callback(view_dispatcher, infrared_custom_event_callback);
     view_dispatcher_set_custom_event_callback(view_dispatcher, infrared_custom_event_callback);
@@ -202,6 +203,7 @@ static void infrared_free(Infrared* infrared) {
 
 
     if(infrared->rpc_ctx) {
     if(infrared->rpc_ctx) {
         rpc_system_app_set_callback(infrared->rpc_ctx, NULL, NULL);
         rpc_system_app_set_callback(infrared->rpc_ctx, NULL, NULL);
+        rpc_system_app_send_exited(infrared->rpc_ctx);
         infrared->rpc_ctx = NULL;
         infrared->rpc_ctx = NULL;
     }
     }
 
 
@@ -434,6 +436,7 @@ int32_t infrared_app(void* p) {
             infrared->rpc_ctx = (void*)rpc_ctx;
             infrared->rpc_ctx = (void*)rpc_ctx;
             rpc_system_app_set_callback(
             rpc_system_app_set_callback(
                 infrared->rpc_ctx, infrared_rpc_command_callback, infrared);
                 infrared->rpc_ctx, infrared_rpc_command_callback, infrared);
+            rpc_system_app_send_started(infrared->rpc_ctx);
             is_rpc_mode = true;
             is_rpc_mode = true;
         } else {
         } else {
             string_set_str(infrared->file_path, (const char*)p);
             string_set_str(infrared->file_path, (const char*)p);
@@ -447,11 +450,17 @@ int32_t infrared_app(void* p) {
     }
     }
 
 
     if(is_rpc_mode) {
     if(is_rpc_mode) {
+        view_dispatcher_attach_to_gui(
+            infrared->view_dispatcher, infrared->gui, ViewDispatcherTypeDesktop);
         scene_manager_next_scene(infrared->scene_manager, InfraredSceneRpc);
         scene_manager_next_scene(infrared->scene_manager, InfraredSceneRpc);
-    } else if(is_remote_loaded) {
-        scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote);
     } else {
     } else {
-        scene_manager_next_scene(infrared->scene_manager, InfraredSceneStart);
+        view_dispatcher_attach_to_gui(
+            infrared->view_dispatcher, infrared->gui, ViewDispatcherTypeFullscreen);
+        if(is_remote_loaded) {
+            scene_manager_next_scene(infrared->scene_manager, InfraredSceneRemote);
+        } else {
+            scene_manager_next_scene(infrared->scene_manager, InfraredSceneStart);
+        }
     }
     }
 
 
     view_dispatcher_run(infrared->view_dispatcher);
     view_dispatcher_run(infrared->view_dispatcher);

+ 1 - 0
applications/infrared/infrared_custom_event.h

@@ -14,6 +14,7 @@ enum InfraredCustomEventType {
     InfraredCustomEventTypePopupClosed,
     InfraredCustomEventTypePopupClosed,
     InfraredCustomEventTypeButtonSelected,
     InfraredCustomEventTypeButtonSelected,
     InfraredCustomEventTypeBackPressed,
     InfraredCustomEventTypeBackPressed,
+    InfraredCustomEventTypeRpcLoaded,
 };
 };
 
 
 #pragma pack(push, 1)
 #pragma pack(push, 1)

+ 10 - 2
applications/infrared/scenes/infrared_scene_rpc.c

@@ -5,12 +5,14 @@ void infrared_scene_rpc_on_enter(void* context) {
     Infrared* infrared = context;
     Infrared* infrared = context;
     Popup* popup = infrared->popup;
     Popup* popup = infrared->popup;
 
 
-    popup_set_text(popup, "Rpc mode", 64, 28, AlignCenter, AlignCenter);
+    popup_set_header(popup, "Infrared", 82, 28, AlignCenter, AlignBottom);
+    popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop);
+
+    popup_set_icon(popup, 2, 14, &I_Warning_30x23); // TODO: icon
 
 
     popup_set_context(popup, context);
     popup_set_context(popup, context);
     popup_set_callback(popup, infrared_popup_closed_callback);
     popup_set_callback(popup, infrared_popup_closed_callback);
 
 
-    infrared_play_notification_message(infrared, InfraredNotificationMessageYellowOn);
     view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup);
     view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewPopup);
 
 
     notification_message(infrared->notifications, &sequence_display_backlight_on);
     notification_message(infrared->notifications, &sequence_display_backlight_on);
@@ -26,6 +28,12 @@ bool infrared_scene_rpc_on_event(void* context, SceneManagerEvent event) {
             view_dispatcher_stop(infrared->view_dispatcher);
             view_dispatcher_stop(infrared->view_dispatcher);
         } else if(event.event == InfraredCustomEventTypePopupClosed) {
         } else if(event.event == InfraredCustomEventTypePopupClosed) {
             view_dispatcher_stop(infrared->view_dispatcher);
             view_dispatcher_stop(infrared->view_dispatcher);
+        } else if(event.event == InfraredCustomEventTypeRpcLoaded) {
+            const char* remote_name = infrared_remote_get_name(infrared->remote);
+
+            infrared_text_store_set(infrared, 0, "loaded\n%s", remote_name);
+            popup_set_text(
+                infrared->popup, infrared->text_store[0], 82, 32, AlignCenter, AlignTop);
         }
         }
     }
     }
     return consumed;
     return consumed;

+ 2 - 0
applications/lfrfid/lfrfid_app.cpp

@@ -44,6 +44,7 @@ LfRfidApp::~LfRfidApp() {
     string_clear(file_path);
     string_clear(file_path);
     if(rpc_ctx) {
     if(rpc_ctx) {
         rpc_system_app_set_callback(rpc_ctx, NULL, NULL);
         rpc_system_app_set_callback(rpc_ctx, NULL, NULL);
+        rpc_system_app_send_exited(rpc_ctx);
     }
     }
 }
 }
 
 
@@ -91,6 +92,7 @@ void LfRfidApp::run(void* _args) {
         if(sscanf(args, "RPC %lX", &rpc_ctx_ptr) == 1) {
         if(sscanf(args, "RPC %lX", &rpc_ctx_ptr) == 1) {
             rpc_ctx = (RpcAppSystem*)rpc_ctx_ptr;
             rpc_ctx = (RpcAppSystem*)rpc_ctx_ptr;
             rpc_system_app_set_callback(rpc_ctx, rpc_command_callback, this);
             rpc_system_app_set_callback(rpc_ctx, rpc_command_callback, this);
+            rpc_system_app_send_started(rpc_ctx);
             scene_controller.add_scene(SceneType::Rpc, new LfRfidAppSceneRpc());
             scene_controller.add_scene(SceneType::Rpc, new LfRfidAppSceneRpc());
             scene_controller.process(100, SceneType::Rpc);
             scene_controller.process(100, SceneType::Rpc);
         } else {
         } else {

+ 22 - 1
applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp

@@ -2,10 +2,24 @@
 #include <core/common_defines.h>
 #include <core/common_defines.h>
 #include <dolphin/dolphin.h>
 #include <dolphin/dolphin.h>
 
 
+static const NotificationSequence sequence_blink_start_magenta = {
+    &message_blink_start_10,
+    &message_blink_set_color_magenta,
+    &message_do_not_reset,
+    NULL,
+};
+
+static const NotificationSequence sequence_blink_stop = {
+    &message_blink_stop,
+    NULL,
+};
+
 void LfRfidAppSceneRpc::on_enter(LfRfidApp* app, bool /* need_restore */) {
 void LfRfidAppSceneRpc::on_enter(LfRfidApp* app, bool /* need_restore */) {
     auto popup = app->view_controller.get<PopupVM>();
     auto popup = app->view_controller.get<PopupVM>();
 
 
-    popup->set_header("RPC Mode", 64, 30, AlignCenter, AlignTop);
+    popup->set_header("LF RFID", 89, 30, AlignCenter, AlignTop);
+    popup->set_text("RPC mode", 89, 43, AlignCenter, AlignTop);
+    popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61);
 
 
     app->view_controller.switch_to<PopupVM>();
     app->view_controller.switch_to<PopupVM>();
 
 
@@ -23,8 +37,14 @@ bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
         view_event.type = LfRfidApp::EventType::Back;
         view_event.type = LfRfidApp::EventType::Back;
         app->view_controller.send_event(&view_event);
         app->view_controller.send_event(&view_event);
     } else if(event->type == LfRfidApp::EventType::EmulateStart) {
     } else if(event->type == LfRfidApp::EventType::EmulateStart) {
+        auto popup = app->view_controller.get<PopupVM>();
         consumed = true;
         consumed = true;
         emulating = true;
         emulating = true;
+
+        app->text_store.set("emulating\n%s", app->worker.key.get_name());
+        popup->set_text(app->text_store.text, 89, 43, AlignCenter, AlignTop);
+
+        notification_message(app->notification, &sequence_blink_start_magenta);
     }
     }
     return consumed;
     return consumed;
 }
 }
@@ -32,6 +52,7 @@ bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
 void LfRfidAppSceneRpc::on_exit(LfRfidApp* app) {
 void LfRfidAppSceneRpc::on_exit(LfRfidApp* app) {
     if(emulating) {
     if(emulating) {
         app->worker.stop_emulate();
         app->worker.stop_emulate();
+        notification_message(app->notification, &sequence_blink_stop);
     }
     }
     app->view_controller.get<PopupVM>()->clean();
     app->view_controller.get<PopupVM>()->clean();
 }
 }

+ 1 - 0
applications/nfc/helpers/nfc_custom_event.h

@@ -9,4 +9,5 @@ enum NfcCustomEvent {
     NfcCustomEventByteInputDone,
     NfcCustomEventByteInputDone,
     NfcCustomEventTextInputDone,
     NfcCustomEventTextInputDone,
     NfcCustomEventDictAttackDone,
     NfcCustomEventDictAttackDone,
+    NfcCustomEventRpcLoad,
 };
 };

+ 20 - 10
applications/nfc/nfc.c

@@ -31,6 +31,7 @@ void nfc_rpc_exit_callback(Nfc* nfc) {
     }
     }
     if(nfc->rpc_ctx) {
     if(nfc->rpc_ctx) {
         rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL);
         rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL);
+        rpc_system_app_send_exited(nfc->rpc_ctx);
         nfc->rpc_ctx = NULL;
         nfc->rpc_ctx = NULL;
     }
     }
 }
 }
@@ -82,6 +83,7 @@ static bool nfc_rpc_command_callback(RpcAppSystemEvent event, const char* arg, v
                         nfc->worker, NfcWorkerStateEmulate, &nfc->dev->dev_data, NULL, nfc);
                         nfc->worker, NfcWorkerStateEmulate, &nfc->dev->dev_data, NULL, nfc);
                 }
                 }
                 nfc->rpc_state = NfcRpcStateEmulating;
                 nfc->rpc_state = NfcRpcStateEmulating;
+                view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcLoad);
                 result = true;
                 result = true;
             }
             }
         }
         }
@@ -107,7 +109,6 @@ Nfc* nfc_alloc() {
 
 
     // Open GUI record
     // Open GUI record
     nfc->gui = furi_record_open("gui");
     nfc->gui = furi_record_open("gui");
-    view_dispatcher_attach_to_gui(nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen);
 
 
     // Open Notification record
     // Open Notification record
     nfc->notifications = furi_record_open("notification");
     nfc->notifications = furi_record_open("notification");
@@ -291,21 +292,30 @@ int32_t nfc_app(void* p) {
         if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) {
         if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) {
             nfc->rpc_ctx = (void*)rpc_ctx;
             nfc->rpc_ctx = (void*)rpc_ctx;
             rpc_system_app_set_callback(nfc->rpc_ctx, nfc_rpc_command_callback, nfc);
             rpc_system_app_set_callback(nfc->rpc_ctx, nfc_rpc_command_callback, nfc);
+            rpc_system_app_send_started(nfc->rpc_ctx);
+            view_dispatcher_attach_to_gui(
+                nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeDesktop);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneRpc);
             scene_manager_next_scene(nfc->scene_manager, NfcSceneRpc);
-        } else if(nfc_device_load(nfc->dev, p, true)) {
-            if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
-                scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
-            } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
-                scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareClassic);
+        } else {
+            view_dispatcher_attach_to_gui(
+                nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen);
+            if(nfc_device_load(nfc->dev, p, true)) {
+                if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
+                    scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
+                } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) {
+                    scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareClassic);
+                } else {
+                    scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
+                }
             } else {
             } else {
-                scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
+                // Exit app
+                view_dispatcher_stop(nfc->view_dispatcher);
             }
             }
-        } else {
-            // Exit app
-            view_dispatcher_stop(nfc->view_dispatcher);
         }
         }
         nfc_device_set_loading_callback(nfc->dev, NULL, nfc);
         nfc_device_set_loading_callback(nfc->dev, NULL, nfc);
     } else {
     } else {
+        view_dispatcher_attach_to_gui(
+            nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen);
         scene_manager_next_scene(nfc->scene_manager, NfcSceneStart);
         scene_manager_next_scene(nfc->scene_manager, NfcSceneStart);
     }
     }
 
 

+ 19 - 6
applications/nfc/scenes/nfc_scene_rpc.c

@@ -2,24 +2,33 @@
 
 
 void nfc_scene_rpc_on_enter(void* context) {
 void nfc_scene_rpc_on_enter(void* context) {
     Nfc* nfc = context;
     Nfc* nfc = context;
-    Widget* widget = nfc->widget;
+    Popup* popup = nfc->popup;
 
 
-    widget_add_text_box_element(
-        widget, 0, 0, 128, 28, AlignCenter, AlignCenter, "RPC mode", false);
+    popup_set_header(popup, "NFC", 82, 28, AlignCenter, AlignBottom);
+    popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop);
 
 
-    notification_message(nfc->notifications, &sequence_display_backlight_on);
+    popup_set_icon(popup, 2, 14, &I_Warning_30x23); // TODO: icon
+
+    view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
 
 
-    view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
+    notification_message(nfc->notifications, &sequence_display_backlight_on);
 }
 }
 
 
 bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) {
 bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) {
     Nfc* nfc = context;
     Nfc* nfc = context;
+    Popup* popup = nfc->popup;
     bool consumed = false;
     bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         consumed = true;
         consumed = true;
         if(event.event == NfcCustomEventViewExit) {
         if(event.event == NfcCustomEventViewExit) {
             view_dispatcher_stop(nfc->view_dispatcher);
             view_dispatcher_stop(nfc->view_dispatcher);
+            nfc_blink_stop(nfc);
+        } else if(event.event == NfcCustomEventRpcLoad) {
+            nfc_blink_start(nfc);
+
+            nfc_text_store_set(nfc, "emulating\n%s", nfc->dev->dev_name);
+            popup_set_text(popup, nfc->text_store, 82, 32, AlignCenter, AlignTop);
         }
         }
     }
     }
     return consumed;
     return consumed;
@@ -27,8 +36,12 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) {
 
 
 void nfc_scene_rpc_on_exit(void* context) {
 void nfc_scene_rpc_on_exit(void* context) {
     Nfc* nfc = context;
     Nfc* nfc = context;
+    Popup* popup = nfc->popup;
 
 
     nfc_rpc_exit_callback(nfc);
     nfc_rpc_exit_callback(nfc);
+    nfc_blink_stop(nfc);
 
 
-    widget_reset(nfc->widget);
+    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);
 }
 }

+ 27 - 2
applications/rpc/rpc_app.c

@@ -12,6 +12,7 @@ struct RpcAppSystem {
     RpcSession* session;
     RpcSession* session;
     RpcAppSystemCallback app_callback;
     RpcAppSystemCallback app_callback;
     void* app_context;
     void* app_context;
+    PB_Main* state_msg;
     FuriTimer* timer;
     FuriTimer* timer;
 };
 };
 
 
@@ -96,7 +97,7 @@ static void rpc_system_app_lock_status_process(const PB_Main* request, void* con
     pb_release(&PB_Main_msg, &response);
     pb_release(&PB_Main_msg, &response);
 }
 }
 
 
-static void rpc_system_app_exit(const PB_Main* request, void* context) {
+static void rpc_system_app_exit_request(const PB_Main* request, void* context) {
     furi_assert(request);
     furi_assert(request);
     furi_assert(context);
     furi_assert(context);
 
 
@@ -194,6 +195,24 @@ static void rpc_system_app_button_release(const PB_Main* request, void* context)
     rpc_send_and_release_empty(session, request->command_id, status);
     rpc_send_and_release_empty(session, request->command_id, status);
 }
 }
 
 
+void rpc_system_app_send_started(RpcAppSystem* rpc_app) {
+    furi_assert(rpc_app);
+    RpcSession* session = rpc_app->session;
+    furi_assert(session);
+
+    rpc_app->state_msg->content.app_state_response.state = PB_App_AppState_APP_STARTED;
+    rpc_send(session, rpc_app->state_msg);
+}
+
+void rpc_system_app_send_exited(RpcAppSystem* rpc_app) {
+    furi_assert(rpc_app);
+    RpcSession* session = rpc_app->session;
+    furi_assert(session);
+
+    rpc_app->state_msg->content.app_state_response.state = PB_App_AppState_APP_CLOSED;
+    rpc_send(session, rpc_app->state_msg);
+}
+
 void rpc_system_app_set_callback(RpcAppSystem* rpc_app, RpcAppSystemCallback callback, void* ctx) {
 void rpc_system_app_set_callback(RpcAppSystem* rpc_app, RpcAppSystemCallback callback, void* ctx) {
     furi_assert(rpc_app);
     furi_assert(rpc_app);
 
 
@@ -209,6 +228,11 @@ void* rpc_system_app_alloc(RpcSession* session) {
 
 
     rpc_app->timer = furi_timer_alloc(rpc_system_app_timer_callback, FuriTimerTypeOnce, rpc_app);
     rpc_app->timer = furi_timer_alloc(rpc_system_app_timer_callback, FuriTimerTypeOnce, rpc_app);
 
 
+    // App exit message
+    rpc_app->state_msg = malloc(sizeof(PB_Main));
+    rpc_app->state_msg->which_content = PB_Main_app_state_response_tag;
+    rpc_app->state_msg->command_status = PB_CommandStatus_OK;
+
     RpcHandler rpc_handler = {
     RpcHandler rpc_handler = {
         .message_handler = NULL,
         .message_handler = NULL,
         .decode_submessage = NULL,
         .decode_submessage = NULL,
@@ -221,7 +245,7 @@ void* rpc_system_app_alloc(RpcSession* session) {
     rpc_handler.message_handler = rpc_system_app_lock_status_process;
     rpc_handler.message_handler = rpc_system_app_lock_status_process;
     rpc_add_handler(session, PB_Main_app_lock_status_request_tag, &rpc_handler);
     rpc_add_handler(session, PB_Main_app_lock_status_request_tag, &rpc_handler);
 
 
-    rpc_handler.message_handler = rpc_system_app_exit;
+    rpc_handler.message_handler = rpc_system_app_exit_request;
     rpc_add_handler(session, PB_Main_app_exit_request_tag, &rpc_handler);
     rpc_add_handler(session, PB_Main_app_exit_request_tag, &rpc_handler);
 
 
     rpc_handler.message_handler = rpc_system_app_load_file;
     rpc_handler.message_handler = rpc_system_app_load_file;
@@ -247,5 +271,6 @@ void rpc_system_app_free(void* context) {
         rpc_app->app_callback(RpcAppEventSessionClose, NULL, rpc_app->app_context);
         rpc_app->app_callback(RpcAppEventSessionClose, NULL, rpc_app->app_context);
     }
     }
 
 
+    free(rpc_app->state_msg);
     free(rpc_app);
     free(rpc_app);
 }
 }

+ 4 - 0
applications/rpc/rpc_app.h

@@ -19,6 +19,10 @@ typedef struct RpcAppSystem RpcAppSystem;
 
 
 void rpc_system_app_set_callback(RpcAppSystem* rpc_app, RpcAppSystemCallback callback, void* ctx);
 void rpc_system_app_set_callback(RpcAppSystem* rpc_app, RpcAppSystemCallback callback, void* ctx);
 
 
+void rpc_system_app_send_started(RpcAppSystem* rpc_app);
+
+void rpc_system_app_send_exited(RpcAppSystem* rpc_app);
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }
 #endif
 #endif

+ 2 - 0
applications/subghz/helpers/subghz_custom_event.h

@@ -46,6 +46,8 @@ typedef enum {
     SubGhzCustomEventSceneExit,
     SubGhzCustomEventSceneExit,
     SubGhzCustomEventSceneStay,
     SubGhzCustomEventSceneStay,
 
 
+    SubGhzCustomEventSceneRpcLoad,
+
     SubGhzCustomEventViewReceiverOK,
     SubGhzCustomEventViewReceiverOK,
     SubGhzCustomEventViewReceiverConfig,
     SubGhzCustomEventViewReceiverConfig,
     SubGhzCustomEventViewReceiverBack,
     SubGhzCustomEventViewReceiverBack,

+ 25 - 8
applications/subghz/scenes/subghz_scene_rpc.c

@@ -2,24 +2,40 @@
 
 
 void subghz_scene_rpc_on_enter(void* context) {
 void subghz_scene_rpc_on_enter(void* context) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
-    Widget* widget = subghz->widget;
+    Popup* popup = subghz->popup;
 
 
-    widget_add_text_box_element(
-        widget, 0, 0, 128, 28, AlignCenter, AlignCenter, "RPC mode", false);
+    popup_set_header(popup, "Sub-GHz", 82, 28, AlignCenter, AlignBottom);
+    popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop);
 
 
-    notification_message(subghz->notifications, &sequence_display_backlight_on);
+    popup_set_icon(popup, 2, 14, &I_Warning_30x23); // TODO: icon
+
+    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdPopup);
 
 
-    view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdWidget);
+    notification_message(subghz->notifications, &sequence_display_backlight_on);
 }
 }
 
 
 bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
 bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
+    Popup* popup = subghz->popup;
     bool consumed = false;
     bool consumed = false;
 
 
     if(event.type == SceneManagerEventTypeCustom) {
     if(event.type == SceneManagerEventTypeCustom) {
         consumed = true;
         consumed = true;
         if(event.event == SubGhzCustomEventSceneExit) {
         if(event.event == SubGhzCustomEventSceneExit) {
             view_dispatcher_stop(subghz->view_dispatcher);
             view_dispatcher_stop(subghz->view_dispatcher);
+        } else if(event.event == SubGhzCustomEventSceneRpcLoad) {
+            string_t file_name;
+            string_init(file_name);
+            path_extract_filename(subghz->file_path, file_name, true);
+
+            snprintf(
+                subghz->file_name_tmp,
+                SUBGHZ_MAX_LEN_NAME,
+                "loaded\n%s",
+                string_get_cstr(file_name));
+            popup_set_text(popup, subghz->file_name_tmp, 82, 32, AlignCenter, AlignTop);
+
+            string_clear(file_name);
         }
         }
     }
     }
     return consumed;
     return consumed;
@@ -27,8 +43,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
 
 
 void subghz_scene_rpc_on_exit(void* context) {
 void subghz_scene_rpc_on_exit(void* context) {
     SubGhz* subghz = context;
     SubGhz* subghz = context;
+    Popup* popup = subghz->popup;
 
 
-    //subghz_rpc_exit_callback(subghz);
-
-    widget_reset(subghz->widget);
+    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);
 }
 }

+ 41 - 15
applications/subghz/subghz.c

@@ -5,6 +5,18 @@
 #include "subghz_i.h"
 #include "subghz_i.h"
 #include <lib/toolbox/path.h>
 #include <lib/toolbox/path.h>
 
 
+static const NotificationSequence sequence_blink_start_magenta = {
+    &message_blink_start_10,
+    &message_blink_set_color_magenta,
+    &message_do_not_reset,
+    NULL,
+};
+
+static const NotificationSequence sequence_blink_stop = {
+    &message_blink_stop,
+    NULL,
+};
+
 bool subghz_custom_event_callback(void* context, uint32_t event) {
 bool subghz_custom_event_callback(void* context, uint32_t event) {
     furi_assert(context);
     furi_assert(context);
     SubGhz* subghz = context;
     SubGhz* subghz = context;
@@ -36,6 +48,7 @@ static bool subghz_rpc_command_callback(RpcAppSystemEvent event, const char* arg
     if(event == RpcAppEventSessionClose) {
     if(event == RpcAppEventSessionClose) {
         rpc_system_app_set_callback(subghz->rpc_ctx, NULL, NULL);
         rpc_system_app_set_callback(subghz->rpc_ctx, NULL, NULL);
         subghz->rpc_ctx = NULL;
         subghz->rpc_ctx = NULL;
+        notification_message(subghz->notifications, &sequence_blink_stop);
         view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneExit);
         view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneExit);
         if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
         if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
             subghz_tx_stop(subghz);
             subghz_tx_stop(subghz);
@@ -53,15 +66,19 @@ static bool subghz_rpc_command_callback(RpcAppSystemEvent event, const char* arg
         if(arg) {
         if(arg) {
             if(subghz_key_load(subghz, arg, false)) {
             if(subghz_key_load(subghz, arg, false)) {
                 string_set_str(subghz->file_path, arg);
                 string_set_str(subghz->file_path, arg);
+                view_dispatcher_send_custom_event(
+                    subghz->view_dispatcher, SubGhzCustomEventSceneRpcLoad);
                 result = true;
                 result = true;
             }
             }
         }
         }
     } else if(event == RpcAppEventButtonPress) {
     } else if(event == RpcAppEventButtonPress) {
         if(subghz->txrx->txrx_state == SubGhzTxRxStateSleep) {
         if(subghz->txrx->txrx_state == SubGhzTxRxStateSleep) {
+            notification_message(subghz->notifications, &sequence_blink_start_magenta);
             result = subghz_tx_start(subghz, subghz->txrx->fff_data);
             result = subghz_tx_start(subghz, subghz->txrx->fff_data);
         }
         }
     } else if(event == RpcAppEventButtonRelease) {
     } else if(event == RpcAppEventButtonRelease) {
         if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
         if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) {
+            notification_message(subghz->notifications, &sequence_blink_stop);
             subghz_tx_stop(subghz);
             subghz_tx_stop(subghz);
             subghz_sleep(subghz);
             subghz_sleep(subghz);
             result = true;
             result = true;
@@ -83,8 +100,6 @@ SubGhz* subghz_alloc() {
     // View Dispatcher
     // View Dispatcher
     subghz->view_dispatcher = view_dispatcher_alloc();
     subghz->view_dispatcher = view_dispatcher_alloc();
     view_dispatcher_enable_queue(subghz->view_dispatcher);
     view_dispatcher_enable_queue(subghz->view_dispatcher);
-    view_dispatcher_attach_to_gui(
-        subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen);
 
 
     subghz->scene_manager = scene_manager_alloc(&subghz_scene_handlers, subghz);
     subghz->scene_manager = scene_manager_alloc(&subghz_scene_handlers, subghz);
     view_dispatcher_set_event_callback_context(subghz->view_dispatcher, subghz);
     view_dispatcher_set_event_callback_context(subghz->view_dispatcher, subghz);
@@ -218,6 +233,8 @@ void subghz_free(SubGhz* subghz) {
 
 
     if(subghz->rpc_ctx) {
     if(subghz->rpc_ctx) {
         rpc_system_app_set_callback(subghz->rpc_ctx, NULL, NULL);
         rpc_system_app_set_callback(subghz->rpc_ctx, NULL, NULL);
+        rpc_system_app_send_exited(subghz->rpc_ctx);
+        notification_message(subghz->notifications, &sequence_blink_stop);
         subghz->rpc_ctx = NULL;
         subghz->rpc_ctx = NULL;
     }
     }
 
 
@@ -322,24 +339,33 @@ int32_t subghz_app(void* p) {
         if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) {
         if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) {
             subghz->rpc_ctx = (void*)rpc_ctx;
             subghz->rpc_ctx = (void*)rpc_ctx;
             rpc_system_app_set_callback(subghz->rpc_ctx, subghz_rpc_command_callback, subghz);
             rpc_system_app_set_callback(subghz->rpc_ctx, subghz_rpc_command_callback, subghz);
+            rpc_system_app_send_started(subghz->rpc_ctx);
+            view_dispatcher_attach_to_gui(
+                subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeDesktop);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneRpc);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneRpc);
-        } else if(subghz_key_load(subghz, p, true)) {
-            string_set_str(subghz->file_path, p);
-
-            if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) {
-                //Load Raw TX
-                subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
-                scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
+        } else {
+            view_dispatcher_attach_to_gui(
+                subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen);
+            if(subghz_key_load(subghz, p, true)) {
+                string_set_str(subghz->file_path, p);
+
+                if((!strcmp(subghz->txrx->decoder_result->protocol->name, "RAW"))) {
+                    //Load Raw TX
+                    subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
+                    scene_manager_next_scene(subghz->scene_manager, SubGhzSceneReadRAW);
+                } else {
+                    //Load transmitter TX
+                    scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter);
+                }
             } else {
             } else {
-                //Load transmitter TX
-                scene_manager_next_scene(subghz->scene_manager, SubGhzSceneTransmitter);
+                //exit app
+                scene_manager_stop(subghz->scene_manager);
+                view_dispatcher_stop(subghz->view_dispatcher);
             }
             }
-        } else {
-            //exit app
-            scene_manager_stop(subghz->scene_manager);
-            view_dispatcher_stop(subghz->view_dispatcher);
         }
         }
     } else {
     } else {
+        view_dispatcher_attach_to_gui(
+            subghz->view_dispatcher, subghz->gui, ViewDispatcherTypeFullscreen);
         string_set_str(subghz->file_path, SUBGHZ_APP_FOLDER);
         string_set_str(subghz->file_path, SUBGHZ_APP_FOLDER);
         if(load_database) {
         if(load_database) {
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart);
             scene_manager_next_scene(subghz->scene_manager, SubGhzSceneStart);

+ 1 - 1
assets/protobuf

@@ -1 +1 @@
-Subproject commit d9e343661dd36cfab792b78be1dea4e5950cb4dd
+Subproject commit cc5918dc488ac3617012ce5377114e086b447324