Merge pull request 'RAM Optimizations and (Including ABOUT scene moved to new PLUGIN)' (#62) from RalphWiggum/ProtoPirate:about_plugin into main
FAP Build / ufbt: Build for Momentum dev (push) Canceled after 0s
FAP Build / ufbt: Build for Momentum release (push) Canceled after 0s
FAP Build / ufbt: Build for OFW dev channel (push) Canceled after 0s
FAP Build / ufbt: Build for OFW release channel (push) Canceled after 0s
FAP Build / ufbt: Build for Unleashed dev (push) Canceled after 0s
FAP Build / ufbt: Build for Unleashed release (push) Canceled after 0s

Reviewed-on: http://protopirate.net/ProtoPirate/ProtoPirate/pulls/62
Reviewed-by: MMX <mmx@no-reply.protopirate.net>
This commit is contained in:
MMX
2026-09-26 05:12:10 -04:00
43 changed files with 538 additions and 395 deletions
+27 -13
View File
@@ -25,6 +25,7 @@ _MAIN_APP_SOURCES = [
"!protopirate_emulate_plugin.c",
"!protopirate_psa_bf_plugin.c",
"!protopirate_saved_info_plugin.c",
"!protopirate_about_plugin.c",
"!protopirate_config_plugin.c",
"protocols/protocol_items.c",
"protocols/protocols_common.c",
@@ -63,7 +64,7 @@ App(
# --- RX protocol plugins ---
App(
appid="protopirate_am_plugin",
appid="pp_am",
apptype=FlipperAppType.PLUGIN,
entry_point="protopirate_am_plugin_ep",
requires=["proto_pirate"],
@@ -92,7 +93,7 @@ App(
)
App(
appid="protopirate_am_vag_plugin",
appid="pp_am_vag",
apptype=FlipperAppType.PLUGIN,
entry_point="protopirate_am_vag_plugin_ep",
requires=["proto_pirate"],
@@ -107,7 +108,7 @@ App(
)
App(
appid="protopirate_fm_plugin",
appid="pp_fm",
apptype=FlipperAppType.PLUGIN,
entry_point="protopirate_fm_plugin_ep",
requires=["proto_pirate"],
@@ -131,7 +132,7 @@ App(
)
App(
appid="protopirate_fm_f4_plugin",
appid="pp_fm_f4",
apptype=FlipperAppType.PLUGIN,
entry_point="protopirate_fm_f4_plugin_ep",
requires=["proto_pirate"],
@@ -148,7 +149,7 @@ App(
)
App(
appid="protopirate_fm_honda1_plugin",
appid="pp_fm_honda1",
apptype=FlipperAppType.PLUGIN,
entry_point="protopirate_fm_honda1_plugin_ep",
requires=["proto_pirate"],
@@ -183,7 +184,7 @@ def ProtoPirateTxProtocolPlugin(
return
App(
appid=f"protopirate_tx_{key}_plugin",
appid=f"pp_tx_{key}",
apptype=FlipperAppType.PLUGIN,
entry_point="protopirate_tx_protocol_plugin_ep",
requires=["proto_pirate"],
@@ -362,7 +363,7 @@ ProtoPirateTxProtocolPlugin(
# --- Tool / scene plugins ---
App(
appid="protopirate_sub_decode_plugin",
appid="pp_sub_decode",
apptype=FlipperAppType.PLUGIN,
entry_point="protopirate_sub_decode_plugin_ep",
requires=["proto_pirate"],
@@ -381,7 +382,7 @@ App(
if _ENABLE_TIMING_TUNER:
App(
appid="protopirate_timing_tuner_plugin",
appid="pp_timing_tuner",
apptype=FlipperAppType.PLUGIN,
entry_point="protopirate_timing_tuner_plugin_ep",
requires=["proto_pirate"],
@@ -395,7 +396,7 @@ if _ENABLE_TIMING_TUNER:
if _ENABLE_EMULATE:
App(
appid="protopirate_emulate_plugin",
appid="pp_emulate",
apptype=FlipperAppType.PLUGIN,
entry_point="protopirate_emulate_plugin_ep",
requires=["proto_pirate"],
@@ -407,7 +408,7 @@ if _ENABLE_EMULATE:
)
App(
appid="protopirate_psa_bf_plugin",
appid="pp_bf",
apptype=FlipperAppType.PLUGIN,
entry_point="protopirate_psa_bf_plugin_ep",
requires=["proto_pirate"],
@@ -425,7 +426,7 @@ App(
)
App(
appid="protopirate_config_plugin",
appid="pp_config",
apptype=FlipperAppType.PLUGIN,
entry_point="protopirate_config_plugin_ep",
requires=["proto_pirate"],
@@ -435,12 +436,12 @@ App(
"helpers/variable_item_list.c",
"scenes/plugins/protopirate_config_plugin.c",
],
fap_icon_assets="images",
fap_icon_assets="helpers/variable_item_list_images",
fal_embedded=True,
)
App(
appid="protopirate_saved_info_plugin",
appid="pp_saved_info",
apptype=FlipperAppType.PLUGIN,
entry_point="protopirate_saved_info_plugin_ep",
requires=["proto_pirate"],
@@ -451,4 +452,17 @@ App(
],
fap_icon_assets="images",
fal_embedded=True,
)
App(
appid="pp_about",
apptype=FlipperAppType.PLUGIN,
entry_point="protopirate_about_plugin_ep",
requires=["proto_pirate"],
cdefines=["PROTOPIRATE_ABOUT_PLUGIN_BUILD"],
sources=[
"scenes/plugins/protopirate_about_plugin.c",
],
fap_icon_assets="images",
fal_embedded=True,
)
+4 -4
View File
@@ -1,6 +1,6 @@
#include "protopirate_models.h"
#define TAG "ProtoPirateModels"
#define TAG "PPModels"
#define PROTOPIRATE_MODELS_FILE APP_ASSETS_PATH("models.txt")
@@ -73,7 +73,7 @@ bool car_model_get_by_index(
//Read the Model Name.
if(!flipper_format_read_string(ff, model_name_index, model_name)) {
FURI_LOG_E("ProtoPirate", "Failed to read %s", model_name_index);
FURI_LOG_E(TAG, "Failed to read %s", model_name_index);
break;
}
@@ -168,7 +168,7 @@ bool car_model_get_by_index(
preset_data_size > 0) {
if(preset_data_size >= 1024) {
FURI_LOG_E(
"ProtoPirate",
TAG,
"%s too large: %lu",
preset_data_index,
(unsigned long)preset_data_size);
@@ -178,7 +178,7 @@ bool car_model_get_by_index(
preset_data = malloc(preset_data_size);
if(!preset_data) {
FURI_LOG_E(
"ProtoPirate",
TAG,
"Malloc failed: %s (%lu bytes)",
preset_data_index,
(unsigned long)preset_data_size);
+8 -11
View File
@@ -6,7 +6,7 @@
#include <stdio.h>
#include <string.h>
#define TAG "ProtoPirateProtocolPlugin"
#define TAG "PPProtocolPlugin"
#ifdef ENABLE_EMULATE_FEATURE
#define PROTOPIRATE_TX_PLUGIN_PATH_MAX 160U
#endif
@@ -14,16 +14,16 @@
static const char* protopirate_get_registry_plugin_path(ProtoPirateProtocolRegistryRoute route) {
switch(route) {
case ProtoPirateProtocolRegistryRouteAMVag:
return APP_ASSETS_PATH("plugins/protopirate_am_vag_plugin.fal");
return APP_ASSETS_PATH("plugins/pp_am_vag.fal");
case ProtoPirateProtocolRegistryRouteFMDefault:
return APP_ASSETS_PATH("plugins/protopirate_fm_plugin.fal");
return APP_ASSETS_PATH("plugins/pp_fm.fal");
case ProtoPirateProtocolRegistryRouteFMF4:
return APP_ASSETS_PATH("plugins/protopirate_fm_f4_plugin.fal");
return APP_ASSETS_PATH("plugins/pp_fm_f4.fal");
case ProtoPirateProtocolRegistryRouteFMHonda1:
return APP_ASSETS_PATH("plugins/protopirate_fm_honda1_plugin.fal");
return APP_ASSETS_PATH("plugins/pp_fm_honda1.fal");
case ProtoPirateProtocolRegistryRouteAMDefault:
default:
return APP_ASSETS_PATH("plugins/protopirate_am_plugin.fal");
return APP_ASSETS_PATH("plugins/pp_am.fal");
}
}
@@ -36,11 +36,8 @@ static bool protopirate_build_tx_protocol_plugin_path(
return false;
}
int written = snprintf(
plugin_path,
plugin_path_size,
APP_ASSETS_PATH("plugins/protopirate_tx_%s_plugin.fal"),
tx_key);
int written =
snprintf(plugin_path, plugin_path_size, APP_ASSETS_PATH("plugins/pp_tx_%s.fal"), tx_key);
return (written > 0) && ((size_t)written < plugin_path_size);
}
#endif
+2 -2
View File
@@ -9,8 +9,8 @@
#include <lib/flipper_application/plugins/composite_resolver.h>
#include <notification/notification_messages.h>
#define TAG "ProtoPiratePsaBfHost"
#define PSA_BF_PLUGIN_PATH APP_ASSETS_PATH("plugins/protopirate_psa_bf_plugin.fal")
#define TAG "PPPsaBfHost"
#define PSA_BF_PLUGIN_PATH APP_ASSETS_PATH("plugins/pp_bf.fal")
static bool host_ensure_widget(void* app) {
return protopirate_ensure_widget((ProtoPirateApp*)app);
+1 -1
View File
@@ -4,7 +4,7 @@
#include <furi.h>
#include <string.h>
#define TAG "ProtoPirateRadio"
#define TAG "PPRadio"
static void protopirate_radio_free_receiver(ProtoPirateApp* app) {
furi_check(app);
+1 -1
View File
@@ -4,7 +4,7 @@
#include <storage/storage.h>
#include <string.h>
#define TAG "ProtoPirateMatch"
#define TAG "PPMatch"
#define CNT_MATCH_MARGIN 50
bool protopirate_saved_match_signal(
+1 -1
View File
@@ -7,7 +7,7 @@
#include "../defines.h"
#include "../protocols/protocols_common.h"
#define TAG "ProtoPirateSettings"
#define TAG "PPSettings"
#define SETTINGS_FILE_HEADER "ProtoPirate Settings"
#define SETTINGS_FILE_VERSION 1
+1 -1
View File
@@ -7,7 +7,7 @@
#include <toolbox/stream/stream.h>
#include <string.h>
#define TAG "ProtoPirateStorage"
#define TAG "PPStorage"
bool protopirate_storage_init(void) {
Storage* storage = furi_record_open(RECORD_STORAGE);
+3 -3
View File
@@ -5,11 +5,11 @@
#include <loader/firmware_api/firmware_api.h>
#include <notification/notification_messages.h>
#define TAG "ProtoPirateToolScene"
#define TAG "PPToolScene"
#define SUB_DECODE_PLUGIN_PATH APP_ASSETS_PATH("plugins/protopirate_sub_decode_plugin.fal")
#define SUB_DECODE_PLUGIN_PATH APP_ASSETS_PATH("plugins/pp_sub_decode.fal")
#ifdef ENABLE_TIMING_TUNER_SCENE
#define TIMING_TUNER_PLUGIN_PATH APP_ASSETS_PATH("plugins/protopirate_timing_tuner_plugin.fal")
#define TIMING_TUNER_PLUGIN_PATH APP_ASSETS_PATH("plugins/pp_timing_tuner.fal")
#endif
static const char* protopirate_tool_scene_plugin_path(ProtoPirateToolScenePluginKind kind) {
+1 -1
View File
@@ -6,7 +6,7 @@
#include <stdio.h>
#define TAG "ProtoPirateTxRx"
#define TAG "PPTxRx"
void protopirate_rx_stack_teardown_for_registry_switch(ProtoPirateApp* app) {
furi_check(app);
+1 -1
View File
@@ -3,7 +3,7 @@
#include <furi.h>
#define TAG "ProtoPirateViews"
#define TAG "PPViews"
bool protopirate_ensure_widget(ProtoPirateApp* app) {
furi_check(app);
+1 -1
View File
@@ -6,7 +6,7 @@
#include <stdint.h>
#ifdef PROTOPIRATE_CONFIG_PLUGIN_BUILD
#include "protopirate_config_plugin_icons.h"
#include "pp_config_icons.h"
#else
#include "proto_pirate_icons.h"
#endif

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

+1 -1
View File
@@ -41,7 +41,7 @@ static const SubGhzProtocolRegistry protopirate_protocol_registry_am = {
};
static const ProtoPirateProtocolPlugin protopirate_am_plugin = {
.plugin_name = "ProtoPirate AM Default Registry",
.plugin_name = "AM Registry",
.kind = ProtoPirateProtocolPluginKindRx,
.route = ProtoPirateProtocolRegistryRouteAMDefault,
.registry = &protopirate_protocol_registry_am,
@@ -13,7 +13,7 @@ static const SubGhzProtocolRegistry protopirate_protocol_registry_am_vag = {
};
static const ProtoPirateProtocolPlugin protopirate_am_vag_plugin = {
.plugin_name = "ProtoPirate AM VAG Registry",
.plugin_name = "AM VAG Registry",
.kind = ProtoPirateProtocolPluginKindRx,
.route = ProtoPirateProtocolRegistryRouteAMVag,
.registry = &protopirate_protocol_registry_am_vag,
+1 -1
View File
@@ -19,7 +19,7 @@ static const SubGhzProtocolRegistry protopirate_protocol_registry_fm_f4 = {
};
static const ProtoPirateProtocolPlugin protopirate_fm_f4_plugin = {
.plugin_name = "ProtoPirate FM F4 Registry",
.plugin_name = "FM F4 Registry",
.kind = ProtoPirateProtocolPluginKindRx,
.route = ProtoPirateProtocolRegistryRouteFMF4,
.registry = &protopirate_protocol_registry_fm_f4,
@@ -13,7 +13,7 @@ static const SubGhzProtocolRegistry protopirate_protocol_registry_fm_honda1 = {
};
static const ProtoPirateProtocolPlugin protopirate_fm_honda1_plugin = {
.plugin_name = "ProtoPirate FM Honda1 Registry",
.plugin_name = "FM Honda1 Registry",
.kind = ProtoPirateProtocolPluginKindRx,
.route = ProtoPirateProtocolRegistryRouteFMHonda1,
.registry = &protopirate_protocol_registry_fm_honda1,
+1 -1
View File
@@ -29,7 +29,7 @@ static const SubGhzProtocolRegistry protopirate_protocol_registry_fm = {
};
static const ProtoPirateProtocolPlugin protopirate_fm_plugin = {
.plugin_name = "ProtoPirate FM Default Registry",
.plugin_name = "FM Default Registry",
.kind = ProtoPirateProtocolPluginKindRx,
.route = ProtoPirateProtocolRegistryRouteFMDefault,
.registry = &protopirate_protocol_registry_fm,
+1 -1
View File
@@ -5,7 +5,7 @@
#include "../defines.h"
#define TAG "ProtoPirateCatalog"
#define TAG "PPCatalog"
#define PROTOPIRATE_CC1101_REG_MDMCFG2 0x12U
#define PROTOPIRATE_CC1101_MOD_FORMAT_MASK 0x70U
+79 -36
View File
@@ -10,18 +10,21 @@
#include "helpers/protopirate_radio.h"
#include <string.h>
#define TAG "ProtoPirateApp"
#define TAG "PPApp"
// -----------------------------------------------------------------------------
// Plugin load / unload
// -----------------------------------------------------------------------------
void config_or_saved_plugin_unload(ProtoPirateApp* app, bool unload_config) {
void shared_plugin_unload(ProtoPirateApp* app, ProtoPirateSharedPlugin plugin_type) {
furi_check(app);
if(unload_config)
if(plugin_type == ProtoPirateSharedPluginsConfig) {
app->config_plugin = NULL;
else
} else if(plugin_type == ProtoPirateSharedPluginsSavedInfo) {
app->saved_info_plugin = NULL;
} else if(plugin_type == ProtoPirateSharedPluginsAbout) {
app->about_plugin = NULL;
}
if(app->plugin_manager) {
plugin_manager_free(app->plugin_manager);
@@ -34,17 +37,19 @@ void config_or_saved_plugin_unload(ProtoPirateApp* app, bool unload_config) {
}
}
bool config_or_saved_plugin_load(ProtoPirateApp* app, bool load_config) {
bool shared_plugin_load(ProtoPirateApp* app, ProtoPirateSharedPlugin plugin_type) {
furi_check(app);
if(load_config) {
if(plugin_type == ProtoPirateSharedPluginsConfig) {
if(app->config_plugin) return true;
} else {
} else if(plugin_type == ProtoPirateSharedPluginsSavedInfo) {
if(app->saved_info_plugin) return true;
} else if(plugin_type == ProtoPirateSharedPluginsAbout) {
if(app->about_plugin) return true;
}
if(app->plugin_manager || app->plugin_resolver) {
config_or_saved_plugin_unload(app, load_config);
shared_plugin_unload(app, plugin_type);
}
CompositeApiResolver* resolver = composite_api_resolver_alloc();
@@ -54,27 +59,41 @@ bool config_or_saved_plugin_load(ProtoPirateApp* app, bool load_config) {
}
composite_api_resolver_add(resolver, firmware_api_interface);
PluginManager* manager = plugin_manager_alloc(
(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));
//Get the APPID and API VERSION for the Plugin we are loading.
const char* application_id = NULL;
const char* plugin_path = NULL;
uint32_t api_version = 0;
if(plugin_type == ProtoPirateSharedPluginsConfig) {
application_id = PROTOPIRATE_CONFIG_PLUGIN_APP_ID;
api_version = PROTOPIRATE_CONFIG_PLUGIN_API_VERSION;
plugin_path = CONFIG_PLUGIN_PATH;
} else if(plugin_type == ProtoPirateSharedPluginsSavedInfo) {
application_id = PROTOPIRATE_SAVED_INFO_PLUGIN_APP_ID;
api_version = PROTOPIRATE_SAVED_INFO_PLUGIN_API_VERSION;
plugin_path = SAVED_INFO_PLUGIN_PATH;
} else if(plugin_type == ProtoPirateSharedPluginsAbout) {
application_id = PROTOPIRATE_ABOUT_PLUGIN_APP_ID;
api_version = PROTOPIRATE_ABOUT_PLUGIN_API_VERSION;
plugin_path = ABOUT_PLUGIN_PATH;
}
PluginManager* manager =
plugin_manager_alloc(application_id, api_version, composite_api_resolver_get(resolver));
if(!manager) {
FURI_LOG_E(TAG, "Failed to allocate plugin manager");
composite_api_resolver_free(resolver);
return false;
}
PluginManagerError error = plugin_manager_load_single(
manager, (load_config) ? CONFIG_PLUGIN_PATH : SAVED_INFO_PLUGIN_PATH);
PluginManagerError error = plugin_manager_load_single(manager, plugin_path);
if(error != PluginManagerErrorNone) {
FURI_LOG_E(TAG, "Failed to load config plugin %s: %d", CONFIG_PLUGIN_PATH, (int)error);
FURI_LOG_E(TAG, "Failed to load plugin %s: %d", plugin_path, (int)error);
plugin_manager_free(manager);
composite_api_resolver_free(resolver);
return false;
}
if(load_config) {
if(plugin_type == ProtoPirateSharedPluginsConfig) {
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");
@@ -83,7 +102,7 @@ bool config_or_saved_plugin_load(ProtoPirateApp* app, bool load_config) {
return false;
}
app->config_plugin = plugin_config;
} else {
} else if(plugin_type == ProtoPirateSharedPluginsSavedInfo) {
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");
@@ -92,7 +111,16 @@ bool config_or_saved_plugin_load(ProtoPirateApp* app, bool load_config) {
return false;
}
app->saved_info_plugin = plugin_saved_info;
};
} else if(plugin_type == ProtoPirateSharedPluginsAbout) {
const ProtoPirateAboutPlugin* plugin_about = plugin_manager_get_ep(manager, 0U);
if(!plugin_about || !plugin_about->on_enter) {
FURI_LOG_E(TAG, "About plugin entry point is invalid");
plugin_manager_free(manager);
composite_api_resolver_free(resolver);
return false;
}
app->about_plugin = plugin_about;
}
app->plugin_resolver = resolver;
app->plugin_manager = manager;
@@ -160,7 +188,6 @@ ProtoPirateApp* protopirate_app_alloc() {
app->view_dispatcher, ProtoPirateViewSubmenu, submenu_get_view(app->submenu));
app->save_protocol = NULL;
app->save_from_saved_info = false;
app->save_history_idx = 0;
app->emulate_disabled_for_loaded = false;
memset(app->save_filename, 0, sizeof(app->save_filename));
@@ -242,8 +269,13 @@ ProtoPirateApp* protopirate_app_alloc() {
settings.auto_save,
settings.hopping_enabled);
config_or_saved_plugin_load(app, true);
app->car_models_count = app->config_plugin->car_model_get_count();
//Load the models database, get the count of the models for the list.
if(shared_plugin_load(app, ProtoPirateSharedPluginsConfig) && app->config_plugin) {
app->car_models_count = app->config_plugin->car_model_get_count();
} else {
notification_message(app->notifications, &sequence_error);
app->car_models_count = 0;
}
app->selected_model = malloc(sizeof(ProtoPirateCarModel));
app->selected_model->name = furi_string_alloc();
app->selected_model->preset = NULL; // important initialization
@@ -251,24 +283,35 @@ ProtoPirateApp* protopirate_app_alloc() {
app->variable_item_list = NULL;
//Grab selected car model.
if(settings.car_model_index) {
app->config_plugin->car_model_get_by_index(
app->selected_model, settings.car_model_index, app->car_models_count, app->setting);
app->selected_model->last_preset_index = settings.preset_index;
if(app->config_plugin) {
if(settings.car_model_index) {
//Get the selected car model.
app->config_plugin->car_model_get_by_index(
app->selected_model, settings.car_model_index, app->car_models_count, app->setting);
app->selected_model->last_preset_index = settings.preset_index;
protopirate_preset_init(
app,
furi_string_get_cstr(app->selected_model->preset->name),
app->selected_model->preset->frequency,
app->selected_model->preset->data,
app->selected_model->preset->data_size);
//Preset for the selected model...
protopirate_preset_init(
app,
furi_string_get_cstr(app->selected_model->preset->name),
app->selected_model->preset->frequency,
app->selected_model->preset->data,
app->selected_model->preset->data_size);
} else {
//This will return Select a model or No Models in Database
app->config_plugin->car_model_get_by_index(
app->selected_model, 0, app->car_models_count, app->setting);
//Preset set in Config.
protopirate_preset_init(app, preset_name, frequency, preset_data, preset_data_size);
}
//Kill the config plugin now.
shared_plugin_unload(app, ProtoPirateSharedPluginsConfig);
} else {
app->config_plugin->car_model_get_by_index(
app->selected_model, 0, app->car_models_count, app->setting);
//Preset set in Config.
protopirate_preset_init(app, preset_name, frequency, preset_data, preset_data_size);
}
config_or_saved_plugin_unload(app, true);
// Apply hopping state from settings
app->txrx->hopper_state = settings.hopping_enabled ? ProtoPirateHopperStateRunning :
+22 -14
View File
@@ -34,6 +34,7 @@
#endif
#include "scenes/plugins/protopirate_config_plugin.h"
#include "scenes/plugins/protopirate_saved_info_plugin.h"
#include "scenes/plugins/protopirate_about_plugin.h"
#include "scenes/plugins/protopirate_psa_bf_plugin.h"
#include "scenes/plugins/protopirate_tool_scene_plugin.h"
#include "helpers/protopirate_views.h"
@@ -44,8 +45,9 @@
#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 SAVED_INFO_PLUGIN_PATH APP_ASSETS_PATH("plugins/protopirate_saved_info_plugin.fal")
#define CONFIG_PLUGIN_PATH APP_ASSETS_PATH("plugins/pp_config.fal")
#define SAVED_INFO_PLUGIN_PATH APP_ASSETS_PATH("plugins/pp_saved_info.fal")
#define ABOUT_PLUGIN_PATH APP_ASSETS_PATH("plugins/pp_about.fal")
#define PROTOPIRATE_KEYSTORE_DIR_NAME APP_ASSETS_PATH("encrypted")
@@ -89,20 +91,19 @@ struct ProtoPirateApp {
SubGhzSetting* setting;
ProtoPirateLock lock;
FuriString* loaded_file_path;
bool deferred_storage_in_progress;
bool auto_save;
bool check_saved;
bool sound;
bool datetime_filenames;
bool radio_initialized;
uint8_t deferred_storage_in_progress : 1;
uint8_t auto_save : 1;
uint8_t check_saved : 1;
uint8_t sound : 1;
uint8_t datetime_filenames : 1;
uint8_t radio_initialized : 1;
uint8_t emulate_disabled_for_loaded : 1;
uint8_t emulate_feature_enabled : 1;
uint32_t start_tx_time;
uint8_t tx_power;
char save_filename[64];
FuriString* save_protocol;
uint16_t save_history_idx;
bool save_from_saved_info;
bool emulate_disabled_for_loaded;
bool emulate_feature_enabled;
CompositeApiResolver* plugin_resolver;
PluginManager* plugin_manager;
#ifdef ENABLE_EMULATE_FEATURE
@@ -114,6 +115,7 @@ struct ProtoPirateApp {
#endif
const ProtoPirateConfigPlugin* config_plugin;
const ProtoPirateSavedInfoPlugin* saved_info_plugin;
const ProtoPirateAboutPlugin* about_plugin;
CompositeApiResolver* psa_bf_plugin_resolver;
PluginManager* psa_bf_plugin_manager;
const ProtoPiratePsaBfPlugin* psa_bf_plugin;
@@ -129,7 +131,7 @@ struct ProtoPirateApp {
uint32_t tool_scene_nav_target;
ProtoPirateCarModel* selected_model;
uint32_t car_models_count;
uint16_t car_models_count;
};
#ifdef ENABLE_EMULATE_FEATURE
@@ -146,8 +148,14 @@ 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_or_saved_plugin_load(ProtoPirateApp* app, bool load_config);
void config_or_saved_plugin_unload(ProtoPirateApp* app, bool unload_config);
typedef enum ProtoPirateSharedPlugin {
ProtoPirateSharedPluginsConfig,
ProtoPirateSharedPluginsSavedInfo,
ProtoPirateSharedPluginsAbout,
} ProtoPirateSharedPlugin;
bool shared_plugin_load(ProtoPirateApp* app, ProtoPirateSharedPlugin plugin_type);
void shared_plugin_unload(ProtoPirateApp* app, ProtoPirateSharedPlugin plugin_type);
void protopirate_app_free(ProtoPirateApp* app);
+310
View File
@@ -0,0 +1,310 @@
#include "../../protopirate_app_i.h"
//#include "protopirate_about_plugin.h"
#include "pp_about_icons.h"
static const ProtoPirateAboutSceneHostApi* g_about_scene_host_api = NULL;
#define TAG "PPAboutPlugin"
#define CREDITS_START_Y 28
#define CREDITS_END_Y 52
#define CREDIT_LINE_HEIGHT 10
#define SCROLL_SPEED 1
#ifdef ENABLE_EMULATE_FEATURE
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]))
#endif
static const char* credits[] = {
"",
"-=> App Development by <=-",
"RocketGod",
"MMX",
"Leeroy",
"gullradriel",
"Skorp's Weather App",
"Vadim's Radio Driver",
"",
"-=> Protocol Magic by <=-",
"L0rdDiakon",
"Leeroy",
"Li0ard",
"MMX",
"YougZ",
"DoobTheGoober",
"RocketGod",
"Skorp",
"Slackware",
"Trikk",
"Wootini",
"",
"-=> RE Support <=-",
"DoobTheGoober",
"Li0ard",
"MMX",
"NeedNotApply",
"RocketGod",
"Slackware",
"Trikk",
// can add more
};
#define CREDITS_COUNT (sizeof(credits) / sizeof(credits[0]))
typedef struct {
uint8_t frame;
uint8_t seed;
int16_t scroll_offset;
#ifdef ENABLE_EMULATE_FEATURE
uint8_t combo_progress;
#endif
} GlitchState;
static GlitchState g_state = {0};
static void draw_noise_pixels(Canvas* canvas, uint8_t density) {
for(uint8_t i = 0; i < density; i++) {
canvas_draw_dot(canvas, rand() % 128, rand() % 64);
}
}
static void about_draw_callback(Canvas* canvas, void* context) {
UNUSED(context);
srand(g_state.seed);
canvas_clear(canvas);
// Light background static
canvas_set_color(canvas, ColorBlack);
draw_noise_pixels(canvas, 6 + (rand() % 6));
// Occasional subtle x-jitter
int8_t x_off = (rand() % 15 == 0) ? ((rand() % 4) - 2) : 0;
// Animated TPP decoration (centered)
canvas_set_font(canvas, FontKeyboard);
if(g_state.frame % 8 < 4) {
canvas_draw_str_aligned(
canvas, 64, 18, AlignCenter, AlignBottom, ">>>=================<<<");
} else {
canvas_draw_str_aligned(
canvas, 64, 18, AlignCenter, AlignBottom, ">>>======[TPP]======<<<");
}
// Draw credits region (clip area)
canvas_set_font(canvas, FontSecondary);
// Calculate total scroll height
int16_t total_height = CREDITS_COUNT * CREDIT_LINE_HEIGHT;
// Draw scrolling credits
for(size_t i = 0; i < CREDITS_COUNT; i++) {
int16_t y = CREDITS_START_Y + (i * CREDIT_LINE_HEIGHT) - g_state.scroll_offset;
// Wrap around for endless scroll
while(y < CREDITS_START_Y - CREDIT_LINE_HEIGHT) {
y += total_height;
}
while(y > CREDITS_START_Y + total_height) {
y -= total_height;
}
// Only draw if in visible region
if(y >= CREDITS_START_Y - CREDIT_LINE_HEIGHT && y <= CREDITS_END_Y) {
canvas_draw_str(canvas, x_off, y, credits[i]);
}
}
// Draw fade/mask bars at top and bottom of credits area
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, 0, 0, 128, CREDITS_START_Y - CREDIT_LINE_HEIGHT);
canvas_draw_box(canvas, 0, CREDITS_END_Y, 128, 14);
// Redraw header over mask
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, x_off, 10, "ProtoPirate v" FAP_VERSION);
canvas_set_font(canvas, FontKeyboard);
if(g_state.frame % 8 < 4) {
canvas_draw_str_aligned(
canvas, 64, 18, AlignCenter, AlignBottom, ">>>=================<<<");
} else {
canvas_draw_str_aligned(
canvas, 64, 18, AlignCenter, AlignBottom, ">>>======[TPP]======<<<");
}
// Redraw static in header area
srand(g_state.seed + 1);
for(uint8_t i = 0; i < 3; i++) {
canvas_draw_dot(canvas, rand() % 128, rand() % (CREDITS_START_Y - CREDIT_LINE_HEIGHT));
}
// Footer: The Pirate's Plunder Discord
canvas_set_font(canvas, FontKeyboard);
canvas_draw_str_aligned(canvas, 127, 62, AlignRight, AlignBottom, "discord.gg/thepirates");
// Rare subtle glitch bar
if(rand() % 30 == 0) {
canvas_set_color(canvas, ColorXOR);
uint8_t y = rand() % 60;
canvas_draw_box(canvas, 0, y, 128, 2);
}
}
static bool about_input_callback(InputEvent* event, void* context) {
furi_check(context);
#ifdef ENABLE_EMULATE_FEATURE
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;
#else
UNUSED(event);
return false;
#endif
}
#ifdef ENABLE_EMULATE_FEATURE
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);
}
#endif
void plugin_protopirate_scene_about_on_enter(void* context) {
furi_check(context);
ProtoPirateApp* app = context;
if(!g_about_scene_host_api->ensure_view_about(app)) {
notification_message(app->notifications, &sequence_error);
scene_manager_previous_scene(app->scene_manager);
return;
}
g_state.frame = 0;
g_state.seed = furi_get_tick() & 0xFF;
g_state.scroll_offset = 0;
#ifdef ENABLE_EMULATE_FEATURE
g_state.combo_progress = 0;
#endif
view_set_draw_callback(app->view_about, about_draw_callback);
view_set_input_callback(app->view_about, about_input_callback);
view_set_context(app->view_about, app);
view_dispatcher_switch_to_view(app->view_dispatcher, ProtoPirateViewAbout);
}
bool plugin_protopirate_scene_about_on_event(void* context, SceneManagerEvent event) {
ProtoPirateApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeTick) {
g_state.frame++;
if(g_state.frame % 2 == 0) {
g_state.scroll_offset += SCROLL_SPEED;
int16_t total_height = CREDITS_COUNT * CREDIT_LINE_HEIGHT;
if(g_state.scroll_offset >= total_height) {
g_state.scroll_offset = 0;
}
}
view_commit_model(app->view_about, true);
consumed = true;
}
#ifdef ENABLE_EMULATE_FEATURE
else if(event.type == SceneManagerEventTypeCustom) {
if(event.event == ProtoPirateCustomEventAboutToggleEmulate) {
//Toggle Emulate on
app->emulate_feature_enabled = !app->emulate_feature_enabled;
ProtoPirateSettings settings;
g_about_scene_host_api->settings_load(&settings);
settings.emulate_feature_enabled = app->emulate_feature_enabled;
g_about_scene_host_api->settings_save(&settings);
notification_message(
app->notifications,
app->emulate_feature_enabled ? &sequence_success : &sequence_semi_success);
about_show_emulate_toggle_popup(app);
consumed = true;
}
}
#endif
return consumed;
}
void plugin_protopirate_scene_about_on_exit(void* context) {
UNUSED(context);
}
void about_plugin_set_host_api(const ProtoPirateAboutSceneHostApi* host_api) {
g_about_scene_host_api = host_api;
}
static const ProtoPirateAboutPlugin protopirate_about_plugin = {
.plugin_name = "About",
.on_enter = plugin_protopirate_scene_about_on_enter,
.on_event = plugin_protopirate_scene_about_on_event,
.on_exit = plugin_protopirate_scene_about_on_exit,
.set_host_api = about_plugin_set_host_api,
};
static const FlipperAppPluginDescriptor protopirate_about_plugin_descriptor = {
.appid = PROTOPIRATE_ABOUT_PLUGIN_APP_ID,
.ep_api_version = PROTOPIRATE_ABOUT_PLUGIN_API_VERSION,
.entry_point = &protopirate_about_plugin,
};
const FlipperAppPluginDescriptor* protopirate_about_plugin_ep(void) {
return &protopirate_about_plugin_descriptor;
}
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include <gui/scene_manager.h>
#include "../../helpers/protopirate_settings.h"
#define PROTOPIRATE_ABOUT_PLUGIN_APP_ID "pp_about"
#define PROTOPIRATE_ABOUT_PLUGIN_API_VERSION 1U
typedef struct ProtoPirateApp ProtoPirateApp;
typedef struct ProtoPirateAboutSceneHostApi {
bool (*ensure_view_about)(ProtoPirateApp* app);
void (*settings_load)(ProtoPirateSettings* settings);
void (*settings_save)(ProtoPirateSettings* settings);
} ProtoPirateAboutSceneHostApi;
typedef struct ProtoPirateAboutPlugin {
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 ProtoPirateAboutSceneHostApi* host_api);
} ProtoPirateAboutPlugin;
+1 -1
View File
@@ -490,7 +490,7 @@ void config_plugin_set_host_api(const ProtoPirateConfigSceneHostApi* host_api) {
}
static const ProtoPirateConfigPlugin protopirate_config_plugin = {
.plugin_name = "ProtoPirate Config",
.plugin_name = "Config",
.car_model_get_by_index = car_model_get_by_index,
.car_model_get_count = car_model_get_count,
.on_enter = plugin_on_enter,
+1 -1
View File
@@ -3,7 +3,7 @@
#include <lib/flipper_application/flipper_application.h>
#include "helpers/variable_item_list.h"
#define PROTOPIRATE_CONFIG_PLUGIN_APP_ID "protopirate_config_plugin"
#define PROTOPIRATE_CONFIG_PLUGIN_APP_ID "pp_config"
#define PROTOPIRATE_CONFIG_PLUGIN_API_VERSION 2U
enum ProtoPirateSettingIndex {
+2 -2
View File
@@ -31,7 +31,7 @@
#include <furi.h>
#include <string.h>
#define TAG "ProtoPirateEmulatePlugin"
#define TAG "PPEmulatePlugin"
#define MIN_TX_TIME 666U
#define MIN_TX_TIME_KIA_V3_V4 1600U
@@ -1571,7 +1571,7 @@ static void plugin_set_host_api(const ProtoPirateEmulateHostApi* host_api) {
}
static const ProtoPirateEmulatePlugin protopirate_emulate_plugin = {
.plugin_name = "ProtoPirate Emulate",
.plugin_name = "Emulate",
.set_host_api = plugin_set_host_api,
.on_enter = plugin_on_enter,
.on_event = plugin_on_event,
+1 -1
View File
@@ -6,7 +6,7 @@
#include <lib/flipper_application/flipper_application.h>
#include <gui/scene_manager.h>
#define PROTOPIRATE_EMULATE_PLUGIN_APP_ID "protopirate_emulate_plugin"
#define PROTOPIRATE_EMULATE_PLUGIN_APP_ID "pp_emulate"
#define PROTOPIRATE_EMULATE_PLUGIN_API_VERSION 2U
typedef struct {
+2 -2
View File
@@ -9,7 +9,7 @@
#include <gui/modules/widget.h>
#include <gui/modules/widget_elements/widget_element.h>
#ifdef PROTOPIRATE_PSA_BF_PLUGIN_BUILD
#include "protopirate_psa_bf_plugin_icons.h"
#include "pp_bf_icons.h"
#else
#include "proto_pirate_icons.h"
#endif
@@ -521,7 +521,7 @@ static void plugin_set_host_api(const ProtoPiratePsaBfHostApi* api) {
}
static const ProtoPiratePsaBfPlugin protopirate_psa_bf_plugin = {
.plugin_name = "ProtoPirate PSA BF",
.plugin_name = "BF",
.set_host_api = plugin_set_host_api,
.needs_bruteforce = plugin_needs_bruteforce,
.is_running = plugin_is_running,
+1 -1
View File
@@ -8,7 +8,7 @@
#include "../../protocols/psa_bf_types.h"
#define PROTOPIRATE_PSA_BF_PLUGIN_APP_ID "protopirate_psa_bf_plugin"
#define PROTOPIRATE_PSA_BF_PLUGIN_APP_ID "pp_bf"
#define PROTOPIRATE_PSA_BF_PLUGIN_API_VERSION 2U
typedef struct ProtoPirateApp ProtoPirateApp;
@@ -3,11 +3,11 @@
#include "../../helpers/protopirate_storage.h"
#include "../../protocols/protocols_common.h"
#include "../../protocols/protocol_items.h"
#include "protopirate_saved_info_plugin_icons.h"
#include "pp_saved_info_icons.h"
static const ProtoPirateSavedInfoSceneHostApi* g_saved_info_scene_host_api = NULL;
#define TAG "ProtoPirateSavedInfoPlugin"
#define TAG "PPSavedInfoPlugin"
#define STATE_EMULATE 0
#define STATE_BF 1
@@ -359,7 +359,7 @@ void saved_info_plugin_set_host_api(const ProtoPirateSavedInfoSceneHostApi* host
}
static const ProtoPirateSavedInfoPlugin protopirate_saved_info_plugin = {
.plugin_name = "ProtoPirate Saved Info",
.plugin_name = "Saved",
.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,
@@ -1,7 +1,7 @@
#pragma once
#include <gui/scene_manager.h>
#define PROTOPIRATE_SAVED_INFO_PLUGIN_APP_ID "protopirate_saved_info_plugin"
#define PROTOPIRATE_SAVED_INFO_PLUGIN_APP_ID "pp_saved_info"
#define PROTOPIRATE_SAVED_INFO_PLUGIN_API_VERSION 1U
typedef struct ProtoPirateApp ProtoPirateApp;
+15 -264
View File
@@ -1,292 +1,43 @@
// scenes/protopirate_scene_about.c
#include "../protopirate_app_i.h"
#include "../helpers/protopirate_settings.h"
#include "proto_pirate_icons.h"
#include <gui/elements.h>
#include <input/input.h>
#include <dialogs/dialogs.h>
#include <stdlib.h>
#define CREDITS_START_Y 28
#define CREDITS_END_Y 52
#define CREDIT_LINE_HEIGHT 10
#define SCROLL_SPEED 1
#ifdef ENABLE_EMULATE_FEATURE
static const InputKey EMULATE_TOGGLE_COMBO[] = {
InputKeyUp,
InputKeyUp,
InputKeyDown,
InputKeyDown,
InputKeyLeft,
InputKeyRight,
InputKeyLeft,
InputKeyRight,
static const ProtoPirateAboutSceneHostApi protopirate_about_scene_host_api = {
.ensure_view_about = protopirate_ensure_view_about,
.settings_load = protopirate_settings_load,
.settings_save = protopirate_settings_save,
};
#define EMULATE_TOGGLE_COMBO_LEN (sizeof(EMULATE_TOGGLE_COMBO) / sizeof(EMULATE_TOGGLE_COMBO[0]))
#endif
static const char* credits[] = {
"",
"-=> App Development by",
"RocketGod",
"MMX",
"Leeroy",
"gullradriel",
"Skorp's Weather App",
"Vadim's Radio Driver",
"-=> Protocol Magic by",
"L0rdDiakon",
"Leeroy",
"Li0ard",
"MMX",
"YougZ",
"DoobTheGoober",
"RocketGod",
"Skorp",
"Slackware",
"Trikk",
"Wootini",
"-=> RE Support",
"DoobTheGoober",
"Li0ard",
"MMX",
"NeedNotApply",
"RocketGod",
"Slackware",
"Trikk",
// can add more
};
#define CREDITS_COUNT (sizeof(credits) / sizeof(credits[0]))
typedef struct {
uint8_t frame;
uint8_t seed;
int16_t scroll_offset;
#ifdef ENABLE_EMULATE_FEATURE
uint8_t combo_progress;
#endif
} GlitchState;
static GlitchState g_state = {0};
static void draw_noise_pixels(Canvas* canvas, uint8_t density) {
for(uint8_t i = 0; i < density; i++) {
canvas_draw_dot(canvas, rand() % 128, rand() % 64);
}
}
static void about_draw_callback(Canvas* canvas, void* context) {
UNUSED(context);
srand(g_state.seed);
canvas_clear(canvas);
// Light background static
canvas_set_color(canvas, ColorBlack);
draw_noise_pixels(canvas, 6 + (rand() % 6));
// Occasional subtle x-jitter
int8_t x_off = (rand() % 15 == 0) ? ((rand() % 4) - 2) : 0;
// Animated TPP decoration (centered)
canvas_set_font(canvas, FontKeyboard);
if(g_state.frame % 8 < 4) {
canvas_draw_str_aligned(
canvas, 64, 18, AlignCenter, AlignBottom, ">>>=================<<<");
} else {
canvas_draw_str_aligned(
canvas, 64, 18, AlignCenter, AlignBottom, ">>>======[TPP]======<<<");
}
// Draw credits region (clip area)
canvas_set_font(canvas, FontSecondary);
// Calculate total scroll height
int16_t total_height = CREDITS_COUNT * CREDIT_LINE_HEIGHT;
// Draw scrolling credits
for(size_t i = 0; i < CREDITS_COUNT; i++) {
int16_t y = CREDITS_START_Y + (i * CREDIT_LINE_HEIGHT) - g_state.scroll_offset;
// Wrap around for endless scroll
while(y < CREDITS_START_Y - CREDIT_LINE_HEIGHT) {
y += total_height;
}
while(y > CREDITS_START_Y + total_height) {
y -= total_height;
}
// Only draw if in visible region
if(y >= CREDITS_START_Y - CREDIT_LINE_HEIGHT && y <= CREDITS_END_Y) {
canvas_draw_str(canvas, x_off, y, credits[i]);
}
}
// Draw fade/mask bars at top and bottom of credits area
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, 0, 0, 128, CREDITS_START_Y - CREDIT_LINE_HEIGHT);
canvas_draw_box(canvas, 0, CREDITS_END_Y, 128, 14);
// Redraw header over mask
canvas_set_color(canvas, ColorBlack);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, x_off, 10, "ProtoPirate v" FAP_VERSION);
canvas_set_font(canvas, FontKeyboard);
if(g_state.frame % 8 < 4) {
canvas_draw_str_aligned(
canvas, 64, 18, AlignCenter, AlignBottom, ">>>=================<<<");
} else {
canvas_draw_str_aligned(
canvas, 64, 18, AlignCenter, AlignBottom, ">>>======[TPP]======<<<");
}
// Redraw static in header area
srand(g_state.seed + 1);
for(uint8_t i = 0; i < 3; i++) {
canvas_draw_dot(canvas, rand() % 128, rand() % (CREDITS_START_Y - CREDIT_LINE_HEIGHT));
}
// Footer: The Pirate's Plunder Discord
canvas_set_font(canvas, FontKeyboard);
canvas_draw_str_aligned(canvas, 127, 62, AlignRight, AlignBottom, "discord.gg/thepirates");
// Rare subtle glitch bar
if(rand() % 30 == 0) {
canvas_set_color(canvas, ColorXOR);
uint8_t y = rand() % 60;
canvas_draw_box(canvas, 0, y, 128, 2);
}
}
static bool about_input_callback(InputEvent* event, void* context) {
furi_check(context);
#ifdef ENABLE_EMULATE_FEATURE
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;
#else
UNUSED(event);
return false;
#endif
}
#ifdef ENABLE_EMULATE_FEATURE
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);
}
#endif
void protopirate_scene_about_on_enter(void* context) {
furi_check(context);
ProtoPirateApp* app = context;
if(!protopirate_ensure_view_about(app)) {
if(!shared_plugin_load(app, ProtoPirateSharedPluginsAbout)) {
notification_message(app->notifications, &sequence_error);
scene_manager_previous_scene(app->scene_manager);
return;
}
g_state.frame = 0;
g_state.seed = furi_get_tick() & 0xFF;
g_state.scroll_offset = 0;
#ifdef ENABLE_EMULATE_FEATURE
g_state.combo_progress = 0;
#endif
view_set_draw_callback(app->view_about, about_draw_callback);
view_set_input_callback(app->view_about, about_input_callback);
view_set_context(app->view_about, app);
view_dispatcher_switch_to_view(app->view_dispatcher, ProtoPirateViewAbout);
app->about_plugin->set_host_api(&protopirate_about_scene_host_api);
app->about_plugin->on_enter(app);
}
bool protopirate_scene_about_on_event(void* context, SceneManagerEvent event) {
ProtoPirateApp* app = context;
bool consumed = false;
ProtoPirateApp* app = (ProtoPirateApp*)context;
if(event.type == SceneManagerEventTypeTick) {
g_state.frame++;
g_state.seed = rand();
if(g_state.frame % 2 == 0) {
g_state.scroll_offset += SCROLL_SPEED;
int16_t total_height = CREDITS_COUNT * CREDIT_LINE_HEIGHT;
if(g_state.scroll_offset >= total_height) {
g_state.scroll_offset = 0;
}
}
view_commit_model(app->view_about, true);
consumed = true;
//I can't set the next scene from inside the plugin, or it causes crazy crashes.
if(event.type == SceneManagerEventTypeBack) {
scene_manager_previous_scene(app->scene_manager);
return true;
}
#ifdef ENABLE_EMULATE_FEATURE
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;
}
}
#endif
return consumed;
//Handle About event in plugin.
return app->about_plugin->on_event(app, event);
}
void protopirate_scene_about_on_exit(void* context) {
furi_check(context);
ProtoPirateApp* app = context;
view_set_draw_callback(app->view_about, NULL);
view_set_input_callback(app->view_about, NULL);
view_set_context(app->view_about, NULL);
shared_plugin_unload(app, ProtoPirateSharedPluginsAbout);
}
+2 -2
View File
@@ -11,9 +11,9 @@
#include <lib/flipper_application/plugins/plugin_manager.h>
#include <lib/flipper_application/plugins/composite_resolver.h>
#define TAG "ProtoPirateSceneEmulate"
#define TAG "PPSceneEmulate"
#define EMULATE_PLUGIN_PATH APP_ASSETS_PATH("plugins/protopirate_emulate_plugin.fal")
#define EMULATE_PLUGIN_PATH APP_ASSETS_PATH("plugins/pp_emulate.fal")
static bool host_radio_init(void* app) {
return protopirate_radio_init((ProtoPirateApp*)app);
+1 -1
View File
@@ -2,7 +2,7 @@
#include "../protopirate_app_i.h"
#include "proto_pirate_icons.h"
#define TAG "ProtoPirateNeedSaving"
#define TAG "PPNeedSaving"
static void
protopirate_scene_need_saving_callback(GuiButtonType result, InputType type, void* context) {
+1 -1
View File
@@ -7,7 +7,7 @@
#include <stdio.h>
#include "proto_pirate_icons.h"
#define TAG "ProtoPirateSceneRx"
#define TAG "PPSceneRx"
#define DEFERRED_STORAGE_TIME 1000
+2 -2
View File
@@ -11,7 +11,7 @@ static const ProtoPirateConfigSceneHostApi protopirate_config_scene_host_api = {
void protopirate_scene_receiver_config_on_enter(void* context) {
ProtoPirateApp* app = context;
if(!config_or_saved_plugin_load(app, true)) {
if(!shared_plugin_load(app, ProtoPirateSharedPluginsConfig)) {
notification_message(app->notifications, &sequence_error);
scene_manager_previous_scene(app->scene_manager);
return;
@@ -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_or_saved_plugin_unload(app, true);
shared_plugin_unload(app, ProtoPirateSharedPluginsConfig);
}
+1 -2
View File
@@ -6,7 +6,7 @@
#include "proto_pirate_icons.h"
#include <storage/storage.h>
#define TAG "ProtoPirateReceiverInfo"
#define TAG "PPReceiverInfo"
#define STATE_EMULATE 0
#define STATE_BF 1
@@ -329,7 +329,6 @@ bool protopirate_scene_receiver_info_on_event(void* context, SceneManagerEvent e
if(app->save_protocol) furi_string_free(app->save_protocol);
app->save_protocol = protocol; // transfer ownership
app->save_history_idx = app->txrx->idx_menu_chosen;
app->save_from_saved_info = false;
// Configure and show text input
text_input_reset(app->text_input);
+2 -2
View File
@@ -4,7 +4,7 @@
#include "proto_pirate_icons.h"
#define TAG "ProtoPirateSceneSaved"
#define TAG "PPSceneSaved"
void protopirate_scene_saved_on_enter(void* context) {
furi_check(context);
@@ -34,7 +34,7 @@ void protopirate_scene_saved_on_enter(void* context) {
}
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, ".psf", &I_subghz_10px);
dialog_file_browser_set_basic_options(&browser_options, ".psf", &I_protopirate_10px);
browser_options.base_path = PROTOPIRATE_APP_FOLDER;
browser_options.skip_assets = true;
browser_options.hide_dot_files = true;
+6 -6
View File
@@ -16,7 +16,7 @@ static const ProtoPirateSavedInfoSceneHostApi protopirate_saved_info_scene_host_
void protopirate_scene_saved_info_on_enter(void* context) {
ProtoPirateApp* app = context;
if(!config_or_saved_plugin_load(app, false)) {
if(!shared_plugin_load(app, ProtoPirateSharedPluginsSavedInfo)) {
notification_message(app->notifications, &sequence_error);
scene_manager_previous_scene(app->scene_manager);
return;
@@ -27,13 +27,14 @@ void protopirate_scene_saved_info_on_enter(void* context) {
}
bool protopirate_scene_saved_info_on_event(void* context, SceneManagerEvent event) {
ProtoPirateApp* app = ((ProtoPirateApp*)context);
//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.
#ifdef ENABLE_EMULATE_FEATURE
scene_manager_next_scene(
((ProtoPirateApp*)context)->scene_manager, ProtoPirateSceneEmulate);
scene_manager_next_scene(app->scene_manager, ProtoPirateSceneEmulate);
return true;
#endif
} else if(event.event == ProtoPirateCustomEventSavedInfoExit) {
@@ -43,12 +44,11 @@ bool protopirate_scene_saved_info_on_event(void* context, SceneManagerEvent even
}
//Handle Saved Info event in plugin.
return ((ProtoPirateApp*)context)->saved_info_plugin->on_event(context, event);
return app->saved_info_plugin->on_event(app, event);
}
void protopirate_scene_saved_info_on_exit(void* context) {
ProtoPirateApp* app = context;
UNUSED(app);
config_or_saved_plugin_unload(app, false);
shared_plugin_unload(app, ProtoPirateSharedPluginsSavedInfo);
}
+1 -1
View File
@@ -4,7 +4,7 @@
#include "proto_pirate_icons.h"
#define TAG "ProtoPirateSceneStart"
#define TAG "PPSceneStart"
typedef enum {
SubmenuIndexProtoPirateReceiver,
+3 -4
View File
@@ -36,12 +36,12 @@ void protopirate_scene_sub_decode_on_exit(void* context) {
#include <lib/subghz/types.h>
#ifdef PROTOPIRATE_SUB_DECODE_PLUGIN_BUILD
#include "protopirate_sub_decode_plugin_icons.h"
#include "pp_sub_decode_icons.h"
#else
#include "proto_pirate_icons.h"
#endif
#define TAG "ProtoPirateSubDecode"
#define TAG "PPSubDecode"
static const ProtoPirateToolSceneHostApi* g_tool_scene_host_api = NULL;
@@ -689,7 +689,6 @@ bool protopirate_scene_sub_decode_on_event(void* context, SceneManagerEvent even
// Store context for when text input confirms
app->save_history_idx = app->txrx->idx_menu_chosen;
app->save_from_saved_info = false;
//Make sure we have a text input window.
app->text_input = text_input_alloc();
@@ -1468,7 +1467,7 @@ static void sub_decode_plugin_set_host_api(const ProtoPirateToolSceneHostApi* ho
}
static const ProtoPirateToolScenePlugin protopirate_sub_decode_plugin = {
.plugin_name = "ProtoPirate Sub Decode",
.plugin_name = "Sub Decode",
.kind = ProtoPirateToolScenePluginKindSubDecode,
.set_host_api = sub_decode_plugin_set_host_api,
.on_enter = protopirate_scene_sub_decode_on_enter,
+2 -2
View File
@@ -23,7 +23,7 @@ void protopirate_scene_timing_tuner_on_exit(void* context) {
#include <gui/elements.h>
#include <math.h>
#define TAG "ProtoPirateTimingTuner"
#define TAG "PPTimingTuner"
static const ProtoPirateToolSceneHostApi* g_tool_scene_host_api = NULL;
@@ -808,7 +808,7 @@ static void timing_tuner_plugin_set_host_api(const ProtoPirateToolSceneHostApi*
}
static const ProtoPirateToolScenePlugin protopirate_timing_tuner_plugin = {
.plugin_name = "ProtoPirate Timing Tuner",
.plugin_name = "Timing Tuner",
.kind = ProtoPirateToolScenePluginKindTimingTuner,
.set_host_api = timing_tuner_plugin_set_host_api,
.on_enter = protopirate_scene_timing_tuner_on_enter,