[FL-1191][FL-1524] Filesystem rework (#568)
* FS-Api: removed datetime manipulation functions and most of the file flags * Filesystem: common proxy api * Filesystem: renamed to Storage. Work has begun on a glue layer. Added functions for reentrance. * Storage: sd mount and sd file open * Storage: sd file close * Storage: temporary test app * Storage: free filedata on close * Storage: sd file read and write * Storage: added internal storage (LittleFS) * Storage: renamed internal commands * Storage: seek, tell, truncate, size, sync, eof * Storage: error descriptions * Storage: directory management api (open, close, read, rewind) * Storage: common management api (stat, fs_stat, remove, rename, mkdir) * Dolphin app and Notifications app now use raw storage. * Storage: storage statuses renamed. Implemented sd card icon. * Storage: added raw sd-card api. * Storage settings: work started * Assets: use new icons approach * Storage settings: working storage settings * Storage: completely redesigned api, no longer sticking out FS_Api * Storage: more simplified api, getting error_id from file is hidden from user, pointer to api is hidden inside file * Storage: cli info and format commands * Storage-cli: file list * Storage: a simpler and more reliable api * FatFS: slightly lighter and faster config. Also disabled reentrancy and file locking functions. They moved to a storage service. * Storage-cli: accommodate to the new cli api. * Storage: filesystem api is separated into internal and common api. * Cli: added the ability to print the list of free heap blocks * Storage: uses a list instead of an array to store the StorageFile. Rewrote api calls to use semaphores instead of thread flags. * Storage settings: added the ability to benchmark the SD card. * Gui module file select: uses new storage api * Apps: removed deprecated sd_card_test application * Args lib: support for enquoted arguments * Dialogs: a new gui app for simple non-asynchronous apps * Dialogs: view holder for easy single view work * File worker: use new storage api * IButton and lfrrfid apps: save keys to any storage * Apps: fix ibutton and lfrfid stack, remove sd_card_test. * SD filesystem: app removed * File worker: fixed api pointer type * Subghz: loading assets using the new storage api * NFC: use the new storage api * Dialogs: the better api for the message element * Archive: use new storage api * Irda: changed assest path, changed app path * FileWorker: removed unused file_buf_cnt * Storage: copying and renaming files now works between storages * Storage cli: read, copy, remove, rename commands * Archive: removed commented code * Storage cli: write command * Applications: add SRV_STORAGE and SRV_DIALOGS * Internal-storage: removed * Storage: improved api * Storage app: changed api pointer from StorageApp to Storage * Storage: better file_id handling * Storage: more consistent errors * Loader: support for NULL icons * Storage: do nothing with the lfs file or directory if it is not open * Storage: fix typo * Storage: minor float usage cleanup, rename some symbols. * Storage: compact doxygen comments. Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
#include "../storage-settings.h"
|
||||
|
||||
#define BENCH_DATA_SIZE 4096
|
||||
#define BENCH_COUNT 6
|
||||
#define BENCH_REPEATS 4
|
||||
#define BENCH_FILE "/ext/rwfiletest.bin"
|
||||
|
||||
static void
|
||||
storage_settings_scene_benchmark_dialog_callback(DialogExResult result, void* context) {
|
||||
StorageSettings* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
|
||||
static bool storage_settings_bench_write(
|
||||
Storage* api,
|
||||
uint16_t size,
|
||||
const uint8_t* data,
|
||||
uint32_t* speed) {
|
||||
File* file = storage_file_alloc(api);
|
||||
bool result = true;
|
||||
if(storage_file_open(file, BENCH_FILE, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
|
||||
uint32_t ticks;
|
||||
ticks = osKernelGetTickCount();
|
||||
|
||||
for(size_t repeat = 0; repeat < BENCH_REPEATS; repeat++) {
|
||||
for(size_t i = 0; i < BENCH_DATA_SIZE / size; i++) {
|
||||
if(storage_file_write(file, (data + i * size), size) != size) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ticks = osKernelGetTickCount() - ticks;
|
||||
*speed = BENCH_DATA_SIZE * osKernelGetTickFreq() * BENCH_REPEATS;
|
||||
*speed /= ticks;
|
||||
*speed /= 1024;
|
||||
}
|
||||
storage_file_close(file);
|
||||
storage_file_free(file);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool
|
||||
storage_settings_bench_read(Storage* api, uint16_t size, uint8_t* data, uint32_t* speed) {
|
||||
File* file = storage_file_alloc(api);
|
||||
bool result = true;
|
||||
*speed = -1;
|
||||
|
||||
if(storage_file_open(file, BENCH_FILE, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
uint32_t ticks;
|
||||
ticks = osKernelGetTickCount();
|
||||
|
||||
for(size_t repeat = 0; repeat < BENCH_REPEATS; repeat++) {
|
||||
for(size_t i = 0; i < BENCH_DATA_SIZE / size; i++) {
|
||||
if(storage_file_read(file, (data + i * size), size) != size) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ticks = osKernelGetTickCount() - ticks;
|
||||
*speed = BENCH_DATA_SIZE * osKernelGetTickFreq() * BENCH_REPEATS;
|
||||
*speed /= ticks;
|
||||
*speed /= 1024;
|
||||
}
|
||||
storage_file_close(file);
|
||||
storage_file_free(file);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void storage_settings_benchmark(StorageSettings* app) {
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
uint8_t* bench_data;
|
||||
dialog_ex_set_header(dialog_ex, "Preparing data...", 64, 32, AlignCenter, AlignCenter);
|
||||
|
||||
bench_data = malloc(BENCH_DATA_SIZE);
|
||||
for(size_t i = 0; i < BENCH_DATA_SIZE; i++) {
|
||||
bench_data[i] = (uint8_t)i;
|
||||
}
|
||||
|
||||
uint16_t bench_size[BENCH_COUNT] = {1, 8, 32, 256, 1024, 4096};
|
||||
uint32_t bench_w_speed[BENCH_COUNT] = {0, 0, 0, 0, 0, 0};
|
||||
uint32_t bench_r_speed[BENCH_COUNT] = {0, 0, 0, 0, 0, 0};
|
||||
|
||||
dialog_ex_set_header(dialog_ex, "Benchmarking...", 64, 32, AlignCenter, AlignCenter);
|
||||
for(size_t i = 0; i < BENCH_COUNT; i++) {
|
||||
if(!storage_settings_bench_write(app->fs_api, bench_size[i], bench_data, &bench_w_speed[i]))
|
||||
break;
|
||||
|
||||
if(i > 0) string_cat_printf(app->text_string, "\n");
|
||||
string_cat_printf(app->text_string, "%ub : W %luK ", bench_size[i], bench_w_speed[i]);
|
||||
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, string_get_cstr(app->text_string), 0, 32, AlignLeft, AlignCenter);
|
||||
|
||||
if(!storage_settings_bench_read(app->fs_api, bench_size[i], bench_data, &bench_r_speed[i]))
|
||||
break;
|
||||
|
||||
string_cat_printf(app->text_string, "R %luK", bench_r_speed[i]);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, string_get_cstr(app->text_string), 0, 32, AlignLeft, AlignCenter);
|
||||
}
|
||||
|
||||
free(bench_data);
|
||||
}
|
||||
|
||||
void storage_settings_scene_benchmark_on_enter(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
dialog_ex_set_result_callback(dialog_ex, storage_settings_scene_benchmark_dialog_callback);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
|
||||
|
||||
if(storage_sd_status(app->fs_api) != FSE_OK) {
|
||||
dialog_ex_set_header(dialog_ex, "SD card not mounted", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex,
|
||||
"If an SD card is inserted,\r\npull it out and reinsert it",
|
||||
64,
|
||||
32,
|
||||
AlignCenter,
|
||||
AlignCenter);
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Back");
|
||||
} else {
|
||||
storage_settings_benchmark(app);
|
||||
notification_message(app->notification, &sequence_blink_green_100);
|
||||
}
|
||||
}
|
||||
|
||||
bool storage_settings_scene_benchmark_on_event(void* context, SceneManagerEvent event) {
|
||||
StorageSettings* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DialogExResultLeft:
|
||||
consumed = scene_manager_previous_scene(app->scene_manager);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void storage_settings_scene_benchmark_on_exit(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
|
||||
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
|
||||
dialog_ex_set_left_button_text(dialog_ex, NULL);
|
||||
dialog_ex_set_right_button_text(dialog_ex, NULL);
|
||||
dialog_ex_set_result_callback(dialog_ex, NULL);
|
||||
dialog_ex_set_context(dialog_ex, NULL);
|
||||
|
||||
string_clean(app->text_string);
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
ADD_SCENE(storage_settings, start, Start)
|
||||
ADD_SCENE(storage_settings, unmount_confirm, UnmountConfirm)
|
||||
ADD_SCENE(storage_settings, unmounted, Unmounted)
|
||||
ADD_SCENE(storage_settings, format_confirm, FormatConfirm)
|
||||
ADD_SCENE(storage_settings, formatting, Formatting)
|
||||
ADD_SCENE(storage_settings, sd_info, SDInfo)
|
||||
ADD_SCENE(storage_settings, internal_info, InternalInfo)
|
||||
ADD_SCENE(storage_settings, benchmark, Benchmark)
|
@@ -0,0 +1,68 @@
|
||||
#include "../storage-settings.h"
|
||||
|
||||
static void
|
||||
storage_settings_scene_unmount_confirm_dialog_callback(DialogExResult result, void* context) {
|
||||
StorageSettings* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void storage_settings_scene_unmount_confirm_on_enter(void* context) {
|
||||
StorageSettings* app = context;
|
||||
FS_Error sd_status = storage_sd_status(app->fs_api);
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Back");
|
||||
|
||||
if(sd_status == FSE_NOT_READY) {
|
||||
dialog_ex_set_header(dialog_ex, "SD card not mounted", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex,
|
||||
"If an SD card is inserted,\r\npull it out and reinsert it",
|
||||
64,
|
||||
32,
|
||||
AlignCenter,
|
||||
AlignCenter);
|
||||
} else {
|
||||
dialog_ex_set_right_button_text(dialog_ex, "Unmount");
|
||||
dialog_ex_set_header(dialog_ex, "Unmount SD card?", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "SD card will be\nunavailable", 64, 32, AlignCenter, AlignCenter);
|
||||
}
|
||||
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
dialog_ex_set_result_callback(
|
||||
dialog_ex, storage_settings_scene_unmount_confirm_dialog_callback);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
|
||||
}
|
||||
|
||||
bool storage_settings_scene_unmount_confirm_on_event(void* context, SceneManagerEvent event) {
|
||||
StorageSettings* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DialogExResultLeft:
|
||||
consumed = scene_manager_previous_scene(app->scene_manager);
|
||||
break;
|
||||
case DialogExResultRight:
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsUnmounted);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void storage_settings_scene_unmount_confirm_on_exit(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
|
||||
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
|
||||
dialog_ex_set_left_button_text(dialog_ex, NULL);
|
||||
dialog_ex_set_right_button_text(dialog_ex, NULL);
|
||||
dialog_ex_set_result_callback(dialog_ex, NULL);
|
||||
dialog_ex_set_context(dialog_ex, NULL);
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
#include "../storage-settings.h"
|
||||
|
||||
static void
|
||||
storage_settings_scene_unmounted_dialog_callback(DialogExResult result, void* context) {
|
||||
StorageSettings* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void storage_settings_scene_unmounted_on_enter(void* context) {
|
||||
StorageSettings* app = context;
|
||||
FS_Error error = storage_sd_unmount(app->fs_api);
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Back");
|
||||
|
||||
if(error == FSE_OK) {
|
||||
dialog_ex_set_header(dialog_ex, "SD card unmounted", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "Now the SD card\ncan be removed.", 64, 32, AlignCenter, AlignCenter);
|
||||
notification_message(app->notification, &sequence_blink_green_100);
|
||||
} else {
|
||||
dialog_ex_set_header(
|
||||
dialog_ex, "Cannot unmount SD Card", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, storage_error_get_desc(error), 64, 32, AlignCenter, AlignCenter);
|
||||
notification_message(app->notification, &sequence_blink_red_100);
|
||||
}
|
||||
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
dialog_ex_set_result_callback(dialog_ex, storage_settings_scene_unmounted_dialog_callback);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
|
||||
}
|
||||
|
||||
bool storage_settings_scene_unmounted_on_event(void* context, SceneManagerEvent event) {
|
||||
StorageSettings* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DialogExResultLeft:
|
||||
consumed =
|
||||
scene_manager_search_previous_scene(app->scene_manager, StorageSettingsStart);
|
||||
break;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeNavigation) {
|
||||
consumed = scene_manager_search_previous_scene(app->scene_manager, StorageSettingsStart);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void storage_settings_scene_unmounted_on_exit(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
|
||||
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
|
||||
dialog_ex_set_left_button_text(dialog_ex, NULL);
|
||||
dialog_ex_set_right_button_text(dialog_ex, NULL);
|
||||
dialog_ex_set_result_callback(dialog_ex, NULL);
|
||||
dialog_ex_set_context(dialog_ex, NULL);
|
||||
}
|
@@ -0,0 +1,67 @@
|
||||
#include "../storage-settings.h"
|
||||
|
||||
static void
|
||||
storage_settings_scene_format_confirm_dialog_callback(DialogExResult result, void* context) {
|
||||
StorageSettings* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void storage_settings_scene_format_confirm_on_enter(void* context) {
|
||||
StorageSettings* app = context;
|
||||
FS_Error sd_status = storage_sd_status(app->fs_api);
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Back");
|
||||
|
||||
if(sd_status == FSE_NOT_READY) {
|
||||
dialog_ex_set_header(dialog_ex, "SD card not mounted", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex,
|
||||
"If an SD card is inserted,\r\npull it out and reinsert it",
|
||||
64,
|
||||
32,
|
||||
AlignCenter,
|
||||
AlignCenter);
|
||||
} else {
|
||||
dialog_ex_set_right_button_text(dialog_ex, "Format");
|
||||
dialog_ex_set_header(dialog_ex, "Format SD card?", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(dialog_ex, "All data will be lost", 64, 32, AlignCenter, AlignCenter);
|
||||
}
|
||||
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
dialog_ex_set_result_callback(
|
||||
dialog_ex, storage_settings_scene_format_confirm_dialog_callback);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
|
||||
}
|
||||
|
||||
bool storage_settings_scene_format_confirm_on_event(void* context, SceneManagerEvent event) {
|
||||
StorageSettings* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DialogExResultLeft:
|
||||
consumed = scene_manager_previous_scene(app->scene_manager);
|
||||
break;
|
||||
case DialogExResultRight:
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsFormatting);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void storage_settings_scene_format_confirm_on_exit(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
|
||||
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
|
||||
dialog_ex_set_left_button_text(dialog_ex, NULL);
|
||||
dialog_ex_set_right_button_text(dialog_ex, NULL);
|
||||
dialog_ex_set_result_callback(dialog_ex, NULL);
|
||||
dialog_ex_set_context(dialog_ex, NULL);
|
||||
}
|
@@ -0,0 +1,85 @@
|
||||
#include "../storage-settings.h"
|
||||
|
||||
static const NotificationMessage message_green_165 = {
|
||||
.type = NotificationMessageTypeLedGreen,
|
||||
.data.led.value = 165,
|
||||
};
|
||||
|
||||
static const NotificationSequence sequence_set_formatting_leds = {
|
||||
&message_red_255,
|
||||
&message_green_165,
|
||||
&message_blue_0,
|
||||
&message_do_not_reset,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const NotificationSequence sequence_reset_formatting_leds = {
|
||||
&message_red_0,
|
||||
&message_green_0,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void
|
||||
storage_settings_scene_formatting_dialog_callback(DialogExResult result, void* context) {
|
||||
StorageSettings* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void storage_settings_scene_formatting_on_enter(void* context) {
|
||||
StorageSettings* app = context;
|
||||
FS_Error error;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_set_header(dialog_ex, "Formatting...", 64, 32, AlignCenter, AlignCenter);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
|
||||
|
||||
notification_message_block(app->notification, &sequence_set_formatting_leds);
|
||||
error = storage_sd_format(app->fs_api);
|
||||
notification_message(app->notification, &sequence_reset_formatting_leds);
|
||||
notification_message(app->notification, &sequence_blink_green_100);
|
||||
|
||||
if(error != FSE_OK) {
|
||||
dialog_ex_set_header(dialog_ex, "Cannot format SD Card", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, storage_error_get_desc(error), 64, 32, AlignCenter, AlignCenter);
|
||||
} else {
|
||||
dialog_ex_set_header(dialog_ex, "SD card formatted", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(dialog_ex, "Press back to return", 64, 32, AlignCenter, AlignCenter);
|
||||
}
|
||||
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
dialog_ex_set_result_callback(dialog_ex, storage_settings_scene_formatting_dialog_callback);
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Back");
|
||||
}
|
||||
|
||||
bool storage_settings_scene_formatting_on_event(void* context, SceneManagerEvent event) {
|
||||
StorageSettings* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DialogExResultLeft:
|
||||
consumed =
|
||||
scene_manager_search_previous_scene(app->scene_manager, StorageSettingsStart);
|
||||
break;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeNavigation) {
|
||||
consumed = scene_manager_search_previous_scene(app->scene_manager, StorageSettingsStart);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void storage_settings_scene_formatting_on_exit(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
|
||||
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
|
||||
dialog_ex_set_left_button_text(dialog_ex, NULL);
|
||||
dialog_ex_set_right_button_text(dialog_ex, NULL);
|
||||
dialog_ex_set_result_callback(dialog_ex, NULL);
|
||||
dialog_ex_set_context(dialog_ex, NULL);
|
||||
}
|
@@ -0,0 +1,68 @@
|
||||
#include "../storage-settings.h"
|
||||
#include <api-hal-version.h>
|
||||
|
||||
static void
|
||||
storage_settings_scene_internal_info_dialog_callback(DialogExResult result, void* context) {
|
||||
StorageSettings* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void storage_settings_scene_internal_info_on_enter(void* context) {
|
||||
StorageSettings* app = context;
|
||||
uint64_t total_space;
|
||||
uint64_t free_space;
|
||||
FS_Error error = storage_common_fs_info(app->fs_api, "/int", &total_space, &free_space);
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
dialog_ex_set_result_callback(dialog_ex, storage_settings_scene_internal_info_dialog_callback);
|
||||
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Back");
|
||||
if(error != FSE_OK) {
|
||||
dialog_ex_set_header(
|
||||
dialog_ex, "Internal storage error", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, storage_error_get_desc(error), 64, 32, AlignCenter, AlignCenter);
|
||||
} else {
|
||||
string_printf(
|
||||
app->text_string,
|
||||
"Label: %s\nType: LittleFS\n%lu KB total\n%lu KB free",
|
||||
api_hal_version_get_name_ptr(),
|
||||
(uint32_t)(total_space / 1024),
|
||||
(uint32_t)(free_space / 1024));
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, string_get_cstr(app->text_string), 4, 4, AlignLeft, AlignTop);
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
|
||||
}
|
||||
|
||||
bool storage_settings_scene_internal_info_on_event(void* context, SceneManagerEvent event) {
|
||||
StorageSettings* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DialogExResultLeft:
|
||||
consumed = scene_manager_previous_scene(app->scene_manager);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void storage_settings_scene_internal_info_on_exit(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
|
||||
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
|
||||
dialog_ex_set_left_button_text(dialog_ex, NULL);
|
||||
dialog_ex_set_right_button_text(dialog_ex, NULL);
|
||||
dialog_ex_set_result_callback(dialog_ex, NULL);
|
||||
dialog_ex_set_context(dialog_ex, NULL);
|
||||
|
||||
string_clean(app->text_string);
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
#include "../storage-settings.h"
|
||||
|
||||
static void storage_settings_scene_sd_info_dialog_callback(DialogExResult result, void* context) {
|
||||
StorageSettings* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void storage_settings_scene_sd_info_on_enter(void* context) {
|
||||
StorageSettings* app = context;
|
||||
SDInfo sd_info;
|
||||
FS_Error sd_status = storage_sd_info(app->fs_api, &sd_info);
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
dialog_ex_set_result_callback(dialog_ex, storage_settings_scene_sd_info_dialog_callback);
|
||||
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Back");
|
||||
if(sd_status != FSE_OK) {
|
||||
dialog_ex_set_header(dialog_ex, "SD card not mounted", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex,
|
||||
"If an SD card is inserted,\r\npull it out and reinsert it",
|
||||
64,
|
||||
32,
|
||||
AlignCenter,
|
||||
AlignCenter);
|
||||
} else {
|
||||
string_printf(
|
||||
app->text_string,
|
||||
"Label: %s\nType: %s\n%lu KB total\n%lu KB free",
|
||||
sd_info.label,
|
||||
sd_api_get_fs_type_text(sd_info.fs_type),
|
||||
sd_info.kb_total,
|
||||
sd_info.kb_free);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, string_get_cstr(app->text_string), 4, 4, AlignLeft, AlignTop);
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
|
||||
}
|
||||
|
||||
bool storage_settings_scene_sd_info_on_event(void* context, SceneManagerEvent event) {
|
||||
StorageSettings* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DialogExResultLeft:
|
||||
consumed = scene_manager_previous_scene(app->scene_manager);
|
||||
break;
|
||||
case DialogExResultRight:
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsUnmounted);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void storage_settings_scene_sd_info_on_exit(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(dialog_ex, NULL, 0, 0, AlignCenter, AlignTop);
|
||||
dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
|
||||
dialog_ex_set_left_button_text(dialog_ex, NULL);
|
||||
dialog_ex_set_right_button_text(dialog_ex, NULL);
|
||||
dialog_ex_set_result_callback(dialog_ex, NULL);
|
||||
dialog_ex_set_context(dialog_ex, NULL);
|
||||
|
||||
string_clean(app->text_string);
|
||||
}
|
@@ -0,0 +1,104 @@
|
||||
#include "../storage-settings.h"
|
||||
|
||||
enum StorageSettingsStartSubmenuIndex {
|
||||
StorageSettingsStartSubmenuIndexInternalInfo,
|
||||
StorageSettingsStartSubmenuIndexSDInfo,
|
||||
StorageSettingsStartSubmenuIndexUnmount,
|
||||
StorageSettingsStartSubmenuIndexFormat,
|
||||
StorageSettingsStartSubmenuIndexBenchy,
|
||||
};
|
||||
|
||||
static void storage_settings_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||
StorageSettings* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void storage_settings_scene_start_on_enter(void* context) {
|
||||
StorageSettings* app = context;
|
||||
Submenu* submenu = app->submenu;
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"About internal storage",
|
||||
StorageSettingsStartSubmenuIndexInternalInfo,
|
||||
storage_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"About SD Card",
|
||||
StorageSettingsStartSubmenuIndexSDInfo,
|
||||
storage_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Unmount SD Card",
|
||||
StorageSettingsStartSubmenuIndexUnmount,
|
||||
storage_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Format SD Card",
|
||||
StorageSettingsStartSubmenuIndexFormat,
|
||||
storage_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Benchmark SD Card",
|
||||
StorageSettingsStartSubmenuIndexBenchy,
|
||||
storage_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(app->scene_manager, StorageSettingsStart));
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewSubmenu);
|
||||
}
|
||||
|
||||
bool storage_settings_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
StorageSettings* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case StorageSettingsStartSubmenuIndexSDInfo:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, StorageSettingsStart, StorageSettingsStartSubmenuIndexSDInfo);
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsSDInfo);
|
||||
consumed = true;
|
||||
break;
|
||||
case StorageSettingsStartSubmenuIndexInternalInfo:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager,
|
||||
StorageSettingsStart,
|
||||
StorageSettingsStartSubmenuIndexInternalInfo);
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsInternalInfo);
|
||||
consumed = true;
|
||||
break;
|
||||
case StorageSettingsStartSubmenuIndexUnmount:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, StorageSettingsStart, StorageSettingsStartSubmenuIndexUnmount);
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsUnmountConfirm);
|
||||
consumed = true;
|
||||
break;
|
||||
case StorageSettingsStartSubmenuIndexFormat:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, StorageSettingsStart, StorageSettingsStartSubmenuIndexFormat);
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsFormatConfirm);
|
||||
consumed = true;
|
||||
break;
|
||||
case StorageSettingsStartSubmenuIndexBenchy:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, StorageSettingsStart, StorageSettingsStartSubmenuIndexBenchy);
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsBenchmark);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void storage_settings_scene_start_on_exit(void* context) {
|
||||
StorageSettings* app = context;
|
||||
submenu_clean(app->submenu);
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
#include "storage-settings-scene.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const storage_settings_on_enter_handlers[])(void*) = {
|
||||
#include "storage-settings-scene-config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
||||
bool (*const storage_settings_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "storage-settings-scene-config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
||||
void (*const storage_settings_on_exit_handlers[])(void* context) = {
|
||||
#include "storage-settings-scene-config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers storage_settings_scene_handlers = {
|
||||
.on_enter_handlers = storage_settings_on_enter_handlers,
|
||||
.on_event_handlers = storage_settings_on_event_handlers,
|
||||
.on_exit_handlers = storage_settings_on_exit_handlers,
|
||||
.scene_num = StorageSettingsSceneNum,
|
||||
};
|
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) StorageSettings##id,
|
||||
typedef enum {
|
||||
#include "storage-settings-scene-config.h"
|
||||
StorageSettingsSceneNum,
|
||||
} StorageSettingsScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers storage_settings_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "storage-settings-scene-config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) \
|
||||
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
||||
#include "storage-settings-scene-config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
||||
#include "storage-settings-scene-config.h"
|
||||
#undef ADD_SCENE
|
75
applications/storage-settings/storage-settings.c
Normal file
75
applications/storage-settings/storage-settings.c
Normal file
@@ -0,0 +1,75 @@
|
||||
#include "storage-settings.h"
|
||||
|
||||
static bool storage_settings_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
StorageSettings* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
static bool storage_settings_navigation_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
StorageSettings* app = context;
|
||||
return scene_manager_handle_navigation_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static StorageSettings* storage_settings_alloc() {
|
||||
StorageSettings* app = malloc(sizeof(StorageSettings));
|
||||
|
||||
app->gui = furi_record_open("gui");
|
||||
app->fs_api = furi_record_open("storage");
|
||||
app->notification = furi_record_open("notification");
|
||||
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
app->scene_manager = scene_manager_alloc(&storage_settings_scene_handlers, app);
|
||||
string_init(app->text_string);
|
||||
|
||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
||||
|
||||
view_dispatcher_set_custom_event_callback(
|
||||
app->view_dispatcher, storage_settings_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
app->view_dispatcher, storage_settings_navigation_event_callback);
|
||||
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
app->submenu = submenu_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, StorageSettingsViewSubmenu, submenu_get_view(app->submenu));
|
||||
|
||||
app->dialog_ex = dialog_ex_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, StorageSettingsViewDialogEx, dialog_ex_get_view(app->dialog_ex));
|
||||
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsStart);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
static void storage_settings_free(StorageSettings* app) {
|
||||
view_dispatcher_remove_view(app->view_dispatcher, StorageSettingsViewSubmenu);
|
||||
submenu_free(app->submenu);
|
||||
|
||||
view_dispatcher_remove_view(app->view_dispatcher, StorageSettingsViewDialogEx);
|
||||
dialog_ex_free(app->dialog_ex);
|
||||
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
scene_manager_free(app->scene_manager);
|
||||
|
||||
furi_record_close("gui");
|
||||
furi_record_close("storage");
|
||||
furi_record_close("notification");
|
||||
|
||||
string_clear(app->text_string);
|
||||
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t storage_settings(void* p) {
|
||||
StorageSettings* app = storage_settings_alloc();
|
||||
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
|
||||
storage_settings_free(app);
|
||||
return 0;
|
||||
}
|
47
applications/storage-settings/storage-settings.h
Normal file
47
applications/storage-settings/storage-settings.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <notification/notification-messages.h>
|
||||
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
#include <gui/modules/popup.h>
|
||||
|
||||
#include <storage/storage.h>
|
||||
#include <storage/storage-sd-api.h>
|
||||
|
||||
#include "scenes/storage-settings-scene.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
// records
|
||||
Gui* gui;
|
||||
NotificationApp* notification;
|
||||
Storage* fs_api;
|
||||
|
||||
// view managment
|
||||
SceneManager* scene_manager;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
|
||||
// view modules
|
||||
Submenu* submenu;
|
||||
DialogEx* dialog_ex;
|
||||
|
||||
// text
|
||||
string_t text_string;
|
||||
} StorageSettings;
|
||||
|
||||
typedef enum {
|
||||
StorageSettingsViewSubmenu,
|
||||
StorageSettingsViewDialogEx,
|
||||
} StorageSettingsView;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user