From 19cc23061cab8c58de96a5c959f43f59a099523f Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Tue, 15 Aug 2023 07:55:08 +0300 Subject: [PATCH] Mass storage: deadlock fix (#22) --- .../assets/ActiveConnection_50x64.png | Bin 0 -> 3842 bytes mass_storage/helpers/mass_storage_usb.c | 1 - mass_storage/mass_storage_app.c | 18 ++++++-- mass_storage/mass_storage_app_i.h | 5 +++ .../scenes/mass_storage_scene_config.h | 1 + .../scenes/mass_storage_scene_file_name.c | 6 ++- .../scenes/mass_storage_scene_file_select.c | 7 ++- .../scenes/mass_storage_scene_usb_locked.c | 40 ++++++++++++++++++ mass_storage/scenes/mass_storage_scene_work.c | 26 +++++------- mass_storage/views/mass_storage_view.c | 2 +- 10 files changed, 82 insertions(+), 24 deletions(-) create mode 100644 mass_storage/assets/ActiveConnection_50x64.png create mode 100644 mass_storage/scenes/mass_storage_scene_usb_locked.c diff --git a/mass_storage/assets/ActiveConnection_50x64.png b/mass_storage/assets/ActiveConnection_50x64.png new file mode 100644 index 0000000000000000000000000000000000000000..1d7686dddf8a33b724c7528ed36435514b7518b2 GIT binary patch literal 3842 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, NULL); - // freed by usb_deinit asynchronously from usb thread } diff --git a/mass_storage/mass_storage_app.c b/mass_storage/mass_storage_app.c index 3ccf938630d..ffb4cc3a1a1 100644 --- a/mass_storage/mass_storage_app.c +++ b/mass_storage/mass_storage_app.c @@ -81,10 +81,18 @@ MassStorageApp* mass_storage_app_alloc(char* arg) { MassStorageAppViewStart, variable_item_list_get_view(app->variable_item_list)); + app->widget = widget_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, MassStorageAppViewWidget, widget_get_view(app->widget)); + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); if(storage_file_exists(app->fs_api, furi_string_get_cstr(app->file_path))) { - scene_manager_next_scene(app->scene_manager, MassStorageSceneWork); + if(!furi_hal_usb_is_locked()) { + scene_manager_next_scene(app->scene_manager, MassStorageSceneWork); + } else { + scene_manager_next_scene(app->scene_manager, MassStorageSceneUsbLocked); + } } else { scene_manager_next_scene(app->scene_manager, MassStorageSceneStart); } @@ -100,11 +108,13 @@ void mass_storage_app_free(MassStorageApp* app) { view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewTextInput); view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewStart); view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewLoading); + view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewWidget); mass_storage_free(app->mass_storage_view); text_input_free(app->text_input); variable_item_list_free(app->variable_item_list); loading_free(app->loading); + widget_free(app->widget); // View dispatcher view_dispatcher_free(app->view_dispatcher); @@ -113,9 +123,9 @@ void mass_storage_app_free(MassStorageApp* app) { furi_string_free(app->file_path); // Close records - furi_record_close("gui"); - furi_record_close("storage"); - furi_record_close("dialogs"); + furi_record_close(RECORD_GUI); + furi_record_close(RECORD_STORAGE); + furi_record_close(RECORD_DIALOGS); free(app); } diff --git a/mass_storage/mass_storage_app_i.h b/mass_storage/mass_storage_app_i.h index 75707a3478a..8ba936bdac5 100644 --- a/mass_storage/mass_storage_app_i.h +++ b/mass_storage/mass_storage_app_i.h @@ -13,8 +13,10 @@ #include #include #include +#include #include #include "views/mass_storage_view.h" +#include #define MASS_STORAGE_APP_PATH_FOLDER STORAGE_APP_DATA_PATH_PREFIX #define MASS_STORAGE_APP_EXTENSION ".img" @@ -25,6 +27,7 @@ struct MassStorageApp { Storage* fs_api; ViewDispatcher* view_dispatcher; SceneManager* scene_manager; + Widget* widget; DialogsApp* dialogs; TextInput* text_input; VariableItemList* variable_item_list; @@ -48,12 +51,14 @@ typedef enum { MassStorageAppViewTextInput, MassStorageAppViewWork, MassStorageAppViewLoading, + MassStorageAppViewWidget, } MassStorageAppView; enum MassStorageCustomEvent { // Reserve first 100 events for button types and indexes, starting from 0 MassStorageCustomEventReserved = 100, + MassStorageCustomEventEject, MassStorageCustomEventFileSelect, MassStorageCustomEventNewImage, MassStorageCustomEventNameInput, diff --git a/mass_storage/scenes/mass_storage_scene_config.h b/mass_storage/scenes/mass_storage_scene_config.h index 5798dd53e65..f4465b45434 100644 --- a/mass_storage/scenes/mass_storage_scene_config.h +++ b/mass_storage/scenes/mass_storage_scene_config.h @@ -2,3 +2,4 @@ ADD_SCENE(mass_storage, start, Start) ADD_SCENE(mass_storage, file_select, FileSelect) ADD_SCENE(mass_storage, work, Work) ADD_SCENE(mass_storage, file_name, FileName) +ADD_SCENE(mass_storage, usb_locked, UsbLocked) diff --git a/mass_storage/scenes/mass_storage_scene_file_name.c b/mass_storage/scenes/mass_storage_scene_file_name.c index 21336e028ff..198fc2dcce1 100644 --- a/mass_storage/scenes/mass_storage_scene_file_name.c +++ b/mass_storage/scenes/mass_storage_scene_file_name.c @@ -66,7 +66,11 @@ bool mass_storage_scene_file_name_on_event(void* context, SceneManagerEvent even MASS_STORAGE_APP_EXTENSION); if(mass_storage_create_image( app->fs_api, furi_string_get_cstr(app->file_path), app->new_file_size)) { - scene_manager_next_scene(app->scene_manager, MassStorageSceneWork); + if(!furi_hal_usb_is_locked()) { + scene_manager_next_scene(app->scene_manager, MassStorageSceneWork); + } else { + scene_manager_next_scene(app->scene_manager, MassStorageSceneUsbLocked); + } } // TODO: error message screen } } diff --git a/mass_storage/scenes/mass_storage_scene_file_select.c b/mass_storage/scenes/mass_storage_scene_file_select.c index 158490e562e..29d279a5214 100644 --- a/mass_storage/scenes/mass_storage_scene_file_select.c +++ b/mass_storage/scenes/mass_storage_scene_file_select.c @@ -1,6 +1,5 @@ #include "../mass_storage_app_i.h" #include "furi_hal_power.h" -#include static bool mass_storage_file_select(MassStorageApp* mass_storage) { furi_assert(mass_storage); @@ -21,7 +20,11 @@ void mass_storage_scene_file_select_on_enter(void* context) { MassStorageApp* mass_storage = context; if(mass_storage_file_select(mass_storage)) { - scene_manager_next_scene(mass_storage->scene_manager, MassStorageSceneWork); + if(!furi_hal_usb_is_locked()) { + scene_manager_next_scene(mass_storage->scene_manager, MassStorageSceneWork); + } else { + scene_manager_next_scene(mass_storage->scene_manager, MassStorageSceneUsbLocked); + } } else { scene_manager_previous_scene(mass_storage->scene_manager); } diff --git a/mass_storage/scenes/mass_storage_scene_usb_locked.c b/mass_storage/scenes/mass_storage_scene_usb_locked.c new file mode 100644 index 00000000000..ad144ec0a51 --- /dev/null +++ b/mass_storage/scenes/mass_storage_scene_usb_locked.c @@ -0,0 +1,40 @@ +#include "../mass_storage_app_i.h" + +void mass_storage_scene_usb_locked_on_enter(void* context) { + MassStorageApp* app = context; + + widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64); + widget_add_string_multiline_element( + app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "Connection\nis active!"); + widget_add_string_multiline_element( + app->widget, + 3, + 30, + AlignLeft, + AlignTop, + FontSecondary, + "Disconnect from\nPC or phone to\nuse this function."); + + view_dispatcher_switch_to_view(app->view_dispatcher, MassStorageAppViewWidget); +} + +bool mass_storage_scene_usb_locked_on_event(void* context, SceneManagerEvent event) { + MassStorageApp* app = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeBack) { + consumed = scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, MassStorageSceneFileSelect); + if(!consumed) { + consumed = scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, MassStorageSceneStart); + } + } + + return consumed; +} + +void mass_storage_scene_usb_locked_on_exit(void* context) { + MassStorageApp* app = context; + widget_reset(app->widget); +} diff --git a/mass_storage/scenes/mass_storage_scene_work.c b/mass_storage/scenes/mass_storage_scene_work.c index 8c5fbc6bfd9..a2d533e4b03 100644 --- a/mass_storage/scenes/mass_storage_scene_work.c +++ b/mass_storage/scenes/mass_storage_scene_work.c @@ -48,27 +48,23 @@ static uint32_t file_num_blocks(void* ctx) { static void file_eject(void* ctx) { MassStorageApp* app = ctx; FURI_LOG_D(TAG, "EJECT"); - furi_check(furi_mutex_acquire(app->usb_mutex, FuriWaitForever) == FuriStatusOk); - mass_storage_usb_stop(app->usb); - app->usb = NULL; - furi_check(furi_mutex_release(app->usb_mutex) == FuriStatusOk); + view_dispatcher_send_custom_event(app->view_dispatcher, MassStorageCustomEventEject); } bool mass_storage_scene_work_on_event(void* context, SceneManagerEvent event) { MassStorageApp* app = context; bool consumed = false; - if(event.type == SceneManagerEventTypeTick) { - // Update stats - mass_storage_set_stats(app->mass_storage_view, app->bytes_read, app->bytes_written); - // Handle eject - bool ejected; - furi_check(furi_mutex_acquire(app->usb_mutex, FuriWaitForever) == FuriStatusOk); - ejected = app->usb == NULL; - furi_check(furi_mutex_release(app->usb_mutex) == FuriStatusOk); - if(ejected) { - scene_manager_previous_scene(app->scene_manager); - consumed = true; + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == MassStorageCustomEventEject) { + consumed = scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, MassStorageSceneFileSelect); + if(!consumed) { + consumed = scene_manager_search_and_switch_to_previous_scene( + app->scene_manager, MassStorageSceneStart); + } } + } else if(event.type == SceneManagerEventTypeTick) { + mass_storage_set_stats(app->mass_storage_view, app->bytes_read, app->bytes_written); } else if(event.type == SceneManagerEventTypeBack) { consumed = scene_manager_search_and_switch_to_previous_scene( app->scene_manager, MassStorageSceneFileSelect); diff --git a/mass_storage/views/mass_storage_view.c b/mass_storage/views/mass_storage_view.c index fd535edb9ac..81517acda81 100644 --- a/mass_storage/views/mass_storage_view.c +++ b/mass_storage/views/mass_storage_view.c @@ -1,6 +1,6 @@ #include "mass_storage_view.h" +#include "../mass_storage_app_i.h" #include -#include struct MassStorage { View* view;