mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-25 03:29:58 -07:00
Move Mass Storage app to firmware repo
This commit is contained in:
30
applications/system/mass_storage/scenes/mass_storage_scene.c
Normal file
30
applications/system/mass_storage/scenes/mass_storage_scene.c
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "mass_storage_scene.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const mass_storage_scene_on_enter_handlers[])(void*) = {
|
||||
#include "mass_storage_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 mass_storage_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "mass_storage_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 mass_storage_scene_on_exit_handlers[])(void* context) = {
|
||||
#include "mass_storage_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers mass_storage_scene_handlers = {
|
||||
.on_enter_handlers = mass_storage_scene_on_enter_handlers,
|
||||
.on_event_handlers = mass_storage_scene_on_event_handlers,
|
||||
.on_exit_handlers = mass_storage_scene_on_exit_handlers,
|
||||
.scene_num = MassStorageSceneNum,
|
||||
};
|
||||
29
applications/system/mass_storage/scenes/mass_storage_scene.h
Normal file
29
applications/system/mass_storage/scenes/mass_storage_scene.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) MassStorageScene##id,
|
||||
typedef enum {
|
||||
#include "mass_storage_scene_config.h"
|
||||
MassStorageSceneNum,
|
||||
} MassStorageScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers mass_storage_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "mass_storage_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 "mass_storage_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 "mass_storage_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
@@ -0,0 +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)
|
||||
@@ -0,0 +1,188 @@
|
||||
#include "../mass_storage_app_i.h"
|
||||
#include <lib/toolbox/value_index.h>
|
||||
|
||||
enum VarItemListIndex {
|
||||
VarItemListIndexImageSize,
|
||||
VarItemListIndexImageName,
|
||||
VarItemListIndexCreateImage,
|
||||
};
|
||||
|
||||
void mass_storage_scene_create_image_variable_item_list_callback(void* context, uint32_t index) {
|
||||
MassStorageApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
static const struct {
|
||||
char* name;
|
||||
uint64_t value;
|
||||
} image_sizes[] = {
|
||||
{"1MB", 1LL * 1024 * 1024},
|
||||
{"2MB", 2LL * 1024 * 1024},
|
||||
{"4MB", 4LL * 1024 * 1024},
|
||||
{"8MB", 8LL * 1024 * 1024},
|
||||
{"16MB", 16LL * 1024 * 1024},
|
||||
{"32MB", 32LL * 1024 * 1024},
|
||||
{"64MB", 64LL * 1024 * 1024},
|
||||
{"128MB", 128LL * 1024 * 1024},
|
||||
{"256MB", 256LL * 1024 * 1024},
|
||||
{"512MB", 512LL * 1024 * 1024},
|
||||
{"1GB", 1LL * 1024 * 1024 * 1024},
|
||||
{"2GB", 2LL * 1024 * 1024 * 1024},
|
||||
{"4GB", 4LL * 1024 * 1024 * 1024},
|
||||
{"8GB", 8LL * 1024 * 1024 * 1024},
|
||||
{"16GB", 16LL * 1024 * 1024 * 1024},
|
||||
{"32GB", 32LL * 1024 * 1024 * 1024},
|
||||
{"64GB", 64LL * 1024 * 1024 * 1024},
|
||||
{"128GB", 128LL * 1024 * 1024 * 1024},
|
||||
{"256GB", 256LL * 1024 * 1024 * 1024},
|
||||
{"512GB", 512LL * 1024 * 1024 * 1024},
|
||||
};
|
||||
static void mass_storage_scene_create_image_image_size_changed(VariableItem* item) {
|
||||
MassStorageApp* app = variable_item_get_context(item);
|
||||
app->create_image_size = variable_item_get_current_value_index(item);
|
||||
variable_item_set_current_value_text(item, image_sizes[app->create_image_size].name);
|
||||
}
|
||||
|
||||
void mass_storage_scene_create_image_on_enter(void* context) {
|
||||
MassStorageApp* app = context;
|
||||
VariableItemList* variable_item_list = app->variable_item_list;
|
||||
VariableItem* item;
|
||||
|
||||
uint8_t size_count = COUNT_OF(image_sizes);
|
||||
if(app->create_image_max) {
|
||||
for(size_t i = 1; i < size_count; i++) {
|
||||
if(image_sizes[i].value > app->create_image_max) {
|
||||
size_count = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(app->create_image_size == (uint8_t)-1) {
|
||||
app->create_image_size = CLAMP(7, size_count - 2, 0); // 7 = 128MB
|
||||
}
|
||||
item = variable_item_list_add(
|
||||
variable_item_list,
|
||||
"Image Size",
|
||||
size_count,
|
||||
mass_storage_scene_create_image_image_size_changed,
|
||||
app);
|
||||
variable_item_set_current_value_index(item, app->create_image_size);
|
||||
variable_item_set_current_value_text(item, image_sizes[app->create_image_size].name);
|
||||
|
||||
item = variable_item_list_add(variable_item_list, "Image Name", 0, NULL, app);
|
||||
variable_item_set_current_value_text(item, app->create_image_name);
|
||||
|
||||
variable_item_list_add(variable_item_list, "Create Image", 0, NULL, app);
|
||||
|
||||
variable_item_list_set_enter_callback(
|
||||
variable_item_list, mass_storage_scene_create_image_variable_item_list_callback, app);
|
||||
|
||||
variable_item_list_set_header(variable_item_list, "Create Disk Image");
|
||||
|
||||
variable_item_list_set_selected_item(
|
||||
variable_item_list,
|
||||
scene_manager_get_scene_state(app->scene_manager, MassStorageSceneCreateImage));
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, MassStorageAppViewStart);
|
||||
}
|
||||
|
||||
static void popup_callback_ok(void* context) {
|
||||
MassStorageApp* app = context;
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, MassStorageSceneStart, MassStorageSceneFileSelect);
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
scene_manager_next_scene(app->scene_manager, MassStorageSceneFileSelect);
|
||||
}
|
||||
|
||||
static void popup_callback_error(void* context) {
|
||||
MassStorageApp* app = context;
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, MassStorageAppViewStart);
|
||||
}
|
||||
|
||||
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 VarItemListIndexImageName:
|
||||
scene_manager_next_scene(app->scene_manager, MassStorageSceneCreateImageName);
|
||||
break;
|
||||
case VarItemListIndexCreateImage: {
|
||||
mass_storage_app_show_loading_popup(app, true);
|
||||
const char* name = strnlen(app->create_image_name, sizeof(app->create_image_name)) ?
|
||||
app->create_image_name :
|
||||
image_sizes[app->create_image_size].name;
|
||||
furi_string_printf(
|
||||
app->file_path,
|
||||
"%s/%s%s",
|
||||
MASS_STORAGE_APP_PATH_FOLDER,
|
||||
name,
|
||||
MASS_STORAGE_APP_EXTENSION);
|
||||
|
||||
app->file = storage_file_alloc(app->fs_api);
|
||||
const char* error = NULL;
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if(!storage_file_open(
|
||||
app->file,
|
||||
furi_string_get_cstr(app->file_path),
|
||||
FSAM_WRITE,
|
||||
FSOM_CREATE_NEW))
|
||||
break;
|
||||
|
||||
uint64_t size = image_sizes[app->create_image_size].value;
|
||||
if(size == app->create_image_max) size--;
|
||||
if(!storage_file_expand(app->file, size)) break;
|
||||
|
||||
// Format as exFAT
|
||||
if(storage_virtual_init(app->fs_api, app->file) != FSE_OK) break;
|
||||
if(storage_virtual_format(app->fs_api) != FSE_OK) break;
|
||||
if(storage_virtual_quit(app->fs_api) != FSE_OK) break;
|
||||
|
||||
success = true;
|
||||
} while(false);
|
||||
|
||||
if(!success) {
|
||||
error = storage_file_get_error_desc(app->file);
|
||||
FS_Error error = storage_file_get_error(app->file);
|
||||
storage_file_close(app->file);
|
||||
if(error != FSE_EXIST) {
|
||||
storage_common_remove(app->fs_api, furi_string_get_cstr(app->file_path));
|
||||
}
|
||||
}
|
||||
storage_file_free(app->file);
|
||||
mass_storage_app_show_loading_popup(app, false);
|
||||
|
||||
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);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void mass_storage_scene_create_image_on_exit(void* context) {
|
||||
MassStorageApp* app = context;
|
||||
variable_item_list_reset(app->variable_item_list);
|
||||
}
|
||||
@@ -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, "Image name, empty = 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_image_name,
|
||||
sizeof(app->create_image_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);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#include "../mass_storage_app_i.h"
|
||||
#include "furi_hal_power.h"
|
||||
|
||||
static bool mass_storage_file_select(MassStorageApp* mass_storage) {
|
||||
furi_assert(mass_storage);
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(&browser_options, ".img|.iso", &I_floppydisk_10px);
|
||||
browser_options.base_path = MASS_STORAGE_APP_PATH_FOLDER;
|
||||
browser_options.hide_ext = false;
|
||||
|
||||
// Input events and views are managed by file_select
|
||||
bool res = dialog_file_browser_show(
|
||||
mass_storage->dialogs, mass_storage->file_path, mass_storage->file_path, &browser_options);
|
||||
return res;
|
||||
}
|
||||
|
||||
void mass_storage_scene_file_select_on_enter(void* context) {
|
||||
MassStorageApp* mass_storage = context;
|
||||
|
||||
if(mass_storage_file_select(mass_storage)) {
|
||||
scene_manager_next_scene(mass_storage->scene_manager, MassStorageSceneWork);
|
||||
} else {
|
||||
scene_manager_previous_scene(mass_storage->scene_manager);
|
||||
}
|
||||
}
|
||||
|
||||
bool mass_storage_scene_file_select_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
// MassStorageApp* mass_storage = context;
|
||||
return false;
|
||||
}
|
||||
|
||||
void mass_storage_scene_file_select_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
#include "../mass_storage_app_i.h"
|
||||
|
||||
enum VarItemListIndex {
|
||||
VarItemListIndexSelectDiskImage,
|
||||
VarItemListIndexCreateDiskImage,
|
||||
};
|
||||
|
||||
static void mass_storage_scene_start_variable_item_list_callback(void* context, uint32_t index) {
|
||||
MassStorageApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void mass_storage_scene_start_on_enter(void* context) {
|
||||
MassStorageApp* app = context;
|
||||
VariableItemList* variable_item_list = app->variable_item_list;
|
||||
|
||||
variable_item_list_add(variable_item_list, "Select Disk Image", 0, NULL, app);
|
||||
|
||||
variable_item_list_add(variable_item_list, "Create Disk Image", 0, NULL, app);
|
||||
|
||||
variable_item_list_set_enter_callback(
|
||||
variable_item_list, mass_storage_scene_start_variable_item_list_callback, app);
|
||||
|
||||
variable_item_list_set_header(variable_item_list, "USB Mass Storage");
|
||||
|
||||
variable_item_list_set_selected_item(
|
||||
variable_item_list,
|
||||
scene_manager_get_scene_state(app->scene_manager, MassStorageSceneStart));
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, MassStorageAppViewStart);
|
||||
}
|
||||
|
||||
bool mass_storage_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
MassStorageApp* app = context;
|
||||
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
scene_manager_set_scene_state(app->scene_manager, MassStorageSceneStart, event.event);
|
||||
consumed = true;
|
||||
switch(event.event) {
|
||||
case VarItemListIndexSelectDiskImage:
|
||||
scene_manager_next_scene(app->scene_manager, MassStorageSceneFileSelect);
|
||||
break;
|
||||
case VarItemListIndexCreateDiskImage:
|
||||
scene_manager_set_scene_state(app->scene_manager, MassStorageSceneCreateImage, 0);
|
||||
scene_manager_next_scene(app->scene_manager, MassStorageSceneCreateImage);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void mass_storage_scene_start_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
MassStorageApp* app = context;
|
||||
variable_item_list_reset(app->variable_item_list);
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
#include "../mass_storage_app_i.h"
|
||||
#include "../views/mass_storage_view.h"
|
||||
#include "../helpers/mass_storage_usb.h"
|
||||
#include <lib/toolbox/path.h>
|
||||
|
||||
#define TAG "MassStorageSceneWork"
|
||||
|
||||
static bool file_read(
|
||||
void* ctx,
|
||||
uint32_t lba,
|
||||
uint16_t count,
|
||||
uint8_t* out,
|
||||
uint32_t* out_len,
|
||||
uint32_t out_cap) {
|
||||
MassStorageApp* app = ctx;
|
||||
FURI_LOG_T(TAG, "file_read lba=%08lX count=%04X out_cap=%08lX", lba, count, out_cap);
|
||||
if(!storage_file_seek(app->file, lba * SCSI_BLOCK_SIZE, true)) {
|
||||
FURI_LOG_W(TAG, "seek failed");
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
static bool file_write(void* ctx, uint32_t lba, uint16_t count, uint8_t* buf, uint32_t len) {
|
||||
MassStorageApp* app = ctx;
|
||||
FURI_LOG_T(TAG, "file_write lba=%08lX count=%04X len=%08lX", lba, count, len);
|
||||
if(len != count * SCSI_BLOCK_SIZE) {
|
||||
FURI_LOG_W(TAG, "bad write params count=%u len=%lu", count, len);
|
||||
return false;
|
||||
}
|
||||
if(!storage_file_seek(app->file, lba * SCSI_BLOCK_SIZE, true)) {
|
||||
FURI_LOG_W(TAG, "seek failed");
|
||||
return false;
|
||||
}
|
||||
app->bytes_written += len;
|
||||
return storage_file_write(app->file, buf, len) == len;
|
||||
}
|
||||
|
||||
static uint32_t file_num_blocks(void* ctx) {
|
||||
MassStorageApp* app = ctx;
|
||||
return storage_file_size(app->file) / SCSI_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
static void file_eject(void* ctx) {
|
||||
MassStorageApp* app = ctx;
|
||||
FURI_LOG_D(TAG, "EJECT");
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, MassStorageCustomEventEject);
|
||||
}
|
||||
|
||||
bool mass_storage_scene_work_on_event(void* context, SceneManagerEvent event) {
|
||||
MassStorageApp* app = context;
|
||||
bool consumed = false;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == MassStorageCustomEventEject) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, MassStorageSceneFileSelect);
|
||||
if(!consumed) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, MassStorageSceneStart);
|
||||
}
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
mass_storage_set_stats(app->mass_storage_view, app->bytes_read, app->bytes_written);
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, MassStorageSceneFileSelect);
|
||||
if(!consumed) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, MassStorageSceneStart);
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
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(
|
||||
app->scene_manager, MassStorageSceneStart);
|
||||
return;
|
||||
}
|
||||
|
||||
mass_storage_app_show_loading_popup(app, true);
|
||||
|
||||
app->usb_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
|
||||
FuriString* file_name = furi_string_alloc();
|
||||
path_extract_filename(app->file_path, file_name, true);
|
||||
|
||||
mass_storage_set_file_name(app->mass_storage_view, file_name);
|
||||
app->file = storage_file_alloc(app->fs_api);
|
||||
furi_assert(storage_file_open(
|
||||
app->file,
|
||||
furi_string_get_cstr(app->file_path),
|
||||
FSAM_READ | FSAM_WRITE,
|
||||
FSOM_OPEN_EXISTING));
|
||||
|
||||
SCSIDeviceFunc fn = {
|
||||
.ctx = app,
|
||||
.read = file_read,
|
||||
.write = file_write,
|
||||
.num_blocks = file_num_blocks,
|
||||
.eject = file_eject,
|
||||
};
|
||||
|
||||
app->usb = mass_storage_usb_start(furi_string_get_cstr(file_name), fn);
|
||||
|
||||
furi_string_free(file_name);
|
||||
|
||||
mass_storage_app_show_loading_popup(app, false);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, MassStorageAppViewWork);
|
||||
}
|
||||
|
||||
void mass_storage_scene_work_on_exit(void* context) {
|
||||
MassStorageApp* app = context;
|
||||
mass_storage_app_show_loading_popup(app, true);
|
||||
|
||||
if(app->usb_mutex) {
|
||||
furi_mutex_free(app->usb_mutex);
|
||||
app->usb_mutex = NULL;
|
||||
}
|
||||
if(app->usb) {
|
||||
mass_storage_usb_stop(app->usb);
|
||||
app->usb = NULL;
|
||||
}
|
||||
if(app->file) {
|
||||
storage_file_free(app->file);
|
||||
app->file = NULL;
|
||||
}
|
||||
mass_storage_app_show_loading_popup(app, false);
|
||||
}
|
||||
Reference in New Issue
Block a user