Create mass storage images on flipper

This commit is contained in:
Willy-JL
2023-08-03 03:02:05 +02:00
parent a029da07b8
commit a02ba763cd
6 changed files with 278 additions and 0 deletions

View File

@@ -31,6 +31,9 @@ MassStorageApp* mass_storage_app_alloc(char* arg) {
furi_string_set_str(app->file_path, MASS_STORAGE_APP_PATH_FOLDER);
}
app->create_image_size = 100;
app->create_size_unit = SizeUnitMb;
app->gui = furi_record_open(RECORD_GUI);
app->fs_api = furi_record_open(RECORD_STORAGE);
app->notifications = furi_record_open(RECORD_NOTIFICATION);
@@ -55,10 +58,24 @@ MassStorageApp* mass_storage_app_alloc(char* arg) {
MassStorageAppViewWork,
mass_storage_get_view(app->mass_storage_view));
app->var_item_list = variable_item_list_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
MassStorageAppViewVarItemList,
variable_item_list_get_view(app->var_item_list));
app->submenu = submenu_alloc();
view_dispatcher_add_view(
app->view_dispatcher, MassStorageAppViewSubmenu, submenu_get_view(app->submenu));
app->text_input = text_input_alloc();
view_dispatcher_add_view(
app->view_dispatcher, MassStorageAppViewTextInput, text_input_get_view(app->text_input));
app->popup = popup_alloc();
view_dispatcher_add_view(
app->view_dispatcher, MassStorageAppViewPopup, popup_get_view(app->popup));
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
scene_manager_set_scene_state(
@@ -78,8 +95,14 @@ void mass_storage_app_free(MassStorageApp* app) {
// Views
view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewWork);
mass_storage_free(app->mass_storage_view);
view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewVarItemList);
variable_item_list_free(app->var_item_list);
view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewSubmenu);
submenu_free(app->submenu);
view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewTextInput);
text_input_free(app->text_input);
view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewPopup);
popup_free(app->popup);
// View dispatcher
view_dispatcher_free(app->view_dispatcher);

View File

@@ -11,13 +11,24 @@
#include <dialogs/dialogs.h>
#include <notification/notification_messages.h>
#include <gui/modules/widget.h>
#include <gui/modules/variable_item_list.h>
#include <gui/modules/submenu.h>
#include <gui/modules/text_input.h>
#include <gui/modules/popup.h>
#include <storage/storage.h>
#include "views/mass_storage_view.h"
#define MASS_STORAGE_APP_PATH_FOLDER STORAGE_APP_DATA_PATH_PREFIX
#define MASS_STORAGE_FILE_NAME_LEN 40
typedef enum {
SizeUnitBytes,
SizeUnitKb,
SizeUnitMb,
SizeUnitGb,
SizeUnitCount,
} SizeUnit;
struct MassStorageApp {
Gui* gui;
Storage* fs_api;
@@ -27,7 +38,14 @@ struct MassStorageApp {
DialogsApp* dialogs;
Widget* widget;
MassStorage* mass_storage_view;
VariableItemList* var_item_list;
Submenu* submenu;
TextInput* text_input;
Popup* popup;
uint32_t create_image_size;
SizeUnit create_size_unit;
char create_name[MASS_STORAGE_FILE_NAME_LEN];
FuriString* file_path;
File* file;
@@ -39,5 +57,8 @@ struct MassStorageApp {
typedef enum {
MassStorageAppViewError,
MassStorageAppViewWork,
MassStorageAppViewVarItemList,
MassStorageAppViewSubmenu,
MassStorageAppViewTextInput,
MassStorageAppViewPopup,
} MassStorageAppView;

View File

@@ -1,3 +1,5 @@
ADD_SCENE(mass_storage, start, Start)
ADD_SCENE(mass_storage, file_select, FileSelect)
ADD_SCENE(mass_storage, work, Work)
ADD_SCENE(mass_storage, create_image, CreateImage)
ADD_SCENE(mass_storage, create_image_name, CreateImageName)

View File

@@ -0,0 +1,172 @@
#include "../mass_storage_app_i.h"
#include <lib/toolbox/value_index.h>
enum VarItemListIndex {
VarItemListIndexImageSize,
VarItemListIndexSizeUnit,
VarItemListIndexName,
VarItemListIndexCreate,
};
void mass_storage_scene_create_image_var_item_list_callback(void* context, uint32_t index) {
MassStorageApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
const uint32_t image_size_values[] = {1, 2, 4, 8, 12, 16, 20, 25, 30, 35, 40,
45, 50, 69, 75, 100, 150, 200, 250, 500, 750};
static void mass_storage_scene_create_image_image_size_changed(VariableItem* item) {
MassStorageApp* app = variable_item_get_context(item);
app->create_image_size = image_size_values[variable_item_get_current_value_index(item)];
char str[4];
snprintf(str, sizeof(str), "%lu", app->create_image_size);
variable_item_set_current_value_text(item, str);
}
const char* const size_unit_names[] = {
[SizeUnitBytes] = "Bytes",
[SizeUnitKb] = "Kb",
[SizeUnitMb] = "Mb",
[SizeUnitGb] = "Gb",
};
static void mass_storage_scene_create_image_size_unit_changed(VariableItem* item) {
MassStorageApp* app = variable_item_get_context(item);
app->create_size_unit = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, size_unit_names[app->create_size_unit]);
}
void mass_storage_scene_create_image_on_enter(void* context) {
MassStorageApp* app = context;
VariableItemList* var_item_list = app->var_item_list;
VariableItem* item;
uint8_t value_index;
value_index =
value_index_uint32(app->create_image_size, image_size_values, COUNT_OF(image_size_values));
app->create_image_size = image_size_values[value_index];
char str[4];
snprintf(str, sizeof(str), "%lu", app->create_image_size);
item = variable_item_list_add(
var_item_list,
"Image Size",
COUNT_OF(image_size_values),
mass_storage_scene_create_image_image_size_changed,
app);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, str);
app->create_size_unit = CLAMP(app->create_size_unit, SizeUnitCount - 1, 0);
item = variable_item_list_add(
var_item_list,
"Size Unit",
SizeUnitCount,
mass_storage_scene_create_image_size_unit_changed,
app);
variable_item_set_current_value_index(item, app->create_size_unit);
variable_item_set_current_value_text(item, size_unit_names[app->create_size_unit]);
item = variable_item_list_add(var_item_list, "Name", 0, NULL, app);
variable_item_set_current_value_text(item, app->create_name);
variable_item_list_add(var_item_list, "Create", 0, NULL, app);
variable_item_list_set_enter_callback(
var_item_list, mass_storage_scene_create_image_var_item_list_callback, app);
variable_item_list_set_selected_item(
var_item_list,
scene_manager_get_scene_state(app->scene_manager, MassStorageSceneCreateImage));
view_dispatcher_switch_to_view(app->view_dispatcher, MassStorageAppViewVarItemList);
}
static void popup_callback_ok(void* context) {
MassStorageApp* app = context;
scene_manager_previous_scene(app->scene_manager);
}
static void popup_callback_error(void* context) {
MassStorageApp* app = context;
view_dispatcher_switch_to_view(app->view_dispatcher, MassStorageAppViewVarItemList);
}
bool mass_storage_scene_create_image_on_event(void* context, SceneManagerEvent event) {
MassStorageApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(
app->scene_manager, MassStorageSceneCreateImage, event.event);
consumed = true;
switch(event.event) {
case VarItemListIndexName:
scene_manager_next_scene(app->scene_manager, MassStorageSceneCreateImageName);
break;
case VarItemListIndexCreate: {
popup_set_header(app->popup, "Creating Image...", 64, 32, AlignCenter, AlignCenter);
popup_set_text(app->popup, "", 0, 0, AlignLeft, AlignBottom);
popup_set_callback(app->popup, NULL);
popup_set_context(app->popup, NULL);
popup_set_timeout(app->popup, 0);
popup_disable_timeout(app->popup);
view_dispatcher_switch_to_view(app->view_dispatcher, MassStorageAppViewPopup);
bool default_name = !strnlen(app->create_name, sizeof(app->create_name));
if(default_name) {
snprintf(
app->create_name,
sizeof(app->create_name),
"%lu%s",
app->create_image_size,
size_unit_names[app->create_size_unit]);
}
furi_string_printf(app->file_path, APP_DATA_PATH("%s.img"), app->create_name);
app->file = storage_file_alloc(app->fs_api);
const char* error = NULL;
if(storage_file_open(
app->file, furi_string_get_cstr(app->file_path), FSAM_WRITE, FSOM_CREATE_NEW)) {
uint64_t size = app->create_image_size;
for(size_t i = app->create_size_unit; i > 0; i--) size *= 1024;
if(!storage_file_expand(app->file, size)) {
error = "Can't allocate data";
}
} else {
if(storage_file_exists(app->fs_api, furi_string_get_cstr(app->file_path))) {
error = "File already exists";
} else {
error = "Can't open file";
}
}
storage_file_free(app->file);
if(error) {
popup_set_header(
app->popup, "Error Creating Image!", 64, 26, AlignCenter, AlignCenter);
popup_set_text(app->popup, error, 64, 40, AlignCenter, AlignCenter);
popup_set_callback(app->popup, popup_callback_error);
} else {
popup_set_header(app->popup, "Image Created!", 64, 32, AlignCenter, AlignCenter);
popup_set_text(app->popup, "", 0, 0, AlignLeft, AlignBottom);
popup_set_callback(app->popup, popup_callback_ok);
}
popup_set_context(app->popup, app);
popup_set_timeout(app->popup, 0);
popup_disable_timeout(app->popup);
view_dispatcher_switch_to_view(app->view_dispatcher, MassStorageAppViewPopup);
if(default_name) strcpy(app->create_name, "");
break;
}
default:
break;
}
}
return consumed;
}
void mass_storage_scene_create_image_on_exit(void* context) {
MassStorageApp* app = context;
variable_item_list_reset(app->var_item_list);
}

View File

@@ -0,0 +1,52 @@
#include "../mass_storage_app_i.h"
enum TextInputIndex {
TextInputResultOk,
};
static void mass_storage_scene_create_image_name_text_input_callback(void* context) {
MassStorageApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, TextInputResultOk);
}
void mass_storage_scene_create_image_name_on_enter(void* context) {
MassStorageApp* app = context;
TextInput* text_input = app->text_input;
text_input_set_header_text(text_input, "Leave empty for default");
text_input_set_minimum_length(text_input, 0);
text_input_set_result_callback(
text_input,
mass_storage_scene_create_image_name_text_input_callback,
app,
app->create_name,
sizeof(app->create_name),
false);
view_dispatcher_switch_to_view(app->view_dispatcher, MassStorageAppViewTextInput);
}
bool mass_storage_scene_create_image_name_on_event(void* context, SceneManagerEvent event) {
MassStorageApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
consumed = true;
switch(event.event) {
case TextInputResultOk:
scene_manager_previous_scene(app->scene_manager);
break;
default:
break;
}
}
return consumed;
}
void mass_storage_scene_create_image_name_on_exit(void* context) {
MassStorageApp* app = context;
text_input_reset(app->text_input);
}

View File

@@ -17,6 +17,14 @@ void mass_storage_scene_start_on_enter(void* context) {
mass_storage_scene_start_submenu_callback,
app);
submenu_add_item(
submenu,
"Create Image",
MassStorageSceneCreateImage,
mass_storage_scene_start_submenu_callback,
app);
scene_manager_set_scene_state(app->scene_manager, MassStorageSceneCreateImage, 0);
submenu_set_header(submenu, "USB Mass Storage");
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(app->scene_manager, MassStorageSceneStart));