[FL-2705] App RPC Bug Fixes and redesign (#1491)
* Rpc: remove callback timer * Rpc: simplify rpc event callback * Rpc: migrate to new confirmation schema * Rpc: migrate to new confirmation schema part2: finalize ibutton and rfid * Rpc: migrate to new confirmation schema part3: finallize nfc and fix id in load * Rpc: hardened sequencing check * Rpc: migrate to new confirmation schema part4: finalize subghz * iButton: properly handle exit * Nfc: correct sequence for rpc exit send * Rpc: fix review issues and nfc exit message * Rpc: more logging and condition race fix in confirmation * Rpc: migrate to new confirmation schema part5: finalize infrared * Rpc: more logging
This commit is contained in:
		
							parent
							
								
									f9386b2649
								
							
						
					
					
						commit
						f9745b4141
					
				| @ -5,7 +5,7 @@ | |||||||
| #include "m-string.h" | #include "m-string.h" | ||||||
| #include <toolbox/path.h> | #include <toolbox/path.h> | ||||||
| #include <flipper_format/flipper_format.h> | #include <flipper_format/flipper_format.h> | ||||||
| #include "rpc/rpc_app.h" | #include <rpc/rpc_app.h> | ||||||
| 
 | 
 | ||||||
| #define TAG "iButtonApp" | #define TAG "iButtonApp" | ||||||
| 
 | 
 | ||||||
| @ -58,7 +58,7 @@ static void ibutton_make_app_folder(iButton* ibutton) { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool ibutton_load_key_data(iButton* ibutton, string_t key_path, bool show_dialog) { | bool ibutton_load_key_data(iButton* ibutton, string_t key_path, bool show_dialog) { | ||||||
|     FlipperFormat* file = flipper_format_file_alloc(ibutton->storage); |     FlipperFormat* file = flipper_format_file_alloc(ibutton->storage); | ||||||
|     bool result = false; |     bool result = false; | ||||||
|     string_t data; |     string_t data; | ||||||
| @ -99,33 +99,20 @@ static bool ibutton_load_key_data(iButton* ibutton, string_t key_path, bool show | |||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool ibutton_rpc_command_callback(RpcAppSystemEvent event, const char* arg, void* context) { | static void ibutton_rpc_command_callback(RpcAppSystemEvent event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     iButton* ibutton = context; |     iButton* ibutton = context; | ||||||
| 
 | 
 | ||||||
|     bool result = false; |  | ||||||
| 
 |  | ||||||
|     if(event == RpcAppEventSessionClose) { |     if(event == RpcAppEventSessionClose) { | ||||||
|         rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL); |         view_dispatcher_send_custom_event( | ||||||
|         ibutton->rpc_ctx = NULL; |             ibutton->view_dispatcher, iButtonCustomEventRpcSessionClose); | ||||||
|         view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcExit); |  | ||||||
|         result = true; |  | ||||||
|     } else if(event == RpcAppEventAppExit) { |     } else if(event == RpcAppEventAppExit) { | ||||||
|         view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcExit); |         view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcExit); | ||||||
|         result = true; |  | ||||||
|     } else if(event == RpcAppEventLoadFile) { |     } else if(event == RpcAppEventLoadFile) { | ||||||
|         if(arg) { |         view_dispatcher_send_custom_event(ibutton->view_dispatcher, iButtonCustomEventRpcLoad); | ||||||
|             string_set_str(ibutton->file_path, arg); |     } else { | ||||||
|             if(ibutton_load_key_data(ibutton, ibutton->file_path, false)) { |         rpc_system_app_confirm(ibutton->rpc_ctx, event, false); | ||||||
|                 ibutton_worker_emulate_start(ibutton->key_worker, ibutton->key); |  | ||||||
|                 view_dispatcher_send_custom_event( |  | ||||||
|                     ibutton->view_dispatcher, iButtonCustomEventRpcLoad); |  | ||||||
|                 result = true; |  | ||||||
|     } |     } | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool ibutton_custom_event_callback(void* context, uint32_t event) { | bool ibutton_custom_event_callback(void* context, uint32_t event) { | ||||||
|  | |||||||
| @ -12,4 +12,5 @@ enum iButtonCustomEvent { | |||||||
| 
 | 
 | ||||||
|     iButtonCustomEventRpcLoad, |     iButtonCustomEventRpcLoad, | ||||||
|     iButtonCustomEventRpcExit, |     iButtonCustomEventRpcExit, | ||||||
|  |     iButtonCustomEventRpcSessionClose, | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -78,6 +78,7 @@ typedef enum { | |||||||
| } iButtonNotificationMessage; | } iButtonNotificationMessage; | ||||||
| 
 | 
 | ||||||
| bool ibutton_file_select(iButton* ibutton); | bool ibutton_file_select(iButton* ibutton); | ||||||
|  | bool ibutton_load_key_data(iButton* ibutton, string_t key_path, bool show_dialog); | ||||||
| bool ibutton_save_key(iButton* ibutton, const char* key_name); | bool ibutton_save_key(iButton* ibutton, const char* key_name); | ||||||
| bool ibutton_delete_key(iButton* ibutton); | bool ibutton_delete_key(iButton* ibutton); | ||||||
| void ibutton_text_store_set(iButton* ibutton, const char* text, ...); | void ibutton_text_store_set(iButton* ibutton, const char* text, ...); | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| #include "../ibutton_i.h" | #include "../ibutton_i.h" | ||||||
| #include <toolbox/path.h> | #include <toolbox/path.h> | ||||||
|  | #include <rpc/rpc_app.h> | ||||||
| 
 | 
 | ||||||
| void ibutton_scene_rpc_on_enter(void* context) { | void ibutton_scene_rpc_on_enter(void* context) { | ||||||
|     iButton* ibutton = context; |     iButton* ibutton = context; | ||||||
| @ -26,6 +27,12 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) { | |||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         consumed = true; |         consumed = true; | ||||||
|         if(event.event == iButtonCustomEventRpcLoad) { |         if(event.event == iButtonCustomEventRpcLoad) { | ||||||
|  |             const char* arg = rpc_system_app_get_data(ibutton->rpc_ctx); | ||||||
|  |             bool result = false; | ||||||
|  |             if(arg) { | ||||||
|  |                 string_set_str(ibutton->file_path, arg); | ||||||
|  |                 if(ibutton_load_key_data(ibutton, ibutton->file_path, false)) { | ||||||
|  |                     ibutton_worker_emulate_start(ibutton->key_worker, ibutton->key); | ||||||
|                     string_t key_name; |                     string_t key_name; | ||||||
|                     string_init(key_name); |                     string_init(key_name); | ||||||
|                     if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) { |                     if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) { | ||||||
| @ -33,7 +40,8 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) { | |||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if(!string_empty_p(key_name)) { |                     if(!string_empty_p(key_name)) { | ||||||
|                 ibutton_text_store_set(ibutton, "emulating\n%s", string_get_cstr(key_name)); |                         ibutton_text_store_set( | ||||||
|  |                             ibutton, "emulating\n%s", string_get_cstr(key_name)); | ||||||
|                     } else { |                     } else { | ||||||
|                         ibutton_text_store_set(ibutton, "emulating"); |                         ibutton_text_store_set(ibutton, "emulating"); | ||||||
|                     } |                     } | ||||||
| @ -42,7 +50,17 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) { | |||||||
|                     ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart); |                     ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart); | ||||||
| 
 | 
 | ||||||
|                     string_clear(key_name); |                     string_clear(key_name); | ||||||
|  |                     result = true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventLoadFile, result); | ||||||
|         } else if(event.event == iButtonCustomEventRpcExit) { |         } else if(event.event == iButtonCustomEventRpcExit) { | ||||||
|  |             rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventAppExit, true); | ||||||
|  |             ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop); | ||||||
|  |             view_dispatcher_stop(ibutton->view_dispatcher); | ||||||
|  |         } else if(event.event == iButtonCustomEventRpcSessionClose) { | ||||||
|  |             rpc_system_app_set_callback(ibutton->rpc_ctx, NULL, NULL); | ||||||
|  |             ibutton->rpc_ctx = NULL; | ||||||
|             ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop); |             ibutton_notification_message(ibutton, iButtonNotificationMessageBlinkStop); | ||||||
|             view_dispatcher_stop(ibutton->view_dispatcher); |             view_dispatcher_stop(ibutton->view_dispatcher); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -36,52 +36,29 @@ static void infrared_tick_event_callback(void* context) { | |||||||
|     scene_manager_handle_tick_event(infrared->scene_manager); |     scene_manager_handle_tick_event(infrared->scene_manager); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool | static void infrared_rpc_command_callback(RpcAppSystemEvent event, void* context) { | ||||||
|     infrared_rpc_command_callback(RpcAppSystemEvent event, const char* arg, void* context) { |  | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Infrared* infrared = context; |     Infrared* infrared = context; | ||||||
| 
 |     furi_assert(infrared->rpc_ctx); | ||||||
|     if(!infrared->rpc_ctx) { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool result = false; |  | ||||||
| 
 | 
 | ||||||
|     if(event == RpcAppEventSessionClose) { |     if(event == RpcAppEventSessionClose) { | ||||||
|         rpc_system_app_set_callback(infrared->rpc_ctx, NULL, NULL); |  | ||||||
|         infrared->rpc_ctx = NULL; |  | ||||||
|         view_dispatcher_send_custom_event( |         view_dispatcher_send_custom_event( | ||||||
|             infrared->view_dispatcher, InfraredCustomEventTypeBackPressed); |             infrared->view_dispatcher, InfraredCustomEventTypeRpcSessionClose); | ||||||
|         result = true; |  | ||||||
|     } else if(event == RpcAppEventAppExit) { |     } else if(event == RpcAppEventAppExit) { | ||||||
|         view_dispatcher_send_custom_event( |         view_dispatcher_send_custom_event( | ||||||
|             infrared->view_dispatcher, InfraredCustomEventTypeBackPressed); |             infrared->view_dispatcher, InfraredCustomEventTypeRpcExit); | ||||||
|         result = true; |  | ||||||
|     } else if(event == RpcAppEventLoadFile) { |     } else if(event == RpcAppEventLoadFile) { | ||||||
|         if(arg) { |  | ||||||
|             string_set_str(infrared->file_path, arg); |  | ||||||
|             result = infrared_remote_load(infrared->remote, infrared->file_path); |  | ||||||
|             infrared_worker_tx_set_get_signal_callback( |  | ||||||
|                 infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared); |  | ||||||
|             infrared_worker_tx_set_signal_sent_callback( |  | ||||||
|                 infrared->worker, infrared_signal_sent_callback, infrared); |  | ||||||
|         view_dispatcher_send_custom_event( |         view_dispatcher_send_custom_event( | ||||||
|                 infrared->view_dispatcher, InfraredCustomEventTypeRpcLoaded); |             infrared->view_dispatcher, InfraredCustomEventTypeRpcLoad); | ||||||
|         } |  | ||||||
|     } else if(event == RpcAppEventButtonPress) { |     } else if(event == RpcAppEventButtonPress) { | ||||||
|         if(arg) { |         view_dispatcher_send_custom_event( | ||||||
|             size_t button_index = 0; |             infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonPress); | ||||||
|             if(infrared_remote_find_button_by_name(infrared->remote, arg, &button_index)) { |  | ||||||
|                 infrared_tx_start_button_index(infrared, button_index); |  | ||||||
|                 result = true; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } else if(event == RpcAppEventButtonRelease) { |     } else if(event == RpcAppEventButtonRelease) { | ||||||
|         infrared_tx_stop(infrared); |         view_dispatcher_send_custom_event( | ||||||
|         result = true; |             infrared->view_dispatcher, InfraredCustomEventTypeRpcButtonRelease); | ||||||
|  |     } else { | ||||||
|  |         rpc_system_app_confirm(infrared->rpc_ctx, event, false); | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void infrared_find_vacant_remote_name(string_t name, const char* path) { | static void infrared_find_vacant_remote_name(string_t name, const char* path) { | ||||||
|  | |||||||
| @ -14,7 +14,12 @@ enum InfraredCustomEventType { | |||||||
|     InfraredCustomEventTypePopupClosed, |     InfraredCustomEventTypePopupClosed, | ||||||
|     InfraredCustomEventTypeButtonSelected, |     InfraredCustomEventTypeButtonSelected, | ||||||
|     InfraredCustomEventTypeBackPressed, |     InfraredCustomEventTypeBackPressed, | ||||||
|     InfraredCustomEventTypeRpcLoaded, | 
 | ||||||
|  |     InfraredCustomEventTypeRpcLoad, | ||||||
|  |     InfraredCustomEventTypeRpcExit, | ||||||
|  |     InfraredCustomEventTypeRpcButtonPress, | ||||||
|  |     InfraredCustomEventTypeRpcButtonRelease, | ||||||
|  |     InfraredCustomEventTypeRpcSessionClose, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #pragma pack(push, 1) | #pragma pack(push, 1) | ||||||
|  | |||||||
| @ -28,12 +28,45 @@ 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) { |         } else if(event.event == InfraredCustomEventTypeRpcLoad) { | ||||||
|  |             bool result = false; | ||||||
|  |             const char* arg = rpc_system_app_get_data(infrared->rpc_ctx); | ||||||
|  |             if(arg) { | ||||||
|  |                 string_set_str(infrared->file_path, arg); | ||||||
|  |                 result = infrared_remote_load(infrared->remote, infrared->file_path); | ||||||
|  |                 infrared_worker_tx_set_get_signal_callback( | ||||||
|  |                     infrared->worker, infrared_worker_tx_get_signal_steady_callback, infrared); | ||||||
|  |                 infrared_worker_tx_set_signal_sent_callback( | ||||||
|  |                     infrared->worker, infrared_signal_sent_callback, infrared); | ||||||
|  |             } | ||||||
|             const char* remote_name = infrared_remote_get_name(infrared->remote); |             const char* remote_name = infrared_remote_get_name(infrared->remote); | ||||||
| 
 | 
 | ||||||
|             infrared_text_store_set(infrared, 0, "loaded\n%s", remote_name); |             infrared_text_store_set(infrared, 0, "loaded\n%s", remote_name); | ||||||
|             popup_set_text( |             popup_set_text( | ||||||
|                 infrared->popup, infrared->text_store[0], 82, 32, AlignCenter, AlignTop); |                 infrared->popup, infrared->text_store[0], 82, 32, AlignCenter, AlignTop); | ||||||
|  | 
 | ||||||
|  |             rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventLoadFile, result); | ||||||
|  |         } else if(event.event == InfraredCustomEventTypeRpcButtonPress) { | ||||||
|  |             bool result = false; | ||||||
|  |             const char* arg = rpc_system_app_get_data(infrared->rpc_ctx); | ||||||
|  |             if(arg) { | ||||||
|  |                 size_t button_index = 0; | ||||||
|  |                 if(infrared_remote_find_button_by_name(infrared->remote, arg, &button_index)) { | ||||||
|  |                     infrared_tx_start_button_index(infrared, button_index); | ||||||
|  |                     result = true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, result); | ||||||
|  |         } else if(event.event == InfraredCustomEventTypeRpcButtonRelease) { | ||||||
|  |             infrared_tx_stop(infrared); | ||||||
|  |             rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventButtonRelease, true); | ||||||
|  |         } else if(event.event == InfraredCustomEventTypeRpcExit) { | ||||||
|  |             view_dispatcher_stop(infrared->view_dispatcher); | ||||||
|  |             rpc_system_app_confirm(infrared->rpc_ctx, RpcAppEventAppExit, true); | ||||||
|  |         } else if(event.event == InfraredCustomEventTypeRpcSessionClose) { | ||||||
|  |             rpc_system_app_set_callback(infrared->rpc_ctx, NULL, NULL); | ||||||
|  |             infrared->rpc_ctx = NULL; | ||||||
|  |             view_dispatcher_stop(infrared->view_dispatcher); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     return consumed; |     return consumed; | ||||||
|  | |||||||
| @ -25,7 +25,7 @@ | |||||||
| #include <toolbox/path.h> | #include <toolbox/path.h> | ||||||
| #include <flipper_format/flipper_format.h> | #include <flipper_format/flipper_format.h> | ||||||
| 
 | 
 | ||||||
| #include "rpc/rpc_app.h" | #include <rpc/rpc_app.h> | ||||||
| 
 | 
 | ||||||
| const char* LfRfidApp::app_folder = ANY_PATH("lfrfid"); | const char* LfRfidApp::app_folder = ANY_PATH("lfrfid"); | ||||||
| const char* LfRfidApp::app_extension = ".rfid"; | const char* LfRfidApp::app_extension = ".rfid"; | ||||||
| @ -48,38 +48,25 @@ LfRfidApp::~LfRfidApp() { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool rpc_command_callback(RpcAppSystemEvent event, const char* arg, void* context) { | static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     LfRfidApp* app = static_cast<LfRfidApp*>(context); |     LfRfidApp* app = static_cast<LfRfidApp*>(context); | ||||||
| 
 | 
 | ||||||
|     bool result = false; |     if(rpc_event == RpcAppEventSessionClose) { | ||||||
| 
 |         LfRfidApp::Event event; | ||||||
|     if(event == RpcAppEventSessionClose) { |         event.type = LfRfidApp::EventType::RpcSessionClose; | ||||||
|         rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL); |         app->view_controller.send_event(&event); | ||||||
|         app->rpc_ctx = NULL; |     } else if(rpc_event == RpcAppEventAppExit) { | ||||||
|         LfRfidApp::Event event; |         LfRfidApp::Event event; | ||||||
|         event.type = LfRfidApp::EventType::Exit; |         event.type = LfRfidApp::EventType::Exit; | ||||||
|         app->view_controller.send_event(&event); |         app->view_controller.send_event(&event); | ||||||
|         result = true; |     } else if(rpc_event == RpcAppEventLoadFile) { | ||||||
|     } else if(event == RpcAppEventAppExit) { |  | ||||||
|         LfRfidApp::Event event; |         LfRfidApp::Event event; | ||||||
|         event.type = LfRfidApp::EventType::Exit; |         event.type = LfRfidApp::EventType::RpcLoadFile; | ||||||
|         app->view_controller.send_event(&event); |         app->view_controller.send_event(&event); | ||||||
|         result = true; |     } else { | ||||||
|     } else if(event == RpcAppEventLoadFile) { |         rpc_system_app_confirm(app->rpc_ctx, rpc_event, false); | ||||||
|         if(arg) { |  | ||||||
|             string_set_str(app->file_path, arg); |  | ||||||
|             if(app->load_key_data(app->file_path, &(app->worker.key), false)) { |  | ||||||
|                 LfRfidApp::Event event; |  | ||||||
|                 event.type = LfRfidApp::EventType::EmulateStart; |  | ||||||
|                 app->view_controller.send_event(&event); |  | ||||||
|                 app->worker.start_emulate(); |  | ||||||
|                 result = true; |  | ||||||
|     } |     } | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void LfRfidApp::run(void* _args) { | void LfRfidApp::run(void* _args) { | ||||||
|  | |||||||
| @ -33,6 +33,8 @@ public: | |||||||
|         Retry, |         Retry, | ||||||
|         Exit, |         Exit, | ||||||
|         EmulateStart, |         EmulateStart, | ||||||
|  |         RpcLoadFile, | ||||||
|  |         RpcSessionClose, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     enum class SceneType : uint8_t { |     enum class SceneType : uint8_t { | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| #include "lfrfid_app_scene_rpc.h" | #include "lfrfid_app_scene_rpc.h" | ||||||
| #include <core/common_defines.h> | #include <core/common_defines.h> | ||||||
| #include <dolphin/dolphin.h> | #include <dolphin/dolphin.h> | ||||||
|  | #include <rpc/rpc_app.h> | ||||||
| 
 | 
 | ||||||
| static const NotificationSequence sequence_blink_start_magenta = { | static const NotificationSequence sequence_blink_start_magenta = { | ||||||
|     &message_blink_start_10, |     &message_blink_start_10, | ||||||
| @ -36,6 +37,16 @@ bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | |||||||
|         LfRfidApp::Event view_event; |         LfRfidApp::Event view_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); | ||||||
|  |         rpc_system_app_confirm(app->rpc_ctx, RpcAppEventAppExit, true); | ||||||
|  |     } else if(event->type == LfRfidApp::EventType::RpcSessionClose) { | ||||||
|  |         // Detach RPC
 | ||||||
|  |         rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL); | ||||||
|  |         app->rpc_ctx = NULL; | ||||||
|  | 
 | ||||||
|  |         consumed = true; | ||||||
|  |         LfRfidApp::Event view_event; | ||||||
|  |         view_event.type = LfRfidApp::EventType::Back; | ||||||
|  |         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>(); |         auto popup = app->view_controller.get<PopupVM>(); | ||||||
|         consumed = true; |         consumed = true; | ||||||
| @ -45,7 +56,22 @@ bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) { | |||||||
|         popup->set_text(app->text_store.text, 89, 43, AlignCenter, AlignTop); |         popup->set_text(app->text_store.text, 89, 43, AlignCenter, AlignTop); | ||||||
| 
 | 
 | ||||||
|         notification_message(app->notification, &sequence_blink_start_magenta); |         notification_message(app->notification, &sequence_blink_start_magenta); | ||||||
|  |     } else if(event->type == LfRfidApp::EventType::RpcLoadFile) { | ||||||
|  |         const char* arg = rpc_system_app_get_data(app->rpc_ctx); | ||||||
|  |         bool result = false; | ||||||
|  |         if(arg) { | ||||||
|  |             string_set_str(app->file_path, arg); | ||||||
|  |             if(app->load_key_data(app->file_path, &(app->worker.key), false)) { | ||||||
|  |                 LfRfidApp::Event event; | ||||||
|  |                 event.type = LfRfidApp::EventType::EmulateStart; | ||||||
|  |                 app->view_controller.send_event(&event); | ||||||
|  |                 app->worker.start_emulate(); | ||||||
|  |                 result = true; | ||||||
|             } |             } | ||||||
|  |         } | ||||||
|  |         rpc_system_app_confirm(app->rpc_ctx, RpcAppEventLoadFile, result); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     return consumed; |     return consumed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -11,4 +11,5 @@ enum NfcCustomEvent { | |||||||
|     NfcCustomEventDictAttackDone, |     NfcCustomEventDictAttackDone, | ||||||
|     NfcCustomEventDictAttackSkip, |     NfcCustomEventDictAttackSkip, | ||||||
|     NfcCustomEventRpcLoad, |     NfcCustomEventRpcLoad, | ||||||
|  |     NfcCustomEventRpcSessionClose, | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -13,78 +13,21 @@ bool nfc_back_event_callback(void* context) { | |||||||
|     return scene_manager_handle_back_event(nfc->scene_manager); |     return scene_manager_handle_back_event(nfc->scene_manager); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void nfc_rpc_exit_callback(Nfc* nfc) { | static void nfc_rpc_command_callback(RpcAppSystemEvent event, void* context) { | ||||||
|     if(nfc->rpc_state == NfcRpcStateEmulating) { |  | ||||||
|         // Stop worker
 |  | ||||||
|         nfc_worker_stop(nfc->worker); |  | ||||||
|     } else if(nfc->rpc_state == NfcRpcStateEmulated) { |  | ||||||
|         // Stop worker
 |  | ||||||
|         nfc_worker_stop(nfc->worker); |  | ||||||
|         // Save data in shadow file
 |  | ||||||
|         nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name); |  | ||||||
|     } |  | ||||||
|     if(nfc->rpc_ctx) { |  | ||||||
|         rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL); |  | ||||||
|         rpc_system_app_send_exited(nfc->rpc_ctx); |  | ||||||
|         nfc->rpc_ctx = NULL; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static bool nfc_rpc_emulate_callback(NfcWorkerEvent event, void* context) { |  | ||||||
|     UNUSED(event); |  | ||||||
|     Nfc* nfc = context; |  | ||||||
| 
 |  | ||||||
|     nfc->rpc_state = NfcRpcStateEmulated; |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static bool nfc_rpc_command_callback(RpcAppSystemEvent event, const char* arg, void* context) { |  | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
| 
 | 
 | ||||||
|     if(!nfc->rpc_ctx) { |     furi_assert(nfc->rpc_ctx); | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool result = false; |  | ||||||
| 
 | 
 | ||||||
|     if(event == RpcAppEventSessionClose) { |     if(event == RpcAppEventSessionClose) { | ||||||
|         rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL); |         view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcSessionClose); | ||||||
|         nfc->rpc_ctx = NULL; |  | ||||||
|         view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); |  | ||||||
|         result = true; |  | ||||||
|     } else if(event == RpcAppEventAppExit) { |     } else if(event == RpcAppEventAppExit) { | ||||||
|         view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); |         view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventViewExit); | ||||||
|         result = true; |  | ||||||
|     } else if(event == RpcAppEventLoadFile) { |     } else if(event == RpcAppEventLoadFile) { | ||||||
|         if((arg) && (nfc->rpc_state == NfcRpcStateIdle)) { |  | ||||||
|             if(nfc_device_load(nfc->dev, arg, false)) { |  | ||||||
|                 if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { |  | ||||||
|                     nfc_worker_start( |  | ||||||
|                         nfc->worker, |  | ||||||
|                         NfcWorkerStateMfUltralightEmulate, |  | ||||||
|                         &nfc->dev->dev_data, |  | ||||||
|                         nfc_rpc_emulate_callback, |  | ||||||
|                         nfc); |  | ||||||
|                 } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { |  | ||||||
|                     nfc_worker_start( |  | ||||||
|                         nfc->worker, |  | ||||||
|                         NfcWorkerStateMfClassicEmulate, |  | ||||||
|                         &nfc->dev->dev_data, |  | ||||||
|                         nfc_rpc_emulate_callback, |  | ||||||
|                         nfc); |  | ||||||
|                 } else { |  | ||||||
|                     nfc_worker_start( |  | ||||||
|                         nfc->worker, NfcWorkerStateUidEmulate, &nfc->dev->dev_data, NULL, nfc); |  | ||||||
|                 } |  | ||||||
|                 nfc->rpc_state = NfcRpcStateEmulating; |  | ||||||
|         view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcLoad); |         view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcLoad); | ||||||
|                 result = true; |     } else { | ||||||
|  |         rpc_system_app_confirm(nfc->rpc_ctx, event, false); | ||||||
|     } |     } | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return result; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Nfc* nfc_alloc() { | Nfc* nfc_alloc() { | ||||||
| @ -163,6 +106,21 @@ Nfc* nfc_alloc() { | |||||||
| void nfc_free(Nfc* nfc) { | void nfc_free(Nfc* nfc) { | ||||||
|     furi_assert(nfc); |     furi_assert(nfc); | ||||||
| 
 | 
 | ||||||
|  |     if(nfc->rpc_state == NfcRpcStateEmulating) { | ||||||
|  |         // Stop worker
 | ||||||
|  |         nfc_worker_stop(nfc->worker); | ||||||
|  |     } else if(nfc->rpc_state == NfcRpcStateEmulated) { | ||||||
|  |         // Stop worker
 | ||||||
|  |         nfc_worker_stop(nfc->worker); | ||||||
|  |         // Save data in shadow file
 | ||||||
|  |         nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name); | ||||||
|  |     } | ||||||
|  |     if(nfc->rpc_ctx) { | ||||||
|  |         rpc_system_app_send_exited(nfc->rpc_ctx); | ||||||
|  |         rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL); | ||||||
|  |         nfc->rpc_ctx = NULL; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     // Nfc device
 |     // Nfc device
 | ||||||
|     nfc_device_free(nfc->dev); |     nfc_device_free(nfc->dev); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -102,5 +102,3 @@ void nfc_blink_start(Nfc* nfc); | |||||||
| void nfc_blink_stop(Nfc* nfc); | void nfc_blink_stop(Nfc* nfc); | ||||||
| 
 | 
 | ||||||
| void nfc_show_loading_popup(void* context, bool show); | void nfc_show_loading_popup(void* context, bool show); | ||||||
| 
 |  | ||||||
| void nfc_rpc_exit_callback(Nfc* nfc); |  | ||||||
|  | |||||||
| @ -14,6 +14,14 @@ void nfc_scene_rpc_on_enter(void* context) { | |||||||
|     notification_message(nfc->notifications, &sequence_display_backlight_on); |     notification_message(nfc->notifications, &sequence_display_backlight_on); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool nfc_scene_rpc_emulate_callback(NfcWorkerEvent event, void* context) { | ||||||
|  |     UNUSED(event); | ||||||
|  |     Nfc* nfc = context; | ||||||
|  | 
 | ||||||
|  |     nfc->rpc_state = NfcRpcStateEmulated; | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| 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; |     Popup* popup = nfc->popup; | ||||||
| @ -22,15 +30,49 @@ bool nfc_scene_rpc_on_event(void* context, SceneManagerEvent event) { | |||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         consumed = true; |         consumed = true; | ||||||
|         if(event.event == NfcCustomEventViewExit) { |         if(event.event == NfcCustomEventViewExit) { | ||||||
|  |             rpc_system_app_confirm(nfc->rpc_ctx, RpcAppEventAppExit, true); | ||||||
|  |             view_dispatcher_stop(nfc->view_dispatcher); | ||||||
|  |             nfc_blink_stop(nfc); | ||||||
|  |         } else if(event.event == NfcCustomEventRpcSessionClose) { | ||||||
|  |             rpc_system_app_set_callback(nfc->rpc_ctx, NULL, NULL); | ||||||
|  |             nfc->rpc_ctx = NULL; | ||||||
|             view_dispatcher_stop(nfc->view_dispatcher); |             view_dispatcher_stop(nfc->view_dispatcher); | ||||||
|             nfc_blink_stop(nfc); |             nfc_blink_stop(nfc); | ||||||
|         } else if(event.event == NfcCustomEventRpcLoad) { |         } else if(event.event == NfcCustomEventRpcLoad) { | ||||||
|             nfc_blink_start(nfc); |             bool result = false; | ||||||
|  |             const char* arg = rpc_system_app_get_data(nfc->rpc_ctx); | ||||||
|  |             if((arg) && (nfc->rpc_state == NfcRpcStateIdle)) { | ||||||
|  |                 if(nfc_device_load(nfc->dev, arg, false)) { | ||||||
|  |                     if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { | ||||||
|  |                         nfc_worker_start( | ||||||
|  |                             nfc->worker, | ||||||
|  |                             NfcWorkerStateMfUltralightEmulate, | ||||||
|  |                             &nfc->dev->dev_data, | ||||||
|  |                             nfc_scene_rpc_emulate_callback, | ||||||
|  |                             nfc); | ||||||
|  |                     } else if(nfc->dev->format == NfcDeviceSaveFormatMifareClassic) { | ||||||
|  |                         nfc_worker_start( | ||||||
|  |                             nfc->worker, | ||||||
|  |                             NfcWorkerStateMfClassicEmulate, | ||||||
|  |                             &nfc->dev->dev_data, | ||||||
|  |                             nfc_scene_rpc_emulate_callback, | ||||||
|  |                             nfc); | ||||||
|  |                     } else { | ||||||
|  |                         nfc_worker_start( | ||||||
|  |                             nfc->worker, NfcWorkerStateUidEmulate, &nfc->dev->dev_data, NULL, nfc); | ||||||
|  |                     } | ||||||
|  |                     nfc->rpc_state = NfcRpcStateEmulating; | ||||||
|  |                     result = true; | ||||||
| 
 | 
 | ||||||
|  |                     nfc_blink_start(nfc); | ||||||
|                     nfc_text_store_set(nfc, "emulating\n%s", nfc->dev->dev_name); |                     nfc_text_store_set(nfc, "emulating\n%s", nfc->dev->dev_name); | ||||||
|                     popup_set_text(popup, nfc->text_store, 82, 32, AlignCenter, AlignTop); |                     popup_set_text(popup, nfc->text_store, 82, 32, AlignCenter, AlignTop); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             rpc_system_app_confirm(nfc->rpc_ctx, RpcAppEventLoadFile, result); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|     return consumed; |     return consumed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -38,7 +80,6 @@ void nfc_scene_rpc_on_exit(void* context) { | |||||||
|     Nfc* nfc = context; |     Nfc* nfc = context; | ||||||
|     Popup* popup = nfc->popup; |     Popup* popup = nfc->popup; | ||||||
| 
 | 
 | ||||||
|     nfc_rpc_exit_callback(nfc); |  | ||||||
|     nfc_blink_stop(nfc); |     nfc_blink_stop(nfc); | ||||||
| 
 | 
 | ||||||
|     popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); |     popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom); | ||||||
|  | |||||||
| @ -6,24 +6,18 @@ | |||||||
| #include "rpc_app.h" | #include "rpc_app.h" | ||||||
| 
 | 
 | ||||||
| #define TAG "RpcSystemApp" | #define TAG "RpcSystemApp" | ||||||
| #define APP_BUTTON_TIMEOUT 1000 |  | ||||||
| 
 | 
 | ||||||
| struct RpcAppSystem { | struct RpcAppSystem { | ||||||
|     RpcSession* session; |     RpcSession* session; | ||||||
|     RpcAppSystemCallback app_callback; |     RpcAppSystemCallback app_callback; | ||||||
|     void* app_context; |     void* app_context; | ||||||
|     PB_Main* state_msg; |     PB_Main* state_msg; | ||||||
|     FuriTimer* timer; | 
 | ||||||
|  |     uint32_t last_id; | ||||||
|  |     char* last_data; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static void rpc_system_app_timer_callback(void* context) { | #define RPC_SYSTEM_APP_TEMP_ARGS_SIZE 16 | ||||||
|     furi_assert(context); |  | ||||||
|     RpcAppSystem* rpc_app = context; |  | ||||||
| 
 |  | ||||||
|     if(rpc_app->app_callback) { |  | ||||||
|         rpc_app->app_callback(RpcAppEventButtonRelease, NULL, rpc_app->app_context); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| static void rpc_system_app_start_process(const PB_Main* request, void* context) { | static void rpc_system_app_start_process(const PB_Main* request, void* context) { | ||||||
|     furi_assert(request); |     furi_assert(request); | ||||||
| @ -33,9 +27,12 @@ static void rpc_system_app_start_process(const PB_Main* request, void* context) | |||||||
|     RpcAppSystem* rpc_app = context; |     RpcAppSystem* rpc_app = context; | ||||||
|     RpcSession* session = rpc_app->session; |     RpcSession* session = rpc_app->session; | ||||||
|     furi_assert(session); |     furi_assert(session); | ||||||
|     char args_temp[16]; |     char args_temp[RPC_SYSTEM_APP_TEMP_ARGS_SIZE]; | ||||||
| 
 | 
 | ||||||
|     FURI_LOG_D(TAG, "Start"); |     furi_assert(!rpc_app->last_id); | ||||||
|  |     furi_assert(!rpc_app->last_data); | ||||||
|  | 
 | ||||||
|  |     FURI_LOG_D(TAG, "StartProcess: id %d", request->command_id); | ||||||
| 
 | 
 | ||||||
|     PB_CommandStatus result = PB_CommandStatus_ERROR_APP_CANT_START; |     PB_CommandStatus result = PB_CommandStatus_ERROR_APP_CANT_START; | ||||||
| 
 | 
 | ||||||
| @ -43,9 +40,9 @@ static void rpc_system_app_start_process(const PB_Main* request, void* context) | |||||||
|     const char* app_name = request->content.app_start_request.name; |     const char* app_name = request->content.app_start_request.name; | ||||||
|     if(app_name) { |     if(app_name) { | ||||||
|         const char* app_args = request->content.app_start_request.args; |         const char* app_args = request->content.app_start_request.args; | ||||||
|         if(strcmp(app_args, "RPC") == 0) { |         if(app_args && strcmp(app_args, "RPC") == 0) { | ||||||
|             // If app is being started in RPC mode - pass RPC context via args string
 |             // If app is being started in RPC mode - pass RPC context via args string
 | ||||||
|             snprintf(args_temp, 16, "RPC %08lX", (uint32_t)rpc_app); |             snprintf(args_temp, RPC_SYSTEM_APP_TEMP_ARGS_SIZE, "RPC %08lX", (uint32_t)rpc_app); | ||||||
|             app_args = args_temp; |             app_args = args_temp; | ||||||
|         } |         } | ||||||
|         LoaderStatus status = loader_start(loader, app_name, app_args); |         LoaderStatus status = loader_start(loader, app_name, app_args); | ||||||
| @ -58,7 +55,7 @@ static void rpc_system_app_start_process(const PB_Main* request, void* context) | |||||||
|         } else if(status == LoaderStatusOk) { |         } else if(status == LoaderStatusOk) { | ||||||
|             result = PB_CommandStatus_OK; |             result = PB_CommandStatus_OK; | ||||||
|         } else { |         } else { | ||||||
|             furi_assert(0); |             furi_crash("Programming Error"); | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
|         result = PB_CommandStatus_ERROR_INVALID_PARAMETERS; |         result = PB_CommandStatus_ERROR_INVALID_PARAMETERS; | ||||||
| @ -66,6 +63,7 @@ static void rpc_system_app_start_process(const PB_Main* request, void* context) | |||||||
| 
 | 
 | ||||||
|     furi_record_close(RECORD_LOADER); |     furi_record_close(RECORD_LOADER); | ||||||
| 
 | 
 | ||||||
|  |     FURI_LOG_D(TAG, "StartProcess: response id %d, result %d", request->command_id, result); | ||||||
|     rpc_send_and_release_empty(session, request->command_id, result); |     rpc_send_and_release_empty(session, request->command_id, result); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -93,6 +91,7 @@ static void rpc_system_app_lock_status_process(const PB_Main* request, void* con | |||||||
| 
 | 
 | ||||||
|     furi_record_close(RECORD_LOADER); |     furi_record_close(RECORD_LOADER); | ||||||
| 
 | 
 | ||||||
|  |     FURI_LOG_D(TAG, "LockStatus: response"); | ||||||
|     rpc_send_and_release(session, &response); |     rpc_send_and_release(session, &response); | ||||||
|     pb_release(&PB_Main_msg, &response); |     pb_release(&PB_Main_msg, &response); | ||||||
| } | } | ||||||
| @ -109,17 +108,17 @@ static void rpc_system_app_exit_request(const PB_Main* request, void* context) { | |||||||
|     PB_CommandStatus status; |     PB_CommandStatus status; | ||||||
| 
 | 
 | ||||||
|     if(rpc_app->app_callback) { |     if(rpc_app->app_callback) { | ||||||
|         if(rpc_app->app_callback(RpcAppEventAppExit, NULL, rpc_app->app_context)) { |         FURI_LOG_D(TAG, "ExitRequest: id %d", request->command_id); | ||||||
|             status = PB_CommandStatus_OK; |         furi_assert(!rpc_app->last_id); | ||||||
|             furi_timer_stop(rpc_app->timer); |         furi_assert(!rpc_app->last_data); | ||||||
|         } else { |         rpc_app->last_id = request->command_id; | ||||||
|             status = PB_CommandStatus_ERROR_APP_CMD_ERROR; |         rpc_app->app_callback(RpcAppEventAppExit, rpc_app->app_context); | ||||||
|         } |  | ||||||
|     } else { |     } else { | ||||||
|         status = PB_CommandStatus_ERROR_APP_NOT_RUNNING; |         status = PB_CommandStatus_ERROR_APP_NOT_RUNNING; | ||||||
|     } |         FURI_LOG_E( | ||||||
| 
 |             TAG, "ExitRequest: APP_NOT_RUNNING, id %d, status: %d", request->command_id, status); | ||||||
|         rpc_send_and_release_empty(session, request->command_id, status); |         rpc_send_and_release_empty(session, request->command_id, status); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void rpc_system_app_load_file(const PB_Main* request, void* context) { | static void rpc_system_app_load_file(const PB_Main* request, void* context) { | ||||||
| @ -133,17 +132,18 @@ static void rpc_system_app_load_file(const PB_Main* request, void* context) { | |||||||
| 
 | 
 | ||||||
|     PB_CommandStatus status; |     PB_CommandStatus status; | ||||||
|     if(rpc_app->app_callback) { |     if(rpc_app->app_callback) { | ||||||
|         const char* file_path = request->content.app_load_file_request.path; |         FURI_LOG_D(TAG, "LoadFile: id %d", request->command_id); | ||||||
|         if(rpc_app->app_callback(RpcAppEventLoadFile, file_path, rpc_app->app_context)) { |         furi_assert(!rpc_app->last_id); | ||||||
|             status = PB_CommandStatus_OK; |         furi_assert(!rpc_app->last_data); | ||||||
|         } else { |         rpc_app->last_id = request->command_id; | ||||||
|             status = PB_CommandStatus_ERROR_APP_CMD_ERROR; |         rpc_app->last_data = strdup(request->content.app_load_file_request.path); | ||||||
|         } |         rpc_app->app_callback(RpcAppEventLoadFile, rpc_app->app_context); | ||||||
|     } else { |     } else { | ||||||
|         status = PB_CommandStatus_ERROR_APP_NOT_RUNNING; |         status = PB_CommandStatus_ERROR_APP_NOT_RUNNING; | ||||||
|     } |         FURI_LOG_E( | ||||||
| 
 |             TAG, "LoadFile: APP_NOT_RUNNING, id %d, status: %d", request->command_id, status); | ||||||
|         rpc_send_and_release_empty(session, request->command_id, status); |         rpc_send_and_release_empty(session, request->command_id, status); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void rpc_system_app_button_press(const PB_Main* request, void* context) { | static void rpc_system_app_button_press(const PB_Main* request, void* context) { | ||||||
| @ -157,18 +157,18 @@ static void rpc_system_app_button_press(const PB_Main* request, void* context) { | |||||||
| 
 | 
 | ||||||
|     PB_CommandStatus status; |     PB_CommandStatus status; | ||||||
|     if(rpc_app->app_callback) { |     if(rpc_app->app_callback) { | ||||||
|         const char* args = request->content.app_button_press_request.args; |         FURI_LOG_D(TAG, "ButtonPress"); | ||||||
|         if(rpc_app->app_callback(RpcAppEventButtonPress, args, rpc_app->app_context)) { |         furi_assert(!rpc_app->last_id); | ||||||
|             status = PB_CommandStatus_OK; |         furi_assert(!rpc_app->last_data); | ||||||
|             furi_timer_start(rpc_app->timer, APP_BUTTON_TIMEOUT); |         rpc_app->last_id = request->command_id; | ||||||
|         } else { |         rpc_app->last_data = strdup(request->content.app_button_press_request.args); | ||||||
|             status = PB_CommandStatus_ERROR_APP_CMD_ERROR; |         rpc_app->app_callback(RpcAppEventButtonPress, rpc_app->app_context); | ||||||
|         } |  | ||||||
|     } else { |     } else { | ||||||
|         status = PB_CommandStatus_ERROR_APP_NOT_RUNNING; |         status = PB_CommandStatus_ERROR_APP_NOT_RUNNING; | ||||||
|     } |         FURI_LOG_E( | ||||||
| 
 |             TAG, "ButtonPress: APP_NOT_RUNNING, id %d, status: %d", request->command_id, status); | ||||||
|         rpc_send_and_release_empty(session, request->command_id, status); |         rpc_send_and_release_empty(session, request->command_id, status); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void rpc_system_app_button_release(const PB_Main* request, void* context) { | static void rpc_system_app_button_release(const PB_Main* request, void* context) { | ||||||
| @ -182,17 +182,17 @@ static void rpc_system_app_button_release(const PB_Main* request, void* context) | |||||||
| 
 | 
 | ||||||
|     PB_CommandStatus status; |     PB_CommandStatus status; | ||||||
|     if(rpc_app->app_callback) { |     if(rpc_app->app_callback) { | ||||||
|         if(rpc_app->app_callback(RpcAppEventButtonRelease, NULL, rpc_app->app_context)) { |         FURI_LOG_D(TAG, "ButtonRelease"); | ||||||
|             status = PB_CommandStatus_OK; |         furi_assert(!rpc_app->last_id); | ||||||
|             furi_timer_stop(rpc_app->timer); |         furi_assert(!rpc_app->last_data); | ||||||
|         } else { |         rpc_app->last_id = request->command_id; | ||||||
|             status = PB_CommandStatus_ERROR_APP_CMD_ERROR; |         rpc_app->app_callback(RpcAppEventButtonRelease, rpc_app->app_context); | ||||||
|         } |  | ||||||
|     } else { |     } else { | ||||||
|         status = PB_CommandStatus_ERROR_APP_NOT_RUNNING; |         status = PB_CommandStatus_ERROR_APP_NOT_RUNNING; | ||||||
|     } |         FURI_LOG_E( | ||||||
| 
 |             TAG, "ButtonRelease: APP_NOT_RUNNING, id %d, status: %d", request->command_id, status); | ||||||
|         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) { | void rpc_system_app_send_started(RpcAppSystem* rpc_app) { | ||||||
| @ -201,6 +201,8 @@ void rpc_system_app_send_started(RpcAppSystem* rpc_app) { | |||||||
|     furi_assert(session); |     furi_assert(session); | ||||||
| 
 | 
 | ||||||
|     rpc_app->state_msg->content.app_state_response.state = PB_App_AppState_APP_STARTED; |     rpc_app->state_msg->content.app_state_response.state = PB_App_AppState_APP_STARTED; | ||||||
|  | 
 | ||||||
|  |     FURI_LOG_D(TAG, "SendStarted"); | ||||||
|     rpc_send(session, rpc_app->state_msg); |     rpc_send(session, rpc_app->state_msg); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -210,9 +212,46 @@ void rpc_system_app_send_exited(RpcAppSystem* rpc_app) { | |||||||
|     furi_assert(session); |     furi_assert(session); | ||||||
| 
 | 
 | ||||||
|     rpc_app->state_msg->content.app_state_response.state = PB_App_AppState_APP_CLOSED; |     rpc_app->state_msg->content.app_state_response.state = PB_App_AppState_APP_CLOSED; | ||||||
|  | 
 | ||||||
|  |     FURI_LOG_D(TAG, "SendExit"); | ||||||
|     rpc_send(session, rpc_app->state_msg); |     rpc_send(session, rpc_app->state_msg); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | const char* rpc_system_app_get_data(RpcAppSystem* rpc_app) { | ||||||
|  |     furi_assert(rpc_app); | ||||||
|  |     furi_assert(rpc_app->last_data); | ||||||
|  |     return rpc_app->last_data; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void rpc_system_app_confirm(RpcAppSystem* rpc_app, RpcAppSystemEvent event, bool result) { | ||||||
|  |     furi_assert(rpc_app); | ||||||
|  |     RpcSession* session = rpc_app->session; | ||||||
|  |     furi_assert(session); | ||||||
|  |     furi_assert(rpc_app->last_id); | ||||||
|  | 
 | ||||||
|  |     PB_CommandStatus status = result ? PB_CommandStatus_OK : PB_CommandStatus_ERROR_APP_CMD_ERROR; | ||||||
|  | 
 | ||||||
|  |     uint32_t last_id = 0; | ||||||
|  |     switch(event) { | ||||||
|  |     case RpcAppEventAppExit: | ||||||
|  |     case RpcAppEventLoadFile: | ||||||
|  |     case RpcAppEventButtonPress: | ||||||
|  |     case RpcAppEventButtonRelease: | ||||||
|  |         last_id = rpc_app->last_id; | ||||||
|  |         rpc_app->last_id = 0; | ||||||
|  |         if(rpc_app->last_data) { | ||||||
|  |             free(rpc_app->last_data); | ||||||
|  |             rpc_app->last_data = NULL; | ||||||
|  |         } | ||||||
|  |         FURI_LOG_D(TAG, "AppConfirm: event %d last_id %d status %d", event, last_id, status); | ||||||
|  |         rpc_send_and_release_empty(session, last_id, status); | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         furi_crash("RPC App state programming Error"); | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| 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); | ||||||
| 
 | 
 | ||||||
| @ -226,8 +265,6 @@ void* rpc_system_app_alloc(RpcSession* session) { | |||||||
|     RpcAppSystem* rpc_app = malloc(sizeof(RpcAppSystem)); |     RpcAppSystem* rpc_app = malloc(sizeof(RpcAppSystem)); | ||||||
|     rpc_app->session = session; |     rpc_app->session = session; | ||||||
| 
 | 
 | ||||||
|     rpc_app->timer = furi_timer_alloc(rpc_system_app_timer_callback, FuriTimerTypeOnce, rpc_app); |  | ||||||
| 
 |  | ||||||
|     // App exit message
 |     // App exit message
 | ||||||
|     rpc_app->state_msg = malloc(sizeof(PB_Main)); |     rpc_app->state_msg = malloc(sizeof(PB_Main)); | ||||||
|     rpc_app->state_msg->which_content = PB_Main_app_state_response_tag; |     rpc_app->state_msg->which_content = PB_Main_app_state_response_tag; | ||||||
| @ -265,12 +302,16 @@ void rpc_system_app_free(void* context) { | |||||||
|     RpcSession* session = rpc_app->session; |     RpcSession* session = rpc_app->session; | ||||||
|     furi_assert(session); |     furi_assert(session); | ||||||
| 
 | 
 | ||||||
|     furi_timer_free(rpc_app->timer); |  | ||||||
| 
 |  | ||||||
|     if(rpc_app->app_callback) { |     if(rpc_app->app_callback) { | ||||||
|         rpc_app->app_callback(RpcAppEventSessionClose, NULL, rpc_app->app_context); |         rpc_app->app_callback(RpcAppEventSessionClose, rpc_app->app_context); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     while(rpc_app->app_callback) { | ||||||
|  |         furi_delay_tick(1); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(rpc_app->last_data) free(rpc_app->last_data); | ||||||
|  | 
 | ||||||
|     free(rpc_app->state_msg); |     free(rpc_app->state_msg); | ||||||
|     free(rpc_app); |     free(rpc_app); | ||||||
| } | } | ||||||
|  | |||||||
| @ -13,7 +13,7 @@ typedef enum { | |||||||
|     RpcAppEventButtonRelease, |     RpcAppEventButtonRelease, | ||||||
| } RpcAppSystemEvent; | } RpcAppSystemEvent; | ||||||
| 
 | 
 | ||||||
| typedef bool (*RpcAppSystemCallback)(RpcAppSystemEvent event, const char* arg, void* context); | typedef void (*RpcAppSystemCallback)(RpcAppSystemEvent event, void* context); | ||||||
| 
 | 
 | ||||||
| typedef struct RpcAppSystem RpcAppSystem; | typedef struct RpcAppSystem RpcAppSystem; | ||||||
| 
 | 
 | ||||||
| @ -23,6 +23,10 @@ void rpc_system_app_send_started(RpcAppSystem* rpc_app); | |||||||
| 
 | 
 | ||||||
| void rpc_system_app_send_exited(RpcAppSystem* rpc_app); | void rpc_system_app_send_exited(RpcAppSystem* rpc_app); | ||||||
| 
 | 
 | ||||||
|  | const char* rpc_system_app_get_data(RpcAppSystem* rpc_app); | ||||||
|  | 
 | ||||||
|  | void rpc_system_app_confirm(RpcAppSystem* rpc_app, RpcAppSystemEvent event, bool result); | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -47,6 +47,9 @@ typedef enum { | |||||||
|     SubGhzCustomEventSceneStay, |     SubGhzCustomEventSceneStay, | ||||||
| 
 | 
 | ||||||
|     SubGhzCustomEventSceneRpcLoad, |     SubGhzCustomEventSceneRpcLoad, | ||||||
|  |     SubGhzCustomEventSceneRpcButtonPress, | ||||||
|  |     SubGhzCustomEventSceneRpcButtonRelease, | ||||||
|  |     SubGhzCustomEventSceneRpcSessionClose, | ||||||
| 
 | 
 | ||||||
|     SubGhzCustomEventViewReceiverOK, |     SubGhzCustomEventViewReceiverOK, | ||||||
|     SubGhzCustomEventViewReceiverConfig, |     SubGhzCustomEventViewReceiverConfig, | ||||||
|  | |||||||
| @ -22,8 +22,45 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { | |||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         consumed = true; |         consumed = true; | ||||||
|         if(event.event == SubGhzCustomEventSceneExit) { |         if(event.event == SubGhzCustomEventSceneExit) { | ||||||
|  |             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { | ||||||
|  |                 subghz_tx_stop(subghz); | ||||||
|  |                 subghz_sleep(subghz); | ||||||
|  |             } | ||||||
|             view_dispatcher_stop(subghz->view_dispatcher); |             view_dispatcher_stop(subghz->view_dispatcher); | ||||||
|  |             rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventAppExit, true); | ||||||
|  |         } else if(event.event == SubGhzCustomEventSceneRpcSessionClose) { | ||||||
|  |             rpc_system_app_set_callback(subghz->rpc_ctx, NULL, NULL); | ||||||
|  |             subghz->rpc_ctx = NULL; | ||||||
|  |             subghz_blink_stop(subghz); | ||||||
|  |             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { | ||||||
|  |                 subghz_tx_stop(subghz); | ||||||
|  |                 subghz_sleep(subghz); | ||||||
|  |             } | ||||||
|  |             view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneExit); | ||||||
|  |         } else if(event.event == SubGhzCustomEventSceneRpcButtonPress) { | ||||||
|  |             bool result = false; | ||||||
|  |             if(subghz->txrx->txrx_state == SubGhzTxRxStateSleep) { | ||||||
|  |                 subghz_blink_start(subghz); | ||||||
|  |                 result = subghz_tx_start(subghz, subghz->txrx->fff_data); | ||||||
|  |                 result = true; | ||||||
|  |             } | ||||||
|  |             rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonPress, result); | ||||||
|  |         } else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) { | ||||||
|  |             bool result = false; | ||||||
|  |             if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { | ||||||
|  |                 subghz_blink_stop(subghz); | ||||||
|  |                 subghz_tx_stop(subghz); | ||||||
|  |                 subghz_sleep(subghz); | ||||||
|  |                 result = true; | ||||||
|  |             } | ||||||
|  |             rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonRelease, result); | ||||||
|         } else if(event.event == SubGhzCustomEventSceneRpcLoad) { |         } else if(event.event == SubGhzCustomEventSceneRpcLoad) { | ||||||
|  |             bool result = false; | ||||||
|  |             const char* arg = rpc_system_app_get_data(subghz->rpc_ctx); | ||||||
|  |             if(arg) { | ||||||
|  |                 if(subghz_key_load(subghz, arg, false)) { | ||||||
|  |                     string_set_str(subghz->file_path, arg); | ||||||
|  |                     result = true; | ||||||
|                     string_t file_name; |                     string_t file_name; | ||||||
|                     string_init(file_name); |                     string_init(file_name); | ||||||
|                     path_extract_filename(subghz->file_path, file_name, true); |                     path_extract_filename(subghz->file_path, file_name, true); | ||||||
| @ -38,6 +75,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) { | |||||||
|                     string_clear(file_name); |                     string_clear(file_name); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |             rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventLoadFile, result); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|     return consumed; |     return consumed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -35,57 +35,38 @@ void subghz_tick_event_callback(void* context) { | |||||||
|     scene_manager_handle_tick_event(subghz->scene_manager); |     scene_manager_handle_tick_event(subghz->scene_manager); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool subghz_rpc_command_callback(RpcAppSystemEvent event, const char* arg, void* context) { | static void subghz_rpc_command_callback(RpcAppSystemEvent event, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     SubGhz* subghz = context; |     SubGhz* subghz = context; | ||||||
| 
 | 
 | ||||||
|     if(!subghz->rpc_ctx) { |     furi_assert(subghz->rpc_ctx); | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     bool result = false; |  | ||||||
| 
 | 
 | ||||||
|     if(event == RpcAppEventSessionClose) { |     if(event == RpcAppEventSessionClose) { | ||||||
|         rpc_system_app_set_callback(subghz->rpc_ctx, NULL, NULL); |         view_dispatcher_send_custom_event( | ||||||
|         subghz->rpc_ctx = NULL; |             subghz->view_dispatcher, SubGhzCustomEventSceneRpcSessionClose); | ||||||
|         notification_message(subghz->notifications, &sequence_blink_stop); |  | ||||||
|         view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneExit); |  | ||||||
|         if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { |  | ||||||
|             subghz_tx_stop(subghz); |  | ||||||
|             subghz_sleep(subghz); |  | ||||||
|         } |  | ||||||
|         result = true; |  | ||||||
|     } else if(event == RpcAppEventAppExit) { |     } else if(event == RpcAppEventAppExit) { | ||||||
|         view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneExit); |         view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneExit); | ||||||
|         if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { |  | ||||||
|             subghz_tx_stop(subghz); |  | ||||||
|             subghz_sleep(subghz); |  | ||||||
|         } |  | ||||||
|         result = true; |  | ||||||
|     } else if(event == RpcAppEventLoadFile) { |     } else if(event == RpcAppEventLoadFile) { | ||||||
|         if(arg) { |         view_dispatcher_send_custom_event(subghz->view_dispatcher, SubGhzCustomEventSceneRpcLoad); | ||||||
|             if(subghz_key_load(subghz, arg, false)) { |  | ||||||
|                 string_set_str(subghz->file_path, arg); |  | ||||||
|                 view_dispatcher_send_custom_event( |  | ||||||
|                     subghz->view_dispatcher, SubGhzCustomEventSceneRpcLoad); |  | ||||||
|                 result = true; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } else if(event == RpcAppEventButtonPress) { |     } else if(event == RpcAppEventButtonPress) { | ||||||
|         if(subghz->txrx->txrx_state == SubGhzTxRxStateSleep) { |         view_dispatcher_send_custom_event( | ||||||
|             notification_message(subghz->notifications, &sequence_blink_start_magenta); |             subghz->view_dispatcher, SubGhzCustomEventSceneRpcButtonPress); | ||||||
|             result = subghz_tx_start(subghz, subghz->txrx->fff_data); |  | ||||||
|         } |  | ||||||
|     } else if(event == RpcAppEventButtonRelease) { |     } else if(event == RpcAppEventButtonRelease) { | ||||||
|         if(subghz->txrx->txrx_state == SubGhzTxRxStateTx) { |         view_dispatcher_send_custom_event( | ||||||
|             notification_message(subghz->notifications, &sequence_blink_stop); |             subghz->view_dispatcher, SubGhzCustomEventSceneRpcButtonRelease); | ||||||
|             subghz_tx_stop(subghz); |     } else { | ||||||
|             subghz_sleep(subghz); |         rpc_system_app_confirm(subghz->rpc_ctx, event, false); | ||||||
|             result = true; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|     return result; | void subghz_blink_start(SubGhz* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     notification_message(instance->notifications, &sequence_blink_start_magenta); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void subghz_blink_stop(SubGhz* instance) { | ||||||
|  |     furi_assert(instance); | ||||||
|  |     notification_message(instance->notifications, &sequence_blink_stop); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| SubGhz* subghz_alloc() { | SubGhz* subghz_alloc() { | ||||||
| @ -237,7 +218,7 @@ 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); |         rpc_system_app_send_exited(subghz->rpc_ctx); | ||||||
|         notification_message(subghz->notifications, &sequence_blink_stop); |         subghz_blink_stop(subghz); | ||||||
|         subghz->rpc_ctx = NULL; |         subghz->rpc_ctx = NULL; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -108,6 +108,10 @@ void subghz_begin(SubGhz* subghz, uint8_t* preset_data); | |||||||
| uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency); | uint32_t subghz_rx(SubGhz* subghz, uint32_t frequency); | ||||||
| void subghz_rx_end(SubGhz* subghz); | void subghz_rx_end(SubGhz* subghz); | ||||||
| void subghz_sleep(SubGhz* subghz); | void subghz_sleep(SubGhz* subghz); | ||||||
|  | 
 | ||||||
|  | void subghz_blink_start(SubGhz* instance); | ||||||
|  | void subghz_blink_stop(SubGhz* instance); | ||||||
|  | 
 | ||||||
| bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format); | bool subghz_tx_start(SubGhz* subghz, FlipperFormat* flipper_format); | ||||||
| void subghz_tx_stop(SubGhz* subghz); | void subghz_tx_stop(SubGhz* subghz); | ||||||
| void subghz_dialog_message_show_only_rx(SubGhz* subghz); | void subghz_dialog_message_show_only_rx(SubGhz* subghz); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 あく
						あく