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):