mirror of
https://protopirate.net/ProtoPirate/ProtoPirate.git
synced 2026-10-06 20:07:17 +00:00
SAVED INFO PLUGIN: Moved Saved Info into its own plugin.
* Has full host API, no FW included functions. * Emulate and BF working well. * Delete not crashing * Share Load and Unload functons for Config and Saved Info plugin (Smaller code) * Get rid of Saved Info Screen Flash when Emulating from favorites
This commit is contained in:
@@ -24,6 +24,8 @@ _MAIN_APP_SOURCES = [
|
||||
"!protocols",
|
||||
"!protopirate_emulate_plugin.c",
|
||||
"!protopirate_psa_bf_plugin.c",
|
||||
"!protopirate_saved_info_plugin.c",
|
||||
"!protopirate_config_plugin.c",
|
||||
"protocols/protocol_items.c",
|
||||
"protocols/protocols_common.c",
|
||||
"!raw_file_reader.c",
|
||||
@@ -435,4 +437,18 @@ App(
|
||||
],
|
||||
fap_icon_assets="images",
|
||||
fal_embedded=True,
|
||||
)
|
||||
|
||||
App(
|
||||
appid="protopirate_saved_info_plugin",
|
||||
apptype=FlipperAppType.PLUGIN,
|
||||
entry_point="protopirate_saved_info_plugin_ep",
|
||||
requires=["proto_pirate"],
|
||||
cdefines=["PROTOPIRATE_SAVED_INFO_PLUGIN_BUILD"],
|
||||
sources=[
|
||||
"scenes/plugins/protopirate_saved_info_plugin.c",
|
||||
"protocols/protocols_common.c",
|
||||
],
|
||||
fap_icon_assets="images",
|
||||
fal_embedded=True,
|
||||
)
|
||||
@@ -31,11 +31,13 @@ typedef enum {
|
||||
ProtoPirateCustomEventReceiverInfoUpdate,
|
||||
ProtoPirateCustomEventReceiverInfoEmulate,
|
||||
ProtoPirateCustomEventSavedInfoDelete,
|
||||
ProtoPirateCustomEventSavedInfoExit,
|
||||
//Bruteforcing PSA & Renault
|
||||
ProtoPirateCustomEventBruteforceStart,
|
||||
ProtoPirateCustomEventBruteforceComplete,
|
||||
// Emulator
|
||||
ProtoPirateCustomEventSavedInfoEmulate,
|
||||
ProtoPirateCustomEventSavedInfoEmulateDelayedStart,
|
||||
ProtoPirateCustomEventEmulateTransmit,
|
||||
ProtoPirateCustomEventEmulateStop,
|
||||
ProtoPirateCustomEventEmulateExit,
|
||||
|
||||
+50
-39
@@ -15,10 +15,13 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// Plugin load / unload
|
||||
// -----------------------------------------------------------------------------
|
||||
void config_plugin_unload(ProtoPirateApp* app) {
|
||||
void config_or_saved_plugin_unload(ProtoPirateApp* app, bool unload_config) {
|
||||
furi_check(app);
|
||||
|
||||
app->config_plugin = NULL;
|
||||
if(unload_config)
|
||||
app->config_plugin = NULL;
|
||||
else
|
||||
app->saved_info_plugin = NULL;
|
||||
|
||||
if(app->plugin_manager) {
|
||||
plugin_manager_free(app->plugin_manager);
|
||||
@@ -31,15 +34,17 @@ void config_plugin_unload(ProtoPirateApp* app) {
|
||||
}
|
||||
}
|
||||
|
||||
bool config_plugin_load(
|
||||
ProtoPirateApp* app,
|
||||
const ProtoPirateConfigSceneHostApi* protopirate_config_scene_host_api) {
|
||||
bool config_or_saved_plugin_load(ProtoPirateApp* app, bool load_config) {
|
||||
furi_check(app);
|
||||
|
||||
if(app->config_plugin) return true;
|
||||
if(load_config) {
|
||||
if(app->config_plugin) return true;
|
||||
} else {
|
||||
if(app->saved_info_plugin) return true;
|
||||
}
|
||||
|
||||
if(app->plugin_manager || app->plugin_resolver) {
|
||||
config_plugin_unload(app);
|
||||
config_or_saved_plugin_unload(app, load_config);
|
||||
}
|
||||
|
||||
CompositeApiResolver* resolver = composite_api_resolver_alloc();
|
||||
@@ -50,16 +55,18 @@ bool config_plugin_load(
|
||||
composite_api_resolver_add(resolver, firmware_api_interface);
|
||||
|
||||
PluginManager* manager = plugin_manager_alloc(
|
||||
PROTOPIRATE_CONFIG_PLUGIN_APP_ID,
|
||||
PROTOPIRATE_CONFIG_PLUGIN_API_VERSION,
|
||||
(load_config) ? PROTOPIRATE_CONFIG_PLUGIN_APP_ID : PROTOPIRATE_SAVED_INFO_PLUGIN_APP_ID,
|
||||
(load_config) ? PROTOPIRATE_CONFIG_PLUGIN_API_VERSION :
|
||||
PROTOPIRATE_SAVED_INFO_PLUGIN_API_VERSION,
|
||||
composite_api_resolver_get(resolver));
|
||||
if(!manager) {
|
||||
FURI_LOG_E(TAG, "Failed to allocate config plugin manager");
|
||||
FURI_LOG_E(TAG, "Failed to allocate plugin manager");
|
||||
composite_api_resolver_free(resolver);
|
||||
return false;
|
||||
}
|
||||
|
||||
PluginManagerError error = plugin_manager_load_single(manager, CONFIG_PLUGIN_PATH);
|
||||
PluginManagerError error = plugin_manager_load_single(
|
||||
manager, (load_config) ? CONFIG_PLUGIN_PATH : SAVED_INFO_PLUGIN_PATH);
|
||||
if(error != PluginManagerErrorNone) {
|
||||
FURI_LOG_E(TAG, "Failed to load config plugin %s: %d", CONFIG_PLUGIN_PATH, (int)error);
|
||||
plugin_manager_free(manager);
|
||||
@@ -67,18 +74,28 @@ bool config_plugin_load(
|
||||
return false;
|
||||
}
|
||||
|
||||
const ProtoPirateConfigPlugin* plugin = plugin_manager_get_ep(manager, 0U);
|
||||
if(!plugin || !plugin->on_enter) {
|
||||
FURI_LOG_E(TAG, "Config plugin entry point is invalid");
|
||||
plugin_manager_free(manager);
|
||||
composite_api_resolver_free(resolver);
|
||||
return false;
|
||||
}
|
||||
if(load_config) {
|
||||
const ProtoPirateConfigPlugin* plugin_config = plugin_manager_get_ep(manager, 0U);
|
||||
if(!plugin_config || !plugin_config->on_enter) {
|
||||
FURI_LOG_E(TAG, "Config plugin entry point is invalid");
|
||||
plugin_manager_free(manager);
|
||||
composite_api_resolver_free(resolver);
|
||||
return false;
|
||||
}
|
||||
app->config_plugin = plugin_config;
|
||||
} else {
|
||||
const ProtoPirateSavedInfoPlugin* plugin_saved_info = plugin_manager_get_ep(manager, 0U);
|
||||
if(!plugin_saved_info || !plugin_saved_info->on_enter) {
|
||||
FURI_LOG_E(TAG, "Saved Info plugin entry point is invalid");
|
||||
plugin_manager_free(manager);
|
||||
composite_api_resolver_free(resolver);
|
||||
return false;
|
||||
}
|
||||
app->saved_info_plugin = plugin_saved_info;
|
||||
};
|
||||
|
||||
app->plugin_resolver = resolver;
|
||||
app->plugin_manager = manager;
|
||||
app->config_plugin = plugin;
|
||||
plugin->set_host_api(protopirate_config_scene_host_api);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -225,7 +242,7 @@ ProtoPirateApp* protopirate_app_alloc() {
|
||||
settings.auto_save,
|
||||
settings.hopping_enabled);
|
||||
|
||||
config_plugin_load(app, NULL);
|
||||
config_or_saved_plugin_load(app, true);
|
||||
app->car_models_count = app->config_plugin->car_model_get_count();
|
||||
app->selected_model = malloc(sizeof(ProtoPirateCarModel));
|
||||
app->selected_model->name = furi_string_alloc();
|
||||
@@ -251,7 +268,7 @@ ProtoPirateApp* protopirate_app_alloc() {
|
||||
|
||||
protopirate_preset_init(app, preset_name, frequency, preset_data, preset_data_size);
|
||||
}
|
||||
config_plugin_unload(app);
|
||||
config_or_saved_plugin_unload(app, true);
|
||||
|
||||
// Apply hopping state from settings
|
||||
app->txrx->hopper_state = settings.hopping_enabled ? ProtoPirateHopperStateRunning :
|
||||
@@ -397,6 +414,7 @@ void protopirate_app_free(ProtoPirateApp* app) {
|
||||
}
|
||||
|
||||
int32_t protopirate_app(char* p) {
|
||||
//Stop charging while running the app.
|
||||
furi_hal_power_suppress_charge_enter();
|
||||
|
||||
ProtoPirateApp* protopirate_app = protopirate_app_alloc();
|
||||
@@ -408,31 +426,24 @@ int32_t protopirate_app(char* p) {
|
||||
// Handle Command line PSF that may have been passed to us
|
||||
bool load_saved = (p && strlen(p));
|
||||
if(load_saved) protopirate_app->loaded_file_path = furi_string_alloc_set(p);
|
||||
|
||||
//We now jump straight to emulate scene from Browser.
|
||||
scene_manager_next_scene(
|
||||
protopirate_app->scene_manager,
|
||||
(load_saved) ? ProtoPirateSceneSavedInfo : ProtoPirateSceneStart);
|
||||
(load_saved) ? ((protopirate_app->emulate_feature_enabled) ? ProtoPirateSceneEmulate :
|
||||
ProtoPirateSceneSavedInfo) :
|
||||
ProtoPirateSceneStart);
|
||||
|
||||
//We now jump straight to emulate scene from Browser. If the user wanted the key to look at, just click back.
|
||||
if(load_saved) {
|
||||
#ifdef ENABLE_EMULATE_FEATURE
|
||||
if(protopirate_app->emulate_feature_enabled) {
|
||||
view_dispatcher_send_custom_event(
|
||||
protopirate_app->view_dispatcher, ProtoPirateCustomEventSavedInfoEmulate);
|
||||
notification_message(protopirate_app->notifications, &sequence_success);
|
||||
} else {
|
||||
#endif
|
||||
view_dispatcher_send_custom_event(
|
||||
protopirate_app->view_dispatcher, ProtoPirateCustomEventReceiverInfoSave);
|
||||
#ifdef ENABLE_EMULATE_FEATURE
|
||||
}
|
||||
#endif
|
||||
//Pop up the beep if we are startng emulate.
|
||||
if(load_saved && protopirate_app->emulate_feature_enabled) {
|
||||
notification_message(protopirate_app->notifications, &sequence_success);
|
||||
}
|
||||
|
||||
//Run the App
|
||||
view_dispatcher_run(protopirate_app->view_dispatcher);
|
||||
|
||||
//Free the App and allow chargin again.
|
||||
protopirate_app_free(protopirate_app);
|
||||
|
||||
furi_hal_power_suppress_charge_exit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+6
-5
@@ -33,6 +33,7 @@
|
||||
#include "scenes/plugins/protopirate_emulate_plugin.h"
|
||||
#endif
|
||||
#include "scenes/plugins/protopirate_config_plugin.h"
|
||||
#include "scenes/plugins/protopirate_saved_info_plugin.h"
|
||||
#include "scenes/plugins/protopirate_psa_bf_plugin.h"
|
||||
#include "scenes/plugins/protopirate_tool_scene_plugin.h"
|
||||
#include "helpers/protopirate_views.h"
|
||||
@@ -43,7 +44,8 @@
|
||||
#include <loader/firmware_api/firmware_api.h>
|
||||
#include "helpers/protopirate_settings.h"
|
||||
|
||||
#define CONFIG_PLUGIN_PATH APP_ASSETS_PATH("plugins/protopirate_config_plugin.fal")
|
||||
#define CONFIG_PLUGIN_PATH APP_ASSETS_PATH("plugins/protopirate_config_plugin.fal")
|
||||
#define SAVED_INFO_PLUGIN_PATH APP_ASSETS_PATH("plugins/protopirate_saved_info_plugin.fal")
|
||||
|
||||
#define PROTOPIRATE_KEYSTORE_DIR_NAME APP_ASSETS_PATH("encrypted")
|
||||
|
||||
@@ -111,6 +113,7 @@ struct ProtoPirateApp {
|
||||
uint8_t emulate_nav_pending;
|
||||
#endif
|
||||
const ProtoPirateConfigPlugin* config_plugin;
|
||||
const ProtoPirateSavedInfoPlugin* saved_info_plugin;
|
||||
CompositeApiResolver* psa_bf_plugin_resolver;
|
||||
PluginManager* psa_bf_plugin_manager;
|
||||
const ProtoPiratePsaBfPlugin* psa_bf_plugin;
|
||||
@@ -143,10 +146,8 @@ bool protopirate_tool_scene_on_event(void* app, SceneManagerEvent event);
|
||||
void protopirate_tool_scene_on_exit(void* app);
|
||||
void protopirate_tool_scene_plugin_release(ProtoPirateApp* app);
|
||||
|
||||
bool config_plugin_load(
|
||||
ProtoPirateApp* app,
|
||||
const ProtoPirateConfigSceneHostApi* protopirate_config_scene_host_api);
|
||||
void config_plugin_unload(ProtoPirateApp* app);
|
||||
bool config_or_saved_plugin_load(ProtoPirateApp* app, bool load_config);
|
||||
void config_or_saved_plugin_unload(ProtoPirateApp* app, bool unload_config);
|
||||
|
||||
void protopirate_app_free(ProtoPirateApp* app);
|
||||
|
||||
|
||||
@@ -0,0 +1,377 @@
|
||||
#include "protopirate_saved_info_plugin.h"
|
||||
#include "../../protopirate_app_i.h"
|
||||
#include "../../helpers/protopirate_storage.h"
|
||||
#include "../../protocols/protocols_common.h"
|
||||
#include "../../protocols/protocol_items.h"
|
||||
#include "protopirate_saved_info_plugin_icons.h"
|
||||
|
||||
static const ProtoPirateSavedInfoSceneHostApi* g_saved_info_scene_host_api = NULL;
|
||||
|
||||
#define TAG "ProtoPirateSavedInfoPlugin"
|
||||
|
||||
#define STATE_EMULATE 0
|
||||
#define STATE_BF 1
|
||||
|
||||
static void plugin_protopirate_scene_saved_info_widget_callback(
|
||||
GuiButtonType result,
|
||||
InputType type,
|
||||
void* context) {
|
||||
ProtoPirateApp* app = context;
|
||||
|
||||
if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
|
||||
const uint32_t left_event =
|
||||
(scene_manager_get_scene_state(app->scene_manager, ProtoPirateSceneSavedInfo) ==
|
||||
STATE_BF) ?
|
||||
ProtoPirateCustomEventBruteforceStart :
|
||||
ProtoPirateCustomEventSavedInfoEmulate;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, left_event);
|
||||
} else if(result == GuiButtonTypeRight && (type == InputTypeShort)) {
|
||||
//Send delete event and get user confirmation to delete.
|
||||
view_dispatcher_send_custom_event(
|
||||
app->view_dispatcher, ProtoPirateCustomEventSavedInfoDelete);
|
||||
}
|
||||
}
|
||||
|
||||
void plugin_protopirate_scene_saved_info_on_enter(void* context) {
|
||||
furi_check(context);
|
||||
ProtoPirateApp* app = context;
|
||||
Storage* storage = NULL;
|
||||
FlipperFormat* ff = NULL;
|
||||
FuriString* info_str = NULL;
|
||||
FuriString* temp_str = NULL;
|
||||
bool success = false;
|
||||
|
||||
FURI_LOG_I(TAG, "=== ENTER START ===");
|
||||
|
||||
//protopirate_release_shared_radio_state(app);
|
||||
|
||||
if(!g_saved_info_scene_host_api->ensure_widget(app)) {
|
||||
notification_message(app->notifications, &sequence_error);
|
||||
view_dispatcher_send_custom_event(
|
||||
app->view_dispatcher, ProtoPirateCustomEventSavedInfoExit);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset widget first
|
||||
widget_reset(app->widget);
|
||||
|
||||
// Validate file path
|
||||
if(!app->loaded_file_path || furi_string_empty(app->loaded_file_path)) {
|
||||
FURI_LOG_E(TAG, "No file path");
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 32, AlignCenter, AlignCenter, FontPrimary, "No file selected");
|
||||
goto switch_view;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Path: %s", furi_string_get_cstr(app->loaded_file_path));
|
||||
|
||||
// Allocate strings first (no I/O)
|
||||
info_str = furi_string_alloc();
|
||||
temp_str = furi_string_alloc();
|
||||
if(!info_str || !temp_str) {
|
||||
FURI_LOG_E(TAG, "String alloc failed");
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 32, AlignCenter, AlignCenter, FontPrimary, "Memory error");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Strings allocated");
|
||||
|
||||
// Open storage
|
||||
FURI_LOG_I(TAG, "Opening storage...");
|
||||
storage = furi_record_open(RECORD_STORAGE);
|
||||
if(!storage) {
|
||||
FURI_LOG_E(TAG, "Storage open failed");
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 32, AlignCenter, AlignCenter, FontPrimary, "Storage error");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Storage opened");
|
||||
|
||||
// Allocate flipper format
|
||||
FURI_LOG_I(TAG, "Allocating FF...");
|
||||
ff = flipper_format_file_alloc(storage);
|
||||
if(!ff) {
|
||||
FURI_LOG_E(TAG, "FF alloc failed");
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 32, AlignCenter, AlignCenter, FontPrimary, "Memory error");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "FF allocated");
|
||||
|
||||
// Open file
|
||||
FURI_LOG_I(TAG, "Opening file...");
|
||||
if(!flipper_format_file_open_existing(ff, furi_string_get_cstr(app->loaded_file_path))) {
|
||||
FURI_LOG_E(TAG, "File open failed");
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 32, AlignCenter, AlignCenter, FontPrimary, "File open failed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "File opened, reading...");
|
||||
bool offers_bf = false;
|
||||
|
||||
// Read fields
|
||||
uint32_t temp_data = 0;
|
||||
app->emulate_disabled_for_loaded = true;
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_string(ff, FF_PROTOCOL, temp_str)) {
|
||||
const char* protocol_name = furi_string_get_cstr(temp_str);
|
||||
furi_string_cat_printf(info_str, "Protocol: %s\n", protocol_name);
|
||||
|
||||
//Can we emulate this type?
|
||||
app->emulate_disabled_for_loaded =
|
||||
!g_saved_info_scene_host_api->protocol_catalog_can_tx(protocol_name);
|
||||
|
||||
//Do we need to offer a Brute Force Option?
|
||||
offers_bf = g_saved_info_scene_host_api->protocol_catalog_offers_bruteforce(protocol_name);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, FF_FREQUENCY, &temp_data, 1)) {
|
||||
furi_string_cat_printf(
|
||||
info_str, "Freq: %lu.%02lu MHz\n", temp_data / 1000000, (temp_data % 1000000) / 10000);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_string(ff, FF_PRESET, temp_str)) {
|
||||
// Convert full preset name to short name
|
||||
const char* preset_name = pp_get_short_preset_name(furi_string_get_cstr(temp_str));
|
||||
furi_string_cat_printf(info_str, "Modulation: %s\n", preset_name);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, FF_SERIAL, &temp_data, 1)) {
|
||||
furi_string_cat_printf(info_str, "Serial: %08lX\n", temp_data);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, FF_BTN, &temp_data, 1)) {
|
||||
furi_string_cat_printf(info_str, "Button: %02X\n", (uint8_t)temp_data);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, FF_CNT, &temp_data, 1)) {
|
||||
furi_string_cat_printf(info_str, "Counter: %04lX\n", temp_data);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, "Checksum", &temp_data, 1)) {
|
||||
furi_string_cat_printf(info_str, "Checksum: %02X\n", (uint8_t)temp_data);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, "CRC", &temp_data, 1)) {
|
||||
furi_string_cat_printf(info_str, "CRC: %02X\n", (uint8_t)temp_data);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, FF_TYPE, &temp_data, 1)) {
|
||||
furi_string_cat_printf(info_str, "Type: %02X\n", (uint8_t)temp_data);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, "KeyIdx", &temp_data, 1)) {
|
||||
furi_string_cat_printf(info_str, "KeyIdx: %d\n", (uint8_t)temp_data);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_string(ff, FF_KEY, temp_str)) {
|
||||
furi_string_cat_printf(info_str, "Key1: %s\n", furi_string_get_cstr(temp_str));
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_string(ff, "Key_2", temp_str)) {
|
||||
furi_string_cat_printf(info_str, "Key2: %s\n", furi_string_get_cstr(temp_str));
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, "ValidationField", &temp_data, 1)) {
|
||||
furi_string_cat_printf(info_str, "ValField: %04X\n", (uint16_t)temp_data);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, "Seed", &temp_data, 1)) {
|
||||
furi_string_cat_printf(info_str, "Seed: %02X\n", (uint8_t)temp_data);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_string(ff, FF_MANUFACTURE, temp_str)) {
|
||||
furi_string_cat_printf(info_str, "Manufacture: %s\n", furi_string_get_cstr(temp_str));
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Read complete, len=%u", furi_string_size(info_str));
|
||||
success = true;
|
||||
|
||||
cleanup:
|
||||
// Now do widget operations
|
||||
if(success && info_str && furi_string_size(info_str) > 0) {
|
||||
FURI_LOG_I(TAG, "Adding scroll element");
|
||||
widget_add_text_scroll_element(app->widget, 0, 0, 128, 50, furi_string_get_cstr(info_str));
|
||||
|
||||
bool needs_bf = false;
|
||||
if(offers_bf && g_saved_info_scene_host_api->psa_bf_plugin_ensure_loaded(app) &&
|
||||
app->psa_bf_plugin) {
|
||||
needs_bf = app->psa_bf_plugin->widget_left_should_bruteforce(app, ff);
|
||||
}
|
||||
|
||||
g_saved_info_scene_host_api->psa_bf_plugin_unload_if_idle(app);
|
||||
if(needs_bf) {
|
||||
scene_manager_set_scene_state(app->scene_manager, ProtoPirateSceneSavedInfo, STATE_BF);
|
||||
widget_add_button_element(
|
||||
app->widget,
|
||||
GuiButtonTypeLeft,
|
||||
"BF",
|
||||
plugin_protopirate_scene_saved_info_widget_callback,
|
||||
app);
|
||||
} else {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, ProtoPirateSceneSavedInfo, STATE_EMULATE);
|
||||
#ifdef ENABLE_EMULATE_FEATURE
|
||||
if(app->emulate_feature_enabled && !app->emulate_disabled_for_loaded) {
|
||||
widget_add_button_element(
|
||||
app->widget,
|
||||
GuiButtonTypeLeft,
|
||||
"Emulate",
|
||||
plugin_protopirate_scene_saved_info_widget_callback,
|
||||
app);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
widget_add_button_element(
|
||||
app->widget,
|
||||
GuiButtonTypeRight,
|
||||
"Delete",
|
||||
plugin_protopirate_scene_saved_info_widget_callback,
|
||||
app);
|
||||
}
|
||||
|
||||
// Close file and storage BEFORE widget operations
|
||||
if(ff) {
|
||||
flipper_format_free(ff);
|
||||
ff = NULL;
|
||||
}
|
||||
if(storage) {
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
storage = NULL;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Storage closed");
|
||||
|
||||
// Free strings
|
||||
if(temp_str) furi_string_free(temp_str);
|
||||
if(info_str) furi_string_free(info_str);
|
||||
|
||||
FURI_LOG_I(TAG, "Cleanup done");
|
||||
|
||||
switch_view:
|
||||
FURI_LOG_I(TAG, "Switching to widget");
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, ProtoPirateViewWidget);
|
||||
FURI_LOG_I(TAG, "=== ENTER DONE ===");
|
||||
}
|
||||
|
||||
bool plugin_protopirate_scene_saved_info_on_event(void* context, SceneManagerEvent event) {
|
||||
ProtoPirateApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
//load_emu* = false;
|
||||
if(event.type == SceneManagerEventTypeTick) {
|
||||
if(app->psa_bf_plugin && app->psa_bf_plugin->is_running(app)) {
|
||||
app->psa_bf_plugin->on_scene_event(app, ProtoPiratePsaBfContextSavedInfo, event);
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
return (
|
||||
app->psa_bf_plugin && app->psa_bf_plugin->is_running &&
|
||||
app->psa_bf_plugin->on_scene_event(app, ProtoPiratePsaBfContextReceiverInfo, event));
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == ProtoPirateCustomEventSavedInfoDelete) {
|
||||
FURI_LOG_I(TAG, "Delete requested");
|
||||
if(app->loaded_file_path && !furi_string_empty(app->loaded_file_path)) {
|
||||
DialogMessage* message = dialog_message_alloc();
|
||||
dialog_message_set_buttons(message, "Delete", NULL, "Keep");
|
||||
dialog_message_set_icon(message, &I_WarningDolphin_45x42, 0, 12);
|
||||
dialog_message_set_header(
|
||||
message, "Confirm Delete Action", 64, 0, AlignCenter, AlignTop);
|
||||
dialog_message_set_text(
|
||||
message,
|
||||
"Are you sure you\nwant to delete\nthis file?",
|
||||
50,
|
||||
14,
|
||||
AlignLeft,
|
||||
AlignTop);
|
||||
DialogMessageButton dialog_result = dialog_message_show(app->dialogs, message);
|
||||
dialog_message_free(message);
|
||||
|
||||
//Delete if the user said yes.
|
||||
if(dialog_result == DialogMessageButtonLeft) {
|
||||
notification_message(app->notifications, &sequence_semi_success);
|
||||
g_saved_info_scene_host_api->storage_delete_file(
|
||||
furi_string_get_cstr(app->loaded_file_path));
|
||||
|
||||
view_dispatcher_send_custom_event(
|
||||
app->view_dispatcher, ProtoPirateCustomEventSavedInfoExit);
|
||||
}
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
if(event.event == ProtoPirateCustomEventBruteforceStart ||
|
||||
event.event == ProtoPirateCustomEventBruteforceComplete) {
|
||||
if(g_saved_info_scene_host_api->psa_bf_plugin_ensure_loaded(app) &&
|
||||
app->psa_bf_plugin &&
|
||||
app->psa_bf_plugin->on_scene_event(app, ProtoPiratePsaBfContextSavedInfo, event)) {
|
||||
}
|
||||
if(event.event == ProtoPirateCustomEventBruteforceComplete)
|
||||
plugin_protopirate_scene_saved_info_on_enter(app);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_EMULATE_FEATURE
|
||||
if(event.event == ProtoPirateCustomEventSavedInfoEmulate && app->emulate_feature_enabled &&
|
||||
!app->emulate_disabled_for_loaded) {
|
||||
FURI_LOG_I(TAG, "Emulate requested");
|
||||
|
||||
//Send custom event back to the scene, so it can start emulate for us and avoid the crashes.
|
||||
view_dispatcher_send_custom_event(
|
||||
app->view_dispatcher, ProtoPirateCustomEventSavedInfoEmulateDelayedStart);
|
||||
|
||||
consumed = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void plugin_protopirate_scene_saved_info_on_exit(void* context) {
|
||||
ProtoPirateApp* app = context;
|
||||
UNUSED(app);
|
||||
FURI_LOG_I(TAG, "Exiting SavedInfo scene");
|
||||
widget_reset(app->widget);
|
||||
}
|
||||
|
||||
void saved_info_plugin_set_host_api(const ProtoPirateSavedInfoSceneHostApi* host_api) {
|
||||
g_saved_info_scene_host_api = host_api;
|
||||
}
|
||||
|
||||
static const ProtoPirateSavedInfoPlugin protopirate_saved_info_plugin = {
|
||||
.plugin_name = "ProtoPirate Saved Info",
|
||||
.on_enter = plugin_protopirate_scene_saved_info_on_enter,
|
||||
.on_event = plugin_protopirate_scene_saved_info_on_event,
|
||||
.on_exit = plugin_protopirate_scene_saved_info_on_exit,
|
||||
.set_host_api = saved_info_plugin_set_host_api,
|
||||
};
|
||||
|
||||
static const FlipperAppPluginDescriptor protopirate_saved_info_plugin_descriptor = {
|
||||
.appid = PROTOPIRATE_SAVED_INFO_PLUGIN_APP_ID,
|
||||
.ep_api_version = PROTOPIRATE_SAVED_INFO_PLUGIN_API_VERSION,
|
||||
.entry_point = &protopirate_saved_info_plugin,
|
||||
};
|
||||
|
||||
const FlipperAppPluginDescriptor* protopirate_saved_info_plugin_ep(void) {
|
||||
return &protopirate_saved_info_plugin_descriptor;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
#define PROTOPIRATE_SAVED_INFO_PLUGIN_APP_ID "protopirate_saved_info_plugin"
|
||||
#define PROTOPIRATE_SAVED_INFO_PLUGIN_API_VERSION 1U
|
||||
|
||||
typedef struct ProtoPirateApp ProtoPirateApp;
|
||||
typedef struct ProtoPirateSavedInfoSceneHostApi {
|
||||
bool (*ensure_widget)(ProtoPirateApp* app);
|
||||
bool (*psa_bf_plugin_ensure_loaded)(ProtoPirateApp* app);
|
||||
void (*psa_bf_plugin_unload_if_idle)(ProtoPirateApp* app);
|
||||
bool (*protocol_catalog_can_tx)(const char* protocol_name);
|
||||
bool (*storage_delete_file)(const char* file_path);
|
||||
bool (*protocol_catalog_offers_bruteforce)(const char* protocol_name);
|
||||
} ProtoPirateSavedInfoSceneHostApi;
|
||||
|
||||
typedef struct ProtoPirateSavedInfoPlugin {
|
||||
const char* plugin_name;
|
||||
void (*on_enter)(void* app);
|
||||
void (*on_exit)(void* app);
|
||||
bool (*on_event)(void* app, SceneManagerEvent event);
|
||||
void (*set_host_api)(const ProtoPirateSavedInfoSceneHostApi* host_api);
|
||||
} ProtoPirateSavedInfoPlugin;
|
||||
@@ -11,12 +11,12 @@ static const ProtoPirateConfigSceneHostApi protopirate_config_scene_host_api = {
|
||||
void protopirate_scene_receiver_config_on_enter(void* context) {
|
||||
ProtoPirateApp* app = context;
|
||||
|
||||
if(!config_plugin_load(app, &protopirate_config_scene_host_api)) {
|
||||
if(!config_or_saved_plugin_load(app, true)) {
|
||||
notification_message(app->notifications, &sequence_error);
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
return;
|
||||
}
|
||||
|
||||
app->config_plugin->set_host_api(&protopirate_config_scene_host_api);
|
||||
app->config_plugin->on_enter(app);
|
||||
}
|
||||
|
||||
@@ -37,5 +37,5 @@ bool protopirate_scene_receiver_config_on_event(void* context, SceneManagerEvent
|
||||
void protopirate_scene_receiver_config_on_exit(void* context) {
|
||||
ProtoPirateApp* app = context;
|
||||
|
||||
config_plugin_unload(app);
|
||||
config_or_saved_plugin_unload(app, true);
|
||||
}
|
||||
|
||||
@@ -1,343 +1,52 @@
|
||||
// scenes/protopirate_scene_saved_info.c
|
||||
#include "../protopirate_app_i.h"
|
||||
#include "../helpers/protopirate_storage.h"
|
||||
#include "plugins/protopirate_saved_info_plugin.h"
|
||||
#include "../helpers/protopirate_psa_bf_host.h"
|
||||
#include "../protocols/protocol_items.h"
|
||||
#include "../protocols/protocols_common.h"
|
||||
#include "../helpers/protopirate_storage.h"
|
||||
|
||||
#include "proto_pirate_icons.h"
|
||||
|
||||
#define TAG "ProtoPirateSceneSavedInfo"
|
||||
|
||||
#define STATE_EMULATE 0
|
||||
#define STATE_BF 1
|
||||
|
||||
static void protopirate_scene_saved_info_widget_callback(
|
||||
GuiButtonType result,
|
||||
InputType type,
|
||||
void* context) {
|
||||
ProtoPirateApp* app = context;
|
||||
|
||||
if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
|
||||
const uint32_t left_event =
|
||||
(scene_manager_get_scene_state(app->scene_manager, ProtoPirateSceneSavedInfo) ==
|
||||
STATE_BF) ?
|
||||
ProtoPirateCustomEventBruteforceStart :
|
||||
ProtoPirateCustomEventSavedInfoEmulate;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, left_event);
|
||||
} else if(result == GuiButtonTypeRight && (type == InputTypeShort)) {
|
||||
//Send delete event and get user confirmation to delete.
|
||||
view_dispatcher_send_custom_event(
|
||||
app->view_dispatcher, ProtoPirateCustomEventSavedInfoDelete);
|
||||
}
|
||||
}
|
||||
static const ProtoPirateSavedInfoSceneHostApi protopirate_saved_info_scene_host_api = {
|
||||
.ensure_widget = protopirate_ensure_widget,
|
||||
.psa_bf_plugin_ensure_loaded = protopirate_psa_bf_plugin_ensure_loaded,
|
||||
.psa_bf_plugin_unload_if_idle = protopirate_psa_bf_plugin_unload_if_idle,
|
||||
.protocol_catalog_can_tx = protopirate_protocol_catalog_can_tx,
|
||||
.storage_delete_file = protopirate_storage_delete_file,
|
||||
.protocol_catalog_offers_bruteforce = protopirate_protocol_catalog_offers_bruteforce,
|
||||
};
|
||||
|
||||
void protopirate_scene_saved_info_on_enter(void* context) {
|
||||
furi_check(context);
|
||||
ProtoPirateApp* app = context;
|
||||
Storage* storage = NULL;
|
||||
FlipperFormat* ff = NULL;
|
||||
FuriString* info_str = NULL;
|
||||
FuriString* temp_str = NULL;
|
||||
bool success = false;
|
||||
|
||||
FURI_LOG_I(TAG, "=== ENTER START ===");
|
||||
|
||||
protopirate_release_shared_radio_state(app);
|
||||
|
||||
if(!protopirate_ensure_widget(app)) {
|
||||
if(!config_or_saved_plugin_load(app, false)) {
|
||||
notification_message(app->notifications, &sequence_error);
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset widget first
|
||||
widget_reset(app->widget);
|
||||
|
||||
// Validate file path
|
||||
if(!app->loaded_file_path || furi_string_empty(app->loaded_file_path)) {
|
||||
FURI_LOG_E(TAG, "No file path");
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 32, AlignCenter, AlignCenter, FontPrimary, "No file selected");
|
||||
goto switch_view;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Path: %s", furi_string_get_cstr(app->loaded_file_path));
|
||||
|
||||
// Allocate strings first (no I/O)
|
||||
info_str = furi_string_alloc();
|
||||
temp_str = furi_string_alloc();
|
||||
if(!info_str || !temp_str) {
|
||||
FURI_LOG_E(TAG, "String alloc failed");
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 32, AlignCenter, AlignCenter, FontPrimary, "Memory error");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Strings allocated");
|
||||
|
||||
// Open storage
|
||||
FURI_LOG_I(TAG, "Opening storage...");
|
||||
storage = furi_record_open(RECORD_STORAGE);
|
||||
if(!storage) {
|
||||
FURI_LOG_E(TAG, "Storage open failed");
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 32, AlignCenter, AlignCenter, FontPrimary, "Storage error");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Storage opened");
|
||||
|
||||
// Allocate flipper format
|
||||
FURI_LOG_I(TAG, "Allocating FF...");
|
||||
ff = flipper_format_file_alloc(storage);
|
||||
if(!ff) {
|
||||
FURI_LOG_E(TAG, "FF alloc failed");
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 32, AlignCenter, AlignCenter, FontPrimary, "Memory error");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "FF allocated");
|
||||
|
||||
// Open file
|
||||
FURI_LOG_I(TAG, "Opening file...");
|
||||
if(!flipper_format_file_open_existing(ff, furi_string_get_cstr(app->loaded_file_path))) {
|
||||
FURI_LOG_E(TAG, "File open failed");
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 32, AlignCenter, AlignCenter, FontPrimary, "File open failed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "File opened, reading...");
|
||||
bool offers_bf = false;
|
||||
|
||||
// Read fields
|
||||
uint32_t temp_data = 0;
|
||||
app->emulate_disabled_for_loaded = true;
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_string(ff, FF_PROTOCOL, temp_str)) {
|
||||
const char* protocol_name = furi_string_get_cstr(temp_str);
|
||||
furi_string_cat_printf(info_str, "Protocol: %s\n", protocol_name);
|
||||
|
||||
//Can we emulate this type?
|
||||
app->emulate_disabled_for_loaded = !protopirate_protocol_catalog_can_tx(protocol_name);
|
||||
|
||||
//Do we need to offer a Brute Force Option?
|
||||
offers_bf = protopirate_protocol_catalog_offers_bruteforce(protocol_name);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, FF_FREQUENCY, &temp_data, 1)) {
|
||||
furi_string_cat_printf(
|
||||
info_str, "Freq: %lu.%02lu MHz\n", temp_data / 1000000, (temp_data % 1000000) / 10000);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_string(ff, FF_PRESET, temp_str)) {
|
||||
// Convert full preset name to short name
|
||||
const char* preset_name = pp_get_short_preset_name(furi_string_get_cstr(temp_str));
|
||||
furi_string_cat_printf(info_str, "Modulation: %s\n", preset_name);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, FF_SERIAL, &temp_data, 1)) {
|
||||
furi_string_cat_printf(info_str, "Serial: %08lX\n", temp_data);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, FF_BTN, &temp_data, 1)) {
|
||||
furi_string_cat_printf(info_str, "Button: %02X\n", (uint8_t)temp_data);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, FF_CNT, &temp_data, 1)) {
|
||||
furi_string_cat_printf(info_str, "Counter: %04lX\n", temp_data);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, "Checksum", &temp_data, 1)) {
|
||||
furi_string_cat_printf(info_str, "Checksum: %02X\n", (uint8_t)temp_data);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, "CRC", &temp_data, 1)) {
|
||||
furi_string_cat_printf(info_str, "CRC: %02X\n", (uint8_t)temp_data);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, FF_TYPE, &temp_data, 1)) {
|
||||
furi_string_cat_printf(info_str, "Type: %02X\n", (uint8_t)temp_data);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, "KeyIdx", &temp_data, 1)) {
|
||||
furi_string_cat_printf(info_str, "KeyIdx: %d\n", (uint8_t)temp_data);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_string(ff, FF_KEY, temp_str)) {
|
||||
furi_string_cat_printf(info_str, "Key1: %s\n", furi_string_get_cstr(temp_str));
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_string(ff, "Key_2", temp_str)) {
|
||||
furi_string_cat_printf(info_str, "Key2: %s\n", furi_string_get_cstr(temp_str));
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, "ValidationField", &temp_data, 1)) {
|
||||
furi_string_cat_printf(info_str, "ValField: %04X\n", (uint16_t)temp_data);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_uint32(ff, "Seed", &temp_data, 1)) {
|
||||
furi_string_cat_printf(info_str, "Seed: %02X\n", (uint8_t)temp_data);
|
||||
}
|
||||
|
||||
flipper_format_rewind(ff);
|
||||
if(flipper_format_read_string(ff, FF_MANUFACTURE, temp_str)) {
|
||||
furi_string_cat_printf(info_str, "Manufacture: %s\n", furi_string_get_cstr(temp_str));
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Read complete, len=%u", furi_string_size(info_str));
|
||||
success = true;
|
||||
|
||||
cleanup:
|
||||
// Now do widget operations
|
||||
if(success && info_str && furi_string_size(info_str) > 0) {
|
||||
FURI_LOG_I(TAG, "Adding scroll element");
|
||||
widget_add_text_scroll_element(app->widget, 0, 0, 128, 50, furi_string_get_cstr(info_str));
|
||||
|
||||
bool needs_bf = false;
|
||||
if(offers_bf && protopirate_psa_bf_plugin_ensure_loaded(app) && app->psa_bf_plugin) {
|
||||
needs_bf = app->psa_bf_plugin->widget_left_should_bruteforce(app, ff);
|
||||
}
|
||||
|
||||
protopirate_psa_bf_plugin_unload_if_idle(app);
|
||||
if(needs_bf) {
|
||||
scene_manager_set_scene_state(app->scene_manager, ProtoPirateSceneSavedInfo, STATE_BF);
|
||||
widget_add_button_element(
|
||||
app->widget,
|
||||
GuiButtonTypeLeft,
|
||||
"BF",
|
||||
protopirate_scene_saved_info_widget_callback,
|
||||
app);
|
||||
} else {
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, ProtoPirateSceneSavedInfo, STATE_EMULATE);
|
||||
#ifdef ENABLE_EMULATE_FEATURE
|
||||
if(app->emulate_feature_enabled && !app->emulate_disabled_for_loaded) {
|
||||
widget_add_button_element(
|
||||
app->widget,
|
||||
GuiButtonTypeLeft,
|
||||
"Emulate",
|
||||
protopirate_scene_saved_info_widget_callback,
|
||||
app);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
widget_add_button_element(
|
||||
app->widget,
|
||||
GuiButtonTypeRight,
|
||||
"Delete",
|
||||
protopirate_scene_saved_info_widget_callback,
|
||||
app);
|
||||
}
|
||||
|
||||
// Close file and storage BEFORE widget operations
|
||||
if(ff) {
|
||||
flipper_format_free(ff);
|
||||
ff = NULL;
|
||||
}
|
||||
if(storage) {
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
storage = NULL;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Storage closed");
|
||||
|
||||
// Free strings
|
||||
if(temp_str) furi_string_free(temp_str);
|
||||
if(info_str) furi_string_free(info_str);
|
||||
|
||||
FURI_LOG_I(TAG, "Cleanup done");
|
||||
|
||||
switch_view:
|
||||
FURI_LOG_I(TAG, "Switching to widget");
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, ProtoPirateViewWidget);
|
||||
FURI_LOG_I(TAG, "=== ENTER DONE ===");
|
||||
app->saved_info_plugin->set_host_api(&protopirate_saved_info_scene_host_api);
|
||||
app->saved_info_plugin->on_enter(app);
|
||||
}
|
||||
|
||||
bool protopirate_scene_saved_info_on_event(void* context, SceneManagerEvent event) {
|
||||
ProtoPirateApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeTick) {
|
||||
if(app->psa_bf_plugin && app->psa_bf_plugin->is_running(app)) {
|
||||
app->psa_bf_plugin->on_scene_event(app, ProtoPiratePsaBfContextSavedInfo, event);
|
||||
consumed = true;
|
||||
//I can't set the next scene from inside the plugin, or it causes crazy crashes.
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == ProtoPirateCustomEventSavedInfoEmulateDelayedStart) {
|
||||
//Start Emulate Scene.
|
||||
scene_manager_next_scene(
|
||||
((ProtoPirateApp*)context)->scene_manager, ProtoPirateSceneEmulate);
|
||||
return true;
|
||||
} else if(event.event == ProtoPirateCustomEventSavedInfoExit) {
|
||||
scene_manager_previous_scene(((ProtoPirateApp*)context)->scene_manager);
|
||||
return true;
|
||||
}
|
||||
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
return (
|
||||
app->psa_bf_plugin && app->psa_bf_plugin->is_running &&
|
||||
app->psa_bf_plugin->on_scene_event(app, ProtoPiratePsaBfContextReceiverInfo, event));
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == ProtoPirateCustomEventSavedInfoDelete) {
|
||||
FURI_LOG_I(TAG, "Delete requested");
|
||||
if(app->loaded_file_path && !furi_string_empty(app->loaded_file_path)) {
|
||||
DialogMessage* message = dialog_message_alloc();
|
||||
dialog_message_set_buttons(message, "Delete", NULL, "Keep");
|
||||
dialog_message_set_icon(message, &I_WarningDolphin_45x42, 0, 12);
|
||||
dialog_message_set_header(
|
||||
message, "Confirm Delete Action", 64, 0, AlignCenter, AlignTop);
|
||||
dialog_message_set_text(
|
||||
message,
|
||||
"Are you sure you\nwant to delete\nthis file?",
|
||||
50,
|
||||
14,
|
||||
AlignLeft,
|
||||
AlignTop);
|
||||
DialogMessageButton dialog_result = dialog_message_show(app->dialogs, message);
|
||||
dialog_message_free(message);
|
||||
|
||||
//Delete if the user said yes.
|
||||
if(dialog_result == DialogMessageButtonLeft) {
|
||||
notification_message(app->notifications, &sequence_semi_success);
|
||||
protopirate_storage_delete_file(furi_string_get_cstr(app->loaded_file_path));
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
}
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
if(event.event == ProtoPirateCustomEventBruteforceStart ||
|
||||
event.event == ProtoPirateCustomEventBruteforceComplete) {
|
||||
if(protopirate_psa_bf_plugin_ensure_loaded(app) && app->psa_bf_plugin &&
|
||||
app->psa_bf_plugin->on_scene_event(app, ProtoPiratePsaBfContextSavedInfo, event)) {
|
||||
}
|
||||
if(event.event == ProtoPirateCustomEventBruteforceComplete)
|
||||
protopirate_scene_saved_info_on_enter(app);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_EMULATE_FEATURE
|
||||
if(event.event == ProtoPirateCustomEventSavedInfoEmulate && app->emulate_feature_enabled &&
|
||||
!app->emulate_disabled_for_loaded) {
|
||||
FURI_LOG_I(TAG, "Emulate requested");
|
||||
scene_manager_next_scene(app->scene_manager, ProtoPirateSceneEmulate);
|
||||
consumed = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return consumed;
|
||||
//Handle Saved Info event in plugin.
|
||||
return ((ProtoPirateApp*)context)->saved_info_plugin->on_event(context, event);
|
||||
}
|
||||
|
||||
void protopirate_scene_saved_info_on_exit(void* context) {
|
||||
ProtoPirateApp* app = context;
|
||||
FURI_LOG_I(TAG, "Exiting SavedInfo scene");
|
||||
widget_reset(app->widget);
|
||||
UNUSED(app);
|
||||
|
||||
config_or_saved_plugin_unload(app, false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user