Merge pull request 'Add ENABLE_MODELS_DATABASE build flag' (#67) from RalphWiggum/ProtoPirate:models_build_flag 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/67
Reviewed-by: MMX <mmx@no-reply.protopirate.net>
This commit is contained in:
MMX committed 2026-09-29 07:03:54 -04:00
commit 1c26a60cf3
48 files changed
+688 -587

No files matched your search

+8 -1
View File
@@ -14,6 +14,7 @@ def ProtoPirateDefineEnabled(name, app_manifest_path=app_manifest_path):
_ENABLE_TIMING_TUNER = ProtoPirateDefineEnabled("ENABLE_TIMING_TUNER_SCENE")
_ENABLE_EMULATE = ProtoPirateDefineEnabled("ENABLE_EMULATE_FEATURE")
_ENABLE_MODELS_DATABASE = ProtoPirateDefineEnabled("ENABLE_MODELS_DATABASE")
_MAIN_APP_SOURCES = [
"*.c*",
@@ -43,6 +44,12 @@ if not _ENABLE_EMULATE:
"!protopirate_scene_emulate.c",
]
if _ENABLE_MODELS_DATABASE:
_ASSETS="assets"
else:
_ASSETS="assets/keystore"
App(
appid="proto_pirate",
name="ProtoPirate",
@@ -56,7 +63,7 @@ App(
fap_icon="images/protopirate_10px.png",
fap_category="Sub-GHz",
fap_icon_assets="images",
fap_file_assets="keystore",
fap_file_assets=_ASSETS,
cdefines=["PROTOPIRATE_PROTOCOL_RX_ONLY=1"],
sources=_MAIN_APP_SOURCES,
)
File renamed without changes.
File renamed without changes.
File renamed without changes.
+2
View File
@@ -1,8 +1,10 @@
#pragma once
#include <furi.h>
// #define ENABLE_TIMING_TUNER_SCENE
#define ENABLE_SUB_DECODE_SCENE
#define ENABLE_EMULATE_FEATURE
#define ENABLE_MODELS_DATABASE
#if defined(ENABLE_EMULATE_FEATURE) && !defined(PROTOPIRATE_PROTOCOL_RX_ONLY)
#define PROTOPIRATE_WITH_ENCODER 1
+3 -1
View File
@@ -1,8 +1,9 @@
#include "protopirate_models.h"
#ifdef ENABLE_MODELS_DATABASE
#define TAG "PPModels"
#define PROTOPIRATE_MODELS_FILE APP_ASSETS_PATH("models.txt")
#define PROTOPIRATE_MODELS_FILE APP_ASSETS_PATH("models_db/models.txt")
//Models File Format.
#define MODELS_FILE_HEADER "ProtoPirate Car Models Database"
@@ -294,3 +295,4 @@ uint16_t car_model_get_count(void) {
//Finished, return the count or 0 if error.
return (uint16_t)model_count;
}
#endif
+4
View File
@@ -1,5 +1,8 @@
#pragma once
#include <furi.h>
#include "../defines.h"
#ifdef ENABLE_MODELS_DATABASE
#include <lib/subghz/types.h>
#include "core/record.h"
#include <lib/subghz/subghz_setting.h>
@@ -18,3 +21,4 @@ bool car_model_get_by_index(
SubGhzSetting* app_settings);
uint16_t car_model_get_count(void);
#endif
+258
View File
@@ -0,0 +1,258 @@
#include "protopirate_plugins.h"
#include <loader/firmware_api/firmware_api.h>
#define TAG "PPPlugins"
// -----------------------------------------------------------------------------
// Plugin load / unload
// -----------------------------------------------------------------------------
const FlipperAppPluginDescriptor* load_plugin_fal(
FlipperApplication** fal_app,
const char* plugin_path,
const char* application_id,
uint32_t api_version) {
const FlipperAppPluginDescriptor* app_descriptor;
bool return_value = false;
do {
FlipperApplicationPreloadStatus preload_res =
flipper_application_preload(*fal_app, plugin_path);
if(preload_res != FlipperApplicationPreloadStatusSuccess) {
FURI_LOG_E(TAG, "Failed to preload plugin: %s", plugin_path);
break;
}
if(!flipper_application_is_plugin(*fal_app)) {
FURI_LOG_E(TAG, "Plugin file is not a library");
break;
}
FlipperApplicationLoadStatus load_status = flipper_application_map_to_memory(*fal_app);
if(load_status != FlipperApplicationLoadStatusSuccess) {
FURI_LOG_E(TAG, "Failed to load plugin file");
break;
}
FURI_LOG_D(TAG, "is mapped to memory");
app_descriptor = flipper_application_plugin_get_descriptor(*fal_app);
if(strcmp(app_descriptor->appid, application_id) != 0) {
FURI_LOG_E(TAG, "Application id mismatch %s", application_id);
break;
}
if(app_descriptor->ep_api_version != api_version) {
FURI_LOG_E(TAG, "API version mismatch %lu", api_version);
break;
}
FURI_LOG_I(
TAG,
"Loaded plugin for appid '%s', API %lu",
app_descriptor->appid,
app_descriptor->ep_api_version);
return_value = true;
} while(false);
//Free the applciation if there was an error, otherwise return the app descriptor.
if(return_value) {
return app_descriptor;
} else {
if(*fal_app) {
flipper_application_free(*fal_app);
*fal_app = NULL;
}
return NULL;
}
}
void shared_plugin_unload(void** flipper_application_pointer, const void** plugin_pointer) {
//Free the flipper application.
if(*flipper_application_pointer) {
flipper_application_free(*flipper_application_pointer);
*flipper_application_pointer = NULL;
}
//Free the pointer.
if(*plugin_pointer) {
*plugin_pointer = NULL;
}
}
bool shared_plugin_load(
void** flipper_application_pointer,
const void** plugin_pointer,
ProtoPirateSharedPlugin plugin_type,
const char* txrx_path) {
const char* application_id = NULL;
const char* plugin_path = NULL;
uint32_t api_version = 0;
if(*plugin_pointer) return true;
switch(plugin_type) {
case ProtoPirateSharedPluginsConfig: {
application_id = PROTOPIRATE_CONFIG_PLUGIN_APP_ID;
api_version = PROTOPIRATE_CONFIG_PLUGIN_API_VERSION;
plugin_path = CONFIG_PLUGIN_PATH;
break;
}
case ProtoPirateSharedPluginsSavedInfo: {
application_id = PROTOPIRATE_SAVED_INFO_PLUGIN_APP_ID;
api_version = PROTOPIRATE_SAVED_INFO_PLUGIN_API_VERSION;
plugin_path = SAVED_INFO_PLUGIN_PATH;
break;
}
case ProtoPirateSharedPluginsAbout: {
application_id = PROTOPIRATE_ABOUT_PLUGIN_APP_ID;
api_version = PROTOPIRATE_ABOUT_PLUGIN_API_VERSION;
plugin_path = ABOUT_PLUGIN_PATH;
break;
}
#ifdef ENABLE_EMULATE_FEATURE
case ProtoPirateSharedPluginsEmulate: {
application_id = PROTOPIRATE_EMULATE_PLUGIN_APP_ID;
api_version = PROTOPIRATE_EMULATE_PLUGIN_API_VERSION;
plugin_path = EMULATE_PLUGIN_PATH;
break;
}
#endif
case ProtoPirateSharedPluginsSubDecode: {
application_id = PROTOPIRATE_TOOL_SCENE_PLUGIN_APP_ID;
api_version = PROTOPIRATE_TOOL_SCENE_PLUGIN_API_VERSION;
plugin_path = SUB_DECODE_PLUGIN_PATH;
break;
}
#ifdef ENABLE_TIMING_TUNER_SCENE
case ProtoPirateSharedPluginsTimingTuner: {
application_id = PROTOPIRATE_TOOL_SCENE_PLUGIN_APP_ID;
api_version = PROTOPIRATE_TOOL_SCENE_PLUGIN_API_VERSION;
plugin_path = TIMING_TUNER_PLUGIN_PATH;
break;
}
#endif
case ProtoPirateSharedPluginsPSABruteforce: {
application_id = PROTOPIRATE_PSA_BF_PLUGIN_APP_ID;
api_version = PROTOPIRATE_PSA_BF_PLUGIN_API_VERSION;
plugin_path = PSA_BF_PLUGIN_PATH;
break;
}
case ProtoPirateSharedPluginsTXRX: {
application_id = PROTOPIRATE_PROTOCOL_PLUGIN_APP_ID;
api_version = PROTOPIRATE_PROTOCOL_PLUGIN_API_VERSION;
plugin_path = txrx_path;
break;
}
default:
return false;
}
FURI_LOG_D(TAG, "Loading plugin: %s", plugin_path);
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperApplication* fal_app = flipper_application_alloc(storage, firmware_api_interface);
bool return_value = false;
do {
//Load the FAP
const FlipperAppPluginDescriptor* app_descriptor =
load_plugin_fal(&fal_app, plugin_path, application_id, api_version);
if(app_descriptor) {
//Get the Plugin and assign it.
if(plugin_type == ProtoPirateSharedPluginsConfig) {
const ProtoPirateConfigPlugin* plugin_config = app_descriptor->entry_point;
if(!plugin_config || !plugin_config->on_enter) {
FURI_LOG_E(TAG, "Config plugin entry point is invalid");
} else {
*plugin_pointer = plugin_config;
return_value = true;
}
} else if(plugin_type == ProtoPirateSharedPluginsSavedInfo) {
const ProtoPirateSavedInfoPlugin* plugin_saved_info = app_descriptor->entry_point;
if(!plugin_saved_info || !plugin_saved_info->on_enter) {
FURI_LOG_E(TAG, "Saved Info plugin entry point is invalid");
} else {
*plugin_pointer = plugin_saved_info;
return_value = true;
}
} else if(plugin_type == ProtoPirateSharedPluginsAbout) {
const ProtoPirateAboutPlugin* plugin_about = app_descriptor->entry_point;
if(!plugin_about || !plugin_about->on_enter) {
FURI_LOG_E(TAG, "About plugin entry point is invalid");
} else {
*plugin_pointer = plugin_about;
return_value = true;
}
}
#ifdef ENABLE_EMULATE_FEATURE
else if(plugin_type == ProtoPirateSharedPluginsEmulate) {
const ProtoPirateEmulatePlugin* plugin_emulate = app_descriptor->entry_point;
if(!plugin_emulate || !plugin_emulate->on_enter) {
FURI_LOG_E(TAG, "Emulate plugin entry point is invalid");
} else {
*plugin_pointer = plugin_emulate;
return_value = true;
}
}
#endif
else if(
plugin_type == ProtoPirateSharedPluginsSubDecode
#ifdef ENABLE_TIMING_TUNER_SCENE
|| plugin_type == ProtoPirateSharedPluginsTimingTuner
#endif
) {
const ProtoPirateToolScenePlugin* plugin_tool_scene = app_descriptor->entry_point;
if(!plugin_tool_scene || !plugin_tool_scene->on_enter) {
FURI_LOG_E(TAG, "Tool Scene plugin entry point is invalid");
} else {
*plugin_pointer = plugin_tool_scene;
return_value = true;
}
} else if(plugin_type == ProtoPirateSharedPluginsPSABruteforce) {
const ProtoPiratePsaBfPlugin* plugin_psa_bf = app_descriptor->entry_point;
if(!plugin_psa_bf || !plugin_psa_bf->needs_bruteforce) {
FURI_LOG_E(TAG, "PSA plugin entry needs_bruteforce is invalid");
} else {
*plugin_pointer = plugin_psa_bf;
return_value = true;
}
} else if(plugin_type == ProtoPirateSharedPluginsTXRX) {
const ProtoPirateProtocolPlugin* plugin_txrx = app_descriptor->entry_point;
if(!plugin_txrx || !plugin_txrx->registry) {
FURI_LOG_E(TAG, "Protocol plugin registry entry is invalid");
} else {
*plugin_pointer = plugin_txrx;
return_value = true;
}
}
}
} while(false);
//Free the plugin if there was an error, otherwise we are done!
*flipper_application_pointer = fal_app;
furi_record_close(RECORD_STORAGE);
return return_value;
}
bool shared_plugin_handle_navigation_events(
SceneManager* scene_manager,
ViewDispatcher* view_dispatcher,
SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == ProtoPirateCustomEventPluginNavigateEmulate) {
#ifdef ENABLE_EMULATE_FEATURE
scene_manager_next_scene(scene_manager, ProtoPirateSceneEmulate);
#endif
return true;
}
if(event.event == ProtoPirateCustomEventPluginNavigateConfig) {
scene_manager_next_scene(scene_manager, ProtoPirateSceneReceiverConfig);
return true;
} else if(event.event == ProtoPirateCustomEventPluginNavigateBack) {
scene_manager_previous_scene(scene_manager);
return true;
} else if(event.event == ProtoPirateCustomEventPluginNavigateStopApp) {
scene_manager_stop(scene_manager);
view_dispatcher_stop(view_dispatcher);
return true;
}
}
return false;
}
+54
View File
@@ -0,0 +1,54 @@
#pragma once
#include "../defines.h"
#include <lib/flipper_application/flipper_application.h>
#include <gui/scene_manager.h>
#include <gui/view_dispatcher.h>
#ifdef ENABLE_EMULATE_FEATURE
#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_about_plugin.h"
#include "scenes/plugins/protopirate_psa_bf_plugin.h"
#include "scenes/plugins/protopirate_tool_scene_plugin.h"
#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")
#ifdef ENABLE_EMULATE_FEATURE
#define EMULATE_PLUGIN_PATH APP_ASSETS_PATH("plugins/pp_emulate.fal")
#endif
#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/pp_timing_tuner.fal")
#endif
#define PSA_BF_PLUGIN_PATH APP_ASSETS_PATH("plugins/pp_bf.fal")
typedef enum ProtoPirateSharedPlugin {
ProtoPirateSharedPluginsConfig,
ProtoPirateSharedPluginsSavedInfo,
ProtoPirateSharedPluginsAbout,
#ifdef ENABLE_EMULATE_FEATURE
ProtoPirateSharedPluginsEmulate,
#endif
ProtoPirateSharedPluginsToolScene,
ProtoPirateSharedPluginsSubDecode,
#ifdef ENABLE_TIMING_TUNER_SCENE
ProtoPirateSharedPluginsTimingTuner,
#endif
ProtoPirateSharedPluginsPSABruteforce,
ProtoPirateSharedPluginsTXRX,
} ProtoPirateSharedPlugin;
bool shared_plugin_load(
void** flipper_application_pointer,
const void** plugin_pointer,
ProtoPirateSharedPlugin plugin_type,
const char* txrx_path);
void shared_plugin_unload(void** flipper_application_pointer, const void** plugin_pointer);
bool shared_plugin_handle_navigation_events(
SceneManager* scene_manager,
ViewDispatcher* view_dispatcher,
SceneManagerEvent event);
+13 -4
View File
@@ -2,7 +2,6 @@
#include "protopirate_txrx.h"
#include "../protocols/protocol_items.h"
#include <loader/firmware_api/firmware_api.h>
#include <stdio.h>
#include <string.h>
@@ -61,7 +60,9 @@ void protopirate_unload_protocol_plugin(ProtoPirateApp* app) {
app->txrx->protocol_plugin->release();
}
shared_plugin_unload(app, ProtoPirateSharedPluginsTXRX);
shared_plugin_unload(
(void**)&app->txrx->protocol_plugin_flipper_application,
(const void**)&app->txrx->protocol_plugin);
}
static bool protopirate_ensure_protocol_registry_plugin(
@@ -91,7 +92,11 @@ static bool protopirate_ensure_protocol_registry_plugin(
}
const char* plugin_path = protopirate_get_registry_plugin_path(route);
shared_plugin_load(app, ProtoPirateSharedPluginsTXRX, plugin_path);
shared_plugin_load(
(void**)&app->txrx->protocol_plugin_flipper_application,
(const void**)&app->txrx->protocol_plugin,
ProtoPirateSharedPluginsTXRX,
plugin_path);
if(app->txrx->protocol_plugin->kind != ProtoPirateProtocolPluginKindRx) {
FURI_LOG_E(TAG, "Protocol plugin kind mismatch for RX route");
@@ -157,7 +162,11 @@ static bool protopirate_ensure_tx_protocol_plugin(
protopirate_unload_protocol_plugin(app);
}
shared_plugin_load(app, ProtoPirateSharedPluginsTXRX, plugin_path);
shared_plugin_load(
(void**)&app->txrx->protocol_plugin_flipper_application,
(const void**)&app->txrx->protocol_plugin,
ProtoPirateSharedPluginsTXRX,
plugin_path);
const SubGhzProtocol* tx_protocol = app->txrx->protocol_plugin->registry->items[0];
if(!tx_protocol || !tx_protocol->encoder || !tx_protocol->encoder->alloc ||
+10 -4
View File
@@ -4,7 +4,6 @@
#include "../protocols/protocols_common.h"
#include "../scenes/plugins/protopirate_psa_bf_plugin.h"
#include <loader/firmware_api/firmware_api.h>
#include <notification/notification_messages.h>
#define TAG "PPPsaBfHost"
@@ -114,7 +113,11 @@ static const ProtoPiratePsaBfHostApi protopirate_psa_bf_host_api = {
};
bool protopirate_psa_bf_plugin_ensure_loaded(ProtoPirateApp* app) {
if(shared_plugin_load(app, ProtoPirateSharedPluginsPSABruteforce, NULL)) {
if(shared_plugin_load(
(void**)&app->psa_bf_plugin_flipper_application,
(const void**)&app->psa_bf_plugin,
ProtoPirateSharedPluginsPSABruteforce,
NULL)) {
app->psa_bf_plugin->set_host_api(&protopirate_psa_bf_host_api);
return true;
} else {
@@ -127,7 +130,9 @@ void protopirate_psa_bf_plugin_unload_if_idle(ProtoPirateApp* app) {
app->psa_bf_plugin->is_running(app)) {
return;
}
shared_plugin_unload(app, ProtoPirateSharedPluginsPSABruteforce);
shared_plugin_unload(
(void**)&app->psa_bf_plugin_flipper_application, (const void**)&app->psa_bf_plugin);
}
void protopirate_psa_bf_context_release(ProtoPirateApp* app) {
@@ -135,5 +140,6 @@ void protopirate_psa_bf_context_release(ProtoPirateApp* app) {
if(app->psa_bf_plugin && app->psa_bf_plugin->context_release) {
app->psa_bf_plugin->context_release(app);
}
shared_plugin_unload(app, ProtoPirateSharedPluginsPSABruteforce);
shared_plugin_unload(
(void**)&app->psa_bf_plugin_flipper_application, (const void**)&app->psa_bf_plugin);
}
+7 -3
View File
@@ -4,7 +4,6 @@
#include <storage/storage.h>
#include <flipper_format/flipper_format.h>
#include <furi.h>
#include "../defines.h"
#include "../protocols/protocols_common.h"
#define TAG "PPSettings"
@@ -22,7 +21,9 @@ void protopirate_settings_set_defaults(ProtoPirateSettings* settings) {
settings->emulate_feature_enabled = false;
settings->check_saved = false;
settings->datetime_filenames = false;
#ifdef ENABLE_MODELS_DATABASE
settings->car_model_index = 0;
#endif
}
void protopirate_settings_load(ProtoPirateSettings* settings) {
@@ -135,13 +136,14 @@ void protopirate_settings_load(ProtoPirateSettings* settings) {
}
settings->datetime_filenames = (datetime_filenames_temp == 1);
// Read Selected Car Model
// Read Selected Car Model
#ifdef ENABLE_MODELS_DATABASE
uint32_t car_model_index_temp = 0;
if(!flipper_format_read_uint32(ff, "CarModelIndex", &car_model_index_temp, 1)) {
car_model_index_temp = 0;
}
settings->car_model_index = car_model_index_temp;
#endif
FURI_LOG_I(
TAG,
"Settings loaded: freq=%lu, preset=%u, auto_save=%d, hopping=%d, emulate=%d, check_saved=%d, sound = %d",
@@ -234,12 +236,14 @@ void protopirate_settings_save(ProtoPirateSettings* settings) {
if(!flipper_format_write_uint32(ff, "DateTimeFilenames", &datetime_filenames_temp, 1)) {
FURI_LOG_E(TAG, "Failed to write Date Time Filenames");
}
#ifdef ENABLE_MODELS_DATABASE
uint32_t car_model_index_temp = settings->car_model_index;
if(!flipper_format_write_uint32(ff, "CarModelIndex", &car_model_index_temp, 1)) {
FURI_LOG_E(TAG, "Failed to write car model");
break;
}
#endif
write_ok = true;
FURI_LOG_I(
+3
View File
@@ -1,6 +1,7 @@
// helpers/protopirate_settings.h
#pragma once
#include "../defines.h"
#include <stdint.h>
#include <stdbool.h>
@@ -19,7 +20,9 @@ typedef struct {
bool emulate_feature_enabled;
bool check_saved;
bool datetime_filenames;
#ifdef ENABLE_MODELS_DATABASE
uint16_t car_model_index;
#endif
} ProtoPirateSettings;
void protopirate_settings_load(ProtoPirateSettings* settings);
+20 -38
View File
@@ -2,7 +2,6 @@
#include "protopirate_psa_bf_host.h"
#include "radio_device_loader.h"
#include <loader/firmware_api/firmware_api.h>
#include <notification/notification_messages.h>
#define TAG "PPToolScene"
@@ -126,14 +125,25 @@ static bool protopirate_tool_scene_plugin_ensure_loaded(
if(app->tool_scene_plugin->release) {
app->tool_scene_plugin->release(app);
}
shared_plugin_unload(app, ProtoPirateSharedPluginsToolScene);
shared_plugin_unload(
(void**)&app->tool_scene_plugin_flipper_application,
(const void**)&app->tool_scene_plugin);
}
if(kind == ProtoPirateToolScenePluginKindSubDecode)
shared_plugin_load(app, ProtoPirateSharedPluginsSubDecode, NULL);
shared_plugin_load(
(void**)&app->tool_scene_plugin_flipper_application,
(const void**)&app->tool_scene_plugin,
ProtoPirateSharedPluginsSubDecode,
NULL);
#ifdef ENABLE_TIMING_TUNER_SCENE
else if(kind == ProtoPirateToolScenePluginKindTimingTuner)
shared_plugin_load(app, ProtoPirateSharedPluginsTimingTuner, NULL);
shared_plugin_load(
(void**)&app->tool_scene_plugin_flipper_application,
(const void**)&app->tool_scene_plugin,
ProtoPirateSharedPluginsTimingTuner,
NULL);
#endif
app->tool_scene_plugin_kind = kind;
@@ -141,40 +151,10 @@ static bool protopirate_tool_scene_plugin_ensure_loaded(
return true;
}
static void protopirate_tool_scene_apply_pending_nav(ProtoPirateApp* app) {
furi_check(app);
const uint8_t nav = app->tool_scene_nav_pending;
if(nav == TOOL_SCENE_NAV_NONE) {
return;
}
const uint32_t target = app->tool_scene_nav_target;
app->tool_scene_nav_pending = TOOL_SCENE_NAV_NONE;
app->tool_scene_nav_target = 0;
switch(nav) {
case TOOL_SCENE_NAV_POP:
scene_manager_previous_scene(app->scene_manager);
break;
case TOOL_SCENE_NAV_NEXT:
scene_manager_next_scene(app->scene_manager, target);
break;
case TOOL_SCENE_NAV_SEARCH_PREVIOUS:
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, target);
break;
default:
break;
}
}
bool protopirate_tool_scene_on_enter(void* context, ProtoPirateToolScenePluginKind kind) {
ProtoPirateApp* app = context;
furi_check(app);
app->tool_scene_nav_pending = TOOL_SCENE_NAV_NONE;
app->tool_scene_nav_target = 0;
if(!protopirate_tool_scene_plugin_ensure_loaded(app, kind) || !app->tool_scene_plugin) {
notification_message(app->notifications, &sequence_error);
scene_manager_previous_scene(app->scene_manager);
@@ -182,7 +162,6 @@ bool protopirate_tool_scene_on_enter(void* context, ProtoPirateToolScenePluginKi
}
app->tool_scene_plugin->on_enter(app);
protopirate_tool_scene_apply_pending_nav(app);
return true;
}
@@ -193,7 +172,6 @@ bool protopirate_tool_scene_on_event(void* context, SceneManagerEvent event) {
}
const bool consumed = app->tool_scene_plugin->on_event(app, event);
protopirate_tool_scene_apply_pending_nav(app);
return consumed;
}
@@ -210,7 +188,9 @@ void protopirate_tool_scene_on_exit(void* context) {
}
}
shared_plugin_unload(app, ProtoPirateSharedPluginsToolScene);
shared_plugin_unload(
(void**)&app->tool_scene_plugin_flipper_application,
(const void**)&app->tool_scene_plugin);
}
void protopirate_tool_scene_plugin_release(ProtoPirateApp* app) {
@@ -219,5 +199,7 @@ void protopirate_tool_scene_plugin_release(ProtoPirateApp* app) {
if(app->tool_scene_plugin && app->tool_scene_plugin->release) {
app->tool_scene_plugin->release(app);
}
shared_plugin_unload(app, ProtoPirateSharedPluginsToolScene);
shared_plugin_unload(
(void**)&app->tool_scene_plugin_flipper_application,
(const void**)&app->tool_scene_plugin);
}
+8 -7
View File
@@ -58,13 +58,13 @@ void protopirate_get_frequency_modulation_str(
size_t modulation_size) {
furi_check(app);
if(frequency && frequency_size > 0) {
if(frequency) {
unsigned long mhz = (unsigned long)((app->txrx->preset->frequency / 1000000UL) % 1000UL);
unsigned long khz = (unsigned long)((app->txrx->preset->frequency / 10000UL) % 100UL);
snprintf(frequency, frequency_size, "%03lu.%02lu", mhz, khz);
}
if(modulation && modulation_size > 0) {
if(modulation) {
snprintf(
modulation, modulation_size, "%.2s", furi_string_get_cstr(app->txrx->preset->name));
}
@@ -73,19 +73,20 @@ void protopirate_get_frequency_modulation_str(
void protopirate_get_frequency_modulation(
ProtoPirateApp* app,
FuriString* frequency,
FuriString* modulation) {
size_t frequency_size,
FuriString* modulation,
size_t modulation_size) {
furi_check(app);
char frequency_buf[16] = {0};
char modulation_buf[8] = {0};
protopirate_get_frequency_modulation_str(
app, frequency_buf, sizeof(frequency_buf), modulation_buf, sizeof(modulation_buf));
protopirate_get_frequency_modulation_str(app, frequency_buf, 16, modulation_buf, 8);
if(frequency != NULL) {
furi_string_set_str(frequency, frequency_buf);
memcpy(frequency, frequency_buf, frequency_size);
}
if(modulation != NULL) {
furi_string_set_str(modulation, modulation_buf);
memcpy(modulation, modulation_buf, modulation_size);
}
}
+4 -1
View File
@@ -20,7 +20,10 @@ void protopirate_preset_init(
void protopirate_get_frequency_modulation(
ProtoPirateApp* app,
FuriString* frequency,
FuriString* modulation);
size_t frequency_size,
FuriString* modulation,
size_t modulation_size);
void protopirate_get_frequency_modulation_str(
ProtoPirateApp* app,
char* frequency,
+6 -4
View File
@@ -31,22 +31,19 @@ typedef enum {
ProtoPirateCustomEventReceiverInfoUpdate,
ProtoPirateCustomEventReceiverInfoEmulate,
ProtoPirateCustomEventSavedInfoDelete,
ProtoPirateCustomEventSavedInfoExit,
//Bruteforcing PSA & Renault
ProtoPirateCustomEventBruteforceStart,
ProtoPirateCustomEventBruteforceComplete,
// Emulator
ProtoPirateCustomEventSavedInfoEmulate,
ProtoPirateCustomEventSavedInfoEmulateDelayedStart,
ProtoPirateCustomEventEmulateTransmit,
ProtoPirateCustomEventEmulateStop,
ProtoPirateCustomEventEmulateExit,
ProtoPirateCustomEventSavedInfoEmulate,
// Sub decode
ProtoPirateCustomEventSubDecodeUpdate,
ProtoPirateCustomEventSubDecodeSave,
ProtoPirateCustomEventSubDecodeEmulate,
ProtoPirateCustomEventSubDecodeSaveConfirm,
ProtoPirateCustomEventSubDecodeEmulateDelayedStart,
// File Browser
ProtoPirateCustomEventSavedFileSelected,
// Need saving confirmation
@@ -54,6 +51,11 @@ typedef enum {
ProtoPirateCustomEventSceneExit,
// About scene
ProtoPirateCustomEventAboutToggleEmulate,
//Plugin Scenes
ProtoPirateCustomEventPluginNavigateBack,
ProtoPirateCustomEventPluginNavigateEmulate,
ProtoPirateCustomEventPluginNavigateConfig,
ProtoPirateCustomEventPluginNavigateStopApp,
} ProtoPirateCustomEvent;
typedef enum {
+4
View File
@@ -1,3 +1,6 @@
#include "../defines.h"
#ifdef ENABLE_MODELS_DATABASE
#include "helpers/variable_item_list.h"
#include <gui/elements.h>
#include <gui/canvas.h>
@@ -639,3 +642,4 @@ void* variable_item_get_context(VariableItem* item) {
furi_check(item);
return item->context;
}
#endif
@@ -15,6 +15,7 @@
#include "../subaru.h"
#include "../star_line.h"
#include "../honda_v1.h"
#include <lib/flipper_application/flipper_application.h>
static const SubGhzProtocol* const protopirate_protocol_registry_am_items[] = {
&chrysler_protocol_v0,
@@ -1,6 +1,7 @@
#include "../protopirate_protocol_plugins.h"
#include "../protocols_common.h"
#include "../vag.h"
#include <lib/flipper_application/flipper_application.h>
static const SubGhzProtocol* const protopirate_protocol_registry_am_vag_items[] = {
&vag_protocol,
@@ -4,6 +4,7 @@
#include "../ford_v2.h"
#include "../ford_v3.h"
#include "../honda_v2.h"
#include <lib/flipper_application/flipper_application.h>
static const SubGhzProtocol* const protopirate_protocol_registry_fm_f4_items[] = {
&ford_protocol_v1,
@@ -1,6 +1,7 @@
#include "../protopirate_protocol_plugins.h"
#include "../protocols_common.h"
#include "../honda_static.h"
#include <lib/flipper_application/flipper_application.h>
static const SubGhzProtocol* const protopirate_protocol_registry_fm_honda1_items[] = {
&honda_static_protocol,
@@ -9,6 +9,7 @@
#include "../mazda_v0.h"
#include "../psa.h"
#include "../renault_v1.h"
#include <lib/flipper_application/flipper_application.h>
static const SubGhzProtocol* const protopirate_protocol_registry_fm_items[] = {
&subghz_protocol_scher_khan,
@@ -1,5 +1,6 @@
#include "../protopirate_protocol_plugins.h"
#include "../protocols_common.h"
#include <lib/flipper_application/flipper_application.h>
#ifndef PP_TX_PROTOCOL_HEADER
#error "PP_TX_PROTOCOL_HEADER must be defined for TX protocol plugins"
-1
View File
@@ -1,6 +1,5 @@
#pragma once
#include <lib/flipper_application/flipper_application.h>
#include <lib/subghz/types.h>
#include "protocol_items.h"
+9 -2
View File
@@ -1,9 +1,16 @@
#include "../defines.h"
#include "vag.h"
#include "aut64.h"
#include "protocols_common.h"
#include <string.h>
#include <lib/subghz/subghz_keystore.h>
#ifdef ENABLE_MODELS_DATABASE
#define PROTOPIRATE_VAG_KEYS_FILE_NAME APP_ASSETS_PATH("keystore/vag")
#else
#define PROTOPIRATE_VAG_KEYS_FILE_NAME APP_ASSETS_PATH("vag")
#endif
#define TAG "VAGProtocol"
#define VAG_ENCODER_UPLOAD_TYPE12_SIZE 635
@@ -548,7 +555,7 @@ void* subghz_protocol_decoder_vag_alloc(SubGhzEnvironment* environment) {
instance->decrypted = false;
instance->key_idx = 0xFF;
protocol_vag_load_keys(APP_ASSETS_PATH("vag"));
protocol_vag_load_keys(PROTOPIRATE_VAG_KEYS_FILE_NAME);
return instance;
}
@@ -1544,7 +1551,7 @@ void* subghz_protocol_encoder_vag_alloc(SubGhzEnvironment* environment) {
instance->is_running = false;
instance->key_idx = 0xFF;
protocol_vag_load_keys(APP_ASSETS_PATH("vag"));
protocol_vag_load_keys(APP_ASSETS_PATH("keystore/vag"));
FURI_LOG_I(TAG, "VAG encoder alloc complete, keys loaded: %d", protocol_vag_keys_loaded);
+21 -295
View File
@@ -8,298 +8,11 @@
#include "helpers/protopirate_psa_bf_host.h"
#include "helpers/protopirate_views.h"
#include "helpers/protopirate_radio.h"
#include "helpers/protopirate_plugins.h"
#include <string.h>
#define TAG "PPApp"
// -----------------------------------------------------------------------------
// Plugin load / unload
// -----------------------------------------------------------------------------
const FlipperAppPluginDescriptor* load_plugin_fal(
FlipperApplication** fal_app,
const char* plugin_path,
const char* application_id,
uint32_t api_version) {
const FlipperAppPluginDescriptor* app_descriptor;
bool return_value = false;
do {
FlipperApplicationPreloadStatus preload_res =
flipper_application_preload(*fal_app, plugin_path);
if(preload_res != FlipperApplicationPreloadStatusSuccess) {
FURI_LOG_E(TAG, "Failed to preload plugin: %s", plugin_path);
break;
}
if(!flipper_application_is_plugin(*fal_app)) {
FURI_LOG_E(TAG, "Plugin file is not a library");
break;
}
FlipperApplicationLoadStatus load_status = flipper_application_map_to_memory(*fal_app);
if(load_status != FlipperApplicationLoadStatusSuccess) {
FURI_LOG_E(TAG, "Failed to load plugin file");
break;
}
FURI_LOG_D(TAG, "is mapped to memory");
app_descriptor = flipper_application_plugin_get_descriptor(*fal_app);
if(strcmp(app_descriptor->appid, application_id) != 0) {
FURI_LOG_E(TAG, "Application id mismatch %s", application_id);
break;
}
if(app_descriptor->ep_api_version != api_version) {
FURI_LOG_E(TAG, "API version mismatch %lu", api_version);
break;
}
FURI_LOG_I(
TAG,
"Loaded plugin for appid '%s', API %lu",
app_descriptor->appid,
app_descriptor->ep_api_version);
return_value = true;
} while(false);
//Free the applciation if there was an error, otherwise return the app descriptor.
if(return_value) {
return app_descriptor;
} else {
if(*fal_app) {
flipper_application_free(*fal_app);
*fal_app = NULL;
}
return NULL;
}
}
void shared_plugin_unload(ProtoPirateApp* app, ProtoPirateSharedPlugin plugin_type) {
//Clear the invalid reference to the plugin.
FlipperApplication** fal_needs_free = NULL;
switch(plugin_type) {
case ProtoPirateSharedPluginsConfig: {
fal_needs_free = &app->plugin_flipper_application;
app->config_plugin = NULL;
break;
}
case ProtoPirateSharedPluginsSavedInfo: {
fal_needs_free = &app->plugin_flipper_application;
app->saved_info_plugin = NULL;
break;
}
case ProtoPirateSharedPluginsAbout: {
fal_needs_free = &app->plugin_flipper_application;
app->about_plugin = NULL;
break;
}
#ifdef ENABLE_EMULATE_FEATURE
case ProtoPirateSharedPluginsEmulate: {
fal_needs_free = &app->plugin_flipper_application;
app->emulate_plugin = NULL;
break;
}
#endif
case ProtoPirateSharedPluginsToolScene:
case ProtoPirateSharedPluginsSubDecode:
#ifdef ENABLE_TIMING_TUNER_SCENE
case ProtoPirateSharedPluginsTimingTuner:
#endif
{
fal_needs_free = &app->tool_scene_plugin_flipper_application;
app->tool_scene_plugin = NULL;
break;
}
case ProtoPirateSharedPluginsPSABruteforce: {
fal_needs_free = &app->psa_bf_plugin_flipper_application;
app->psa_bf_plugin = NULL;
break;
}
case ProtoPirateSharedPluginsTXRX: {
fal_needs_free = &app->txrx->protocol_plugin_flipper_application;
app->txrx->protocol_plugin = NULL;
break;
}
default:
return;
}
//Free the flipper application.
if(*fal_needs_free) {
flipper_application_free(*fal_needs_free);
*fal_needs_free = NULL;
}
}
bool shared_plugin_load(
ProtoPirateApp* app,
ProtoPirateSharedPlugin plugin_type,
const char* txrx_path) {
//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;
FlipperApplication** fal_needs_alloc = NULL;
switch(plugin_type) {
case ProtoPirateSharedPluginsConfig: {
if(app->config_plugin) return true;
application_id = PROTOPIRATE_CONFIG_PLUGIN_APP_ID;
api_version = PROTOPIRATE_CONFIG_PLUGIN_API_VERSION;
plugin_path = CONFIG_PLUGIN_PATH;
fal_needs_alloc = &app->plugin_flipper_application;
break;
}
case ProtoPirateSharedPluginsSavedInfo: {
if(app->saved_info_plugin) return true;
application_id = PROTOPIRATE_SAVED_INFO_PLUGIN_APP_ID;
api_version = PROTOPIRATE_SAVED_INFO_PLUGIN_API_VERSION;
plugin_path = SAVED_INFO_PLUGIN_PATH;
fal_needs_alloc = &app->plugin_flipper_application;
break;
}
case ProtoPirateSharedPluginsAbout: {
if(app->about_plugin) return true;
application_id = PROTOPIRATE_ABOUT_PLUGIN_APP_ID;
api_version = PROTOPIRATE_ABOUT_PLUGIN_API_VERSION;
plugin_path = ABOUT_PLUGIN_PATH;
fal_needs_alloc = &app->plugin_flipper_application;
break;
}
#ifdef ENABLE_EMULATE_FEATURE
case ProtoPirateSharedPluginsEmulate: {
if(app->emulate_plugin) return true;
application_id = PROTOPIRATE_EMULATE_PLUGIN_APP_ID;
api_version = PROTOPIRATE_EMULATE_PLUGIN_API_VERSION;
plugin_path = EMULATE_PLUGIN_PATH;
fal_needs_alloc = &app->plugin_flipper_application;
break;
}
#endif
case ProtoPirateSharedPluginsSubDecode: {
if(app->tool_scene_plugin) return true;
application_id = PROTOPIRATE_TOOL_SCENE_PLUGIN_APP_ID;
api_version = PROTOPIRATE_TOOL_SCENE_PLUGIN_API_VERSION;
plugin_path = SUB_DECODE_PLUGIN_PATH;
fal_needs_alloc = &app->tool_scene_plugin_flipper_application;
break;
}
#ifdef ENABLE_TIMING_TUNER_SCENE
case ProtoPirateSharedPluginsTimingTuner: {
if(app->tool_scene_plugin) return true;
application_id = PROTOPIRATE_TOOL_SCENE_PLUGIN_APP_ID;
api_version = PROTOPIRATE_TOOL_SCENE_PLUGIN_API_VERSION;
plugin_path = TIMING_TUNER_PLUGIN_PATH;
fal_needs_alloc = &app->tool_scene_plugin_flipper_application;
break;
}
#endif
case ProtoPirateSharedPluginsPSABruteforce: {
if(app->psa_bf_plugin) return true;
application_id = PROTOPIRATE_PSA_BF_PLUGIN_APP_ID;
api_version = PROTOPIRATE_PSA_BF_PLUGIN_API_VERSION;
plugin_path = PSA_BF_PLUGIN_PATH;
fal_needs_alloc = &app->psa_bf_plugin_flipper_application;
break;
}
case ProtoPirateSharedPluginsTXRX: {
if(app->txrx->protocol_plugin) return true;
application_id = PROTOPIRATE_PROTOCOL_PLUGIN_APP_ID;
api_version = PROTOPIRATE_PROTOCOL_PLUGIN_API_VERSION;
plugin_path = txrx_path;
fal_needs_alloc = &app->txrx->protocol_plugin_flipper_application;
break;
}
default:
return false;
}
FURI_LOG_D(TAG, "Loading plugin: %s", plugin_path);
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperApplication* fal_app = flipper_application_alloc(storage, firmware_api_interface);
bool return_value = false;
do {
//Load the FAP
const FlipperAppPluginDescriptor* app_descriptor =
load_plugin_fal(&fal_app, plugin_path, application_id, api_version);
if(app_descriptor) {
//Get the Plugin and assign it.
if(plugin_type == ProtoPirateSharedPluginsConfig) {
const ProtoPirateConfigPlugin* plugin_config = app_descriptor->entry_point;
if(!plugin_config || !plugin_config->on_enter) {
FURI_LOG_E(TAG, "Config plugin entry point is invalid");
} else {
app->config_plugin = plugin_config;
return_value = true;
}
} else if(plugin_type == ProtoPirateSharedPluginsSavedInfo) {
const ProtoPirateSavedInfoPlugin* plugin_saved_info = app_descriptor->entry_point;
if(!plugin_saved_info || !plugin_saved_info->on_enter) {
FURI_LOG_E(TAG, "Saved Info plugin entry point is invalid");
} else {
app->saved_info_plugin = plugin_saved_info;
return_value = true;
}
} else if(plugin_type == ProtoPirateSharedPluginsAbout) {
const ProtoPirateAboutPlugin* plugin_about = app_descriptor->entry_point;
if(!plugin_about || !plugin_about->on_enter) {
FURI_LOG_E(TAG, "About plugin entry point is invalid");
} else {
app->about_plugin = plugin_about;
return_value = true;
}
}
#ifdef ENABLE_EMULATE_FEATURE
else if(plugin_type == ProtoPirateSharedPluginsEmulate) {
const ProtoPirateEmulatePlugin* plugin_emulate = app_descriptor->entry_point;
if(!plugin_emulate || !plugin_emulate->on_enter) {
FURI_LOG_E(TAG, "Emulate plugin entry point is invalid");
} else {
app->emulate_plugin = plugin_emulate;
return_value = true;
}
}
#endif
else if(
plugin_type == ProtoPirateSharedPluginsSubDecode
#ifdef ENABLE_TIMING_TUNER_SCENE
|| plugin_type == ProtoPirateSharedPluginsTimingTuner
#endif
) {
const ProtoPirateToolScenePlugin* plugin_tool_scene = app_descriptor->entry_point;
if(!plugin_tool_scene || !plugin_tool_scene->on_enter) {
FURI_LOG_E(TAG, "Tool Scene plugin entry point is invalid");
} else {
app->tool_scene_plugin = plugin_tool_scene;
return_value = true;
}
} else if(plugin_type == ProtoPirateSharedPluginsPSABruteforce) {
const ProtoPiratePsaBfPlugin* plugin_psa_bf = app_descriptor->entry_point;
if(!plugin_psa_bf || !plugin_psa_bf->needs_bruteforce) {
FURI_LOG_E(TAG, "PSA plugin entry needs_bruteforce is invalid");
} else {
app->psa_bf_plugin = plugin_psa_bf;
return_value = true;
}
} else if(plugin_type == ProtoPirateSharedPluginsTXRX) {
const ProtoPirateProtocolPlugin* plugin_txrx = app_descriptor->entry_point;
if(!plugin_txrx || !plugin_txrx->registry) {
FURI_LOG_E(TAG, "Protocol plugin registry entry is invalid");
} else {
app->txrx->protocol_plugin = plugin_txrx;
return_value = true;
}
}
}
} while(false);
//Free the plugin if there was an error, otherwise we are done!
if(fal_needs_alloc) *fal_needs_alloc = fal_app;
furi_record_close(RECORD_STORAGE);
return return_value;
}
static bool protopirate_app_custom_event_callback(void* context, uint32_t event) {
furi_check(context);
ProtoPirateApp* app = context;
@@ -451,9 +164,16 @@ ProtoPirateApp* protopirate_app_alloc() {
app->psa_bf_plugin = NULL;
app->tool_scene_plugin_flipper_application = NULL;
app->tool_scene_plugin = NULL;
app->variable_item_list = NULL;
//Load the models database, get the count of the models for the list.
if(shared_plugin_load(app, ProtoPirateSharedPluginsConfig, NULL) && app->config_plugin) {
#ifdef ENABLE_MODELS_DATABASE
if(shared_plugin_load(
(void**)&app->plugin_flipper_application,
(const void**)&app->config_plugin,
ProtoPirateSharedPluginsConfig,
NULL) &&
app->config_plugin) {
app->car_models_count = app->config_plugin->car_model_get_count();
} else {
notification_message(app->notifications, &sequence_error);
@@ -463,7 +183,6 @@ ProtoPirateApp* protopirate_app_alloc() {
app->selected_model->name = NULL;
app->selected_model->preset = NULL; // important initialization
app->selected_model->index = 0; // optional but clean
app->variable_item_list = NULL;
//Grab selected car model.
if(app->config_plugin) {
@@ -490,11 +209,15 @@ ProtoPirateApp* protopirate_app_alloc() {
}
//Kill the config plugin now.
shared_plugin_unload(app, ProtoPirateSharedPluginsConfig);
shared_plugin_unload(
(void**)&app->plugin_flipper_application, (const void**)&app->config_plugin);
} else {
#endif
//Preset set in Config.
protopirate_preset_init(app, preset_name, frequency, preset_data, preset_data_size);
#ifdef ENABLE_MODELS_DATABASE
}
#endif
// Apply hopping state from settings
app->txrx->hopper_state = settings.hopping_enabled ? ProtoPirateHopperStateRunning :
@@ -530,6 +253,7 @@ void protopirate_app_free(ProtoPirateApp* app) {
#endif
//Get the selected Model, and get the preset to save.
#ifdef ENABLE_MODELS_DATABASE
if(app->selected_model && app->selected_model->index) {
//Get Preset Index before model was selected.
settings.car_model_index = app->selected_model->index;
@@ -570,6 +294,7 @@ void protopirate_app_free(ProtoPirateApp* app) {
//Free the Model.
free(app->selected_model);
app->selected_model = NULL;
#endif
FURI_LOG_I(
TAG,
@@ -645,15 +370,14 @@ 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();
if(!protopirate_app) {
furi_hal_power_suppress_charge_exit();
return -1;
}
//Stop charging while running the app.
furi_hal_power_suppress_charge_enter();
// Handle Command line PSF that may have been passed to us
bool load_saved = (p && strlen(p));
if(load_saved) {
@@ -683,6 +407,8 @@ int32_t protopirate_app(char* p) {
//Free the App and allow chargin again.
protopirate_app_free(protopirate_app);
//Restore Charging State
furi_hal_power_suppress_charge_exit();
return 0;
}
+7 -44
View File
@@ -35,25 +35,19 @@
#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_plugins.h"
#include "helpers/protopirate_views.h"
#include "helpers/protopirate_radio.h"
#include "helpers/protopirate_protocol_plugin_host.h"
#include "helpers/protopirate_txrx.h"
#include "helpers/protopirate_models.h"
#include <loader/firmware_api/firmware_api.h>
#include "helpers/protopirate_settings.h"
#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 EMULATE_PLUGIN_PATH APP_ASSETS_PATH("plugins/pp_emulate.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/pp_timing_tuner.fal")
#endif
#define PSA_BF_PLUGIN_PATH APP_ASSETS_PATH("plugins/pp_bf.fal")
#ifdef ENABLE_MODELS_DATABASE
#define PROTOPIRATE_KEYSTORE_DIR_NAME APP_ASSETS_PATH("keystore/encrypted")
#else
#define PROTOPIRATE_KEYSTORE_DIR_NAME APP_ASSETS_PATH("encrypted")
#endif
typedef struct VariableItemList VariableItemList;
@@ -110,9 +104,6 @@ struct ProtoPirateApp {
uint16_t save_history_idx;
FlipperApplication* plugin_flipper_application;
#ifdef ENABLE_EMULATE_FEATURE
#define EMULATE_NAV_NONE 0U
#define EMULATE_NAV_POP 1U
#define EMULATE_NAV_STOP_APP 2U
const ProtoPirateEmulatePlugin* emulate_plugin;
uint8_t emulate_nav_pending;
#endif
@@ -124,15 +115,10 @@ struct ProtoPirateApp {
FlipperApplication* tool_scene_plugin_flipper_application;
const ProtoPirateToolScenePlugin* tool_scene_plugin;
ProtoPirateToolScenePluginKind tool_scene_plugin_kind;
#define TOOL_SCENE_NAV_NONE 0U
#define TOOL_SCENE_NAV_POP 1U
#define TOOL_SCENE_NAV_NEXT 2U
#define TOOL_SCENE_NAV_SEARCH_PREVIOUS 3U
uint8_t tool_scene_nav_pending;
uint32_t tool_scene_nav_target;
#ifdef ENABLE_MODELS_DATABASE
ProtoPirateCarModel* selected_model;
uint16_t car_models_count;
#endif
};
#ifdef ENABLE_EMULATE_FEATURE
@@ -148,29 +134,6 @@ bool protopirate_tool_scene_on_enter(void* app, ProtoPirateToolScenePluginKind k
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);
typedef enum ProtoPirateSharedPlugin {
ProtoPirateSharedPluginsConfig,
ProtoPirateSharedPluginsSavedInfo,
ProtoPirateSharedPluginsAbout,
#ifdef ENABLE_EMULATE_FEATURE
ProtoPirateSharedPluginsEmulate,
#endif
ProtoPirateSharedPluginsToolScene,
ProtoPirateSharedPluginsSubDecode,
#ifdef ENABLE_TIMING_TUNER_SCENE
ProtoPirateSharedPluginsTimingTuner,
#endif
ProtoPirateSharedPluginsPSABruteforce,
ProtoPirateSharedPluginsTXRX,
} ProtoPirateSharedPlugin;
bool shared_plugin_load(
ProtoPirateApp* app,
ProtoPirateSharedPlugin plugin_type,
const char* txrx_path);
void shared_plugin_unload(ProtoPirateApp* app, ProtoPirateSharedPlugin plugin_type);
void protopirate_app_free(ProtoPirateApp* app);
static const NotificationSequence sequence_tx = {
-13
View File
@@ -204,10 +204,6 @@ void protopirate_history_format_status_text(
furi_check(instance);
furi_check(output);
if(output_size == 0) {
return;
}
uint16_t n = protopirate_history_get_item(instance);
if(n >= PROTOPIRATE_HISTORY_MAX) {
snprintf(output, output_size, "FULL");
@@ -216,15 +212,6 @@ void protopirate_history_format_status_text(
}
}
void protopirate_history_get_status_text(ProtoPirateHistory* instance, FuriString* output) {
furi_check(instance);
furi_check(output);
char status_text[16];
protopirate_history_format_status_text(instance, status_text, sizeof(status_text));
furi_string_set_str(output, status_text);
}
bool protopirate_history_get_capture_path(
ProtoPirateHistory* instance,
uint16_t idx,
-1
View File
@@ -19,7 +19,6 @@ void protopirate_history_format_status_text(
ProtoPirateHistory* instance,
char* output,
size_t output_size);
void protopirate_history_get_status_text(ProtoPirateHistory* instance, FuriString* output);
bool protopirate_history_get_capture_path(
ProtoPirateHistory* instance,
+18 -7
View File
@@ -131,10 +131,10 @@ static void protopirate_scene_receiver_config_set_hopping_running(VariableItem*
app->scene_manager, ProtoPirateSceneReceiverConfig),
subghz_setting_get_frequency_default_index(app->setting));
}
app->txrx->hopper_state = hopping_value[index];
}
#ifdef ENABLE_MODELS_DATABASE
static void protopirate_scene_receiver_config_set_model(VariableItem* item) {
ProtoPirateApp* app = variable_item_get_context(item);
uint8_t direction = variable_item_get_current_value_index(item);
@@ -238,6 +238,7 @@ static void protopirate_scene_receiver_config_set_model(VariableItem* item) {
variable_item_set_locked(hop_menu, lock, "Turn off\nCar Model\nto do that!");
variable_item_set_locked(preset_menu, lock, "Turn off\nCar Model\nto do that!");
}
#endif
static uint8_t
protopirate_scene_receiver_config_next_frequency(const uint32_t value, void* context) {
@@ -279,13 +280,13 @@ static uint8_t protopirate_scene_receiver_config_hopper_value_index(
ProtoPirateApp* app = context;
if(value == values[0]) {
return 0;
return false;
} else {
variable_item_set_current_value_text(
(VariableItem*)scene_manager_get_scene_state(
app->scene_manager, ProtoPirateSceneReceiverConfig),
" -----");
return 1;
return true;
}
}
@@ -339,20 +340,20 @@ static void
FURI_LOG_D("TEST", "Index= %lu", index);
switch(index) {
case ProtoPirateSettingIndexCarModel: {
#ifdef ENABLE_MODELS_DATABASE
case ProtoPirateSettingIndexCarModel:
//Reset the Models Menu
VariableItem* model_menu =
variable_item_list_get(app->variable_item_list, ProtoPirateSettingIndexCarModel);
variable_item_set_current_value_index(model_menu, 0);
protopirate_scene_receiver_config_set_model(model_menu);
break;
}
case ProtoPirateSettingIndexLock: {
#endif
case ProtoPirateSettingIndexLock:
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventSceneSettingLock);
break;
}
}
}
static void plugin_on_enter(void* context, bool show_lock_keyboard) {
@@ -367,12 +368,14 @@ static void plugin_on_enter(void* context, bool show_lock_keyboard) {
}
//Add he car model the list, with the correct selection and text.
#ifdef ENABLE_MODELS_DATABASE
item = variable_item_list_add(
app->variable_item_list,
app->selected_model->name,
0, //Plus NONE
protopirate_scene_receiver_config_set_model,
app);
#endif
item = variable_item_list_add(
app->variable_item_list,
@@ -393,10 +396,12 @@ static void plugin_on_enter(void* context, bool show_lock_keyboard) {
subghz_setting_get_frequency(app->setting, value_index) / 1000000,
(subghz_setting_get_frequency(app->setting, value_index) % 1000000) / 10000);
variable_item_set_current_value_text(item, text_buf);
#ifdef ENABLE_MODELS_DATABASE
variable_item_set_locked(
item,
app->selected_model && (app->selected_model->index),
"Turn off\nCar Model\nto do that!");
#endif
item = variable_item_list_add(
app->variable_item_list,
@@ -408,10 +413,12 @@ static void plugin_on_enter(void* context, bool show_lock_keyboard) {
app->txrx->hopper_state, hopping_value, ON_OFF_COUNT, app);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, on_off_text[value_index]);
#ifdef ENABLE_MODELS_DATABASE
variable_item_set_locked(
item,
app->selected_model && (app->selected_model->index),
"Turn off\nCar Model\nto do that!");
#endif
item = variable_item_list_add(
app->variable_item_list,
@@ -424,10 +431,12 @@ static void plugin_on_enter(void* context, bool show_lock_keyboard) {
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(
item, subghz_setting_get_preset_name(app->setting, value_index));
#ifdef ENABLE_MODELS_DATABASE
variable_item_set_locked(
item,
app->selected_model && (app->selected_model->index),
"Turn off\nCar Model\nto do that!");
#endif
#ifdef ENABLE_EMULATE_FEATURE
// TX power option
@@ -495,8 +504,10 @@ void config_plugin_set_host_api(const ProtoPirateConfigSceneHostApi* host_api) {
static const ProtoPirateConfigPlugin protopirate_config_plugin = {
.plugin_name = "Config",
#ifdef ENABLE_MODELS_DATABASE
.car_model_get_by_index = car_model_get_by_index,
.car_model_get_count = car_model_get_count,
#endif
.on_enter = plugin_on_enter,
.set_host_api = config_plugin_set_host_api,
};
@@ -2,13 +2,16 @@
#include "../../protopirate_app_i.h"
#include "helpers/protopirate_models.h"
#include <lib/flipper_application/flipper_application.h>
#include "helpers/variable_item_list.h"
#define PROTOPIRATE_CONFIG_PLUGIN_APP_ID "pp_config"
#define PROTOPIRATE_CONFIG_PLUGIN_API_VERSION 2U
enum ProtoPirateSettingIndex {
#ifdef ENABLE_MODELS_DATABASE
ProtoPirateSettingIndexCarModel,
#endif
ProtoPirateSettingIndexFrequency,
ProtoPirateSettingIndexHopping,
ProtoPirateSettingIndexModulation,
@@ -35,12 +38,14 @@ typedef struct ProtoPirateConfigSceneHostApi {
typedef struct ProtoPirateConfigPlugin {
const char* plugin_name;
#ifdef ENABLE_MODELS_DATABASE
bool (*car_model_get_by_index)(
ProtoPirateCarModel* car_model,
uint16_t index,
uint16_t model_count,
SubGhzSetting* app_settings);
uint16_t (*car_model_get_count)(void);
#endif
void (*on_enter)(void* app, bool show_lock_keyboard);
void (*set_host_api)(const ProtoPirateConfigSceneHostApi* host_api);
} ProtoPirateConfigPlugin;
+29 -24
View File
@@ -179,18 +179,6 @@ static bool emulate_hitag2_recovered_yes(FlipperFormat* flipper_format) {
return false;
}
static void emulate_request_nav_pop(ProtoPirateApp* app) {
app->emulate_nav_pending = EMULATE_NAV_POP;
}
static void emulate_request_nav_after_exit(ProtoPirateApp* app) {
if(scene_manager_has_previous_scene(app->scene_manager, ProtoPirateSceneStart)) {
app->emulate_nav_pending = EMULATE_NAV_POP;
} else {
app->emulate_nav_pending = EMULATE_NAV_STOP_APP;
}
}
static bool emulate_prompt_hitag2_key(ProtoPirateApp* app, EmulateContext* ctx);
static void emulate_hitag2_key_input_callback(void* context) {
@@ -211,7 +199,8 @@ static void emulate_hitag2_key_input_callback(void* context) {
if(!emulate_write_hitag2_key(ctx->flipper_format, key)) {
notification_message(app->notifications, &sequence_error);
emulate_request_nav_pop(app);
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
@@ -1080,7 +1069,8 @@ static void plugin_on_enter(void* context) {
if(!g_host_api->ensure_view_about || !g_host_api->ensure_view_about(app)) {
notification_message(app->notifications, &sequence_error);
emulate_request_nav_pop(app);
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
@@ -1101,7 +1091,8 @@ static void plugin_on_enter(void* context) {
if(!g_host_api->radio_init || !g_host_api->radio_init(app)) {
FURI_LOG_E(TAG, "Failed to initialize radio for emulate scene");
notification_message(app->notifications, &sequence_error);
emulate_request_nav_pop(app);
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
}
@@ -1109,14 +1100,16 @@ static void plugin_on_enter(void* context) {
if(!emulate_radio_ready(app)) {
FURI_LOG_E(TAG, "Radio still incomplete after emulate init");
notification_message(app->notifications, &sequence_error);
emulate_request_nav_pop(app);
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
emulate_context = malloc(sizeof(EmulateContext));
if(!emulate_context) {
FURI_LOG_E(TAG, "Failed to allocate emulate context");
emulate_request_nav_pop(app);
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
memset(emulate_context, 0, sizeof(EmulateContext));
@@ -1126,7 +1119,8 @@ static void plugin_on_enter(void* context) {
if(!ctx->protocol_name) {
FURI_LOG_E(TAG, "Failed to allocate protocol name string");
emulate_context_free();
emulate_request_nav_pop(app);
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
@@ -1134,7 +1128,8 @@ static void plugin_on_enter(void* context) {
FURI_LOG_E(TAG, "No file path set");
emulate_context_free();
notification_message(app->notifications, &sequence_error);
emulate_request_nav_pop(app);
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
@@ -1143,7 +1138,8 @@ static void plugin_on_enter(void* context) {
FURI_LOG_E(TAG, "Failed to open storage");
emulate_context_free();
notification_message(app->notifications, &sequence_error);
emulate_request_nav_pop(app);
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
@@ -1152,7 +1148,8 @@ static void plugin_on_enter(void* context) {
FURI_LOG_E(TAG, "Failed to allocate FlipperFormat");
emulate_context_free();
notification_message(app->notifications, &sequence_error);
emulate_request_nav_pop(app);
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
@@ -1160,7 +1157,8 @@ static void plugin_on_enter(void* context) {
FURI_LOG_E(TAG, "Failed to open file: %s", app->loaded_file_path);
emulate_context_free();
notification_message(app->notifications, &sequence_error);
emulate_request_nav_pop(app);
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
@@ -1313,7 +1311,8 @@ static void plugin_on_enter(void* context) {
FURI_LOG_E(TAG, "Failed to show HITAG2 key input");
notification_message(app->notifications, &sequence_error);
emulate_context_free();
emulate_request_nav_pop(app);
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
}
return;
}
@@ -1474,7 +1473,13 @@ static bool plugin_on_event(void* context, SceneManagerEvent event) {
}
}
emulate_request_nav_after_exit(app);
if(!scene_manager_has_previous_scene(app->scene_manager, ProtoPirateSceneStart)) {
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateStopApp);
} else {
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
}
consumed = true;
break;
}
@@ -3,7 +3,6 @@
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <lib/flipper_application/flipper_application.h>
#include <gui/scene_manager.h>
#define PROTOPIRATE_EMULATE_PLUGIN_APP_ID "pp_emulate"
@@ -8,6 +8,8 @@
#include <gui/modules/widget.h>
#include <gui/modules/widget_elements/widget_element.h>
#include <lib/flipper_application/flipper_application.h>
#ifdef PROTOPIRATE_PSA_BF_PLUGIN_BUILD
#include "pp_bf_icons.h"
#else
@@ -2,7 +2,6 @@
#include <stdbool.h>
#include <stdint.h>
#include <lib/flipper_application/flipper_application.h>
#include <gui/scene_manager.h>
#include <flipper_format/flipper_format.h>
+24 -8
View File
@@ -47,8 +47,12 @@ void plugin_protopirate_scene_saved_info_on_enter(void* context) {
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);
if(!scene_manager_has_previous_scene(app->scene_manager, ProtoPirateSceneStart)) {
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateStopApp);
} else
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
@@ -285,9 +289,16 @@ bool plugin_protopirate_scene_saved_info_on_event(void* context, SceneManagerEve
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));
if(app->psa_bf_plugin && app->psa_bf_plugin->is_running &&
app->psa_bf_plugin->on_scene_event(app, ProtoPiratePsaBfContextReceiverInfo, event)) {
consumed = true;
} else {
if(!scene_manager_has_previous_scene(app->scene_manager, ProtoPirateSceneStart)) {
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateStopApp);
consumed = true;
}
}
} else if(event.type == SceneManagerEventTypeCustom) {
if(event.event == ProtoPirateCustomEventSavedInfoDelete) {
FURI_LOG_I(TAG, "Delete requested");
@@ -312,8 +323,13 @@ bool plugin_protopirate_scene_saved_info_on_event(void* context, SceneManagerEve
g_saved_info_scene_host_api->storage_delete_file(app->loaded_file_path);
notification_message(app->notifications, &sequence_semi_success);
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventSavedInfoExit);
if(!scene_manager_has_previous_scene(
app->scene_manager, ProtoPirateSceneStart)) {
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateStopApp);
} else
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
}
}
consumed = true;
@@ -336,7 +352,7 @@ bool plugin_protopirate_scene_saved_info_on_event(void* context, SceneManagerEve
//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);
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateEmulate);
consumed = true;
}
@@ -5,7 +5,6 @@
#include <stdint.h>
#include <gui/scene_manager.h>
#include <lib/flipper_application/flipper_application.h>
#include <lib/subghz/devices/devices.h>
#include "../../defines.h"
@@ -58,9 +57,13 @@ typedef struct {
void (*receiver_add_data_statusbar)(
ProtoPirateReceiver* receiver,
const char* frequency_str,
size_t frequency_size,
const char* preset_str,
size_t preset_size,
const char* history_stat_str,
size_t history_stat_size,
bool external_radio);
uint16_t (*receiver_get_idx_menu)(ProtoPirateReceiver* receiver);
void (*receiver_set_idx_menu)(ProtoPirateReceiver* receiver, uint16_t idx);
void (*receiver_set_callback)(
+7 -2
View File
@@ -12,7 +12,11 @@ static const ProtoPirateAboutSceneHostApi protopirate_about_scene_host_api = {
void protopirate_scene_about_on_enter(void* context) {
ProtoPirateApp* app = context;
if(!shared_plugin_load(app, ProtoPirateSharedPluginsAbout, NULL)) {
if(!shared_plugin_load(
(void**)&app->plugin_flipper_application,
(const void**)&app->about_plugin,
ProtoPirateSharedPluginsAbout,
NULL)) {
notification_message(app->notifications, &sequence_error);
scene_manager_previous_scene(app->scene_manager);
return;
@@ -40,5 +44,6 @@ void protopirate_scene_about_on_exit(void* 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);
shared_plugin_unload(
(void**)&app->plugin_flipper_application, (const void**)&app->about_plugin);
}
+14 -30
View File
@@ -7,8 +7,6 @@
#include "../helpers/protopirate_storage.h"
#include "../protopirate_history.h"
#include <loader/firmware_api/firmware_api.h>
#define TAG "PPSceneEmulate"
static bool host_radio_init(void* app) {
@@ -53,24 +51,6 @@ static void host_storage_delete_temp(void) {
protopirate_storage_delete_temp();
}
static void protopirate_emulate_apply_pending_nav(ProtoPirateApp* app) {
furi_check(app);
const uint8_t nav = app->emulate_nav_pending;
if(nav == EMULATE_NAV_NONE) {
return;
}
app->emulate_nav_pending = EMULATE_NAV_NONE;
if(nav == EMULATE_NAV_POP) {
scene_manager_previous_scene(app->scene_manager);
} else if(nav == EMULATE_NAV_STOP_APP) {
scene_manager_stop(app->scene_manager);
view_dispatcher_stop(app->view_dispatcher);
}
}
static const ProtoPirateEmulateHostApi protopirate_emulate_host_api = {
.radio_init = host_radio_init,
.apply_protocol_registry_for_context = host_apply_protocol_registry_for_context,
@@ -86,15 +66,18 @@ void protopirate_emulate_context_release(ProtoPirateApp* app) {
if(app->emulate_plugin && app->emulate_plugin->context_release) {
app->emulate_plugin->context_release(app);
}
shared_plugin_unload(app, ProtoPirateSharedPluginsEmulate);
shared_plugin_unload(
(void**)&app->plugin_flipper_application, (const void**)&app->emulate_plugin);
}
void protopirate_scene_emulate_on_enter(void* context) {
ProtoPirateApp* app = context;
app->emulate_nav_pending = EMULATE_NAV_NONE;
if(!shared_plugin_load(app, ProtoPirateSharedPluginsEmulate, NULL)) {
if(!shared_plugin_load(
(void**)&app->plugin_flipper_application,
(const void**)&app->emulate_plugin,
ProtoPirateSharedPluginsEmulate,
NULL)) {
notification_message(app->notifications, &sequence_error);
scene_manager_previous_scene(app->scene_manager);
return;
@@ -103,18 +86,19 @@ void protopirate_scene_emulate_on_enter(void* context) {
}
app->emulate_plugin->on_enter(app);
protopirate_emulate_apply_pending_nav(app);
}
bool protopirate_scene_emulate_on_event(void* context, SceneManagerEvent event) {
ProtoPirateApp* app = context;
if(!app->emulate_plugin || !app->emulate_plugin->on_event) {
return false;
bool consumed = false;
//Handle Saved event in plugin.
if(app->emulate_plugin && app->emulate_plugin->on_event(app, event)) {
consumed = true;
} else {
consumed = shared_plugin_handle_navigation_events(
app->scene_manager, app->view_dispatcher, event);
}
const bool consumed = app->emulate_plugin->on_event(app, event);
protopirate_emulate_apply_pending_nav(app);
return consumed;
}
+11 -6
View File
@@ -24,8 +24,7 @@ static void protopirate_scene_receiver_update_statusbar(void* context) {
char modulation_str[8] = {0};
char history_stat_str[16] = {0};
protopirate_get_frequency_modulation_str(
app, frequency_str, sizeof(frequency_str), modulation_str, sizeof(modulation_str));
protopirate_get_frequency_modulation_str(app, frequency_str, 16, modulation_str, 8);
bool is_external = false;
if(app->radio_initialized && app->txrx->radio_device) {
@@ -33,14 +32,20 @@ static void protopirate_scene_receiver_update_statusbar(void* context) {
}
if(app->txrx->history) {
protopirate_history_format_status_text(
app->txrx->history, history_stat_str, sizeof(history_stat_str));
protopirate_history_format_status_text(app->txrx->history, history_stat_str, 20);
} else {
snprintf(history_stat_str, sizeof(history_stat_str), "0/%u", PROTOPIRATE_HISTORY_MAX);
snprintf(history_stat_str, 16, "0/%u", PROTOPIRATE_HISTORY_MAX);
}
protopirate_view_receiver_add_data_statusbar(
app->protopirate_receiver, frequency_str, modulation_str, history_stat_str, is_external);
app->protopirate_receiver,
frequency_str,
16,
modulation_str,
8,
history_stat_str,
16,
is_external);
}
static void protopirate_scene_receiver_callback(
+7 -3
View File
@@ -11,7 +11,11 @@ static const ProtoPirateConfigSceneHostApi protopirate_config_scene_host_api = {
void protopirate_scene_receiver_config_on_enter(void* context) {
ProtoPirateApp* app = context;
if(!shared_plugin_load(app, ProtoPirateSharedPluginsConfig, NULL)) {
if(!shared_plugin_load(
(void**)&app->plugin_flipper_application,
(const void**)&app->config_plugin,
ProtoPirateSharedPluginsConfig,
NULL)) {
notification_message(app->notifications, &sequence_error);
scene_manager_previous_scene(app->scene_manager);
return;
@@ -39,6 +43,6 @@ bool protopirate_scene_receiver_config_on_event(void* context, SceneManagerEvent
void protopirate_scene_receiver_config_on_exit(void* context) {
ProtoPirateApp* app = context;
shared_plugin_unload(app, ProtoPirateSharedPluginsConfig);
shared_plugin_unload(
(void**)&app->plugin_flipper_application, (const void**)&app->config_plugin);
}
+13 -17
View File
@@ -16,7 +16,11 @@ static const ProtoPirateSavedInfoSceneHostApi protopirate_saved_info_scene_host_
void protopirate_scene_saved_info_on_enter(void* context) {
ProtoPirateApp* app = context;
if(!shared_plugin_load(app, ProtoPirateSharedPluginsSavedInfo, NULL)) {
if(!shared_plugin_load(
(void**)&app->plugin_flipper_application,
(const void**)&app->saved_info_plugin,
ProtoPirateSharedPluginsSavedInfo,
NULL)) {
notification_message(app->notifications, &sequence_error);
scene_manager_previous_scene(app->scene_manager);
return;
@@ -29,26 +33,18 @@ 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(app->scene_manager, ProtoPirateSceneEmulate);
return true;
#endif
} else if(event.event == ProtoPirateCustomEventSavedInfoExit) {
scene_manager_previous_scene(((ProtoPirateApp*)context)->scene_manager);
return true;
}
//Handle event in plugin.
if(app->saved_info_plugin->on_event(app, event)) {
return true;
} else {
return shared_plugin_handle_navigation_events(
app->scene_manager, app->view_dispatcher, event);
}
//Handle Saved Info event in plugin.
return app->saved_info_plugin->on_event(app, event);
}
void protopirate_scene_saved_info_on_exit(void* context) {
ProtoPirateApp* app = context;
widget_reset(app->widget);
shared_plugin_unload(app, ProtoPirateSharedPluginsSavedInfo);
shared_plugin_unload(
(void**)&app->plugin_flipper_application, (const void**)&app->saved_info_plugin);
}
-2
View File
@@ -92,7 +92,6 @@ bool protopirate_scene_start_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(app->scene_manager, ProtoPirateSceneStart, event.event);
FURI_LOG_I(TAG, "Suppressing Charging While in a scene.");
if(event.event == SubmenuIndexProtoPirateAbout) {
scene_manager_next_scene(app->scene_manager, ProtoPirateSceneAbout);
consumed = true;
@@ -128,7 +127,6 @@ bool protopirate_scene_start_on_event(void* context, SceneManagerEvent event) {
}
void protopirate_scene_start_on_exit(void* context) {
furi_check(context);
ProtoPirateApp* app = context;
submenu_reset(app->submenu);
}
+52 -30
View File
@@ -12,17 +12,13 @@ void protopirate_scene_sub_decode_on_enter(void* context) {
}
bool protopirate_scene_sub_decode_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == ProtoPirateCustomEventSubDecodeEmulateDelayedStart) {
#ifdef ENABLE_EMULATE_FEATURE
scene_manager_next_scene(
((ProtoPirateApp*)context)->scene_manager, ProtoPirateSceneEmulate);
#endif
return true;
}
ProtoPirateApp* app = (ProtoPirateApp*)context;
if(protopirate_tool_scene_on_event(context, event)) {
return true;
} else {
return shared_plugin_handle_navigation_events(
app->scene_manager, app->view_dispatcher, event);
}
return protopirate_tool_scene_on_event(context, event);
}
void protopirate_scene_sub_decode_on_exit(void* context) {
@@ -74,10 +70,26 @@ static const ProtoPirateToolSceneHostApi* g_tool_scene_host_api = NULL;
app, frequency, frequency_size, modulation, modulation_size)
#define radio_device_loader_is_external(radio_device) \
g_tool_scene_host_api->radio_device_is_external(radio_device)
#define protopirate_view_receiver_add_data_statusbar( \
receiver, frequency, modulation, history, external) \
receiver, \
frequency, \
frequency_size, \
modulation, \
modulation_size, \
history, \
history_size, \
external) \
g_tool_scene_host_api->receiver_add_data_statusbar( \
receiver, frequency, modulation, history, external)
receiver, \
frequency, \
frequency_size, \
modulation, \
modulation_size, \
history, \
history_size, \
external)
#define protopirate_view_receiver_get_idx_menu(receiver) \
g_tool_scene_host_api->receiver_get_idx_menu(receiver)
#define protopirate_view_receiver_set_idx_menu(receiver, idx) \
@@ -231,12 +243,11 @@ static void protopirate_scene_sub_decode_update_receiver_statusbar(
char modulation_str[8] = {0};
char history_stat_str[16] = {0};
protopirate_get_frequency_modulation_str(
app, frequency_str, sizeof(frequency_str), modulation_str, sizeof(modulation_str));
protopirate_get_frequency_modulation_str(app, frequency_str, 16, modulation_str, 8);
if(ctx && ctx->frequency > 0U) {
snprintf(
frequency_str,
sizeof(frequency_str),
20,
"%03lu.%02lu",
(unsigned long)((ctx->frequency / 1000000UL) % 1000UL),
(unsigned long)((ctx->frequency / 10000UL) % 100UL));
@@ -244,13 +255,20 @@ static void protopirate_scene_sub_decode_update_receiver_statusbar(
const uint16_t signal_count =
(ctx && ctx->history) ? protopirate_history_get_item(ctx->history) : 0U;
snprintf(
history_stat_str, sizeof(history_stat_str), "%u/%u", signal_count, PROTOPIRATE_HISTORY_MAX);
snprintf(history_stat_str, 16, "%u/%u", signal_count, PROTOPIRATE_HISTORY_MAX);
bool is_external =
app->txrx->radio_device ? radio_device_loader_is_external(app->txrx->radio_device) : false;
protopirate_view_receiver_add_data_statusbar(
app->protopirate_receiver, frequency_str, modulation_str, history_stat_str, is_external);
app->protopirate_receiver,
frequency_str,
16,
modulation_str,
8,
history_stat_str,
16,
is_external);
}
static void protopirate_scene_sub_decode_update_receiver_progress(
@@ -523,14 +541,16 @@ void protopirate_scene_sub_decode_on_enter(void* context) {
if(!protopirate_ensure_receiver_view(app) || !protopirate_ensure_widget(app)) {
notification_message(app->notifications, &sequence_error);
app->tool_scene_nav_pending = TOOL_SCENE_NAV_POP;
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
if(!app->radio_initialized && !protopirate_radio_init(app)) {
FURI_LOG_E(TAG, "Failed to initialize radio for sub decode scene");
notification_message(app->notifications, &sequence_error);
app->tool_scene_nav_pending = TOOL_SCENE_NAV_POP;
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
@@ -542,7 +562,8 @@ void protopirate_scene_sub_decode_on_enter(void* context) {
if(!app->txrx->receiver) {
FURI_LOG_E(TAG, "Failed to allocate receiver for sub decode scene");
notification_message(app->notifications, &sequence_error);
app->tool_scene_nav_pending = TOOL_SCENE_NAV_POP;
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
@@ -551,7 +572,8 @@ void protopirate_scene_sub_decode_on_enter(void* context) {
g_decode_ctx = malloc(sizeof(SubDecodeContext));
if(!g_decode_ctx) {
FURI_LOG_E(TAG, "Failed to allocate decode context");
app->tool_scene_nav_pending = TOOL_SCENE_NAV_POP;
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
memset(g_decode_ctx, 0, sizeof(SubDecodeContext));
@@ -579,7 +601,8 @@ void protopirate_scene_sub_decode_on_enter(void* context) {
free(g_decode_ctx);
g_decode_ctx = NULL;
notification_message(app->notifications, &sequence_error);
app->tool_scene_nav_pending = TOOL_SCENE_NAV_POP;
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
owns_history = true;
@@ -607,17 +630,17 @@ void protopirate_scene_sub_decode_on_enter(void* context) {
g_decode_ctx->state = DecodeStateOpenFile;
protopirate_scene_sub_decode_prepare_receiver_view(app);
} else {
app->tool_scene_nav_pending = TOOL_SCENE_NAV_POP;
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
}
}
bool protopirate_scene_sub_decode_on_event(void* context, SceneManagerEvent event) {
ProtoPirateApp* app = context;
bool consumed = false;
SubDecodeContext* ctx = g_decode_ctx;
if(!ctx) return false;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == ProtoPirateCustomEventSubDecodeUpdate) {
// Update receiver view with new history items (when signals are detected during decoding)
@@ -786,7 +809,7 @@ bool protopirate_scene_sub_decode_on_event(void* context, SceneManagerEvent even
FURI_LOG_I(TAG, "Emulate from sub-decode temp file: %s", app->loaded_file_path);
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventSubDecodeEmulateDelayedStart);
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateEmulate);
} else {
FURI_LOG_E(
TAG, "Failed to prepare emulate capture %u", ctx->selected_history_index);
@@ -836,8 +859,8 @@ bool protopirate_scene_sub_decode_on_event(void* context, SceneManagerEvent even
if(!protopirate_scene_sub_decode_open_browser_for_next_file(app)) {
protopirate_history_reset(ctx->history);
app->tool_scene_nav_pending = TOOL_SCENE_NAV_SEARCH_PREVIOUS;
app->tool_scene_nav_target = ProtoPirateSceneStart;
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
}
consumed = true;
}
@@ -1420,7 +1443,6 @@ bool protopirate_scene_sub_decode_on_event(void* context, SceneManagerEvent even
}
// If in history view, back is handled by ViewReceiverBack event
}
return consumed;
}
+23 -11
View File
@@ -1,7 +1,7 @@
// scenes/protopirate_scene_timing_tuner.c
#include "../protopirate_app_i.h"
#ifdef ENABLE_TIMING_TUNER_SCENE
#ifdef ENABLE_TIMING_TUNER_SCENE
#ifndef PROTOPIRATE_TIMING_TUNER_PLUGIN_BUILD
void protopirate_scene_timing_tuner_on_enter(void* context) {
@@ -9,7 +9,13 @@ void protopirate_scene_timing_tuner_on_enter(void* context) {
}
bool protopirate_scene_timing_tuner_on_event(void* context, SceneManagerEvent event) {
return protopirate_tool_scene_on_event(context, event);
ProtoPirateApp* app = (ProtoPirateApp*)context;
if(protopirate_tool_scene_on_event(context, event)) {
return true;
} else {
return shared_plugin_handle_navigation_events(
app->scene_manager, app->view_dispatcher, event);
}
}
void protopirate_scene_timing_tuner_on_exit(void* context) {
@@ -651,14 +657,16 @@ void protopirate_scene_timing_tuner_on_enter(void* context) {
if(!protopirate_ensure_view_about(app)) {
notification_message(app->notifications, &sequence_error);
app->tool_scene_nav_pending = TOOL_SCENE_NAV_POP;
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
if(!app->radio_initialized && !protopirate_radio_init(app)) {
FURI_LOG_E(TAG, "Failed to initialize radio for timing tuner");
notification_message(app->notifications, &sequence_error);
app->tool_scene_nav_pending = TOOL_SCENE_NAV_POP;
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
@@ -670,7 +678,8 @@ void protopirate_scene_timing_tuner_on_enter(void* context) {
if(!app->txrx->receiver) {
FURI_LOG_E(TAG, "Failed to allocate receiver for timing tuner");
notification_message(app->notifications, &sequence_error);
app->tool_scene_nav_pending = TOOL_SCENE_NAV_POP;
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
@@ -678,7 +687,8 @@ void protopirate_scene_timing_tuner_on_enter(void* context) {
if(!g_timing_ctx) {
FURI_LOG_E(TAG, "Failed to allocate timing tuner context");
notification_message(app->notifications, &sequence_error);
app->tool_scene_nav_pending = TOOL_SCENE_NAV_POP;
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
memset(g_timing_ctx, 0, sizeof(TimingTunerContext));
@@ -706,7 +716,8 @@ void protopirate_scene_timing_tuner_on_enter(void* context) {
view_set_input_callback(app->view_about, NULL);
timing_tuner_context_free();
notification_message(app->notifications, &sequence_error);
app->tool_scene_nav_pending = TOOL_SCENE_NAV_POP;
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
return;
}
// Set up worker callbacks
@@ -738,19 +749,20 @@ void protopirate_scene_timing_tuner_on_enter(void* context) {
bool protopirate_scene_timing_tuner_on_event(void* context, SceneManagerEvent event) {
ProtoPirateApp* app = context;
bool consumed = false;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == 0) {
app->tool_scene_nav_pending = TOOL_SCENE_NAV_POP;
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateBack);
consumed = true;
} else if(event.event == 1) {
if(g_timing_ctx && g_timing_ctx->is_receiving) {
protopirate_rx_end(app);
g_timing_ctx->is_receiving = false;
}
app->tool_scene_nav_pending = TOOL_SCENE_NAV_NEXT;
app->tool_scene_nav_target = ProtoPirateSceneReceiverConfig;
view_dispatcher_send_custom_event(
app->view_dispatcher, ProtoPirateCustomEventPluginNavigateConfig);
consumed = true;
}
} else if(event.type == SceneManagerEventTypeTick) {
+29 -25
View File
@@ -27,9 +27,9 @@ typedef struct {
uint8_t history_item;
float rssi;
bool auto_save;
FuriString* frequency_str;
FuriString* preset_str;
FuriString* history_stat_str;
char* frequency_str;
char* preset_str;
char* history_stat_str;
FuriString* draw_scratch;
bool external_radio;
ProtoPirateLock lock;
@@ -191,24 +191,26 @@ static void protopirate_view_receiver_update_offset(ProtoPirateReceiver* receive
void protopirate_view_receiver_add_data_statusbar(
ProtoPirateReceiver* receiver,
const char* frequency_str,
size_t freqency_size,
const char* preset_str,
size_t preset_size,
const char* history_stat_str,
size_t history_stat_size,
bool external_radio) {
furi_check(receiver);
with_view_model(
receiver->view,
ProtoPirateReceiverModel * model,
{
furi_string_set_str(model->frequency_str, frequency_str);
furi_string_set_str(model->preset_str, preset_str);
furi_string_set_str(model->history_stat_str, history_stat_str);
memcpy(model->frequency_str, frequency_str, freqency_size);
memcpy(model->preset_str, preset_str, preset_size);
memcpy(model->history_stat_str, history_stat_str, history_stat_size);
model->external_radio = external_radio;
},
true);
}
static void protopirate_view_receiver_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) {
canvas_set_color(canvas, ColorBlack);
canvas_draw_box(canvas, 0, 0 + idx * FRAME_HEIGHT, scrollbar ? 122 : 127, FRAME_HEIGHT);
canvas_set_color(canvas, ColorWhite);
@@ -280,6 +282,9 @@ void protopirate_view_receiver_draw(Canvas* canvas, ProtoPirateReceiverModel* mo
canvas, 4, 9 + (i * FRAME_HEIGHT), furi_string_get_cstr(model->draw_scratch));
}
//Last item may be selected, it wont reset.
canvas_set_color(canvas, ColorBlack);
//Draw scrollbar if needed
if(scrollbar) {
// Calculate maximum scroll position
@@ -360,8 +365,7 @@ void protopirate_view_receiver_draw(Canvas* canvas, ProtoPirateReceiverModel* mo
canvas_set_font(canvas, FontSecondary);
if(model->sub_decode_mode) {
canvas_draw_str_aligned(
canvas, 127, 0, AlignRight, AlignTop, furi_string_get_cstr(model->preset_str));
canvas_draw_str_aligned(canvas, 127, 0, AlignRight, AlignTop, model->preset_str);
} else {
if(model->external_radio) {
canvas_draw_str_aligned(canvas, 127, 0, AlignRight, AlignTop, "Ext");
@@ -381,12 +385,12 @@ void protopirate_view_receiver_draw(Canvas* canvas, ProtoPirateReceiverModel* mo
//Draw the unlock instructions last, so they appear on top...
if(model->lock_count) {
if(model->sub_decode_mode) {
canvas_draw_str(canvas, 44, 63, furi_string_get_cstr(model->frequency_str));
canvas_draw_str(canvas, 96, 63, furi_string_get_cstr(model->history_stat_str));
canvas_draw_str(canvas, 44, 63, model->frequency_str);
canvas_draw_str(canvas, 96, 63, model->history_stat_str);
} else {
canvas_draw_str(canvas, 44, 63, furi_string_get_cstr(model->frequency_str));
canvas_draw_str(canvas, 79, 63, furi_string_get_cstr(model->preset_str));
canvas_draw_str(canvas, 96, 63, furi_string_get_cstr(model->history_stat_str));
canvas_draw_str(canvas, 44, 63, model->frequency_str);
canvas_draw_str(canvas, 79, 63, model->preset_str);
canvas_draw_str(canvas, 96, 63, model->history_stat_str);
}
canvas_set_font(canvas, FontSecondary);
elements_bold_rounded_frame(canvas, 14, 8, 99, 48);
@@ -402,12 +406,12 @@ void protopirate_view_receiver_draw(Canvas* canvas, ProtoPirateReceiverModel* mo
canvas_draw_str(canvas, 74, 62, "Locked");
} else {
if(model->sub_decode_mode) {
canvas_draw_str(canvas, 44, 63, furi_string_get_cstr(model->frequency_str));
canvas_draw_str(canvas, 96, 63, furi_string_get_cstr(model->history_stat_str));
canvas_draw_str(canvas, 44, 63, model->frequency_str);
canvas_draw_str(canvas, 96, 63, model->history_stat_str);
} else {
canvas_draw_str(canvas, 44, 63, furi_string_get_cstr(model->frequency_str));
canvas_draw_str(canvas, 79, 63, furi_string_get_cstr(model->preset_str));
canvas_draw_str(canvas, 96, 63, furi_string_get_cstr(model->history_stat_str));
canvas_draw_str(canvas, 44, 63, model->frequency_str);
canvas_draw_str(canvas, 79, 63, model->preset_str);
canvas_draw_str(canvas, 96, 63, model->history_stat_str);
}
}
}
@@ -583,9 +587,9 @@ ProtoPirateReceiver* protopirate_view_receiver_alloc(bool auto_save) {
ProtoPirateReceiverModel * model,
{
model->history = NULL;
model->frequency_str = furi_string_alloc();
model->preset_str = furi_string_alloc();
model->history_stat_str = furi_string_alloc();
model->frequency_str = malloc(16);
model->preset_str = malloc(8);
model->history_stat_str = malloc(16);
model->draw_scratch = furi_string_alloc();
furi_check(model->draw_scratch);
model->list_offset = 0;
@@ -612,9 +616,9 @@ void protopirate_view_receiver_free(ProtoPirateReceiver* receiver) {
receiver->view,
ProtoPirateReceiverModel * model,
{
furi_string_free(model->frequency_str);
furi_string_free(model->preset_str);
furi_string_free(model->history_stat_str);
free(model->frequency_str);
free(model->preset_str);
free(model->history_stat_str);
furi_string_free(model->draw_scratch);
},
false);
+3
View File
@@ -21,8 +21,11 @@ View* protopirate_view_receiver_get_view(ProtoPirateReceiver* receiver);
void protopirate_view_receiver_add_data_statusbar(
ProtoPirateReceiver* receiver,
const char* frequency_str,
size_t freqency_size,
const char* preset_str,
size_t preset_size,
const char* history_stat_str,
size_t history_stat_size,
bool external_radio);
uint16_t protopirate_view_receiver_get_idx_menu(ProtoPirateReceiver* receiver);