mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-14 12:28:36 -07:00
Refactor mass storage to current flipper api (WIP)
This commit is contained in:
13
applications/external/mass_storage/application.fam
vendored
Normal file
13
applications/external/mass_storage/application.fam
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
App(
|
||||
appid="mass_storage",
|
||||
name="USB Mass Storage",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="mass_storage_app",
|
||||
cdefines=["APP_MASS_STORAGE"],
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=2,
|
||||
# fap_icon="",
|
||||
fap_category="Misc",
|
||||
fap_libs=["assets"],
|
||||
)
|
||||
@@ -1,7 +1,5 @@
|
||||
#include "mass_storage_scsi.h"
|
||||
|
||||
#include <furi/log.h>
|
||||
|
||||
#define TAG "MassStorageSCSI"
|
||||
|
||||
#define SCSI_TEST_UNIT_READY (0x00)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define SCSI_BLOCK_SIZE (0x200)
|
||||
#define SCSI_BLOCK_SIZE (0x200u)
|
||||
|
||||
#define SCSI_SK_ILLEGAL_REQUEST (5)
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#define USB_MSC_TX_EP (0x82)
|
||||
|
||||
#define USB_MSC_RX_EP_SIZE (64)
|
||||
#define USB_MSC_TX_EP_SIZE (64)
|
||||
#define USB_MSC_TX_EP_SIZE (64u)
|
||||
|
||||
#define USB_MSC_BOT_GET_MAX_LUN (0xFE)
|
||||
#define USB_MSC_BOT_RESET (0xFF)
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
// must be SCSI_BLOCK_SIZE aligned
|
||||
// larger than 0x10000 exceeds size_t, storage_file_* ops fail
|
||||
#define USB_MSC_BUF_MAX (0x10000 - SCSI_BLOCK_SIZE)
|
||||
#define USB_MSC_BUF_MAX (0x10000u - SCSI_BLOCK_SIZE)
|
||||
|
||||
static usbd_respond usb_ep_config(usbd_device* dev, uint8_t cfg);
|
||||
static usbd_respond usb_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback);
|
||||
@@ -79,7 +79,7 @@ static int32_t mass_thread_worker(void* context) {
|
||||
StateWriteCSW,
|
||||
} state = StateReadCBW;
|
||||
while(true) {
|
||||
uint32_t flags = osThreadFlagsWait(EventAll, osFlagsWaitAny, osWaitForever);
|
||||
uint32_t flags = furi_thread_flags_wait(EventAll, FuriFlagWaitAny, FuriFlagWaitAny);
|
||||
if(flags & EventExit) {
|
||||
FURI_LOG_I(TAG, "exit");
|
||||
free(buf);
|
||||
@@ -235,7 +235,7 @@ static int32_t mass_thread_worker(void* context) {
|
||||
break;
|
||||
}
|
||||
if(len != sizeof(csw)) {
|
||||
FURI_LOG_W(TAG, "bad csw write %d", len);
|
||||
FURI_LOG_W(TAG, "bad csw write %ld", len);
|
||||
usbd_ep_stall(dev, USB_MSC_TX_EP);
|
||||
break;
|
||||
}
|
||||
@@ -255,6 +255,7 @@ static int32_t mass_thread_worker(void* context) {
|
||||
static MassStorageUsb* mass_cur = NULL;
|
||||
|
||||
static void usb_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx) {
|
||||
UNUSED(intf);
|
||||
MassStorageUsb* mass = ctx;
|
||||
mass_cur = mass;
|
||||
mass->dev = dev;
|
||||
@@ -283,7 +284,7 @@ static void usb_deinit(usbd_device* dev) {
|
||||
mass_cur = NULL;
|
||||
|
||||
furi_assert(mass->thread);
|
||||
osThreadFlagsSet(furi_thread_get_thread_id(mass->thread), EventExit);
|
||||
furi_thread_flags_set(furi_thread_get_id(mass->thread), EventExit);
|
||||
furi_thread_join(mass->thread);
|
||||
furi_thread_free(mass->thread);
|
||||
mass->thread = NULL;
|
||||
@@ -296,18 +297,21 @@ static void usb_deinit(usbd_device* dev) {
|
||||
}
|
||||
|
||||
static void usb_wakeup(usbd_device* dev) {
|
||||
UNUSED(dev);
|
||||
}
|
||||
|
||||
static void usb_suspend(usbd_device* dev) {
|
||||
MassStorageUsb* mass = mass_cur;
|
||||
if(!mass || mass->dev != dev) return;
|
||||
osThreadFlagsSet(furi_thread_get_thread_id(mass->thread), EventReset);
|
||||
furi_thread_flags_set(furi_thread_get_id(mass->thread), EventReset);
|
||||
}
|
||||
|
||||
static void usb_rxtx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) {
|
||||
UNUSED(event);
|
||||
UNUSED(ep);
|
||||
MassStorageUsb* mass = mass_cur;
|
||||
if(!mass || mass->dev != dev) return;
|
||||
osThreadFlagsSet(furi_thread_get_thread_id(mass->thread), EventRxTx);
|
||||
furi_thread_flags_set(furi_thread_get_id(mass->thread), EventRxTx);
|
||||
}
|
||||
|
||||
static usbd_respond usb_ep_config(usbd_device* dev, uint8_t cfg) {
|
||||
@@ -331,6 +335,7 @@ static usbd_respond usb_ep_config(usbd_device* dev, uint8_t cfg) {
|
||||
}
|
||||
|
||||
static usbd_respond usb_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback) {
|
||||
UNUSED(callback);
|
||||
if(((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) !=
|
||||
(USB_REQ_INTERFACE | USB_REQ_CLASS)) {
|
||||
return usbd_fail;
|
||||
@@ -345,7 +350,7 @@ static usbd_respond usb_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_cal
|
||||
case USB_MSC_BOT_RESET: {
|
||||
MassStorageUsb* mass = mass_cur;
|
||||
if(!mass || mass->dev != dev) return usbd_fail;
|
||||
osThreadFlagsSet(furi_thread_get_thread_id(mass->thread), EventReset);
|
||||
furi_thread_flags_set(furi_thread_get_id(mass->thread), EventReset);
|
||||
return usbd_ack;
|
||||
}; break;
|
||||
}
|
||||
|
||||
@@ -40,19 +40,20 @@ MassStorageApp* mass_storage_app_alloc(char* arg) {
|
||||
memset(app, 0, sizeof(MassStorageApp));
|
||||
|
||||
if(arg != NULL) {
|
||||
string_t filename;
|
||||
string_init_set(filename, arg);
|
||||
if(string_start_with_str_p(filename, MASS_STORAGE_APP_PATH_FOLDER)) {
|
||||
string_right(filename, strlen(MASS_STORAGE_APP_PATH_FOLDER) + 1);
|
||||
FuriString* filename = furi_string_alloc_set(arg);
|
||||
if(furi_string_start_with_str(filename, MASS_STORAGE_APP_PATH_FOLDER)) {
|
||||
furi_string_right(filename, strlen(MASS_STORAGE_APP_PATH_FOLDER) + 1);
|
||||
}
|
||||
strncpy(app->file_name, string_get_cstr(filename), MASS_STORAGE_FILE_NAME_LEN);
|
||||
string_clear(filename);
|
||||
strlcpy(app->file_name, furi_string_get_cstr(filename), MASS_STORAGE_FILE_NAME_LEN);
|
||||
furi_string_free(filename);
|
||||
}
|
||||
|
||||
app->gui = furi_record_open("gui");
|
||||
app->fs_api = furi_record_open("storage");
|
||||
app->notifications = furi_record_open("notification");
|
||||
app->dialogs = furi_record_open("dialogs");
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
app->fs_api = furi_record_open(RECORD_STORAGE);
|
||||
app->notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||
app->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
|
||||
storage_simply_mkdir(app->fs_api, MASS_STORAGE_APP_PATH_FOLDER);
|
||||
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||
@@ -95,7 +96,6 @@ void mass_storage_app_free(MassStorageApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
// Views
|
||||
view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewFileSelect);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewWork);
|
||||
mass_storage_free(app->mass_storage_view);
|
||||
|
||||
@@ -108,10 +108,10 @@ void mass_storage_app_free(MassStorageApp* app) {
|
||||
scene_manager_free(app->scene_manager);
|
||||
|
||||
// Close records
|
||||
furi_record_close("gui");
|
||||
furi_record_close("storage");
|
||||
furi_record_close("notification");
|
||||
furi_record_close("dialogs");
|
||||
furi_record_close(RECORD_GUI);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
|
||||
free(app);
|
||||
}
|
||||
|
||||
@@ -29,11 +29,11 @@ struct MassStorageApp {
|
||||
DialogsApp* dialogs;
|
||||
Widget* widget;
|
||||
|
||||
char file_name[MASS_STORAGE_FILE_NAME_LEN + 1];
|
||||
char file_name[MASS_STORAGE_FILE_NAME_LEN];
|
||||
File* file;
|
||||
MassStorage* mass_storage_view;
|
||||
|
||||
osMutexId_t usb_mutex;
|
||||
FuriMutex* usb_mutex;
|
||||
MassStorageUsb* usb;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "../mass_storage_app_i.h"
|
||||
#include <assets_icons.h>
|
||||
|
||||
typedef enum {
|
||||
SubghzCustomEventErrorBack,
|
||||
|
||||
@@ -4,14 +4,22 @@
|
||||
static bool mass_storage_file_select(MassStorageApp* mass_storage) {
|
||||
furi_assert(mass_storage);
|
||||
|
||||
// Input events and views are managed by file_select
|
||||
bool res = dialog_file_select_show(
|
||||
mass_storage->dialogs,
|
||||
MASS_STORAGE_APP_PATH_FOLDER,
|
||||
"*",
|
||||
mass_storage->file_name,
|
||||
sizeof(mass_storage->file_name),
|
||||
NULL);
|
||||
FuriString* file_path = furi_string_alloc();
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(&browser_options, "*", NULL);
|
||||
browser_options.base_path = MASS_STORAGE_APP_PATH_FOLDER;
|
||||
furi_string_set(file_path, MASS_STORAGE_APP_PATH_FOLDER);
|
||||
|
||||
bool res =
|
||||
dialog_file_browser_show(mass_storage->dialogs, file_path, file_path, &browser_options);
|
||||
|
||||
if(res) {
|
||||
strlcpy(
|
||||
mass_storage->file_name,
|
||||
furi_string_get_cstr(file_path),
|
||||
sizeof(mass_storage->file_name));
|
||||
}
|
||||
furi_string_free(file_path);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -27,10 +35,13 @@ void mass_storage_scene_file_select_on_enter(void* context) {
|
||||
}
|
||||
|
||||
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);
|
||||
// MassStorageApp* mass_storage = context;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ static bool file_write(void* ctx, uint32_t lba, uint16_t count, uint8_t* buf, ui
|
||||
MassStorageApp* app = ctx;
|
||||
// FURI_LOG_I(TAG, "file_write lba=%08lx count=%04x len=%04x", lba, count, len);
|
||||
if(len != count * SCSI_BLOCK_SIZE) {
|
||||
FURI_LOG_W(TAG, "bad write params count=%d len=%d", count, len);
|
||||
FURI_LOG_W(TAG, "bad write params count=%d len=%ld", count, len);
|
||||
return false;
|
||||
}
|
||||
if(!storage_file_seek(app->file, lba * SCSI_BLOCK_SIZE, true)) {
|
||||
@@ -45,19 +45,19 @@ static uint32_t file_num_blocks(void* ctx) {
|
||||
static void file_eject(void* ctx) {
|
||||
MassStorageApp* app = ctx;
|
||||
FURI_LOG_I(TAG, "EJECT");
|
||||
furi_check(osMutexAcquire(app->usb_mutex, osWaitForever) == osOK);
|
||||
furi_check(furi_mutex_acquire(app->usb_mutex, FuriWaitForever) == FuriStatusOk);
|
||||
mass_storage_usb_stop(app->usb);
|
||||
app->usb = NULL;
|
||||
furi_check(osMutexRelease(app->usb_mutex) == osOK);
|
||||
furi_check(furi_mutex_release(app->usb_mutex) == FuriStatusOk);
|
||||
}
|
||||
|
||||
bool mass_storage_scene_work_on_event(void* context, SceneManagerEvent event) {
|
||||
MassStorageApp* app = context;
|
||||
if(event.type == SceneManagerEventTypeTick) {
|
||||
bool ejected;
|
||||
furi_check(osMutexAcquire(app->usb_mutex, osWaitForever) == osOK);
|
||||
furi_check(furi_mutex_acquire(app->usb_mutex, FuriWaitForever) == FuriStatusOk);
|
||||
ejected = app->usb == NULL;
|
||||
furi_check(osMutexRelease(app->usb_mutex) == osOK);
|
||||
furi_check(furi_mutex_release(app->usb_mutex) == FuriStatusOk);
|
||||
if(ejected) scene_manager_previous_scene(app->scene_manager);
|
||||
}
|
||||
return false;
|
||||
@@ -66,17 +66,16 @@ bool mass_storage_scene_work_on_event(void* context, SceneManagerEvent event) {
|
||||
void mass_storage_scene_work_on_enter(void* context) {
|
||||
MassStorageApp* app = context;
|
||||
|
||||
app->usb_mutex = osMutexNew(NULL);
|
||||
app->usb_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
|
||||
string_t file_name;
|
||||
string_init(file_name);
|
||||
FuriString* file_name = furi_string_alloc();
|
||||
|
||||
mass_storage_set_file_name(app->mass_storage_view, app->file_name);
|
||||
string_printf(file_name, "%s/%s", MASS_STORAGE_APP_PATH_FOLDER, app->file_name);
|
||||
furi_string_printf(file_name, "%s/%s", MASS_STORAGE_APP_PATH_FOLDER, app->file_name);
|
||||
app->file = storage_file_alloc(app->fs_api);
|
||||
furi_assert(storage_file_open(
|
||||
app->file, string_get_cstr(file_name), FSAM_READ | FSAM_WRITE, FSOM_OPEN_EXISTING));
|
||||
string_clear(file_name);
|
||||
app->file, furi_string_get_cstr(file_name), FSAM_READ | FSAM_WRITE, FSOM_OPEN_EXISTING));
|
||||
furi_string_free(file_name);
|
||||
|
||||
SCSIDeviceFunc fn = {
|
||||
.ctx = app,
|
||||
@@ -93,7 +92,7 @@ void mass_storage_scene_work_on_enter(void* context) {
|
||||
void mass_storage_scene_work_on_exit(void* context) {
|
||||
MassStorageApp* app = context;
|
||||
|
||||
furi_assert(osMutexDelete(app->usb_mutex) == osOK);
|
||||
furi_mutex_free(app->usb_mutex);
|
||||
if(app->usb) {
|
||||
mass_storage_usb_stop(app->usb);
|
||||
app->usb = NULL;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "mass_storage_view.h"
|
||||
#include <gui/elements.h>
|
||||
#include <assets_icons.h>
|
||||
|
||||
struct MassStorage {
|
||||
View* view;
|
||||
@@ -12,16 +13,15 @@ typedef struct {
|
||||
static void mass_storage_draw_callback(Canvas* canvas, void* _model) {
|
||||
MassStorageModel* model = _model;
|
||||
|
||||
string_t disp_str;
|
||||
string_init_set_str(disp_str, model->file_name);
|
||||
FuriString* disp_str = furi_string_alloc_set(model->file_name);
|
||||
elements_string_fit_width(canvas, disp_str, 128 - 2);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 2, 8, string_get_cstr(disp_str));
|
||||
string_reset(disp_str);
|
||||
canvas_draw_str(canvas, 2, 8, furi_string_get_cstr(disp_str));
|
||||
furi_string_reset(disp_str);
|
||||
|
||||
canvas_draw_icon(canvas, 40, 20, &I_UsbTree_48x22);
|
||||
|
||||
string_clear(disp_str);
|
||||
furi_string_free(disp_str);
|
||||
}
|
||||
|
||||
MassStorage* mass_storage_alloc() {
|
||||
@@ -49,8 +49,5 @@ View* mass_storage_get_view(MassStorage* mass_storage) {
|
||||
void mass_storage_set_file_name(MassStorage* mass_storage, char* name) {
|
||||
furi_assert(name);
|
||||
with_view_model(
|
||||
mass_storage->view, (MassStorageModel * model) {
|
||||
model->file_name = name;
|
||||
return true;
|
||||
});
|
||||
mass_storage->view, MassStorageModel * model, { model->file_name = name; }, true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user