diff --git a/applications/archive/archive.c b/applications/archive/archive.c index 8b4918a5..c2fe4c6d 100644 --- a/applications/archive/archive.c +++ b/applications/archive/archive.c @@ -39,6 +39,10 @@ ArchiveApp* archive_alloc() { view_dispatcher_add_view( archive->view_dispatcher, ArchiveViewTextInput, text_input_get_view(archive->text_input)); + archive->widget = widget_alloc(); + view_dispatcher_add_view( + archive->view_dispatcher, ArchiveViewWidget, widget_get_view(archive->widget)); + return archive; } @@ -47,6 +51,8 @@ void archive_free(ArchiveApp* archive) { view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewBrowser); view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewTextInput); + view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewWidget); + widget_free(archive->widget); view_dispatcher_free(archive->view_dispatcher); scene_manager_free(archive->scene_manager); browser_free(archive->browser); diff --git a/applications/archive/archive_i.h b/applications/archive/archive_i.h index b450bb9c..c11a1803 100644 --- a/applications/archive/archive_i.h +++ b/applications/archive/archive_i.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "views/archive_browser_view.h" @@ -15,6 +16,7 @@ typedef enum { ArchiveViewBrowser, ArchiveViewTextInput, + ArchiveViewWidget, ArchiveViewTotal, } ArchiveViewEnum; @@ -24,6 +26,7 @@ struct ArchiveApp { SceneManager* scene_manager; ArchiveBrowserView* browser; TextInput* text_input; + Widget* widget; char text_store[MAX_NAME_LEN]; char file_extension[MAX_EXT_LEN + 1]; }; diff --git a/applications/archive/helpers/archive_apps.c b/applications/archive/helpers/archive_apps.c new file mode 100644 index 00000000..9293d225 --- /dev/null +++ b/applications/archive/helpers/archive_apps.c @@ -0,0 +1,74 @@ +#include "archive_files.h" +#include "archive_apps.h" +#include "archive_browser.h" + +static const char* known_apps[] = { + [ArchiveAppTypeU2f] = "u2f", +}; + +ArchiveAppTypeEnum archive_get_app_type(const char* path) { + for(size_t i = 0; i < SIZEOF_ARRAY(known_apps); i++) { + if(strncmp(path, known_apps[i], strlen(known_apps[i])) != STRING_FAILURE) { + return i; + } + } + return ArchiveAppTypeUnknown; +} + +bool archive_app_is_available(void* context, const char* path) { + furi_assert(path); + + ArchiveAppTypeEnum app = archive_get_app_type(path); + + if(app == ArchiveAppTypeU2f) { + FileWorker* file_worker = file_worker_alloc(true); + bool file_exists = false; + file_worker_is_file_exist(file_worker, "/any/u2f/key.u2f", &file_exists); + if(file_exists) { + file_worker_is_file_exist(file_worker, "/any/u2f/cnt.u2f", &file_exists); + } + file_worker_free(file_worker); + return file_exists; + } else { + return false; + } +} + +bool archive_app_read_dir(void* context, const char* path) { + furi_assert(context); + furi_assert(path); + ArchiveBrowserView* browser = context; + + ArchiveAppTypeEnum app = archive_get_app_type(path); + + if(app == ArchiveAppTypeU2f) { + archive_add_app_item(browser, "/app:u2f/U2F Token"); + return true; + } else { + return false; + } +} + +void archive_app_delete_file(void* context, const char* path) { + furi_assert(context); + furi_assert(path); + ArchiveBrowserView* browser = context; + + ArchiveAppTypeEnum app = archive_get_app_type(path); + bool res = false; + + if(app == ArchiveAppTypeU2f) { + FileWorker* file_worker = file_worker_alloc(true); + res = file_worker_remove(file_worker, "/any/u2f/key.u2f"); + res |= file_worker_remove(file_worker, "/any/u2f/cnt.u2f"); + file_worker_free(file_worker); + + if(archive_is_favorite("/app:u2f/U2F Token")) { + archive_favorites_delete("/app:u2f/U2F Token"); + } + } + + if(res) { + archive_file_array_rm_selected(browser); + } +} diff --git a/applications/archive/helpers/archive_apps.h b/applications/archive/helpers/archive_apps.h new file mode 100644 index 00000000..5abc27a5 --- /dev/null +++ b/applications/archive/helpers/archive_apps.h @@ -0,0 +1,21 @@ +#pragma once + +typedef enum { + ArchiveAppTypeU2f, + ArchiveAppTypeUnknown, + ArchiveAppsTotal, +} ArchiveAppTypeEnum; + +static const ArchiveFileTypeEnum app_file_types[] = { + [ArchiveAppTypeU2f] = ArchiveFileTypeU2f, + [ArchiveAppTypeUnknown] = ArchiveFileTypeUnknown, +}; + +static inline const ArchiveFileTypeEnum archive_get_app_filetype(ArchiveAppTypeEnum app) { + return app_file_types[app]; +} + +ArchiveAppTypeEnum archive_get_app_type(const char* path); +bool archive_app_is_available(void* context, const char* path); +bool archive_app_read_dir(void* context, const char* path); +void archive_app_delete_file(void* context, const char* path); diff --git a/applications/archive/helpers/archive_browser.c b/applications/archive/helpers/archive_browser.c index eb316c1e..c1e9cacb 100644 --- a/applications/archive/helpers/archive_browser.c +++ b/applications/archive/helpers/archive_browser.c @@ -1,5 +1,7 @@ +#include "archive_files.h" +#include "archive_apps.h" #include "archive_browser.h" -#include "math.h" +#include void archive_update_offset(ArchiveBrowserView* browser) { furi_assert(browser); @@ -177,24 +179,53 @@ void archive_set_last_tab(ArchiveBrowserView* browser, ArchiveTabEnum tab) { }); } -void archive_add_item(ArchiveBrowserView* browser, FileInfo* file_info, const char* name) { +void archive_add_app_item(ArchiveBrowserView* browser, const char* name) { + furi_assert(browser); + furi_assert(name); + + ArchiveFile_t item; + + string_t full_name; + + string_init_set(full_name, browser->path); + string_cat_printf(full_name, "/%s", name); + + char* app_name = strchr(string_get_cstr(full_name), ':'); + if(app_name == NULL) { + string_clear(full_name); + return; + } + + ArchiveFile_t_init(&item); + string_init_set_str(item.name, name); + set_file_type(&item, NULL, app_name + 1, true); + + with_view_model( + browser->view, (ArchiveBrowserViewModel * model) { + files_array_push_back(model->files, item); + return false; + }); + ArchiveFile_t_clear(&item); + string_clear(full_name); +} + +void archive_add_file_item(ArchiveBrowserView* browser, FileInfo* file_info, const char* name) { furi_assert(browser); furi_assert(file_info); furi_assert(name); ArchiveFile_t item; - if(filter_by_extension(file_info, get_tab_ext(archive_get_tab(browser)), name)) { + if(filter_by_extension(file_info, archive_get_tab_ext(archive_get_tab(browser)), name)) { ArchiveFile_t_init(&item); string_init_set_str(item.name, name); - set_file_type(&item, file_info); + set_file_type(&item, file_info, archive_get_path(browser), false); with_view_model( browser->view, (ArchiveBrowserViewModel * model) { files_array_push_back(model->files, item); return false; }); - ArchiveFile_t_clear(&item); } } @@ -208,8 +239,7 @@ void archive_show_file_menu(ArchiveBrowserView* browser, bool show) { if(show) { ArchiveFile_t* selected = files_array_get(model->files, model->idx); - selected->fav = archive_is_favorite( - "%s/%s", string_get_cstr(browser->path), string_get_cstr(selected->name)); + selected->fav = archive_is_favorite("%s", string_get_cstr(selected->name)); } return true; @@ -245,12 +275,18 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) { archive_set_tab(browser, tab); - if((tab != ArchiveTabFavorites && - !archive_dir_empty(browser, archive_get_default_path(tab))) || - (tab == ArchiveTabFavorites && !archive_favorites_count(browser))) { - if(tab != ArchiveTabBrowser) { - archive_switch_tab(browser, key); - } + const char* path = archive_get_default_path(tab); + bool tab_empty = true; + if(tab == ArchiveTabFavorites) { + if(archive_favorites_count(browser) > 0) tab_empty = false; + } else if(strncmp(path, "/app:", 5) == 0) { + if(archive_app_is_available(browser, path)) tab_empty = false; + } else { + if(archive_dir_not_empty(browser, archive_get_default_path(tab))) tab_empty = false; + } + + if((tab_empty) && (tab != ArchiveTabBrowser)) { + archive_switch_tab(browser, key); } else { with_view_model( browser->view, (ArchiveBrowserViewModel * model) { @@ -277,8 +313,7 @@ void archive_enter_dir(ArchiveBrowserView* browser, string_t name) { return false; }); - string_cat(browser->path, "/"); - string_cat(browser->path, name); + string_set(browser->path, name); archive_switch_dir(browser, string_get_cstr(browser->path)); } diff --git a/applications/archive/helpers/archive_browser.h b/applications/archive/helpers/archive_browser.h index 44bce914..6486967f 100644 --- a/applications/archive/helpers/archive_browser.h +++ b/applications/archive/helpers/archive_browser.h @@ -11,6 +11,8 @@ static const char* tab_default_paths[] = { [ArchiveTabSubGhz] = "/any/subghz", [ArchiveTabLFRFID] = "/any/lfrfid", [ArchiveTabIrda] = "/any/irda", + [ArchiveTabBadUsb] = "/any/badusb", + [ArchiveTabU2f] = "/app:u2f", [ArchiveTabBrowser] = "/any", }; @@ -20,30 +22,37 @@ static const char* known_ext[] = { [ArchiveFileTypeSubGhz] = ".sub", [ArchiveFileTypeLFRFID] = ".rfid", [ArchiveFileTypeIrda] = ".ir", + [ArchiveFileTypeBadUsb] = ".txt", + [ArchiveFileTypeU2f] = "?", + [ArchiveFileTypeFolder] = "?", + [ArchiveFileTypeUnknown] = "*", }; -static inline const char* get_tab_ext(ArchiveTabEnum tab) { - switch(tab) { - case ArchiveTabIButton: - return known_ext[ArchiveFileTypeIButton]; - case ArchiveTabNFC: - return known_ext[ArchiveFileTypeNFC]; - case ArchiveTabSubGhz: - return known_ext[ArchiveFileTypeSubGhz]; - case ArchiveTabLFRFID: - return known_ext[ArchiveFileTypeLFRFID]; - case ArchiveTabIrda: - return known_ext[ArchiveFileTypeIrda]; - default: - return "*"; - } +static const ArchiveFileTypeEnum known_type[] = { + [ArchiveTabFavorites] = ArchiveFileTypeUnknown, + [ArchiveTabIButton] = ArchiveFileTypeIButton, + [ArchiveTabNFC] = ArchiveFileTypeNFC, + [ArchiveTabSubGhz] = ArchiveFileTypeSubGhz, + [ArchiveTabLFRFID] = ArchiveFileTypeLFRFID, + [ArchiveTabIrda] = ArchiveFileTypeIrda, + [ArchiveTabBadUsb] = ArchiveFileTypeBadUsb, + [ArchiveTabU2f] = ArchiveFileTypeU2f, + [ArchiveTabBrowser] = ArchiveFileTypeUnknown, +}; + +static inline const ArchiveFileTypeEnum archive_get_tab_filetype(ArchiveTabEnum tab) { + return known_type[tab]; +} + +static inline const char* archive_get_tab_ext(ArchiveTabEnum tab) { + return known_ext[archive_get_tab_filetype(tab)]; } static inline const char* archive_get_default_path(ArchiveTabEnum tab) { return tab_default_paths[tab]; } -inline bool is_known_app(ArchiveFileTypeEnum type) { +inline bool archive_is_known_app(ArchiveFileTypeEnum type) { return (type != ArchiveFileTypeFolder && type != ArchiveFileTypeUnknown); } @@ -62,7 +71,8 @@ uint8_t archive_get_depth(ArchiveBrowserView* browser); const char* archive_get_path(ArchiveBrowserView* browser); const char* archive_get_name(ArchiveBrowserView* browser); -void archive_add_item(ArchiveBrowserView* browser, FileInfo* file_info, const char* name); +void archive_add_app_item(ArchiveBrowserView* browser, const char* name); +void archive_add_file_item(ArchiveBrowserView* browser, FileInfo* file_info, const char* name); void archive_show_file_menu(ArchiveBrowserView* browser, bool show); void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active); diff --git a/applications/archive/helpers/archive_favorites.c b/applications/archive/helpers/archive_favorites.c index b622e76f..97bf9149 100644 --- a/applications/archive/helpers/archive_favorites.c +++ b/applications/archive/helpers/archive_favorites.c @@ -1,5 +1,7 @@ #include "archive_favorites.h" +#include "archive_files.h" +#include "archive_apps.h" #include "archive_browser.h" uint16_t archive_favorites_count(void* context) { @@ -46,10 +48,16 @@ static bool archive_favourites_rescan() { break; } - bool file_exists = false; - file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists); - if(file_exists) { - archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer)); + if(string_search(buffer, "/app:") == 0) { + if(archive_app_is_available(NULL, string_get_cstr(buffer))) { + archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer)); + } + } else { + bool file_exists = false; + file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists); + if(file_exists) { + archive_file_append(ARCHIVE_FAV_TEMP_PATH, "%s\n", string_get_cstr(buffer)); + } } } } @@ -88,13 +96,22 @@ bool archive_favorites_read(void* context) { break; } - bool file_exists = false; - file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists); + if(string_search(buffer, "/app:") == 0) { + if(archive_app_is_available(browser, string_get_cstr(buffer))) { + archive_add_app_item(browser, string_get_cstr(buffer)); + } else { + need_refresh = true; + } + } else { + bool file_exists = false; + file_worker_is_file_exist(file_worker, string_get_cstr(buffer), &file_exists); + + if(file_exists) + archive_add_file_item(browser, &file_info, string_get_cstr(buffer)); + else + need_refresh = true; + } - if(file_exists) - archive_add_item(browser, &file_info, string_get_cstr(buffer)); - else - need_refresh = true; string_reset(buffer); } } @@ -185,8 +202,7 @@ bool archive_is_favorite(const char* format, ...) { return found; } -bool archive_favorites_rename(const char* file_path, const char* src, const char* dst) { - furi_assert(file_path); +bool archive_favorites_rename(const char* src, const char* dst) { furi_assert(src); furi_assert(dst); @@ -198,7 +214,7 @@ bool archive_favorites_rename(const char* file_path, const char* src, const char string_init(buffer); string_init(path); - string_printf(path, "%s/%s", file_path, src); + string_printf(path, "%s", src); bool result = file_worker_open(file_worker, ARCHIVE_FAV_PATH, FSAM_READ, FSOM_OPEN_EXISTING); if(result) { diff --git a/applications/archive/helpers/archive_favorites.h b/applications/archive/helpers/archive_favorites.h index c028bd2b..3a517f4b 100644 --- a/applications/archive/helpers/archive_favorites.h +++ b/applications/archive/helpers/archive_favorites.h @@ -8,6 +8,6 @@ uint16_t archive_favorites_count(void* context); bool archive_favorites_read(void* context); bool archive_favorites_delete(const char* format, ...); bool archive_is_favorite(const char* format, ...); -bool archive_favorites_rename(const char* file_path, const char* src, const char* dst); +bool archive_favorites_rename(const char* src, const char* dst); void archive_add_to_favorites(const char* file_path); void archive_favorites_save(void* context); diff --git a/applications/archive/helpers/archive_files.c b/applications/archive/helpers/archive_files.c index a5bd2eb9..08542bfe 100644 --- a/applications/archive/helpers/archive_files.c +++ b/applications/archive/helpers/archive_files.c @@ -1,8 +1,11 @@ #include "archive_files.h" +#include "archive_apps.h" #include "archive_browser.h" #define TAG "Archive" +#define ASSETS_DIR "assets" + bool filter_by_extension(FileInfo* file_info, const char* tab_ext, const char* name) { furi_assert(file_info); furi_assert(tab_ext); @@ -15,7 +18,11 @@ bool filter_by_extension(FileInfo* file_info, const char* tab_ext, const char* n } else if(strstr(name, tab_ext) != NULL) { result = true; } else if(file_info->flags & FSF_DIRECTORY) { - result = true; + if(strstr(name, ASSETS_DIR) != NULL) { + result = false; // Skip assets folder in all tabs except browser + } else { + result = true; + } } return result; @@ -38,21 +45,36 @@ void archive_get_file_extension(char* name, char* ext) { strncpy(ext, dot, MAX_EXT_LEN); } -void set_file_type(ArchiveFile_t* file, FileInfo* file_info) { +void set_file_type(ArchiveFile_t* file, FileInfo* file_info, const char* path, bool is_app) { furi_assert(file); - furi_assert(file_info); - for(size_t i = 0; i < SIZEOF_ARRAY(known_ext); i++) { - if(string_search_str(file->name, known_ext[i], 0) != STRING_FAILURE) { - file->type = i; - return; - } - } - - if(file_info->flags & FSF_DIRECTORY) { - file->type = ArchiveFileTypeFolder; + file->is_app = is_app; + if(is_app) { + file->type = archive_get_app_filetype(archive_get_app_type(path)); } else { - file->type = ArchiveFileTypeUnknown; + furi_assert(file_info); + + for(size_t i = 0; i < SIZEOF_ARRAY(known_ext); i++) { + if((known_ext[i][0] == '?') || (known_ext[i][0] == '*')) continue; + if(string_search_str(file->name, known_ext[i], 0) != STRING_FAILURE) { + if(i == ArchiveFileTypeBadUsb) { + if(string_search_str(file->name, archive_get_default_path(ArchiveTabBadUsb)) == + 0) { + file->type = i; + return; // *.txt file is a BadUSB script only if it is in BadUSB folder + } + } else { + file->type = i; + return; + } + } + } + + if(file_info->flags & FSF_DIRECTORY) { + file->type = ArchiveFileTypeFolder; + } else { + file->type = ArchiveFileTypeUnknown; + } } } @@ -63,17 +85,21 @@ bool archive_get_filenames(void* context, const char* path) { ArchiveBrowserView* browser = context; archive_file_array_rm_all(browser); - if(archive_get_tab(browser) != ArchiveTabFavorites) { - res = archive_read_dir(browser, path); - } else { + if(archive_get_tab(browser) == ArchiveTabFavorites) { res = archive_favorites_read(browser); + } else if(strncmp(path, "/app:", 5) == 0) { + res = archive_app_read_dir(browser, path); + } else { + res = archive_read_dir(browser, path); } return res; } -bool archive_dir_empty(void* context, const char* path) { // can be simpler? +bool archive_dir_not_empty(void* context, const char* path) { // can be simpler? furi_assert(context); + ArchiveBrowserView* browser = context; + FileInfo file_info; Storage* fs_api = furi_record_open("storage"); File* directory = storage_file_alloc(fs_api); @@ -92,8 +118,11 @@ bool archive_dir_empty(void* context, const char* path) { // can be simpler? } if(files_found) { break; - } else if(storage_file_get_error(directory) == FSE_OK) { - files_found = name[0]; + } else if((storage_file_get_error(directory) == FSE_OK) && (name[0])) { + if(filter_by_extension( + &file_info, archive_get_tab_ext(archive_get_tab(browser)), name)) { + files_found = true; + } } else { return false; } @@ -114,6 +143,8 @@ bool archive_read_dir(void* context, const char* path) { Storage* fs_api = furi_record_open("storage"); File* directory = storage_file_alloc(fs_api); char name[MAX_NAME_LEN]; + snprintf(name, MAX_NAME_LEN, "%s/", path); + size_t path_len = strlen(name); size_t files_cnt = 0; if(!storage_dir_open(directory, path)) { @@ -123,13 +154,14 @@ bool archive_read_dir(void* context, const char* path) { } while(1) { - if(!storage_dir_read(directory, &file_info, name, MAX_NAME_LEN)) { + if(!storage_dir_read(directory, &file_info, &name[path_len], MAX_NAME_LEN - path_len)) { break; } + if(files_cnt > MAX_FILES) { break; } else if(storage_file_get_error(directory) == FSE_OK) { - archive_add_item(browser, &file_info, name); + archive_add_file_item(browser, &file_info, name); ++files_cnt; } else { storage_dir_close(directory); diff --git a/applications/archive/helpers/archive_files.h b/applications/archive/helpers/archive_files.h index 12fde2fb..ff751d9b 100644 --- a/applications/archive/helpers/archive_files.h +++ b/applications/archive/helpers/archive_files.h @@ -9,29 +9,38 @@ typedef enum { ArchiveFileTypeSubGhz, ArchiveFileTypeLFRFID, ArchiveFileTypeIrda, + ArchiveFileTypeBadUsb, + ArchiveFileTypeU2f, ArchiveFileTypeFolder, ArchiveFileTypeUnknown, - AppIdTotal, + ArchiveFileTypesTotal, } ArchiveFileTypeEnum; typedef struct { string_t name; ArchiveFileTypeEnum type; bool fav; + bool is_app; } ArchiveFile_t; static void ArchiveFile_t_init(ArchiveFile_t* obj) { obj->type = ArchiveFileTypeUnknown; + obj->is_app = false; + obj->fav = false; string_init(obj->name); } static void ArchiveFile_t_init_set(ArchiveFile_t* obj, const ArchiveFile_t* src) { obj->type = src->type; + obj->is_app = src->is_app; + obj->fav = src->fav; string_init_set(obj->name, src->name); } static void ArchiveFile_t_set(ArchiveFile_t* obj, const ArchiveFile_t* src) { obj->type = src->type; + obj->is_app = src->is_app; + obj->fav = src->fav; string_set(obj->name, src->name); } @@ -48,11 +57,11 @@ ARRAY_DEF( CLEAR(API_2(ArchiveFile_t_clear)))) bool filter_by_extension(FileInfo* file_info, const char* tab_ext, const char* name); -void set_file_type(ArchiveFile_t* file, FileInfo* file_info); +void set_file_type(ArchiveFile_t* file, FileInfo* file_info, const char* path, bool is_app); void archive_trim_file_path(char* name, bool ext); void archive_get_file_extension(char* name, char* ext); bool archive_get_filenames(void* context, const char* path); -bool archive_dir_empty(void* context, const char* path); +bool archive_dir_not_empty(void* context, const char* path); bool archive_read_dir(void* context, const char* path); void archive_file_append(const char* path, const char* format, ...); void archive_delete_file(void* context, const char* format, ...); \ No newline at end of file diff --git a/applications/archive/scenes/archive_scene_browser.c b/applications/archive/scenes/archive_scene_browser.c index 88a058bb..228bb305 100644 --- a/applications/archive/scenes/archive_scene_browser.c +++ b/applications/archive/scenes/archive_scene_browser.c @@ -1,5 +1,6 @@ #include "../archive_i.h" #include "../helpers/archive_files.h" +#include "../helpers/archive_apps.h" #include "../helpers/archive_favorites.h" #include "../helpers/archive_browser.h" #include "../views/archive_browser_view.h" @@ -12,29 +13,29 @@ static const char* flipper_app_name[] = { [ArchiveFileTypeSubGhz] = "Sub-GHz", [ArchiveFileTypeLFRFID] = "125 kHz RFID", [ArchiveFileTypeIrda] = "Infrared", + [ArchiveFileTypeBadUsb] = "Bad USB", + [ArchiveFileTypeU2f] = "U2F", }; -static void archive_run_in_app( - ArchiveBrowserView* browser, - ArchiveFile_t* selected, - bool full_path_provided) { +static void archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selected) { Loader* loader = furi_record_open("loader"); - string_t full_path; - if(!full_path_provided) { - string_init_printf( - full_path, "%s/%s", string_get_cstr(browser->path), string_get_cstr(selected->name)); + LoaderStatus status; + if(selected->is_app) { + char* param = strrchr(string_get_cstr(selected->name), '/'); + if(param != NULL) { + param++; + } + status = loader_start(loader, flipper_app_name[selected->type], param); } else { - string_init_set(full_path, selected->name); + status = loader_start( + loader, flipper_app_name[selected->type], string_get_cstr(selected->name)); } - LoaderStatus status = - loader_start(loader, flipper_app_name[selected->type], string_get_cstr(full_path)); if(status != LoaderStatusOk) { FURI_LOG_E(TAG, "loader_start failed: %d", status); } - string_clear(full_path); furi_record_close("loader"); } @@ -57,9 +58,8 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { ArchiveBrowserView* browser = archive->browser; ArchiveFile_t* selected = archive_get_current_file(browser); - const char* path = archive_get_path(browser); const char* name = archive_get_name(browser); - bool known_app = is_known_app(selected->type); + bool known_app = archive_is_known_app(selected->type); bool favorites = archive_get_tab(browser) == ArchiveTabFavorites; bool consumed = false; @@ -75,7 +75,7 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { break; case ArchiveBrowserEventFileMenuRun: if(known_app) { - archive_run_in_app(browser, selected, favorites); + archive_run_in_app(browser, selected); } consumed = true; break; @@ -85,10 +85,10 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { archive_file_array_rm_selected(browser); archive_show_file_menu(browser, false); } else if(known_app) { - if(archive_is_favorite("%s/%s", path, name)) { - archive_favorites_delete("%s/%s", path, name); + if(archive_is_favorite("%s", name)) { + archive_favorites_delete("%s", name); } else { - archive_file_append(ARCHIVE_FAV_PATH, "%s/%s\n", path, name); + archive_file_append(ARCHIVE_FAV_PATH, "%s\n", name); } archive_show_file_menu(browser, false); } @@ -98,18 +98,13 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { case ArchiveBrowserEventFileMenuAction: if(favorites) { browser->callback(ArchiveBrowserEventEnterFavMove, browser->context); - } else if(known_app) { + } else if((known_app) && (selected->is_app == false)) { scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneRename); } consumed = true; break; case ArchiveBrowserEventFileMenuDelete: - if(favorites) { - archive_delete_file(browser, "%s", name); - } else { - archive_delete_file(browser, "%s/%s", path, name); - } - archive_show_file_menu(browser, false); + scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneDelete); consumed = true; break; case ArchiveBrowserEventEnterDir: diff --git a/applications/archive/scenes/archive_scene_config.h b/applications/archive/scenes/archive_scene_config.h index 2ed4e00c..4145f43d 100644 --- a/applications/archive/scenes/archive_scene_config.h +++ b/applications/archive/scenes/archive_scene_config.h @@ -1,2 +1,3 @@ ADD_SCENE(archive, browser, Browser) ADD_SCENE(archive, rename, Rename) +ADD_SCENE(archive, delete, Delete) diff --git a/applications/archive/scenes/archive_scene_delete.c b/applications/archive/scenes/archive_scene_delete.c new file mode 100644 index 00000000..04b37510 --- /dev/null +++ b/applications/archive/scenes/archive_scene_delete.c @@ -0,0 +1,70 @@ +#include "../archive_i.h" +#include "../helpers/archive_favorites.h" +#include "../helpers/archive_files.h" +#include "../helpers/archive_apps.h" +#include "../helpers/archive_browser.h" + +#define SCENE_DELETE_CUSTOM_EVENT (0UL) +#define MAX_TEXT_INPUT_LEN 22 + +void archive_scene_delete_widget_callback(GuiButtonType result, InputType type, void* context) { + furi_assert(context); + ArchiveApp* app = (ArchiveApp*)context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(app->view_dispatcher, result); + } +} + +void archive_scene_delete_on_enter(void* context) { + furi_assert(context); + ArchiveApp* app = (ArchiveApp*)context; + + widget_add_button_element( + app->widget, GuiButtonTypeLeft, "Back", archive_scene_delete_widget_callback, app); + widget_add_button_element( + app->widget, GuiButtonTypeRight, "Delete", archive_scene_delete_widget_callback, app); + + ArchiveFile_t* current = archive_get_current_file(app->browser); + strlcpy(app->text_store, string_get_cstr(current->name), MAX_NAME_LEN); + char* name = strrchr(app->text_store, '/'); + if(name != NULL) { + name++; + } + + char delete_str[64]; + snprintf(delete_str, sizeof(delete_str), "\e#Delete %s?\e#", name); + widget_add_text_box_element(app->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, delete_str); + + view_dispatcher_switch_to_view(app->view_dispatcher, ArchiveViewWidget); +} + +bool archive_scene_delete_on_event(void* context, SceneManagerEvent event) { + furi_assert(context); + ArchiveApp* app = (ArchiveApp*)context; + + ArchiveBrowserView* browser = app->browser; + ArchiveFile_t* selected = archive_get_current_file(browser); + const char* name = archive_get_name(browser); + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == GuiButtonTypeRight) { + if(selected->is_app) { + archive_app_delete_file(browser, name); + } else { + archive_delete_file(browser, "%s", name); + } + archive_show_file_menu(browser, false); + return scene_manager_previous_scene(app->scene_manager); + } else if(event.event == GuiButtonTypeLeft) { + return scene_manager_previous_scene(app->scene_manager); + } + } + return false; +} + +void archive_scene_delete_on_exit(void* context) { + furi_assert(context); + ArchiveApp* app = (ArchiveApp*)context; + + widget_reset(app->widget); +} diff --git a/applications/archive/scenes/archive_scene_rename.c b/applications/archive/scenes/archive_scene_rename.c index 8f32eb8a..9e573801 100644 --- a/applications/archive/scenes/archive_scene_rename.c +++ b/applications/archive/scenes/archive_scene_rename.c @@ -52,7 +52,8 @@ bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) { const char* path = archive_get_path(archive->browser); const char* name = archive_get_name(archive->browser); - string_init_printf(buffer_src, "%s/%s", path, name); + string_init_printf(buffer_src, "%s", name); + //TODO: take path from src name string_init_printf(buffer_dst, "%s/%s", path, archive->text_store); // append extension @@ -64,7 +65,7 @@ bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) { furi_record_close("storage"); if(file->fav) { - archive_favorites_rename(path, name, string_get_cstr(buffer_dst)); + archive_favorites_rename(name, string_get_cstr(buffer_dst)); } string_clear(buffer_src); diff --git a/applications/archive/views/archive_browser_view.c b/applications/archive/views/archive_browser_view.c index 525fbbcb..5e079436 100644 --- a/applications/archive/views/archive_browser_view.c +++ b/applications/archive/views/archive_browser_view.c @@ -10,6 +10,8 @@ static const char* ArchiveTabNames[] = { [ArchiveTabSubGhz] = "Sub-GHz", [ArchiveTabLFRFID] = "RFID LF", [ArchiveTabIrda] = "Infrared", + [ArchiveTabBadUsb] = "Bad USB", + [ArchiveTabU2f] = "U2F", [ArchiveTabBrowser] = "Browser"}; static const Icon* ArchiveItemIcons[] = { @@ -18,6 +20,8 @@ static const Icon* ArchiveItemIcons[] = { [ArchiveFileTypeSubGhz] = &I_sub1_10px, [ArchiveFileTypeLFRFID] = &I_125_10px, [ArchiveFileTypeIrda] = &I_ir_10px, + [ArchiveFileTypeBadUsb] = &I_badusb_10px, + [ArchiveFileTypeU2f] = &I_u2f_10px, [ArchiveFileTypeFolder] = &I_dir_10px, [ArchiveFileTypeUnknown] = &I_unknown_10px, }; @@ -47,15 +51,20 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { ArchiveFile_t* selected = files_array_get(model->files, model->idx); - if(!is_known_app(selected->type)) { + if(!archive_is_known_app(selected->type)) { string_set_str(menu[0], "---"); string_set_str(menu[1], "---"); string_set_str(menu[2], "---"); - } else if(selected->fav) { + } else { + if(model->tab_idx == ArchiveTabFavorites) { + string_set_str(menu[2], "Move"); + } else if(selected->is_app) { + string_set_str(menu[2], "---"); + } + } + + if((selected->fav) || (model->tab_idx == ArchiveTabFavorites)) { string_set_str(menu[1], "Unpin"); - } else if(model->tab_idx == ArchiveTabFavorites) { - string_set_str(menu[1], "Unpin"); - string_set_str(menu[2], "Move"); } for(size_t i = 0; i < MENU_ITEMS; i++) { @@ -102,7 +111,7 @@ static void draw_list(Canvas* canvas, ArchiveBrowserViewModel* model) { ArchiveFile_t* file = files_array_get(model->files, CLAMP(idx, array_size - 1, 0)); strlcpy(cstr_buff, string_get_cstr(file->name), string_size(file->name) + 1); - archive_trim_file_path(cstr_buff, is_known_app(file->type)); + archive_trim_file_path(cstr_buff, archive_is_known_app(file->type)); string_init_set_str(str_buff, cstr_buff); elements_string_fit_width( canvas, str_buff, (scrollbar ? MAX_LEN_PX - 6 : MAX_LEN_PX) - x_offset); diff --git a/applications/archive/views/archive_browser_view.h b/applications/archive/views/archive_browser_view.h index 634dec44..af4ed85e 100644 --- a/applications/archive/views/archive_browser_view.h +++ b/applications/archive/views/archive_browser_view.h @@ -24,6 +24,8 @@ typedef enum { ArchiveTabNFC, ArchiveTabIrda, ArchiveTabIButton, + ArchiveTabBadUsb, + ArchiveTabU2f, ArchiveTabBrowser, ArchiveTabTotal, } ArchiveTabEnum; diff --git a/applications/bad_usb/bad_usb_app.c b/applications/bad_usb/bad_usb_app.c index c4a3c930..49809562 100644 --- a/applications/bad_usb/bad_usb_app.c +++ b/applications/bad_usb/bad_usb_app.c @@ -2,6 +2,7 @@ #include #include #include +#include static bool bad_usb_app_custom_event_callback(void* context, uint32_t event) { furi_assert(context); @@ -39,27 +40,34 @@ static bool bad_usb_check_assets() { return ret; } -BadUsbApp* bad_usb_app_alloc() { +BadUsbApp* bad_usb_app_alloc(char* arg) { BadUsbApp* app = furi_alloc(sizeof(BadUsbApp)); + if(arg != NULL) { + string_t filename; + string_init(filename); + path_extract_filename_no_ext(arg, filename); + strncpy(app->file_name, string_get_cstr(filename), BAD_USB_FILE_NAME_LEN); + string_clear(filename); + } + app->gui = furi_record_open("gui"); app->notifications = furi_record_open("notification"); app->dialogs = furi_record_open("dialogs"); app->view_dispatcher = view_dispatcher_alloc(); - app->scene_manager = scene_manager_alloc(&bad_usb_scene_handlers, app); view_dispatcher_enable_queue(app->view_dispatcher); + + app->scene_manager = scene_manager_alloc(&bad_usb_scene_handlers, app); + view_dispatcher_set_event_callback_context(app->view_dispatcher, app); view_dispatcher_set_tick_event_callback( app->view_dispatcher, bad_usb_app_tick_event_callback, 500); - view_dispatcher_set_custom_event_callback( app->view_dispatcher, bad_usb_app_custom_event_callback); view_dispatcher_set_navigation_event_callback( app->view_dispatcher, bad_usb_app_back_event_callback); - view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); - // Custom Widget app->widget = widget_alloc(); view_dispatcher_add_view( @@ -69,7 +77,11 @@ BadUsbApp* bad_usb_app_alloc() { view_dispatcher_add_view( app->view_dispatcher, BadUsbAppViewWork, bad_usb_get_view(app->bad_usb_view)); - if(bad_usb_check_assets()) { + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + + if(*app->file_name != '\0') { + scene_manager_next_scene(app->scene_manager, BadUsbSceneWork); + } else if(bad_usb_check_assets()) { scene_manager_next_scene(app->scene_manager, BadUsbSceneFileSelect); } else { scene_manager_next_scene(app->scene_manager, BadUsbSceneError); @@ -106,7 +118,7 @@ int32_t bad_usb_app(void* p) { FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); furi_hal_usb_set_config(&usb_hid); - BadUsbApp* bad_usb_app = bad_usb_app_alloc(); + BadUsbApp* bad_usb_app = bad_usb_app_alloc((char*)p); view_dispatcher_run(bad_usb_app->view_dispatcher); diff --git a/applications/bad_usb/views/bad_usb_view.c b/applications/bad_usb/views/bad_usb_view.c index fecd2f7a..6d226ca7 100644 --- a/applications/bad_usb/views/bad_usb_view.c +++ b/applications/bad_usb/views/bad_usb_view.c @@ -144,7 +144,7 @@ void bad_usb_set_ok_callback(BadUsb* bad_usb, BadUsbOkCallback callback, void* c bad_usb->view, (BadUsbModel * model) { bad_usb->callback = callback; bad_usb->context = context; - return false; + return true; }); } @@ -153,7 +153,7 @@ void bad_usb_set_file_name(BadUsb* bad_usb, char* name) { with_view_model( bad_usb->view, (BadUsbModel * model) { model->file_name = name; - return false; + return true; }); } @@ -163,6 +163,6 @@ void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) { bad_usb->view, (BadUsbModel * model) { memcpy(&(model->state), st, sizeof(BadUsbState)); model->anim_frame ^= 1; - return false; + return true; }); } diff --git a/applications/gpio/views/gpio_usb_uart.c b/applications/gpio/views/gpio_usb_uart.c index 3b2d1f38..be80f019 100644 --- a/applications/gpio/views/gpio_usb_uart.c +++ b/applications/gpio/views/gpio_usb_uart.c @@ -151,6 +151,6 @@ void gpio_usb_uart_update_state(GpioUsbUart* instance, UsbUartConfig* cfg, UsbUa model->rx_active = (model->rx_cnt != st->rx_cnt); model->tx_cnt = st->tx_cnt; model->rx_cnt = st->rx_cnt; - return false; + return true; }); } diff --git a/applications/u2f/views/u2f_view.c b/applications/u2f/views/u2f_view.c index c810d141..8a6f441a 100644 --- a/applications/u2f/views/u2f_view.c +++ b/applications/u2f/views/u2f_view.c @@ -96,6 +96,6 @@ void u2f_view_set_state(U2fView* u2f, U2fViewMsg msg) { with_view_model( u2f->view, (U2fModel * model) { model->display_msg = msg; - return false; + return true; }); } diff --git a/assets/compiled/assets_icons.c b/assets/compiled/assets_icons.c index 1d395b96..4a779743 100644 --- a/assets/compiled/assets_icons.c +++ b/assets/compiled/assets_icons.c @@ -40,6 +40,9 @@ const uint8_t *_I_125_10px[] = {_I_125_10px_0}; const uint8_t _I_Nfc_10px_0[] = {0x00,0x80,0x00,0x00,0x01,0x22,0x02,0x43,0x02,0x45,0x02,0x49,0x02,0x31,0x02,0x22,0x02,0x00,0x01,0x80,0x00,}; const uint8_t *_I_Nfc_10px[] = {_I_Nfc_10px_0}; +const uint8_t _I_badusb_10px_0[] = {0x01,0x00,0x11,0x00,0x00,0x0f,0xe2,0x01,0xfc,0x80,0xdd,0x20,0x32,0x48,0x08,0x14,0x40,0x23,0xa8,0x08,0xa0,}; +const uint8_t *_I_badusb_10px[] = {_I_badusb_10px_0}; + const uint8_t _I_ble_10px_0[] = {0x00,0x04,0x00,0x8C,0x00,0x15,0x01,0x56,0x02,0x8C,0x02,0x8C,0x02,0x56,0x02,0x15,0x01,0x8C,0x00,0x04,0x00,}; const uint8_t *_I_ble_10px[] = {_I_ble_10px_0}; @@ -55,6 +58,9 @@ const uint8_t *_I_ir_10px[] = {_I_ir_10px_0}; const uint8_t _I_sub1_10px_0[] = {0x01,0x00,0x12,0x00,0x81,0x40,0x69,0x30,0x2c,0x2c,0x0b,0x6a,0x01,0x28,0x0c,0x0a,0x65,0x01,0x98,0x40,0x00,0x26,}; const uint8_t *_I_sub1_10px[] = {_I_sub1_10px_0}; +const uint8_t _I_u2f_10px_0[] = {0x00,0x00,0x00,0xFE,0x01,0x01,0x02,0x0C,0x00,0xF2,0x03,0x92,0x02,0x0C,0x00,0x01,0x02,0xFE,0x01,0x00,0x00,}; +const uint8_t *_I_u2f_10px[] = {_I_u2f_10px_0}; + const uint8_t _I_unknown_10px_0[] = {0x01,0x00,0x12,0x00,0xbc,0x40,0x39,0x90,0x0c,0x24,0x03,0x81,0x00,0xb0,0x40,0x26,0x00,0x12,0x00,0x08,0x14,0xc0,}; const uint8_t *_I_unknown_10px[] = {_I_unknown_10px_0}; @@ -624,11 +630,13 @@ const Icon A_Levelup1_128x64 = {.width=128,.height=64,.frame_count=11,.frame_rat const Icon A_Levelup2_128x64 = {.width=128,.height=64,.frame_count=11,.frame_rate=2,.frames=_A_Levelup2_128x64}; const Icon I_125_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_125_10px}; const Icon I_Nfc_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_Nfc_10px}; +const Icon I_badusb_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_badusb_10px}; const Icon I_ble_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_ble_10px}; const Icon I_dir_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_dir_10px}; const Icon I_ibutt_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_ibutt_10px}; const Icon I_ir_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_ir_10px}; const Icon I_sub1_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_sub1_10px}; +const Icon I_u2f_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_u2f_10px}; const Icon I_unknown_10px = {.width=10,.height=10,.frame_count=1,.frame_rate=0,.frames=_I_unknown_10px}; const Icon I_BLE_Pairing_128x64 = {.width=128,.height=64,.frame_count=1,.frame_rate=0,.frames=_I_BLE_Pairing_128x64}; const Icon I_Ble_connected_38x34 = {.width=38,.height=34,.frame_count=1,.frame_rate=0,.frames=_I_Ble_connected_38x34}; diff --git a/assets/compiled/assets_icons.h b/assets/compiled/assets_icons.h index 8fa6d6c6..8f53bc36 100644 --- a/assets/compiled/assets_icons.h +++ b/assets/compiled/assets_icons.h @@ -7,11 +7,13 @@ extern const Icon A_Levelup1_128x64; extern const Icon A_Levelup2_128x64; extern const Icon I_125_10px; extern const Icon I_Nfc_10px; +extern const Icon I_badusb_10px; extern const Icon I_ble_10px; extern const Icon I_dir_10px; extern const Icon I_ibutt_10px; extern const Icon I_ir_10px; extern const Icon I_sub1_10px; +extern const Icon I_u2f_10px; extern const Icon I_unknown_10px; extern const Icon I_BLE_Pairing_128x64; extern const Icon I_Ble_connected_38x34; diff --git a/assets/icons/Archive/badusb_10px.png b/assets/icons/Archive/badusb_10px.png new file mode 100644 index 00000000..037474aa Binary files /dev/null and b/assets/icons/Archive/badusb_10px.png differ diff --git a/assets/icons/Archive/u2f_10px.png b/assets/icons/Archive/u2f_10px.png new file mode 100644 index 00000000..fcd87a2e Binary files /dev/null and b/assets/icons/Archive/u2f_10px.png differ diff --git a/firmware/targets/f6/ble_glue/ble_glue.c b/firmware/targets/f6/ble_glue/ble_glue.c index c38c0731..6e55b368 100644 --- a/firmware/targets/f6/ble_glue/ble_glue.c +++ b/firmware/targets/f6/ble_glue/ble_glue.c @@ -116,6 +116,7 @@ void ble_glue_init() { bool ble_glue_wait_for_fus_start(WirelessFwInfo_t* info) { bool ret = false; + size_t countdown = 1000; while(countdown > 0) { if(ble_glue->status == BleGlueStatusFusStarted) { @@ -125,13 +126,14 @@ bool ble_glue_wait_for_fus_start(WirelessFwInfo_t* info) { countdown--; osDelay(1); } + if(ble_glue->status == BleGlueStatusFusStarted) { SHCI_GetWirelessFwInfo(info); } else { FURI_LOG_E(TAG, "Failed to start FUS"); ble_glue->status = BleGlueStatusBroken; } - furi_hal_power_insomnia_exit(); + return ret; } diff --git a/firmware/targets/f6/furi_hal/furi_hal_power.c b/firmware/targets/f6/furi_hal/furi_hal_power.c index 1dbdb3dd..a211b8c5 100644 --- a/firmware/targets/f6/furi_hal/furi_hal_power.c +++ b/firmware/targets/f6/furi_hal/furi_hal_power.c @@ -90,12 +90,14 @@ uint16_t furi_hal_power_insomnia_level() { void furi_hal_power_insomnia_enter() { vTaskSuspendAll(); + furi_assert(furi_hal_power.insomnia < UINT8_MAX); furi_hal_power.insomnia++; xTaskResumeAll(); } void furi_hal_power_insomnia_exit() { vTaskSuspendAll(); + furi_assert(furi_hal_power.insomnia > 0); furi_hal_power.insomnia--; xTaskResumeAll(); } diff --git a/firmware/targets/f7/ble_glue/ble_glue.c b/firmware/targets/f7/ble_glue/ble_glue.c index c38c0731..6e55b368 100644 --- a/firmware/targets/f7/ble_glue/ble_glue.c +++ b/firmware/targets/f7/ble_glue/ble_glue.c @@ -116,6 +116,7 @@ void ble_glue_init() { bool ble_glue_wait_for_fus_start(WirelessFwInfo_t* info) { bool ret = false; + size_t countdown = 1000; while(countdown > 0) { if(ble_glue->status == BleGlueStatusFusStarted) { @@ -125,13 +126,14 @@ bool ble_glue_wait_for_fus_start(WirelessFwInfo_t* info) { countdown--; osDelay(1); } + if(ble_glue->status == BleGlueStatusFusStarted) { SHCI_GetWirelessFwInfo(info); } else { FURI_LOG_E(TAG, "Failed to start FUS"); ble_glue->status = BleGlueStatusBroken; } - furi_hal_power_insomnia_exit(); + return ret; } diff --git a/firmware/targets/f7/furi_hal/furi_hal_power.c b/firmware/targets/f7/furi_hal/furi_hal_power.c index 1dbdb3dd..a211b8c5 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_power.c +++ b/firmware/targets/f7/furi_hal/furi_hal_power.c @@ -90,12 +90,14 @@ uint16_t furi_hal_power_insomnia_level() { void furi_hal_power_insomnia_enter() { vTaskSuspendAll(); + furi_assert(furi_hal_power.insomnia < UINT8_MAX); furi_hal_power.insomnia++; xTaskResumeAll(); } void furi_hal_power_insomnia_exit() { vTaskSuspendAll(); + furi_assert(furi_hal_power.insomnia > 0); furi_hal_power.insomnia--; xTaskResumeAll(); }