[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:
あく 2022-08-02 21:54:12 +09:00 committed by GitHub
parent f9386b2649
commit f9745b4141
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 378 additions and 270 deletions

View File

@ -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) {

View File

@ -12,4 +12,5 @@ enum iButtonCustomEvent {
iButtonCustomEventRpcLoad, iButtonCustomEventRpcLoad,
iButtonCustomEventRpcExit, iButtonCustomEventRpcExit,
iButtonCustomEventRpcSessionClose,
}; };

View File

@ -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, ...);

View File

@ -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,23 +27,40 @@ 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) {
string_t key_name; const char* arg = rpc_system_app_get_data(ibutton->rpc_ctx);
string_init(key_name); bool result = false;
if(string_end_with_str_p(ibutton->file_path, IBUTTON_APP_EXTENSION)) { if(arg) {
path_extract_filename(ibutton->file_path, key_name, true); 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_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);
result = true;
}
} }
rpc_system_app_confirm(ibutton->rpc_ctx, RpcAppEventLoadFile, result);
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) { } 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);
} }

View File

@ -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) { view_dispatcher_send_custom_event(
string_set_str(infrared->file_path, arg); infrared->view_dispatcher, InfraredCustomEventTypeRpcLoad);
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(
infrared->view_dispatcher, InfraredCustomEventTypeRpcLoaded);
}
} 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) {

View File

@ -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)

View File

@ -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;

View File

@ -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) {

View File

@ -33,6 +33,8 @@ public:
Retry, Retry,
Exit, Exit,
EmulateStart, EmulateStart,
RpcLoadFile,
RpcSessionClose,
}; };
enum class SceneType : uint8_t { enum class SceneType : uint8_t {

View File

@ -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;
} }

View File

@ -11,4 +11,5 @@ enum NfcCustomEvent {
NfcCustomEventDictAttackDone, NfcCustomEventDictAttackDone,
NfcCustomEventDictAttackSkip, NfcCustomEventDictAttackSkip,
NfcCustomEventRpcLoad, NfcCustomEventRpcLoad,
NfcCustomEventRpcSessionClose,
}; };

View File

@ -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)) { view_dispatcher_send_custom_event(nfc->view_dispatcher, NfcCustomEventRpcLoad);
if(nfc_device_load(nfc->dev, arg, false)) { } else {
if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) { rpc_system_app_confirm(nfc->rpc_ctx, event, false);
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);
result = true;
}
}
} }
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);

View File

@ -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);

View File

@ -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,13 +30,47 @@ 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_text_store_set(nfc, "emulating\n%s", nfc->dev->dev_name); nfc_blink_start(nfc);
popup_set_text(popup, nfc->text_store, 82, 32, AlignCenter, AlignTop); nfc_text_store_set(nfc, "emulating\n%s", nfc->dev->dev_name);
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);

View File

@ -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);
} }

View File

@ -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

View File

@ -47,6 +47,9 @@ typedef enum {
SubGhzCustomEventSceneStay, SubGhzCustomEventSceneStay,
SubGhzCustomEventSceneRpcLoad, SubGhzCustomEventSceneRpcLoad,
SubGhzCustomEventSceneRpcButtonPress,
SubGhzCustomEventSceneRpcButtonRelease,
SubGhzCustomEventSceneRpcSessionClose,
SubGhzCustomEventViewReceiverOK, SubGhzCustomEventViewReceiverOK,
SubGhzCustomEventViewReceiverConfig, SubGhzCustomEventViewReceiverConfig,

View File

@ -22,20 +22,60 @@ 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) {
string_t file_name; bool result = false;
string_init(file_name); const char* arg = rpc_system_app_get_data(subghz->rpc_ctx);
path_extract_filename(subghz->file_path, file_name, true); if(arg) {
if(subghz_key_load(subghz, arg, false)) {
string_set_str(subghz->file_path, arg);
result = true;
string_t file_name;
string_init(file_name);
path_extract_filename(subghz->file_path, file_name, true);
snprintf( snprintf(
subghz->file_name_tmp, subghz->file_name_tmp,
SUBGHZ_MAX_LEN_NAME, SUBGHZ_MAX_LEN_NAME,
"loaded\n%s", "loaded\n%s",
string_get_cstr(file_name)); string_get_cstr(file_name));
popup_set_text(popup, subghz->file_name_tmp, 82, 32, AlignCenter, AlignTop); popup_set_text(popup, subghz->file_name_tmp, 82, 32, AlignCenter, AlignTop);
string_clear(file_name); string_clear(file_name);
}
}
rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventLoadFile, result);
} }
} }
return consumed; return consumed;

View File

@ -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;
} }

View File

@ -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);