From 7da67c9a73d3ff5c868e25e80d5abb68bf6cdefd Mon Sep 17 00:00:00 2001 From: zero-mega Date: Wed, 20 May 2026 19:04:43 +0200 Subject: [PATCH] Now you don't have to know how to edit code to enable emulate you just need to know how to read it x) --- defines.h | 4 +- helpers/protopirate_settings.c | 24 +++++-- helpers/protopirate_settings.h | 1 + helpers/protopirate_types.h | 2 + protopirate_app.c | 28 ++++---- protopirate_app_i.h | 1 + scenes/protopirate_scene_about.c | 88 +++++++++++++++++++++++- scenes/protopirate_scene_receiver_info.c | 6 +- scenes/protopirate_scene_saved_info.c | 6 +- 9 files changed, 130 insertions(+), 30 deletions(-) diff --git a/defines.h b/defines.h index 4744959..4fceb7c 100644 --- a/defines.h +++ b/defines.h @@ -3,9 +3,9 @@ //#define ENABLE_TIMING_TUNER_SCENE //#define ENABLE_SUB_DECODE_SCENE -// #define ENABLE_EMULATE_FEATURE +#define ENABLE_EMULATE_FEATURE -#define REMOVE_LOGS +//#define REMOVE_LOGS #ifdef REMOVE_LOGS // Undefine existing macros diff --git a/helpers/protopirate_settings.c b/helpers/protopirate_settings.c index bf02229..91d5d63 100644 --- a/helpers/protopirate_settings.c +++ b/helpers/protopirate_settings.c @@ -17,6 +17,7 @@ void protopirate_settings_set_defaults(ProtoPirateSettings* settings) { settings->tx_power = 0; settings->auto_save = false; settings->hopping_enabled = false; + settings->emulate_feature_enabled = false; } void protopirate_settings_load(ProtoPirateSettings* settings) { @@ -93,13 +94,21 @@ void protopirate_settings_load(ProtoPirateSettings* settings) { } settings->hopping_enabled = (hopping_temp == 1); + uint32_t emulate_temp = 0; + if(!flipper_format_read_uint32(ff, "EmulateFeature", &emulate_temp, 1)) { + FURI_LOG_I(TAG, "EmulateFeature key missing, defaulting to disabled"); + emulate_temp = 0; + } + settings->emulate_feature_enabled = (emulate_temp == 1); + FURI_LOG_I( TAG, - "Settings loaded: freq=%lu, preset=%u, auto_save=%d, hopping=%d", + "Settings loaded: freq=%lu, preset=%u, auto_save=%d, hopping=%d, emulate=%d", settings->frequency, settings->preset_index, settings->auto_save, - settings->hopping_enabled); + settings->hopping_enabled, + settings->emulate_feature_enabled); } while(false); @@ -155,13 +164,20 @@ void protopirate_settings_save(ProtoPirateSettings* settings) { break; } + uint32_t emulate_temp = settings->emulate_feature_enabled ? 1 : 0; + if(!flipper_format_write_uint32(ff, "EmulateFeature", &emulate_temp, 1)) { + FURI_LOG_E(TAG, "Failed to write emulate feature flag"); + break; + } + FURI_LOG_I( TAG, - "Settings saved: freq=%lu, preset=%u, auto_save=%d, hopping=%d", + "Settings saved: freq=%lu, preset=%u, auto_save=%d, hopping=%d, emulate=%d", settings->frequency, settings->preset_index, settings->auto_save, - settings->hopping_enabled); + settings->hopping_enabled, + settings->emulate_feature_enabled); } while(false); diff --git a/helpers/protopirate_settings.h b/helpers/protopirate_settings.h index 04fe92c..f215998 100644 --- a/helpers/protopirate_settings.h +++ b/helpers/protopirate_settings.h @@ -13,6 +13,7 @@ typedef struct { uint8_t tx_power; bool auto_save; bool hopping_enabled; + bool emulate_feature_enabled; } ProtoPirateSettings; void protopirate_settings_load(ProtoPirateSettings* settings); diff --git a/helpers/protopirate_types.h b/helpers/protopirate_types.h index df4f4bb..971a269 100644 --- a/helpers/protopirate_types.h +++ b/helpers/protopirate_types.h @@ -47,6 +47,8 @@ typedef enum { // Need saving confirmation ProtoPirateCustomEventSceneStay, ProtoPirateCustomEventSceneExit, + // About scene + ProtoPirateCustomEventAboutToggleEmulate, } ProtoPirateCustomEvent; typedef enum { diff --git a/protopirate_app.c b/protopirate_app.c index 973f8b0..eff6765 100644 --- a/protopirate_app.c +++ b/protopirate_app.c @@ -215,6 +215,7 @@ ProtoPirateApp* protopirate_app_alloc() { // Apply auto-save setting app->auto_save = settings.auto_save; app->tx_power = settings.tx_power; + app->emulate_feature_enabled = settings.emulate_feature_enabled; // Init setting - KEEP THIS, it's small app->setting = subghz_setting_alloc(); @@ -484,6 +485,7 @@ void protopirate_app_free(ProtoPirateApp* app) { settings.auto_save = app->auto_save; settings.tx_power = app->tx_power; settings.hopping_enabled = (app->txrx->hopper_state != ProtoPirateHopperStateOFF); + settings.emulate_feature_enabled = app->emulate_feature_enabled; // Find current preset index settings.preset_index = 0; @@ -497,11 +499,12 @@ void protopirate_app_free(ProtoPirateApp* app) { FURI_LOG_I( TAG, - "Saving settings: freq=%lu, preset=%u, auto_save=%d, hopping=%d", + "Saving settings: freq=%lu, preset=%u, auto_save=%d, hopping=%d, emulate=%d", settings.frequency, settings.preset_index, settings.auto_save, - settings.hopping_enabled); + settings.hopping_enabled, + settings.emulate_feature_enabled); protopirate_settings_save(&settings); @@ -635,22 +638,17 @@ int32_t protopirate_app(char* p) { protopirate_app->scene_manager, (load_saved) ? ProtoPirateSceneSavedInfo : ProtoPirateSceneStart); -#ifdef ENABLE_EMULATE_FEATURE //We now jump straight to emulate scene from Browser. If the user wanted the key to look at, just click back. - //Makes it faster in my use case if(load_saved) { - view_dispatcher_send_custom_event( - protopirate_app->view_dispatcher, ProtoPirateCustomEventSavedInfoEmulate); - notification_message(protopirate_app->notifications, &sequence_success); + if(protopirate_app->emulate_feature_enabled) { + view_dispatcher_send_custom_event( + protopirate_app->view_dispatcher, ProtoPirateCustomEventSavedInfoEmulate); + notification_message(protopirate_app->notifications, &sequence_success); + } else { + view_dispatcher_send_custom_event( + protopirate_app->view_dispatcher, ProtoPirateCustomEventReceiverInfoSave); + } } -#else - //We now jump straight to emulate scene from Browser. If the user wanted the key to look at, just click back. - //Makes it faster in my use case - if(load_saved) { - view_dispatcher_send_custom_event( - protopirate_app->view_dispatcher, ProtoPirateCustomEventReceiverInfoSave); - } -#endif view_dispatcher_run(protopirate_app->view_dispatcher); diff --git a/protopirate_app_i.h b/protopirate_app_i.h index 25492f3..6c59f5b 100644 --- a/protopirate_app_i.h +++ b/protopirate_app_i.h @@ -85,6 +85,7 @@ struct ProtoPirateApp { uint16_t save_history_idx; bool save_from_saved_info; bool emulate_disabled_for_loaded; + bool emulate_feature_enabled; }; #ifdef ENABLE_EMULATE_FEATURE diff --git a/scenes/protopirate_scene_about.c b/scenes/protopirate_scene_about.c index 6645b12..9c319e2 100644 --- a/scenes/protopirate_scene_about.c +++ b/scenes/protopirate_scene_about.c @@ -1,6 +1,10 @@ // scenes/protopirate_scene_about.c #include "../protopirate_app_i.h" +#include "../helpers/protopirate_settings.h" +#include "proto_pirate_icons.h" #include +#include +#include #include #define CREDITS_START_Y 28 @@ -8,6 +12,18 @@ #define CREDIT_LINE_HEIGHT 10 #define SCROLL_SPEED 1 +static const InputKey EMULATE_TOGGLE_COMBO[] = { + InputKeyUp, + InputKeyUp, + InputKeyDown, + InputKeyDown, + InputKeyLeft, + InputKeyRight, + InputKeyLeft, + InputKeyRight, +}; +#define EMULATE_TOGGLE_COMBO_LEN (sizeof(EMULATE_TOGGLE_COMBO) / sizeof(EMULATE_TOGGLE_COMBO[0])) + static const char* credits[] = { "", "-=> App Development by", @@ -46,6 +62,7 @@ typedef struct { uint8_t frame; uint8_t seed; int16_t scroll_offset; + uint8_t combo_progress; } GlitchState; static GlitchState g_state = {0}; @@ -141,9 +158,57 @@ static void about_draw_callback(Canvas* canvas, void* context) { } static bool about_input_callback(InputEvent* event, void* context) { - UNUSED(context); - UNUSED(event); - return false; + furi_check(context); + ProtoPirateApp* app = context; + + if(event->type != InputTypePress) { + return false; + } + + if(event->key == InputKeyBack) { + return false; + } + + InputKey expected = EMULATE_TOGGLE_COMBO[g_state.combo_progress]; + if(event->key == expected) { + g_state.combo_progress++; + if(g_state.combo_progress >= EMULATE_TOGGLE_COMBO_LEN) { + g_state.combo_progress = 0; + view_dispatcher_send_custom_event( + app->view_dispatcher, ProtoPirateCustomEventAboutToggleEmulate); + } + } else if(event->key == EMULATE_TOGGLE_COMBO[0]) { + + g_state.combo_progress = 1; + } else { + g_state.combo_progress = 0; + } + + return true; +} + +static void about_show_emulate_toggle_popup(ProtoPirateApp* app) { + const bool now_enabled = app->emulate_feature_enabled; + + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_buttons(message, NULL, "OK", NULL); + dialog_message_set_icon(message, &I_WarningDolphin_45x42, 0, 12); + dialog_message_set_header( + message, + now_enabled ? "Emulate Unlocked" : "Emulate Locked", + 64, + 0, + AlignCenter, + AlignTop); + dialog_message_set_text( + message, + now_enabled ? "Transmission is\nnow enabled!" : "Transmission is\nnow disabled!", + 50, + 14, + AlignLeft, + AlignTop); + dialog_message_show(app->dialogs, message); + dialog_message_free(message); } void protopirate_scene_about_on_enter(void* context) { @@ -159,6 +224,7 @@ void protopirate_scene_about_on_enter(void* context) { g_state.frame = 0; g_state.seed = furi_get_tick() & 0xFF; g_state.scroll_offset = 0; + g_state.combo_progress = 0; view_set_draw_callback(app->view_about, about_draw_callback); view_set_input_callback(app->view_about, about_input_callback); @@ -185,6 +251,22 @@ bool protopirate_scene_about_on_event(void* context, SceneManagerEvent event) { view_commit_model(app->view_about, true); consumed = true; + } else if(event.type == SceneManagerEventTypeCustom) { + if(event.event == ProtoPirateCustomEventAboutToggleEmulate) { + app->emulate_feature_enabled = !app->emulate_feature_enabled; + + ProtoPirateSettings settings; + protopirate_settings_load(&settings); + settings.emulate_feature_enabled = app->emulate_feature_enabled; + protopirate_settings_save(&settings); + + notification_message( + app->notifications, + app->emulate_feature_enabled ? &sequence_success : &sequence_semi_success); + + about_show_emulate_toggle_popup(app); + consumed = true; + } } return consumed; diff --git a/scenes/protopirate_scene_receiver_info.c b/scenes/protopirate_scene_receiver_info.c index d14214e..9e4d128 100644 --- a/scenes/protopirate_scene_receiver_info.c +++ b/scenes/protopirate_scene_receiver_info.c @@ -187,7 +187,7 @@ static void protopirate_receiver_info_build_normal_widget(ProtoPirateApp* app) { app); } #ifdef ENABLE_EMULATE_FEATURE - else if(!app->emulate_disabled_for_loaded) { + else if(app->emulate_feature_enabled && !app->emulate_disabled_for_loaded) { widget_add_button_element( app->widget, GuiButtonTypeLeft, @@ -246,7 +246,7 @@ static void protopirate_scene_receiver_info_widget_callback( app->view_dispatcher, ProtoPirateCustomEventReceiverInfoBruteforceStart); } #ifdef ENABLE_EMULATE_FEATURE - else if(!app->emulate_disabled_for_loaded) { + else if(app->emulate_feature_enabled && !app->emulate_disabled_for_loaded) { view_dispatcher_send_custom_event( app->view_dispatcher, ProtoPirateCustomEventReceiverInfoEmulate); } @@ -530,7 +530,7 @@ bool protopirate_scene_receiver_info_on_event(void* context, SceneManagerEvent e #ifdef ENABLE_EMULATE_FEATURE if(event.event == ProtoPirateCustomEventReceiverInfoEmulate && - !app->emulate_disabled_for_loaded) { + app->emulate_feature_enabled && !app->emulate_disabled_for_loaded) { FuriString* hist_path = furi_string_alloc(); if(protopirate_history_get_capture_path( app->txrx->history, app->txrx->idx_menu_chosen, hist_path)) { diff --git a/scenes/protopirate_scene_saved_info.c b/scenes/protopirate_scene_saved_info.c index d997e08..aaffb91 100644 --- a/scenes/protopirate_scene_saved_info.c +++ b/scenes/protopirate_scene_saved_info.c @@ -14,7 +14,7 @@ static void protopirate_scene_saved_info_widget_callback( if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) { #ifdef ENABLE_EMULATE_FEATURE - if(!app->emulate_disabled_for_loaded) { + if(app->emulate_feature_enabled && !app->emulate_disabled_for_loaded) { view_dispatcher_send_custom_event( app->view_dispatcher, ProtoPirateCustomEventSavedInfoEmulate); } @@ -212,7 +212,7 @@ cleanup: widget_add_text_scroll_element(app->widget, 0, 0, 128, 50, furi_string_get_cstr(info_str)); #ifdef ENABLE_EMULATE_FEATURE - if(!app->emulate_disabled_for_loaded) { + if(app->emulate_feature_enabled && !app->emulate_disabled_for_loaded) { widget_add_button_element( app->widget, GuiButtonTypeLeft, @@ -275,7 +275,7 @@ bool protopirate_scene_saved_info_on_event(void* context, SceneManagerEvent even } #ifdef ENABLE_EMULATE_FEATURE if(event.event == ProtoPirateCustomEventSavedInfoEmulate && - !app->emulate_disabled_for_loaded) { + 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;