From 0a8fc7e772dcac9911676ea6877a0ed71a523f6a Mon Sep 17 00:00:00 2001 From: hedger Date: Fri, 11 Aug 2023 14:56:11 +0300 Subject: [PATCH] Mass storage 1.1 (#18) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: あく --- .catalog/CHANGELOG.md | 8 ++++ application.fam | 2 +- mass_storage_app.c | 6 +-- mass_storage_app_i.h | 2 + scenes/mass_storage_scene_file_name.c | 30 ++++++------ scenes/mass_storage_scene_start.c | 9 +++- scenes/mass_storage_scene_work.c | 6 +++ views/mass_storage_view.c | 67 ++++++++++++++++++++++++--- views/mass_storage_view.h | 2 + 9 files changed, 105 insertions(+), 27 deletions(-) create mode 100644 .catalog/CHANGELOG.md diff --git a/.catalog/CHANGELOG.md b/.catalog/CHANGELOG.md new file mode 100644 index 00000000000..e70d101cc42 --- /dev/null +++ b/.catalog/CHANGELOG.md @@ -0,0 +1,8 @@ +## v.1.1 + + * Faster image creation + * Speed and transfer size in UI + +## v.1.0 + +Initial release. \ No newline at end of file diff --git a/application.fam b/application.fam index 239af0c8ca3..e43fe58dab4 100644 --- a/application.fam +++ b/application.fam @@ -9,7 +9,7 @@ App( ], stack_size=2 * 1024, fap_description="Implements a mass storage device over USB for disk images", - fap_version="1.0", + fap_version="1.1", fap_icon="assets/mass_storage_10px.png", fap_icon_assets="assets", fap_category="USB", diff --git a/mass_storage_app.c b/mass_storage_app.c index a05c1d47be1..3ccf938630d 100644 --- a/mass_storage_app.c +++ b/mass_storage_app.c @@ -44,9 +44,9 @@ MassStorageApp* mass_storage_app_alloc(char* arg) { furi_string_set_str(app->file_path, MASS_STORAGE_APP_PATH_FOLDER); } - app->gui = furi_record_open("gui"); - app->fs_api = furi_record_open("storage"); - app->dialogs = furi_record_open("dialogs"); + app->gui = furi_record_open(RECORD_GUI); + app->fs_api = furi_record_open(RECORD_STORAGE); + app->dialogs = furi_record_open(RECORD_DIALOGS); app->view_dispatcher = view_dispatcher_alloc(); view_dispatcher_enable_queue(app->view_dispatcher); diff --git a/mass_storage_app_i.h b/mass_storage_app_i.h index 715b2a95642..75707a3478a 100644 --- a/mass_storage_app_i.h +++ b/mass_storage_app_i.h @@ -39,6 +39,8 @@ struct MassStorageApp { char new_file_name[MASS_STORAGE_FILE_NAME_LEN + 1]; uint32_t new_file_size; + + uint32_t bytes_read, bytes_written; }; typedef enum { diff --git a/scenes/mass_storage_scene_file_name.c b/scenes/mass_storage_scene_file_name.c index 8acd4fad392..21336e028ff 100644 --- a/scenes/mass_storage_scene_file_name.c +++ b/scenes/mass_storage_scene_file_name.c @@ -9,29 +9,26 @@ static void mass_storage_file_name_text_callback(void* context) { view_dispatcher_send_custom_event(app->view_dispatcher, MassStorageCustomEventNameInput); } -static void mass_storage_create_image(Storage* storage, const char* file_path, uint32_t size) { +static bool mass_storage_create_image(Storage* storage, const char* file_path, uint32_t size) { FURI_LOG_I("TAG", "Creating image %s, len:%lu", file_path, size); File* file = storage_file_alloc(storage); + bool success = false; + uint8_t* buffer = malloc(WRITE_BUF_LEN); do { if(!storage_file_open(file, file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) break; - uint32_t size_left = size; - uint8_t* buf = malloc(WRITE_BUF_LEN); - memset(buf, 0, WRITE_BUF_LEN); - while(size_left > 0) { - uint32_t wr_len = size_left; - if(wr_len > WRITE_BUF_LEN) { - wr_len = WRITE_BUF_LEN; - } - if(storage_file_write(file, buf, wr_len) != wr_len) break; - size_left -= wr_len; - } - free(buf); + if(!storage_file_seek(file, size, true)) break; + if(!storage_file_seek(file, 0, true)) break; + // Zero out first 4k - partition table and adjacent data + if(!storage_file_write(file, buffer, WRITE_BUF_LEN)) break; + success = true; } while(false); + free(buffer); storage_file_close(file); storage_file_free(file); + return success; } void mass_storage_scene_file_name_on_enter(void* context) { @@ -67,9 +64,10 @@ bool mass_storage_scene_file_name_on_event(void* context, SceneManagerEvent even MASS_STORAGE_APP_PATH_FOLDER, app->new_file_name, MASS_STORAGE_APP_EXTENSION); - 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(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); + } // TODO: error message screen } } return consumed; diff --git a/scenes/mass_storage_scene_start.c b/scenes/mass_storage_scene_start.c index ab8687c867a..e62e42f51d3 100644 --- a/scenes/mass_storage_scene_start.c +++ b/scenes/mass_storage_scene_start.c @@ -11,6 +11,12 @@ static const struct { {"16M", 16 * 1024 * 1024}, {"32M", 32 * 1024 * 1024}, {"64M", 64 * 1024 * 1024}, + {"128M", 128 * 1024 * 1024}, + {"256M", 256 * 1024 * 1024}, + {"512M", 512 * 1024 * 1024}, + {"700M", 700 * 1024 * 1024}, + {"1G", 1024 * 1024 * 1024}, + {"2G", 2u * 1024 * 1024 * 1024}, }; static void mass_storage_item_select(void* context, uint32_t index) { @@ -31,8 +37,9 @@ static void mass_storage_image_size(VariableItem* item) { void mass_storage_scene_start_on_enter(void* context) { MassStorageApp* app = context; + VariableItem* item = - variable_item_list_add(app->variable_item_list, "Select disc image", 0, NULL, NULL); + variable_item_list_add(app->variable_item_list, "Select disk image", 0, NULL, NULL); item = variable_item_list_add( app->variable_item_list, "New image", COUNT_OF(image_size), mass_storage_image_size, app); diff --git a/scenes/mass_storage_scene_work.c b/scenes/mass_storage_scene_work.c index ad3630a481d..8c5fbc6bfd9 100644 --- a/scenes/mass_storage_scene_work.c +++ b/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; } @@ -56,6 +58,9 @@ 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; @@ -77,6 +82,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/views/mass_storage_view.c b/views/mass_storage_view.c index ad38f1849ca..fd535edb9ac 100644 --- a/views/mass_storage_view.c +++ b/views/mass_storage_view.c @@ -7,9 +7,24 @@ struct MassStorage { }; 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; @@ -19,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, 12, 25, "Disc image:"); - canvas_draw_str(canvas, 12, 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() { @@ -33,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); @@ -46,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); @@ -65,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/views/mass_storage_view.h b/views/mass_storage_view.h index 96df01c8d5e..2edbf2a62c7 100644 --- a/views/mass_storage_view.h +++ b/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);