Skip to content

Commit 0a8fc7e

Browse files
hedgerskotopes
andauthored
Mass storage 1.1 (#18)
Co-authored-by: あく <alleteam@gmail.com>
1 parent 1d53f68 commit 0a8fc7e

9 files changed

+105
-27
lines changed

.catalog/CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
## v.1.1
2+
3+
* Faster image creation
4+
* Speed and transfer size in UI
5+
6+
## v.1.0
7+
8+
Initial release.

application.fam

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ App(
99
],
1010
stack_size=2 * 1024,
1111
fap_description="Implements a mass storage device over USB for disk images",
12-
fap_version="1.0",
12+
fap_version="1.1",
1313
fap_icon="assets/mass_storage_10px.png",
1414
fap_icon_assets="assets",
1515
fap_category="USB",

mass_storage_app.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ MassStorageApp* mass_storage_app_alloc(char* arg) {
4444
furi_string_set_str(app->file_path, MASS_STORAGE_APP_PATH_FOLDER);
4545
}
4646

47-
app->gui = furi_record_open("gui");
48-
app->fs_api = furi_record_open("storage");
49-
app->dialogs = furi_record_open("dialogs");
47+
app->gui = furi_record_open(RECORD_GUI);
48+
app->fs_api = furi_record_open(RECORD_STORAGE);
49+
app->dialogs = furi_record_open(RECORD_DIALOGS);
5050

5151
app->view_dispatcher = view_dispatcher_alloc();
5252
view_dispatcher_enable_queue(app->view_dispatcher);

mass_storage_app_i.h

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ struct MassStorageApp {
3939

4040
char new_file_name[MASS_STORAGE_FILE_NAME_LEN + 1];
4141
uint32_t new_file_size;
42+
43+
uint32_t bytes_read, bytes_written;
4244
};
4345

4446
typedef enum {

scenes/mass_storage_scene_file_name.c

+14-16
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,26 @@ static void mass_storage_file_name_text_callback(void* context) {
99
view_dispatcher_send_custom_event(app->view_dispatcher, MassStorageCustomEventNameInput);
1010
}
1111

12-
static void mass_storage_create_image(Storage* storage, const char* file_path, uint32_t size) {
12+
static bool mass_storage_create_image(Storage* storage, const char* file_path, uint32_t size) {
1313
FURI_LOG_I("TAG", "Creating image %s, len:%lu", file_path, size);
1414
File* file = storage_file_alloc(storage);
1515

16+
bool success = false;
17+
uint8_t* buffer = malloc(WRITE_BUF_LEN);
1618
do {
1719
if(!storage_file_open(file, file_path, FSAM_WRITE, FSOM_CREATE_ALWAYS)) break;
18-
uint32_t size_left = size;
19-
uint8_t* buf = malloc(WRITE_BUF_LEN);
20-
memset(buf, 0, WRITE_BUF_LEN);
21-
while(size_left > 0) {
22-
uint32_t wr_len = size_left;
23-
if(wr_len > WRITE_BUF_LEN) {
24-
wr_len = WRITE_BUF_LEN;
25-
}
26-
if(storage_file_write(file, buf, wr_len) != wr_len) break;
27-
size_left -= wr_len;
28-
}
29-
free(buf);
20+
if(!storage_file_seek(file, size, true)) break;
21+
if(!storage_file_seek(file, 0, true)) break;
22+
// Zero out first 4k - partition table and adjacent data
23+
if(!storage_file_write(file, buffer, WRITE_BUF_LEN)) break;
3024

25+
success = true;
3126
} while(false);
3227

28+
free(buffer);
3329
storage_file_close(file);
3430
storage_file_free(file);
31+
return success;
3532
}
3633

3734
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
6764
MASS_STORAGE_APP_PATH_FOLDER,
6865
app->new_file_name,
6966
MASS_STORAGE_APP_EXTENSION);
70-
mass_storage_create_image(
71-
app->fs_api, furi_string_get_cstr(app->file_path), app->new_file_size);
72-
scene_manager_next_scene(app->scene_manager, MassStorageSceneWork);
67+
if(mass_storage_create_image(
68+
app->fs_api, furi_string_get_cstr(app->file_path), app->new_file_size)) {
69+
scene_manager_next_scene(app->scene_manager, MassStorageSceneWork);
70+
} // TODO: error message screen
7371
}
7472
}
7573
return consumed;

scenes/mass_storage_scene_start.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ static const struct {
1111
{"16M", 16 * 1024 * 1024},
1212
{"32M", 32 * 1024 * 1024},
1313
{"64M", 64 * 1024 * 1024},
14+
{"128M", 128 * 1024 * 1024},
15+
{"256M", 256 * 1024 * 1024},
16+
{"512M", 512 * 1024 * 1024},
17+
{"700M", 700 * 1024 * 1024},
18+
{"1G", 1024 * 1024 * 1024},
19+
{"2G", 2u * 1024 * 1024 * 1024},
1420
};
1521

1622
static void mass_storage_item_select(void* context, uint32_t index) {
@@ -31,8 +37,9 @@ static void mass_storage_image_size(VariableItem* item) {
3137

3238
void mass_storage_scene_start_on_enter(void* context) {
3339
MassStorageApp* app = context;
40+
3441
VariableItem* item =
35-
variable_item_list_add(app->variable_item_list, "Select disc image", 0, NULL, NULL);
42+
variable_item_list_add(app->variable_item_list, "Select disk image", 0, NULL, NULL);
3643

3744
item = variable_item_list_add(
3845
app->variable_item_list, "New image", COUNT_OF(image_size), mass_storage_image_size, app);

scenes/mass_storage_scene_work.c

+6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ static bool file_read(
2121
uint16_t clamp = MIN(out_cap, count * SCSI_BLOCK_SIZE);
2222
*out_len = storage_file_read(app->file, out, clamp);
2323
FURI_LOG_T(TAG, "%lu/%lu", *out_len, count * SCSI_BLOCK_SIZE);
24+
app->bytes_read += *out_len;
2425
return *out_len == clamp;
2526
}
2627

@@ -35,6 +36,7 @@ static bool file_write(void* ctx, uint32_t lba, uint16_t count, uint8_t* buf, ui
3536
FURI_LOG_W(TAG, "seek failed");
3637
return false;
3738
}
39+
app->bytes_written += len;
3840
return storage_file_write(app->file, buf, len) == len;
3941
}
4042

@@ -56,6 +58,9 @@ bool mass_storage_scene_work_on_event(void* context, SceneManagerEvent event) {
5658
MassStorageApp* app = context;
5759
bool consumed = false;
5860
if(event.type == SceneManagerEventTypeTick) {
61+
// Update stats
62+
mass_storage_set_stats(app->mass_storage_view, app->bytes_read, app->bytes_written);
63+
// Handle eject
5964
bool ejected;
6065
furi_check(furi_mutex_acquire(app->usb_mutex, FuriWaitForever) == FuriStatusOk);
6166
ejected = app->usb == NULL;
@@ -77,6 +82,7 @@ bool mass_storage_scene_work_on_event(void* context, SceneManagerEvent event) {
7782

7883
void mass_storage_scene_work_on_enter(void* context) {
7984
MassStorageApp* app = context;
85+
app->bytes_read = app->bytes_written = 0;
8086

8187
if(!storage_file_exists(app->fs_api, furi_string_get_cstr(app->file_path))) {
8288
scene_manager_search_and_switch_to_previous_scene(

views/mass_storage_view.c

+61-6
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,24 @@ struct MassStorage {
77
};
88

99
typedef struct {
10-
FuriString* file_name;
10+
FuriString *file_name, *status_string;
11+
uint32_t read_speed, write_speed;
12+
uint32_t bytes_read, bytes_written;
13+
uint32_t update_time;
1114
} MassStorageModel;
1215

16+
static void append_suffixed_byte_count(FuriString* string, uint32_t count) {
17+
if(count < 1024) {
18+
furi_string_cat_printf(string, "%luB", count);
19+
} else if(count < 1024 * 1024) {
20+
furi_string_cat_printf(string, "%luK", count / 1024);
21+
} else if(count < 1024 * 1024 * 1024) {
22+
furi_string_cat_printf(string, "%.3fM", (double)count / (1024 * 1024));
23+
} else {
24+
furi_string_cat_printf(string, "%.3fG", (double)count / (1024 * 1024 * 1024));
25+
}
26+
}
27+
1328
static void mass_storage_draw_callback(Canvas* canvas, void* _model) {
1429
MassStorageModel* model = _model;
1530

@@ -19,10 +34,28 @@ static void mass_storage_draw_callback(Canvas* canvas, void* _model) {
1934
canvas_draw_str_aligned(
2035
canvas, canvas_width(canvas) / 2, 0, AlignCenter, AlignTop, "USB Mass Storage");
2136

22-
elements_string_fit_width(canvas, model->file_name, 87 - 2);
2337
canvas_set_font(canvas, FontSecondary);
24-
canvas_draw_str(canvas, 12, 25, "Disc image:");
25-
canvas_draw_str(canvas, 12, 40, furi_string_get_cstr(model->file_name));
38+
elements_string_fit_width(canvas, model->file_name, 89 - 2);
39+
canvas_draw_str_aligned(
40+
canvas, 50, 23, AlignCenter, AlignBottom, furi_string_get_cstr(model->file_name));
41+
42+
furi_string_set_str(model->status_string, "R:");
43+
append_suffixed_byte_count(model->status_string, model->bytes_read);
44+
if(model->read_speed) {
45+
furi_string_cat_str(model->status_string, "; ");
46+
append_suffixed_byte_count(model->status_string, model->read_speed);
47+
furi_string_cat_str(model->status_string, "ps");
48+
}
49+
canvas_draw_str(canvas, 12, 34, furi_string_get_cstr(model->status_string));
50+
51+
furi_string_set_str(model->status_string, "W:");
52+
append_suffixed_byte_count(model->status_string, model->bytes_written);
53+
if(model->write_speed) {
54+
furi_string_cat_str(model->status_string, "; ");
55+
append_suffixed_byte_count(model->status_string, model->write_speed);
56+
furi_string_cat_str(model->status_string, "ps");
57+
}
58+
canvas_draw_str(canvas, 12, 44, furi_string_get_cstr(model->status_string));
2659
}
2760

2861
MassStorage* mass_storage_alloc() {
@@ -33,7 +66,10 @@ MassStorage* mass_storage_alloc() {
3366
with_view_model(
3467
mass_storage->view,
3568
MassStorageModel * model,
36-
{ model->file_name = furi_string_alloc(); },
69+
{
70+
model->file_name = furi_string_alloc();
71+
model->status_string = furi_string_alloc();
72+
},
3773
false);
3874
view_set_context(mass_storage->view, mass_storage);
3975
view_set_draw_callback(mass_storage->view, mass_storage_draw_callback);
@@ -46,7 +82,10 @@ void mass_storage_free(MassStorage* mass_storage) {
4682
with_view_model(
4783
mass_storage->view,
4884
MassStorageModel * model,
49-
{ furi_string_free(model->file_name); },
85+
{
86+
furi_string_free(model->file_name);
87+
furi_string_free(model->status_string);
88+
},
5089
false);
5190
view_free(mass_storage->view);
5291
free(mass_storage);
@@ -65,3 +104,19 @@ void mass_storage_set_file_name(MassStorage* mass_storage, FuriString* name) {
65104
{ furi_string_set(model->file_name, name); },
66105
true);
67106
}
107+
108+
void mass_storage_set_stats(MassStorage* mass_storage, uint32_t read, uint32_t written) {
109+
with_view_model(
110+
mass_storage->view,
111+
MassStorageModel * model,
112+
{
113+
uint32_t now = furi_get_tick();
114+
model->read_speed = (read - model->bytes_read) * 1000 / (now - model->update_time);
115+
model->write_speed =
116+
(written - model->bytes_written) * 1000 / (now - model->update_time);
117+
model->bytes_read = read;
118+
model->bytes_written = written;
119+
model->update_time = now;
120+
},
121+
true);
122+
}

views/mass_storage_view.h

+2
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ void mass_storage_free(MassStorage* mass_storage);
1111
View* mass_storage_get_view(MassStorage* mass_storage);
1212

1313
void mass_storage_set_file_name(MassStorage* mass_storage, FuriString* name);
14+
15+
void mass_storage_set_stats(MassStorage* mass_storage, uint32_t read, uint32_t written);

0 commit comments

Comments
 (0)