From d87d982b2b915c27dfc2b2de48018fe5a083ade0 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Tue, 29 Aug 2023 01:33:54 +0200 Subject: [PATCH] Update mass storage --- .../external/mass_storage/application.fam | 2 +- .../mass_storage/helpers/mass_storage_scsi.h | 2 +- .../mass_storage/helpers/mass_storage_usb.c | 1 - .../mass_storage/mass_storage_app_i.h | 19 +++-- .../scenes/mass_storage_scene_create_image.c | 2 +- .../scenes/mass_storage_scene_file_select.c | 1 - .../scenes/mass_storage_scene_start.c | 4 +- .../scenes/mass_storage_scene_work.c | 26 +++---- .../mass_storage/views/mass_storage_view.c | 70 ++++++++++++++++--- .../mass_storage/views/mass_storage_view.h | 2 + 10 files changed, 98 insertions(+), 31 deletions(-) diff --git a/applications/external/mass_storage/application.fam b/applications/external/mass_storage/application.fam index 402affc9c..96cd28aec 100644 --- a/applications/external/mass_storage/application.fam +++ b/applications/external/mass_storage/application.fam @@ -8,7 +8,7 @@ App( "dialogs", ], stack_size=2 * 1024, - order=20, + fap_description="Implements a mass storage device over USB for disk images", fap_icon="assets/mass_storage_10px.png", fap_icon_assets="assets", fap_category="USB", diff --git a/applications/external/mass_storage/helpers/mass_storage_scsi.h b/applications/external/mass_storage/helpers/mass_storage_scsi.h index 24c24a69e..a35d6aff3 100644 --- a/applications/external/mass_storage/helpers/mass_storage_scsi.h +++ b/applications/external/mass_storage/helpers/mass_storage_scsi.h @@ -53,4 +53,4 @@ typedef struct { bool scsi_cmd_start(SCSISession* scsi, uint8_t* cmd, uint8_t len); bool scsi_cmd_rx_data(SCSISession* scsi, uint8_t* data, uint32_t len); bool scsi_cmd_tx_data(SCSISession* scsi, uint8_t* data, uint32_t* len, uint32_t cap); -bool scsi_cmd_end(SCSISession* scsi); +bool scsi_cmd_end(SCSISession* scsi); \ No newline at end of file diff --git a/applications/external/mass_storage/helpers/mass_storage_usb.c b/applications/external/mass_storage/helpers/mass_storage_usb.c index 8e3e0f875..f493203a6 100644 --- a/applications/external/mass_storage/helpers/mass_storage_usb.c +++ b/applications/external/mass_storage/helpers/mass_storage_usb.c @@ -478,5 +478,4 @@ MassStorageUsb* mass_storage_usb_start(const char* filename, SCSIDeviceFunc fn) void mass_storage_usb_stop(MassStorageUsb* mass) { furi_hal_usb_set_config(mass->usb_prev, NULL); - // freed by usb_deinit asynchronously from usb thread } diff --git a/applications/external/mass_storage/mass_storage_app_i.h b/applications/external/mass_storage/mass_storage_app_i.h index 1901fb10a..fe8a2d944 100644 --- a/applications/external/mass_storage/mass_storage_app_i.h +++ b/applications/external/mass_storage/mass_storage_app_i.h @@ -16,6 +16,8 @@ #include #include #include "views/mass_storage_view.h" +#include +#include #define MASS_STORAGE_APP_PATH_FOLDER STORAGE_APP_DATA_PATH_PREFIX #define MASS_STORAGE_APP_EXTENSION ".img" @@ -33,16 +35,18 @@ struct MassStorageApp { Popup* popup; Loading* loading; - uint64_t create_image_max; - uint8_t create_image_size; - char create_image_name[MASS_STORAGE_FILE_NAME_LEN]; - FuriString* file_path; File* file; MassStorage* mass_storage_view; FuriMutex* usb_mutex; MassStorageUsb* usb; + + uint64_t create_image_max; + uint8_t create_image_size; + char create_image_name[MASS_STORAGE_FILE_NAME_LEN]; + + uint32_t bytes_read, bytes_written; }; typedef enum { @@ -54,4 +58,11 @@ typedef enum { MassStorageAppViewWork, } MassStorageAppView; +enum MassStorageCustomEvent { + // Reserve first 100 events for button types and indexes, starting from 0 + MassStorageCustomEventReserved = 100, + + MassStorageCustomEventEject, +}; + void mass_storage_app_show_loading_popup(MassStorageApp* app, bool show); diff --git a/applications/external/mass_storage/scenes/mass_storage_scene_create_image.c b/applications/external/mass_storage/scenes/mass_storage_scene_create_image.c index 1c12ff8a3..4455a7aee 100644 --- a/applications/external/mass_storage/scenes/mass_storage_scene_create_image.c +++ b/applications/external/mass_storage/scenes/mass_storage_scene_create_image.c @@ -77,7 +77,7 @@ void mass_storage_scene_create_image_on_enter(void* context) { variable_item_list_set_enter_callback( var_item_list, mass_storage_scene_create_image_var_item_list_callback, app); - variable_item_list_set_header(var_item_list, "Create Disc Image"); + variable_item_list_set_header(var_item_list, "Create Disk Image"); variable_item_list_set_selected_item( var_item_list, diff --git a/applications/external/mass_storage/scenes/mass_storage_scene_file_select.c b/applications/external/mass_storage/scenes/mass_storage_scene_file_select.c index 1f37f028c..51d4f4dd2 100644 --- a/applications/external/mass_storage/scenes/mass_storage_scene_file_select.c +++ b/applications/external/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); diff --git a/applications/external/mass_storage/scenes/mass_storage_scene_start.c b/applications/external/mass_storage/scenes/mass_storage_scene_start.c index fdad77362..c85d73dab 100644 --- a/applications/external/mass_storage/scenes/mass_storage_scene_start.c +++ b/applications/external/mass_storage/scenes/mass_storage_scene_start.c @@ -12,14 +12,14 @@ void mass_storage_scene_start_on_enter(void* context) { submenu_add_item( submenu, - "Select Disc Image", + "Select Disk Image", MassStorageSceneFileSelect, mass_storage_scene_start_submenu_callback, app); submenu_add_item( submenu, - "Create Disc Image", + "Create Disk Image", MassStorageSceneCreateImage, mass_storage_scene_start_submenu_callback, app); diff --git a/applications/external/mass_storage/scenes/mass_storage_scene_work.c b/applications/external/mass_storage/scenes/mass_storage_scene_work.c index ad3630a48..a2d533e4b 100644 --- a/applications/external/mass_storage/scenes/mass_storage_scene_work.c +++ b/applications/external/mass_storage/scenes/mass_storage_scene_work.c @@ -21,6 +21,7 @@ static bool file_read( uint16_t clamp = MIN(out_cap, count * SCSI_BLOCK_SIZE); *out_len = storage_file_read(app->file, out, clamp); FURI_LOG_T(TAG, "%lu/%lu", *out_len, count * SCSI_BLOCK_SIZE); + app->bytes_read += *out_len; return *out_len == clamp; } @@ -35,6 +36,7 @@ static bool file_write(void* ctx, uint32_t lba, uint16_t count, uint8_t* buf, ui FURI_LOG_W(TAG, "seek failed"); return false; } + app->bytes_written += len; return storage_file_write(app->file, buf, len) == len; } @@ -46,24 +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) { - 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); @@ -77,6 +78,7 @@ bool mass_storage_scene_work_on_event(void* context, SceneManagerEvent event) { void mass_storage_scene_work_on_enter(void* context) { MassStorageApp* app = context; + app->bytes_read = app->bytes_written = 0; if(!storage_file_exists(app->fs_api, furi_string_get_cstr(app->file_path))) { scene_manager_search_and_switch_to_previous_scene( diff --git a/applications/external/mass_storage/views/mass_storage_view.c b/applications/external/mass_storage/views/mass_storage_view.c index ac2754cf1..81517acda 100644 --- a/applications/external/mass_storage/views/mass_storage_view.c +++ b/applications/external/mass_storage/views/mass_storage_view.c @@ -1,16 +1,30 @@ #include "mass_storage_view.h" +#include "../mass_storage_app_i.h" #include -#include -#include struct MassStorage { View* view; }; typedef struct { - FuriString* file_name; + FuriString *file_name, *status_string; + uint32_t read_speed, write_speed; + uint32_t bytes_read, bytes_written; + uint32_t update_time; } MassStorageModel; +static void append_suffixed_byte_count(FuriString* string, uint32_t count) { + if(count < 1024) { + furi_string_cat_printf(string, "%luB", count); + } else if(count < 1024 * 1024) { + furi_string_cat_printf(string, "%luK", count / 1024); + } else if(count < 1024 * 1024 * 1024) { + furi_string_cat_printf(string, "%.3fM", (double)count / (1024 * 1024)); + } else { + furi_string_cat_printf(string, "%.3fG", (double)count / (1024 * 1024 * 1024)); + } +} + static void mass_storage_draw_callback(Canvas* canvas, void* _model) { MassStorageModel* model = _model; @@ -20,10 +34,28 @@ static void mass_storage_draw_callback(Canvas* canvas, void* _model) { canvas_draw_str_aligned( canvas, canvas_width(canvas) / 2, 0, AlignCenter, AlignTop, "USB Mass Storage"); - elements_string_fit_width(canvas, model->file_name, 87 - 2); canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 16, 27, "Disc image:"); - canvas_draw_str(canvas, 16, 40, furi_string_get_cstr(model->file_name)); + elements_string_fit_width(canvas, model->file_name, 89 - 2); + canvas_draw_str_aligned( + canvas, 50, 23, AlignCenter, AlignBottom, furi_string_get_cstr(model->file_name)); + + furi_string_set_str(model->status_string, "R:"); + append_suffixed_byte_count(model->status_string, model->bytes_read); + if(model->read_speed) { + furi_string_cat_str(model->status_string, "; "); + append_suffixed_byte_count(model->status_string, model->read_speed); + furi_string_cat_str(model->status_string, "ps"); + } + canvas_draw_str(canvas, 12, 34, furi_string_get_cstr(model->status_string)); + + furi_string_set_str(model->status_string, "W:"); + append_suffixed_byte_count(model->status_string, model->bytes_written); + if(model->write_speed) { + furi_string_cat_str(model->status_string, "; "); + append_suffixed_byte_count(model->status_string, model->write_speed); + furi_string_cat_str(model->status_string, "ps"); + } + canvas_draw_str(canvas, 12, 44, furi_string_get_cstr(model->status_string)); } MassStorage* mass_storage_alloc() { @@ -34,7 +66,10 @@ MassStorage* mass_storage_alloc() { with_view_model( mass_storage->view, MassStorageModel * model, - { model->file_name = furi_string_alloc(); }, + { + model->file_name = furi_string_alloc(); + model->status_string = furi_string_alloc(); + }, false); view_set_context(mass_storage->view, mass_storage); view_set_draw_callback(mass_storage->view, mass_storage_draw_callback); @@ -47,7 +82,10 @@ void mass_storage_free(MassStorage* mass_storage) { with_view_model( mass_storage->view, MassStorageModel * model, - { furi_string_free(model->file_name); }, + { + furi_string_free(model->file_name); + furi_string_free(model->status_string); + }, false); view_free(mass_storage->view); free(mass_storage); @@ -66,3 +104,19 @@ void mass_storage_set_file_name(MassStorage* mass_storage, FuriString* name) { { furi_string_set(model->file_name, name); }, true); } + +void mass_storage_set_stats(MassStorage* mass_storage, uint32_t read, uint32_t written) { + with_view_model( + mass_storage->view, + MassStorageModel * model, + { + uint32_t now = furi_get_tick(); + model->read_speed = (read - model->bytes_read) * 1000 / (now - model->update_time); + model->write_speed = + (written - model->bytes_written) * 1000 / (now - model->update_time); + model->bytes_read = read; + model->bytes_written = written; + model->update_time = now; + }, + true); +} diff --git a/applications/external/mass_storage/views/mass_storage_view.h b/applications/external/mass_storage/views/mass_storage_view.h index 96df01c8d..2edbf2a62 100644 --- a/applications/external/mass_storage/views/mass_storage_view.h +++ b/applications/external/mass_storage/views/mass_storage_view.h @@ -11,3 +11,5 @@ void mass_storage_free(MassStorage* mass_storage); View* mass_storage_get_view(MassStorage* mass_storage); void mass_storage_set_file_name(MassStorage* mass_storage, FuriString* name); + +void mass_storage_set_stats(MassStorage* mass_storage, uint32_t read, uint32_t written);