Explorar el Código

Mass storage 1.1 (#18)

Co-authored-by: あく <alleteam@gmail.com>
hedger hace 2 años
padre
commit
0a8fc7e772

+ 8 - 0
.catalog/CHANGELOG.md

@@ -0,0 +1,8 @@
+## v.1.1
+
+ * Faster image creation
+ * Speed and transfer size in UI
+
+## v.1.0
+
+Initial release.

+ 1 - 1
application.fam

@@ -9,7 +9,7 @@ App(
     ],
     ],
     stack_size=2 * 1024,
     stack_size=2 * 1024,
     fap_description="Implements a mass storage device over USB for disk images",
     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/mass_storage_10px.png",
     fap_icon_assets="assets",
     fap_icon_assets="assets",
     fap_category="USB",
     fap_category="USB",

+ 3 - 3
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);
         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();
     app->view_dispatcher = view_dispatcher_alloc();
     view_dispatcher_enable_queue(app->view_dispatcher);
     view_dispatcher_enable_queue(app->view_dispatcher);

+ 2 - 0
mass_storage_app_i.h

@@ -39,6 +39,8 @@ struct MassStorageApp {
 
 
     char new_file_name[MASS_STORAGE_FILE_NAME_LEN + 1];
     char new_file_name[MASS_STORAGE_FILE_NAME_LEN + 1];
     uint32_t new_file_size;
     uint32_t new_file_size;
+
+    uint32_t bytes_read, bytes_written;
 };
 };
 
 
 typedef enum {
 typedef enum {

+ 14 - 16
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);
     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);
     FURI_LOG_I("TAG", "Creating image %s, len:%lu", file_path, size);
     File* file = storage_file_alloc(storage);
     File* file = storage_file_alloc(storage);
 
 
+    bool success = false;
+    uint8_t* buffer = malloc(WRITE_BUF_LEN);
     do {
     do {
         if(!storage_file_open(file, file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) break;
         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);
     } while(false);
 
 
+    free(buffer);
     storage_file_close(file);
     storage_file_close(file);
     storage_file_free(file);
     storage_file_free(file);
+    return success;
 }
 }
 
 
 void mass_storage_scene_file_name_on_enter(void* context) {
 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,
                 MASS_STORAGE_APP_PATH_FOLDER,
                 app->new_file_name,
                 app->new_file_name,
                 MASS_STORAGE_APP_EXTENSION);
                 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;
     return consumed;

+ 8 - 1
scenes/mass_storage_scene_start.c

@@ -11,6 +11,12 @@ static const struct {
     {"16M", 16 * 1024 * 1024},
     {"16M", 16 * 1024 * 1024},
     {"32M", 32 * 1024 * 1024},
     {"32M", 32 * 1024 * 1024},
     {"64M", 64 * 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) {
 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) {
 void mass_storage_scene_start_on_enter(void* context) {
     MassStorageApp* app = context;
     MassStorageApp* app = context;
+
     VariableItem* item =
     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(
     item = variable_item_list_add(
         app->variable_item_list, "New image", COUNT_OF(image_size), mass_storage_image_size, app);
         app->variable_item_list, "New image", COUNT_OF(image_size), mass_storage_image_size, app);

+ 6 - 0
scenes/mass_storage_scene_work.c

@@ -21,6 +21,7 @@ static bool file_read(
     uint16_t clamp = MIN(out_cap, count * SCSI_BLOCK_SIZE);
     uint16_t clamp = MIN(out_cap, count * SCSI_BLOCK_SIZE);
     *out_len = storage_file_read(app->file, out, clamp);
     *out_len = storage_file_read(app->file, out, clamp);
     FURI_LOG_T(TAG, "%lu/%lu", *out_len, count * SCSI_BLOCK_SIZE);
     FURI_LOG_T(TAG, "%lu/%lu", *out_len, count * SCSI_BLOCK_SIZE);
+    app->bytes_read += *out_len;
     return *out_len == clamp;
     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");
         FURI_LOG_W(TAG, "seek failed");
         return false;
         return false;
     }
     }
+    app->bytes_written += len;
     return storage_file_write(app->file, buf, len) == 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;
     MassStorageApp* app = context;
     bool consumed = false;
     bool consumed = false;
     if(event.type == SceneManagerEventTypeTick) {
     if(event.type == SceneManagerEventTypeTick) {
+        // Update stats
+        mass_storage_set_stats(app->mass_storage_view, app->bytes_read, app->bytes_written);
+        // Handle eject
         bool ejected;
         bool ejected;
         furi_check(furi_mutex_acquire(app->usb_mutex, FuriWaitForever) == FuriStatusOk);
         furi_check(furi_mutex_acquire(app->usb_mutex, FuriWaitForever) == FuriStatusOk);
         ejected = app->usb == NULL;
         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) {
 void mass_storage_scene_work_on_enter(void* context) {
     MassStorageApp* app = 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))) {
     if(!storage_file_exists(app->fs_api, furi_string_get_cstr(app->file_path))) {
         scene_manager_search_and_switch_to_previous_scene(
         scene_manager_search_and_switch_to_previous_scene(

+ 61 - 6
views/mass_storage_view.c

@@ -7,9 +7,24 @@ struct MassStorage {
 };
 };
 
 
 typedef struct {
 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;
 } 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) {
 static void mass_storage_draw_callback(Canvas* canvas, void* _model) {
     MassStorageModel* model = _model;
     MassStorageModel* model = _model;
 
 
@@ -19,10 +34,28 @@ static void mass_storage_draw_callback(Canvas* canvas, void* _model) {
     canvas_draw_str_aligned(
     canvas_draw_str_aligned(
         canvas, canvas_width(canvas) / 2, 0, AlignCenter, AlignTop, "USB Mass Storage");
         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_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() {
 MassStorage* mass_storage_alloc() {
@@ -33,7 +66,10 @@ MassStorage* mass_storage_alloc() {
     with_view_model(
     with_view_model(
         mass_storage->view,
         mass_storage->view,
         MassStorageModel * model,
         MassStorageModel * model,
-        { model->file_name = furi_string_alloc(); },
+        {
+            model->file_name = furi_string_alloc();
+            model->status_string = furi_string_alloc();
+        },
         false);
         false);
     view_set_context(mass_storage->view, mass_storage);
     view_set_context(mass_storage->view, mass_storage);
     view_set_draw_callback(mass_storage->view, mass_storage_draw_callback);
     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(
     with_view_model(
         mass_storage->view,
         mass_storage->view,
         MassStorageModel * model,
         MassStorageModel * model,
-        { furi_string_free(model->file_name); },
+        {
+            furi_string_free(model->file_name);
+            furi_string_free(model->status_string);
+        },
         false);
         false);
     view_free(mass_storage->view);
     view_free(mass_storage->view);
     free(mass_storage);
     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); },
         { furi_string_set(model->file_name, name); },
         true);
         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);
+}

+ 2 - 0
views/mass_storage_view.h

@@ -11,3 +11,5 @@ void mass_storage_free(MassStorage* mass_storage);
 View* mass_storage_get_view(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_file_name(MassStorage* mass_storage, FuriString* name);
+
+void mass_storage_set_stats(MassStorage* mass_storage, uint32_t read, uint32_t written);