From c997e9a819b615520eea979dde0ae3652423a50a Mon Sep 17 00:00:00 2001 From: ESurge Date: Mon, 19 Sep 2022 19:37:56 -0700 Subject: [PATCH 1/4] Added iButton and Clock to Main Menu but they are loaded via FAP Loader. --- applications/main/application.fam | 2 + .../main/clock_loader/application.fam | 10 + .../main/clock_loader/clock_loader_app.c | 179 ++++++++++++++++++ .../main/ibutton_loader/application.fam | 13 ++ .../main/ibutton_loader/ibutton_loader_app.c | 179 ++++++++++++++++++ 5 files changed, 383 insertions(+) create mode 100644 applications/main/clock_loader/application.fam create mode 100644 applications/main/clock_loader/clock_loader_app.c create mode 100644 applications/main/ibutton_loader/application.fam create mode 100644 applications/main/ibutton_loader/ibutton_loader_app.c diff --git a/applications/main/application.fam b/applications/main/application.fam index 3bdec8aa6..db9c507f5 100644 --- a/applications/main/application.fam +++ b/applications/main/application.fam @@ -3,8 +3,10 @@ App( name="Basic applications for main menu", apptype=FlipperAppType.METAPACKAGE, provides=[ + "clock_loader", "gpio", # "ibutton", + "ibutton_loader", "infrared", "lfrfid", "nfc", diff --git a/applications/main/clock_loader/application.fam b/applications/main/clock_loader/application.fam new file mode 100644 index 000000000..703c78f63 --- /dev/null +++ b/applications/main/clock_loader/application.fam @@ -0,0 +1,10 @@ +App( + appid="clock_loader", + name="Clock", + apptype=FlipperAppType.APP, + entry_point="clock_loader_app", + requires=["gui"], + stack_size=int(1.5 * 1024), + icon="A_Clock_14", + order=9, +) diff --git a/applications/main/clock_loader/clock_loader_app.c b/applications/main/clock_loader/clock_loader_app.c new file mode 100644 index 000000000..c4579bdb2 --- /dev/null +++ b/applications/main/clock_loader/clock_loader_app.c @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define TAG "clock_loader_app" + +typedef struct { + FlipperApplication* app; + Storage* storage; + DialogsApp* dialogs; + Gui* gui; + string_t fap_path; +} FapLoader; + +static bool + fap_loader_item_callback(string_t path, void* context, uint8_t** icon_ptr, string_t item_name) { + FapLoader* loader = context; + furi_assert(loader); + + FlipperApplication* app = flipper_application_alloc(loader->storage, &hashtable_api_interface); + + FlipperApplicationPreloadStatus preload_res = + flipper_application_preload(app, string_get_cstr(path)); + + bool load_success = false; + + if(preload_res == FlipperApplicationPreloadStatusSuccess) { + const FlipperApplicationManifest* manifest = flipper_application_get_manifest(app); + if(manifest->has_icon) { + memcpy(*icon_ptr, manifest->icon, FAP_MANIFEST_MAX_ICON_SIZE); + } + string_set_str(item_name, manifest->name); + load_success = true; + } else { + FURI_LOG_E(TAG, "FAP Loader failed to preload %s", string_get_cstr(path)); + load_success = false; + } + + flipper_application_free(app); + return load_success; +} + +static bool fap_loader_run_selected_app(FapLoader* loader) { + furi_assert(loader); + + string_t error_message; + + string_init_set(error_message, "unknown error"); + + bool file_selected = false; + bool show_error = true; + do { + file_selected = true; + loader->app = flipper_application_alloc(loader->storage, &hashtable_api_interface); + + FURI_LOG_I(TAG, "FAP Loader is loading %s", string_get_cstr(loader->fap_path)); + + FlipperApplicationPreloadStatus preload_res = + flipper_application_preload(loader->app, string_get_cstr(loader->fap_path)); + if(preload_res != FlipperApplicationPreloadStatusSuccess) { + const char* err_msg = flipper_application_preload_status_to_string(preload_res); + string_printf(error_message, "Preload failed: %s", err_msg); + FURI_LOG_E( + TAG, + "FAP Loader failed to preload %s: %s", + string_get_cstr(loader->fap_path), + err_msg); + break; + } + + FURI_LOG_I(TAG, "FAP Loader is mapping"); + FlipperApplicationLoadStatus load_status = flipper_application_map_to_memory(loader->app); + if(load_status != FlipperApplicationLoadStatusSuccess) { + const char* err_msg = flipper_application_load_status_to_string(load_status); + string_printf(error_message, "Load failed: %s", err_msg); + FURI_LOG_E( + TAG, + "FAP Loader failed to map to memory %s: %s", + string_get_cstr(loader->fap_path), + err_msg); + break; + } + + FURI_LOG_I(TAG, "FAP Loader is staring app"); + + FuriThread* thread = flipper_application_spawn(loader->app, NULL); + furi_thread_start(thread); + furi_thread_join(thread); + + show_error = false; + int ret = furi_thread_get_return_code(thread); + + FURI_LOG_I(TAG, "FAP app returned: %i", ret); + } while(0); + + if(show_error) { + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_header(message, "Error", 64, 0, AlignCenter, AlignTop); + dialog_message_set_buttons(message, NULL, NULL, NULL); + + string_t buffer; + string_init(buffer); + string_printf(buffer, "%s", string_get_cstr(error_message)); + string_replace_str(buffer, ":", "\n"); + dialog_message_set_text( + message, string_get_cstr(buffer), 64, 32, AlignCenter, AlignCenter); + + dialog_message_show(loader->dialogs, message); + dialog_message_free(message); + string_clear(buffer); + } + + string_clear(error_message); + + if(file_selected) { + flipper_application_free(loader->app); + } + + return file_selected; +} + +static bool fap_loader_select_app(FapLoader* loader) { + const DialogsFileBrowserOptions browser_options = { + .extension = ".fap", + .skip_assets = true, + .icon = &I_badusb_10px, + .hide_ext = true, + .item_loader_callback = fap_loader_item_callback, + .item_loader_context = loader, + }; + + return dialog_file_browser_show( + loader->dialogs, loader->fap_path, loader->fap_path, &browser_options); +} + +int32_t clock_loader_app(void* p) { + UNUSED(p); + FapLoader* loader = malloc(sizeof(FapLoader)); + loader->storage = furi_record_open(RECORD_STORAGE); + loader->dialogs = furi_record_open(RECORD_DIALOGS); + loader->gui = furi_record_open(RECORD_GUI); + + ViewDispatcher* view_dispatcher = view_dispatcher_alloc(); + Loading* loading = loading_alloc(); + + view_dispatcher_enable_queue(view_dispatcher); + view_dispatcher_attach_to_gui(view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen); + view_dispatcher_add_view(view_dispatcher, 0, loading_get_view(loading)); + + const char* file = "/ext/apps/Main/Clock.fap"; + + if(file) { + string_init_set(loader->fap_path, file); + fap_loader_run_selected_app(loader); + } else { + string_init_set(loader->fap_path, EXT_PATH("apps")); + + while(fap_loader_select_app(loader)) { + view_dispatcher_switch_to_view(view_dispatcher, 0); + fap_loader_run_selected_app(loader); + }; + } + + view_dispatcher_remove_view(view_dispatcher, 0); + loading_free(loading); + view_dispatcher_free(view_dispatcher); + + string_clear(loader->fap_path); + furi_record_close(RECORD_GUI); + furi_record_close(RECORD_DIALOGS); + furi_record_close(RECORD_STORAGE); + free(loader); + return 0; +} \ No newline at end of file diff --git a/applications/main/ibutton_loader/application.fam b/applications/main/ibutton_loader/application.fam new file mode 100644 index 000000000..20663fea0 --- /dev/null +++ b/applications/main/ibutton_loader/application.fam @@ -0,0 +1,13 @@ +App( + appid="ibutton_loader", + name="iButton", + apptype=FlipperAppType.APP, + entry_point="ibutton_loader_app", + requires=[ + "gui", + "storage", + ], + stack_size=int(1.5 * 1024), + icon="A_iButton_14", + order=60, +) diff --git a/applications/main/ibutton_loader/ibutton_loader_app.c b/applications/main/ibutton_loader/ibutton_loader_app.c new file mode 100644 index 000000000..6eb071603 --- /dev/null +++ b/applications/main/ibutton_loader/ibutton_loader_app.c @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define TAG "ibutton_loader_app" + +typedef struct { + FlipperApplication* app; + Storage* storage; + DialogsApp* dialogs; + Gui* gui; + string_t fap_path; +} FapLoader; + +static bool + fap_loader_item_callback(string_t path, void* context, uint8_t** icon_ptr, string_t item_name) { + FapLoader* loader = context; + furi_assert(loader); + + FlipperApplication* app = flipper_application_alloc(loader->storage, &hashtable_api_interface); + + FlipperApplicationPreloadStatus preload_res = + flipper_application_preload(app, string_get_cstr(path)); + + bool load_success = false; + + if(preload_res == FlipperApplicationPreloadStatusSuccess) { + const FlipperApplicationManifest* manifest = flipper_application_get_manifest(app); + if(manifest->has_icon) { + memcpy(*icon_ptr, manifest->icon, FAP_MANIFEST_MAX_ICON_SIZE); + } + string_set_str(item_name, manifest->name); + load_success = true; + } else { + FURI_LOG_E(TAG, "FAP Loader failed to preload %s", string_get_cstr(path)); + load_success = false; + } + + flipper_application_free(app); + return load_success; +} + +static bool fap_loader_run_selected_app(FapLoader* loader) { + furi_assert(loader); + + string_t error_message; + + string_init_set(error_message, "unknown error"); + + bool file_selected = false; + bool show_error = true; + do { + file_selected = true; + loader->app = flipper_application_alloc(loader->storage, &hashtable_api_interface); + + FURI_LOG_I(TAG, "FAP Loader is loading %s", string_get_cstr(loader->fap_path)); + + FlipperApplicationPreloadStatus preload_res = + flipper_application_preload(loader->app, string_get_cstr(loader->fap_path)); + if(preload_res != FlipperApplicationPreloadStatusSuccess) { + const char* err_msg = flipper_application_preload_status_to_string(preload_res); + string_printf(error_message, "Preload failed: %s", err_msg); + FURI_LOG_E( + TAG, + "FAP Loader failed to preload %s: %s", + string_get_cstr(loader->fap_path), + err_msg); + break; + } + + FURI_LOG_I(TAG, "FAP Loader is mapping"); + FlipperApplicationLoadStatus load_status = flipper_application_map_to_memory(loader->app); + if(load_status != FlipperApplicationLoadStatusSuccess) { + const char* err_msg = flipper_application_load_status_to_string(load_status); + string_printf(error_message, "Load failed: %s", err_msg); + FURI_LOG_E( + TAG, + "FAP Loader failed to map to memory %s: %s", + string_get_cstr(loader->fap_path), + err_msg); + break; + } + + FURI_LOG_I(TAG, "FAP Loader is staring app"); + + FuriThread* thread = flipper_application_spawn(loader->app, NULL); + furi_thread_start(thread); + furi_thread_join(thread); + + show_error = false; + int ret = furi_thread_get_return_code(thread); + + FURI_LOG_I(TAG, "FAP app returned: %i", ret); + } while(0); + + if(show_error) { + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_header(message, "Error", 64, 0, AlignCenter, AlignTop); + dialog_message_set_buttons(message, NULL, NULL, NULL); + + string_t buffer; + string_init(buffer); + string_printf(buffer, "%s", string_get_cstr(error_message)); + string_replace_str(buffer, ":", "\n"); + dialog_message_set_text( + message, string_get_cstr(buffer), 64, 32, AlignCenter, AlignCenter); + + dialog_message_show(loader->dialogs, message); + dialog_message_free(message); + string_clear(buffer); + } + + string_clear(error_message); + + if(file_selected) { + flipper_application_free(loader->app); + } + + return file_selected; +} + +static bool fap_loader_select_app(FapLoader* loader) { + const DialogsFileBrowserOptions browser_options = { + .extension = ".fap", + .skip_assets = true, + .icon = &I_badusb_10px, + .hide_ext = true, + .item_loader_callback = fap_loader_item_callback, + .item_loader_context = loader, + }; + + return dialog_file_browser_show( + loader->dialogs, loader->fap_path, loader->fap_path, &browser_options); +} + +int32_t ibutton_loader_app(void* p) { + UNUSED(p); + FapLoader* loader = malloc(sizeof(FapLoader)); + loader->storage = furi_record_open(RECORD_STORAGE); + loader->dialogs = furi_record_open(RECORD_DIALOGS); + loader->gui = furi_record_open(RECORD_GUI); + + ViewDispatcher* view_dispatcher = view_dispatcher_alloc(); + Loading* loading = loading_alloc(); + + view_dispatcher_enable_queue(view_dispatcher); + view_dispatcher_attach_to_gui(view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen); + view_dispatcher_add_view(view_dispatcher, 0, loading_get_view(loading)); + + const char* file = "/ext/apps/Main/ibutton.fap"; + + if(file) { + string_init_set(loader->fap_path, file); + fap_loader_run_selected_app(loader); + } else { + string_init_set(loader->fap_path, EXT_PATH("apps")); + + while(fap_loader_select_app(loader)) { + view_dispatcher_switch_to_view(view_dispatcher, 0); + fap_loader_run_selected_app(loader); + }; + } + + view_dispatcher_remove_view(view_dispatcher, 0); + loading_free(loading); + view_dispatcher_free(view_dispatcher); + + string_clear(loader->fap_path); + furi_record_close(RECORD_GUI); + furi_record_close(RECORD_DIALOGS); + furi_record_close(RECORD_STORAGE); + free(loader); + return 0; +} \ No newline at end of file From 244a8456ef83ab0a2024f268f8f7feaf4d525336 Mon Sep 17 00:00:00 2001 From: ESurge Date: Wed, 21 Sep 2022 03:08:32 -0700 Subject: [PATCH 2/4] Changed the way loader.c loads Clock/iButton/U2F Added a new variable in application.fam file to add the link to the FAP. It now supports any FAP as long as the application.fam file is formatted correctly and you create a loader "app". If no link is specified in the application.fam file, it doesn't attempt to load a FAP. --- applications/main/application.fam | 1 + .../main/clock_loader/application.fam | 1 + .../main/clock_loader/clock_loader_app.c | 174 +----------------- .../main/ibutton_loader/application.fam | 1 + .../main/ibutton_loader/ibutton_loader_app.c | 174 +----------------- applications/main/u2f_loader/application.fam | 14 ++ applications/main/u2f_loader/u2f_loader_app.c | 9 + applications/services/applications.h | 3 +- applications/services/loader/loader.c | 62 ++----- site_scons/fbt/appmanifest.py | 2 + 10 files changed, 48 insertions(+), 393 deletions(-) create mode 100644 applications/main/u2f_loader/application.fam create mode 100644 applications/main/u2f_loader/u2f_loader_app.c diff --git a/applications/main/application.fam b/applications/main/application.fam index 9fff87d81..94aff522e 100644 --- a/applications/main/application.fam +++ b/applications/main/application.fam @@ -13,6 +13,7 @@ App( "subghz", "bad_usb", # "u2f", + "u2f_loader", "fap_loader", "archive", # "Clock", diff --git a/applications/main/clock_loader/application.fam b/applications/main/clock_loader/application.fam index 703c78f63..cbb627c9c 100644 --- a/applications/main/clock_loader/application.fam +++ b/applications/main/clock_loader/application.fam @@ -7,4 +7,5 @@ App( stack_size=int(1.5 * 1024), icon="A_Clock_14", order=9, + link="/ext/apps/Main/Clock.fap", ) diff --git a/applications/main/clock_loader/clock_loader_app.c b/applications/main/clock_loader/clock_loader_app.c index c4579bdb2..cf345d9f3 100644 --- a/applications/main/clock_loader/clock_loader_app.c +++ b/applications/main/clock_loader/clock_loader_app.c @@ -1,179 +1,9 @@ -#include -#include -#include -#include -#include -#include -#include -#include +#include #define TAG "clock_loader_app" -typedef struct { - FlipperApplication* app; - Storage* storage; - DialogsApp* dialogs; - Gui* gui; - string_t fap_path; -} FapLoader; - -static bool - fap_loader_item_callback(string_t path, void* context, uint8_t** icon_ptr, string_t item_name) { - FapLoader* loader = context; - furi_assert(loader); - - FlipperApplication* app = flipper_application_alloc(loader->storage, &hashtable_api_interface); - - FlipperApplicationPreloadStatus preload_res = - flipper_application_preload(app, string_get_cstr(path)); - - bool load_success = false; - - if(preload_res == FlipperApplicationPreloadStatusSuccess) { - const FlipperApplicationManifest* manifest = flipper_application_get_manifest(app); - if(manifest->has_icon) { - memcpy(*icon_ptr, manifest->icon, FAP_MANIFEST_MAX_ICON_SIZE); - } - string_set_str(item_name, manifest->name); - load_success = true; - } else { - FURI_LOG_E(TAG, "FAP Loader failed to preload %s", string_get_cstr(path)); - load_success = false; - } - - flipper_application_free(app); - return load_success; -} - -static bool fap_loader_run_selected_app(FapLoader* loader) { - furi_assert(loader); - - string_t error_message; - - string_init_set(error_message, "unknown error"); - - bool file_selected = false; - bool show_error = true; - do { - file_selected = true; - loader->app = flipper_application_alloc(loader->storage, &hashtable_api_interface); - - FURI_LOG_I(TAG, "FAP Loader is loading %s", string_get_cstr(loader->fap_path)); - - FlipperApplicationPreloadStatus preload_res = - flipper_application_preload(loader->app, string_get_cstr(loader->fap_path)); - if(preload_res != FlipperApplicationPreloadStatusSuccess) { - const char* err_msg = flipper_application_preload_status_to_string(preload_res); - string_printf(error_message, "Preload failed: %s", err_msg); - FURI_LOG_E( - TAG, - "FAP Loader failed to preload %s: %s", - string_get_cstr(loader->fap_path), - err_msg); - break; - } - - FURI_LOG_I(TAG, "FAP Loader is mapping"); - FlipperApplicationLoadStatus load_status = flipper_application_map_to_memory(loader->app); - if(load_status != FlipperApplicationLoadStatusSuccess) { - const char* err_msg = flipper_application_load_status_to_string(load_status); - string_printf(error_message, "Load failed: %s", err_msg); - FURI_LOG_E( - TAG, - "FAP Loader failed to map to memory %s: %s", - string_get_cstr(loader->fap_path), - err_msg); - break; - } - - FURI_LOG_I(TAG, "FAP Loader is staring app"); - - FuriThread* thread = flipper_application_spawn(loader->app, NULL); - furi_thread_start(thread); - furi_thread_join(thread); - - show_error = false; - int ret = furi_thread_get_return_code(thread); - - FURI_LOG_I(TAG, "FAP app returned: %i", ret); - } while(0); - - if(show_error) { - DialogMessage* message = dialog_message_alloc(); - dialog_message_set_header(message, "Error", 64, 0, AlignCenter, AlignTop); - dialog_message_set_buttons(message, NULL, NULL, NULL); - - string_t buffer; - string_init(buffer); - string_printf(buffer, "%s", string_get_cstr(error_message)); - string_replace_str(buffer, ":", "\n"); - dialog_message_set_text( - message, string_get_cstr(buffer), 64, 32, AlignCenter, AlignCenter); - - dialog_message_show(loader->dialogs, message); - dialog_message_free(message); - string_clear(buffer); - } - - string_clear(error_message); - - if(file_selected) { - flipper_application_free(loader->app); - } - - return file_selected; -} - -static bool fap_loader_select_app(FapLoader* loader) { - const DialogsFileBrowserOptions browser_options = { - .extension = ".fap", - .skip_assets = true, - .icon = &I_badusb_10px, - .hide_ext = true, - .item_loader_callback = fap_loader_item_callback, - .item_loader_context = loader, - }; - - return dialog_file_browser_show( - loader->dialogs, loader->fap_path, loader->fap_path, &browser_options); -} - int32_t clock_loader_app(void* p) { - UNUSED(p); - FapLoader* loader = malloc(sizeof(FapLoader)); - loader->storage = furi_record_open(RECORD_STORAGE); - loader->dialogs = furi_record_open(RECORD_DIALOGS); - loader->gui = furi_record_open(RECORD_GUI); + UNUSED(p); - ViewDispatcher* view_dispatcher = view_dispatcher_alloc(); - Loading* loading = loading_alloc(); - - view_dispatcher_enable_queue(view_dispatcher); - view_dispatcher_attach_to_gui(view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen); - view_dispatcher_add_view(view_dispatcher, 0, loading_get_view(loading)); - - const char* file = "/ext/apps/Main/Clock.fap"; - - if(file) { - string_init_set(loader->fap_path, file); - fap_loader_run_selected_app(loader); - } else { - string_init_set(loader->fap_path, EXT_PATH("apps")); - - while(fap_loader_select_app(loader)) { - view_dispatcher_switch_to_view(view_dispatcher, 0); - fap_loader_run_selected_app(loader); - }; - } - - view_dispatcher_remove_view(view_dispatcher, 0); - loading_free(loading); - view_dispatcher_free(view_dispatcher); - - string_clear(loader->fap_path); - furi_record_close(RECORD_GUI); - furi_record_close(RECORD_DIALOGS); - furi_record_close(RECORD_STORAGE); - free(loader); return 0; } \ No newline at end of file diff --git a/applications/main/ibutton_loader/application.fam b/applications/main/ibutton_loader/application.fam index 20663fea0..b4150f46b 100644 --- a/applications/main/ibutton_loader/application.fam +++ b/applications/main/ibutton_loader/application.fam @@ -10,4 +10,5 @@ App( stack_size=int(1.5 * 1024), icon="A_iButton_14", order=60, + link="/ext/apps/Main/ibutton.fap", ) diff --git a/applications/main/ibutton_loader/ibutton_loader_app.c b/applications/main/ibutton_loader/ibutton_loader_app.c index 6eb071603..8738d9491 100644 --- a/applications/main/ibutton_loader/ibutton_loader_app.c +++ b/applications/main/ibutton_loader/ibutton_loader_app.c @@ -1,179 +1,9 @@ -#include -#include -#include -#include -#include -#include -#include -#include +#include #define TAG "ibutton_loader_app" -typedef struct { - FlipperApplication* app; - Storage* storage; - DialogsApp* dialogs; - Gui* gui; - string_t fap_path; -} FapLoader; - -static bool - fap_loader_item_callback(string_t path, void* context, uint8_t** icon_ptr, string_t item_name) { - FapLoader* loader = context; - furi_assert(loader); - - FlipperApplication* app = flipper_application_alloc(loader->storage, &hashtable_api_interface); - - FlipperApplicationPreloadStatus preload_res = - flipper_application_preload(app, string_get_cstr(path)); - - bool load_success = false; - - if(preload_res == FlipperApplicationPreloadStatusSuccess) { - const FlipperApplicationManifest* manifest = flipper_application_get_manifest(app); - if(manifest->has_icon) { - memcpy(*icon_ptr, manifest->icon, FAP_MANIFEST_MAX_ICON_SIZE); - } - string_set_str(item_name, manifest->name); - load_success = true; - } else { - FURI_LOG_E(TAG, "FAP Loader failed to preload %s", string_get_cstr(path)); - load_success = false; - } - - flipper_application_free(app); - return load_success; -} - -static bool fap_loader_run_selected_app(FapLoader* loader) { - furi_assert(loader); - - string_t error_message; - - string_init_set(error_message, "unknown error"); - - bool file_selected = false; - bool show_error = true; - do { - file_selected = true; - loader->app = flipper_application_alloc(loader->storage, &hashtable_api_interface); - - FURI_LOG_I(TAG, "FAP Loader is loading %s", string_get_cstr(loader->fap_path)); - - FlipperApplicationPreloadStatus preload_res = - flipper_application_preload(loader->app, string_get_cstr(loader->fap_path)); - if(preload_res != FlipperApplicationPreloadStatusSuccess) { - const char* err_msg = flipper_application_preload_status_to_string(preload_res); - string_printf(error_message, "Preload failed: %s", err_msg); - FURI_LOG_E( - TAG, - "FAP Loader failed to preload %s: %s", - string_get_cstr(loader->fap_path), - err_msg); - break; - } - - FURI_LOG_I(TAG, "FAP Loader is mapping"); - FlipperApplicationLoadStatus load_status = flipper_application_map_to_memory(loader->app); - if(load_status != FlipperApplicationLoadStatusSuccess) { - const char* err_msg = flipper_application_load_status_to_string(load_status); - string_printf(error_message, "Load failed: %s", err_msg); - FURI_LOG_E( - TAG, - "FAP Loader failed to map to memory %s: %s", - string_get_cstr(loader->fap_path), - err_msg); - break; - } - - FURI_LOG_I(TAG, "FAP Loader is staring app"); - - FuriThread* thread = flipper_application_spawn(loader->app, NULL); - furi_thread_start(thread); - furi_thread_join(thread); - - show_error = false; - int ret = furi_thread_get_return_code(thread); - - FURI_LOG_I(TAG, "FAP app returned: %i", ret); - } while(0); - - if(show_error) { - DialogMessage* message = dialog_message_alloc(); - dialog_message_set_header(message, "Error", 64, 0, AlignCenter, AlignTop); - dialog_message_set_buttons(message, NULL, NULL, NULL); - - string_t buffer; - string_init(buffer); - string_printf(buffer, "%s", string_get_cstr(error_message)); - string_replace_str(buffer, ":", "\n"); - dialog_message_set_text( - message, string_get_cstr(buffer), 64, 32, AlignCenter, AlignCenter); - - dialog_message_show(loader->dialogs, message); - dialog_message_free(message); - string_clear(buffer); - } - - string_clear(error_message); - - if(file_selected) { - flipper_application_free(loader->app); - } - - return file_selected; -} - -static bool fap_loader_select_app(FapLoader* loader) { - const DialogsFileBrowserOptions browser_options = { - .extension = ".fap", - .skip_assets = true, - .icon = &I_badusb_10px, - .hide_ext = true, - .item_loader_callback = fap_loader_item_callback, - .item_loader_context = loader, - }; - - return dialog_file_browser_show( - loader->dialogs, loader->fap_path, loader->fap_path, &browser_options); -} - int32_t ibutton_loader_app(void* p) { - UNUSED(p); - FapLoader* loader = malloc(sizeof(FapLoader)); - loader->storage = furi_record_open(RECORD_STORAGE); - loader->dialogs = furi_record_open(RECORD_DIALOGS); - loader->gui = furi_record_open(RECORD_GUI); + UNUSED(p); - ViewDispatcher* view_dispatcher = view_dispatcher_alloc(); - Loading* loading = loading_alloc(); - - view_dispatcher_enable_queue(view_dispatcher); - view_dispatcher_attach_to_gui(view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen); - view_dispatcher_add_view(view_dispatcher, 0, loading_get_view(loading)); - - const char* file = "/ext/apps/Main/ibutton.fap"; - - if(file) { - string_init_set(loader->fap_path, file); - fap_loader_run_selected_app(loader); - } else { - string_init_set(loader->fap_path, EXT_PATH("apps")); - - while(fap_loader_select_app(loader)) { - view_dispatcher_switch_to_view(view_dispatcher, 0); - fap_loader_run_selected_app(loader); - }; - } - - view_dispatcher_remove_view(view_dispatcher, 0); - loading_free(loading); - view_dispatcher_free(view_dispatcher); - - string_clear(loader->fap_path); - furi_record_close(RECORD_GUI); - furi_record_close(RECORD_DIALOGS); - furi_record_close(RECORD_STORAGE); - free(loader); return 0; } \ No newline at end of file diff --git a/applications/main/u2f_loader/application.fam b/applications/main/u2f_loader/application.fam new file mode 100644 index 000000000..3da5bf205 --- /dev/null +++ b/applications/main/u2f_loader/application.fam @@ -0,0 +1,14 @@ +App( + appid="u2f_loader", + name="U2F", + apptype=FlipperAppType.APP, + entry_point="u2f_loader_app", + requires=[ + "gui", + "dialogs", + ], + stack_size=int(2 * 1024), + icon="A_U2F_14", + order=80, + link="/ext/apps/Main/u2f.fap", +) diff --git a/applications/main/u2f_loader/u2f_loader_app.c b/applications/main/u2f_loader/u2f_loader_app.c new file mode 100644 index 000000000..186d2489b --- /dev/null +++ b/applications/main/u2f_loader/u2f_loader_app.c @@ -0,0 +1,9 @@ +#include + +#define TAG "u2f_loader_app" + +int32_t u2f_loader_app(void* p) { + UNUSED(p); + + return 0; +} \ No newline at end of file diff --git a/applications/services/applications.h b/applications/services/applications.h index 012e80ddb..63c9c1c26 100644 --- a/applications/services/applications.h +++ b/applications/services/applications.h @@ -10,10 +10,11 @@ typedef enum { typedef struct { const FuriThreadCallback app; - const char* name; + char* name; const size_t stack_size; const Icon* icon; const FlipperApplicationFlag flags; + char* link; } FlipperApplication; typedef void (*FlipperOnStartHook)(void); diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index 4ab9bce80..3b9f76f87 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -41,13 +41,18 @@ static void loader_menu_callback(void* _ctx, uint32_t index) { furi_assert(application->app); furi_assert(application->name); + furi_assert(application->link); - if(!loader_lock(loader_instance)) { - FURI_LOG_E(TAG, "Loader is locked"); - return; + if(strcmp(application->link, "NULL") != 0) { + LoaderStatus status = loader_start(NULL, "Applications", application->link); + } else { + if(!loader_lock(loader_instance)) { + FURI_LOG_E(TAG, "Loader is locked"); + return; + } + + loader_start_application(application, NULL); } - - loader_start_application(application, NULL); } static void loader_submenu_callback(void* context, uint32_t index) { @@ -56,24 +61,6 @@ static void loader_submenu_callback(void* context, uint32_t index) { view_dispatcher_switch_to_view(loader_instance->view_dispatcher, view_id); } -static void loader_clock_callback(void* context, uint32_t index) { - UNUSED(context); - UNUSED(index); - LoaderStatus status = loader_start(NULL, "Applications", EXT_PATH("/apps/Main/Clock.fap")); -} - -static void loader_ibutton_callback(void* context, uint32_t index) { - UNUSED(context); - UNUSED(index); - LoaderStatus status = loader_start(NULL, "Applications", EXT_PATH("/apps/Main/ibutton.fap")); -} - -static void loader_u2f_callback(void* context, uint32_t index) { - UNUSED(context); - UNUSED(index); - LoaderStatus status = loader_start(NULL, "Applications", EXT_PATH("/apps/Main/u2f.fap")); -} - static void loader_cli_print_usage() { printf("Usage:\r\n"); printf("loader \r\n"); @@ -161,7 +148,7 @@ void loader_cli_list(Cli* cli, string_t args, Loader* instance) { UNUSED(args); UNUSED(instance); printf("Applications:\r\n"); - printf("\t%s\r\n", "Clock"); + //printf("\t%s\r\n", "Clock"); for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { printf("\t%s\r\n", FLIPPER_APPS[i].name); } @@ -170,10 +157,10 @@ void loader_cli_list(Cli* cli, string_t args, Loader* instance) { for(size_t i = 0; i < FLIPPER_PLUGINS_COUNT; i++) { printf("\t%s\r\n", FLIPPER_PLUGINS[i].name); } - printf("\t%s\r\n", "iButton"); - printf("\t%s\r\n", "U2F"); + //printf("\t%s\r\n", "iButton"); + //printf("\t%s\r\n", "U2F"); - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) && FLIPPER_DEBUG_APPS_COUNT!=0) { + if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) && FLIPPER_DEBUG_APPS_COUNT != 0) { printf("Debug:\r\n"); for(size_t i = 0; i < FLIPPER_DEBUG_APPS_COUNT; i++) { printf("\t%s\r\n", FLIPPER_DEBUG_APPS[i].name); @@ -392,13 +379,6 @@ static void loader_free(Loader* instance) { static void loader_build_menu() { FURI_LOG_I(TAG, "Building main menu"); size_t i; - menu_add_item( - loader_instance->primary_menu, - "Clock", - &A_Clock_14, - 0, - loader_clock_callback, - (void*)NULL); for(i = 0; i < FLIPPER_APPS_COUNT; i++) { menu_add_item( loader_instance->primary_menu, @@ -417,20 +397,6 @@ static void loader_build_menu() { loader_submenu_callback, (void*)LoaderMenuViewPlugins); } - menu_add_item( - loader_instance->primary_menu, - "iButton", - &A_iButton_14, - i++, - loader_ibutton_callback, - (void*)NULL); - menu_add_item( - loader_instance->primary_menu, - "U2F", - &A_U2F_14, - i++, - loader_u2f_callback, - (void*)NULL); if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) && FLIPPER_DEBUG_APPS_COUNT != 0) { menu_add_item( loader_instance->primary_menu, diff --git a/site_scons/fbt/appmanifest.py b/site_scons/fbt/appmanifest.py index a0ab5e7c6..9df436712 100644 --- a/site_scons/fbt/appmanifest.py +++ b/site_scons/fbt/appmanifest.py @@ -35,6 +35,7 @@ class FlipperApplication: stack_size: int = 2048 icon: Optional[str] = None order: int = 0 + link: Optional[str] = "" sdk_headers: List[str] = field(default_factory=list) # .fap-specific sources: List[str] = field(default_factory=lambda: ["*.c*"]) @@ -255,6 +256,7 @@ class ApplicationsCGenerator: .name = "{app.name}", .stack_size = {app.stack_size}, .icon = {f"&{app.icon}" if app.icon else "NULL"}, + .link = "{f"{app.link}" if app.link else "NULL"}", .flags = {'|'.join(f"FlipperApplicationFlag{flag}" for flag in app.flags)} }}""" def generate(self): From bb4a5cea5763c38cced5f1045a2ad2fb65b24936 Mon Sep 17 00:00:00 2001 From: ESurge Date: Wed, 21 Sep 2022 03:23:58 -0700 Subject: [PATCH 3/4] Fixed CLI loader list entries if FAP is being used with "loader_app" method --- applications/services/loader/loader.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/applications/services/loader/loader.c b/applications/services/loader/loader.c index 3b9f76f87..73fd6b70e 100644 --- a/applications/services/loader/loader.c +++ b/applications/services/loader/loader.c @@ -150,7 +150,12 @@ void loader_cli_list(Cli* cli, string_t args, Loader* instance) { printf("Applications:\r\n"); //printf("\t%s\r\n", "Clock"); for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) { - printf("\t%s\r\n", FLIPPER_APPS[i].name); + if(strcmp(FLIPPER_APPS[i].link, "NULL") != 0) { + printf( + "\tFor %s, Use: Applications %s\r\n", FLIPPER_APPS[i].name, FLIPPER_APPS[i].link); + } else { + printf("\t%s\r\n", FLIPPER_APPS[i].name); + } } printf("Plugins:\r\n"); From 7cb7a20914f87c3eeff73131da336c5c077a68c6 Mon Sep 17 00:00:00 2001 From: ESurge Date: Wed, 21 Sep 2022 03:28:29 -0700 Subject: [PATCH 4/4] Fixed a small discrepancy with applications.h file --- applications/services/applications.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/applications/services/applications.h b/applications/services/applications.h index 63c9c1c26..6559174bf 100644 --- a/applications/services/applications.h +++ b/applications/services/applications.h @@ -10,11 +10,11 @@ typedef enum { typedef struct { const FuriThreadCallback app; - char* name; + const char* name; const size_t stack_size; const Icon* icon; const FlipperApplicationFlag flags; - char* link; + const char* link; } FlipperApplication; typedef void (*FlipperOnStartHook)(void);