Skip to content
This repository has been archived by the owner on Jul 28, 2024. It is now read-only.

Commit

Permalink
Mass storage 1.1 (#18)
Browse files Browse the repository at this point in the history
Co-authored-by: あく <[email protected]>
  • Loading branch information
hedger and skotopes authored Aug 11, 2023
1 parent f3d0a51 commit 64625d3
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 27 deletions.
8 changes: 8 additions & 0 deletions mass_storage/.catalog/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
## v.1.1

* Faster image creation
* Speed and transfer size in UI

## v.1.0

Initial release.
2 changes: 1 addition & 1 deletion mass_storage/application.fam
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
6 changes: 3 additions & 3 deletions mass_storage/mass_storage_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions mass_storage/mass_storage_app_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
30 changes: 14 additions & 16 deletions mass_storage/scenes/mass_storage_scene_file_name.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down
9 changes: 8 additions & 1 deletion mass_storage/scenes/mass_storage_scene_start.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions mass_storage/scenes/mass_storage_scene_work.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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;
}

Expand All @@ -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;
Expand All @@ -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(
Expand Down
67 changes: 61 additions & 6 deletions mass_storage/views/mass_storage_view.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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() {
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
}
2 changes: 2 additions & 0 deletions mass_storage/views/mass_storage_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

0 comments on commit 64625d3

Please sign in to comment.