mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-10 05:59:08 -07:00
Create mass storage images on flipper
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
172
applications/external/mass_storage/scenes/mass_storage_scene_create_image.c
vendored
Normal file
172
applications/external/mass_storage/scenes/mass_storage_scene_create_image.c
vendored
Normal 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);
|
||||
}
|
||||
52
applications/external/mass_storage/scenes/mass_storage_scene_create_image_name.c
vendored
Normal file
52
applications/external/mass_storage/scenes/mass_storage_scene_create_image_name.c
vendored
Normal 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);
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user