Refactor mass storage to current flipper api (WIP)

This commit is contained in:
Willy-JL
2023-06-14 00:58:18 +01:00
parent eb1e81621c
commit 40cff8a603
10 changed files with 82 additions and 58 deletions

View 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"],
)

View File

@@ -1,7 +1,5 @@
#include "mass_storage_scsi.h" #include "mass_storage_scsi.h"
#include <furi/log.h>
#define TAG "MassStorageSCSI" #define TAG "MassStorageSCSI"
#define SCSI_TEST_UNIT_READY (0x00) #define SCSI_TEST_UNIT_READY (0x00)

View File

@@ -2,7 +2,7 @@
#include <furi.h> #include <furi.h>
#define SCSI_BLOCK_SIZE (0x200) #define SCSI_BLOCK_SIZE (0x200u)
#define SCSI_SK_ILLEGAL_REQUEST (5) #define SCSI_SK_ILLEGAL_REQUEST (5)

View File

@@ -8,7 +8,7 @@
#define USB_MSC_TX_EP (0x82) #define USB_MSC_TX_EP (0x82)
#define USB_MSC_RX_EP_SIZE (64) #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_GET_MAX_LUN (0xFE)
#define USB_MSC_BOT_RESET (0xFF) #define USB_MSC_BOT_RESET (0xFF)
@@ -23,7 +23,7 @@
// must be SCSI_BLOCK_SIZE aligned // must be SCSI_BLOCK_SIZE aligned
// larger than 0x10000 exceeds size_t, storage_file_* ops fail // 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_ep_config(usbd_device* dev, uint8_t cfg);
static usbd_respond usb_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback); 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, StateWriteCSW,
} state = StateReadCBW; } state = StateReadCBW;
while(true) { while(true) {
uint32_t flags = osThreadFlagsWait(EventAll, osFlagsWaitAny, osWaitForever); uint32_t flags = furi_thread_flags_wait(EventAll, FuriFlagWaitAny, FuriFlagWaitAny);
if(flags & EventExit) { if(flags & EventExit) {
FURI_LOG_I(TAG, "exit"); FURI_LOG_I(TAG, "exit");
free(buf); free(buf);
@@ -235,7 +235,7 @@ static int32_t mass_thread_worker(void* context) {
break; break;
} }
if(len != sizeof(csw)) { 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); usbd_ep_stall(dev, USB_MSC_TX_EP);
break; break;
} }
@@ -255,6 +255,7 @@ static int32_t mass_thread_worker(void* context) {
static MassStorageUsb* mass_cur = NULL; static MassStorageUsb* mass_cur = NULL;
static void usb_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx) { static void usb_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx) {
UNUSED(intf);
MassStorageUsb* mass = ctx; MassStorageUsb* mass = ctx;
mass_cur = mass; mass_cur = mass;
mass->dev = dev; mass->dev = dev;
@@ -283,7 +284,7 @@ static void usb_deinit(usbd_device* dev) {
mass_cur = NULL; mass_cur = NULL;
furi_assert(mass->thread); 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_join(mass->thread);
furi_thread_free(mass->thread); furi_thread_free(mass->thread);
mass->thread = NULL; mass->thread = NULL;
@@ -296,18 +297,21 @@ static void usb_deinit(usbd_device* dev) {
} }
static void usb_wakeup(usbd_device* dev) { static void usb_wakeup(usbd_device* dev) {
UNUSED(dev);
} }
static void usb_suspend(usbd_device* dev) { static void usb_suspend(usbd_device* dev) {
MassStorageUsb* mass = mass_cur; MassStorageUsb* mass = mass_cur;
if(!mass || mass->dev != dev) return; 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) { static void usb_rxtx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) {
UNUSED(event);
UNUSED(ep);
MassStorageUsb* mass = mass_cur; MassStorageUsb* mass = mass_cur;
if(!mass || mass->dev != dev) return; 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) { 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) { 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) != if(((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) !=
(USB_REQ_INTERFACE | USB_REQ_CLASS)) { (USB_REQ_INTERFACE | USB_REQ_CLASS)) {
return usbd_fail; 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: { case USB_MSC_BOT_RESET: {
MassStorageUsb* mass = mass_cur; MassStorageUsb* mass = mass_cur;
if(!mass || mass->dev != dev) return usbd_fail; 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; return usbd_ack;
}; break; }; break;
} }

View File

@@ -40,19 +40,20 @@ MassStorageApp* mass_storage_app_alloc(char* arg) {
memset(app, 0, sizeof(MassStorageApp)); memset(app, 0, sizeof(MassStorageApp));
if(arg != NULL) { if(arg != NULL) {
string_t filename; FuriString* filename = furi_string_alloc_set(arg);
string_init_set(filename, arg); if(furi_string_start_with_str(filename, MASS_STORAGE_APP_PATH_FOLDER)) {
if(string_start_with_str_p(filename, MASS_STORAGE_APP_PATH_FOLDER)) { furi_string_right(filename, strlen(MASS_STORAGE_APP_PATH_FOLDER) + 1);
string_right(filename, strlen(MASS_STORAGE_APP_PATH_FOLDER) + 1);
} }
strncpy(app->file_name, string_get_cstr(filename), MASS_STORAGE_FILE_NAME_LEN); strlcpy(app->file_name, furi_string_get_cstr(filename), MASS_STORAGE_FILE_NAME_LEN);
string_clear(filename); furi_string_free(filename);
} }
app->gui = furi_record_open("gui"); app->gui = furi_record_open(RECORD_GUI);
app->fs_api = furi_record_open("storage"); app->fs_api = furi_record_open(RECORD_STORAGE);
app->notifications = furi_record_open("notification"); app->notifications = furi_record_open(RECORD_NOTIFICATION);
app->dialogs = furi_record_open("dialogs"); app->dialogs = furi_record_open(RECORD_DIALOGS);
storage_simply_mkdir(app->fs_api, MASS_STORAGE_APP_PATH_FOLDER);
app->view_dispatcher = view_dispatcher_alloc(); app->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(app->view_dispatcher); view_dispatcher_enable_queue(app->view_dispatcher);
@@ -95,7 +96,6 @@ void mass_storage_app_free(MassStorageApp* app) {
furi_assert(app); furi_assert(app);
// Views // Views
view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewFileSelect);
view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewWork); view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewWork);
mass_storage_free(app->mass_storage_view); mass_storage_free(app->mass_storage_view);
@@ -108,10 +108,10 @@ void mass_storage_app_free(MassStorageApp* app) {
scene_manager_free(app->scene_manager); scene_manager_free(app->scene_manager);
// Close records // Close records
furi_record_close("gui"); furi_record_close(RECORD_GUI);
furi_record_close("storage"); furi_record_close(RECORD_STORAGE);
furi_record_close("notification"); furi_record_close(RECORD_NOTIFICATION);
furi_record_close("dialogs"); furi_record_close(RECORD_DIALOGS);
free(app); free(app);
} }

View File

@@ -29,11 +29,11 @@ struct MassStorageApp {
DialogsApp* dialogs; DialogsApp* dialogs;
Widget* widget; Widget* widget;
char file_name[MASS_STORAGE_FILE_NAME_LEN + 1]; char file_name[MASS_STORAGE_FILE_NAME_LEN];
File* file; File* file;
MassStorage* mass_storage_view; MassStorage* mass_storage_view;
osMutexId_t usb_mutex; FuriMutex* usb_mutex;
MassStorageUsb* usb; MassStorageUsb* usb;
}; };

View File

@@ -1,4 +1,5 @@
#include "../mass_storage_app_i.h" #include "../mass_storage_app_i.h"
#include <assets_icons.h>
typedef enum { typedef enum {
SubghzCustomEventErrorBack, SubghzCustomEventErrorBack,

View File

@@ -4,14 +4,22 @@
static bool mass_storage_file_select(MassStorageApp* mass_storage) { static bool mass_storage_file_select(MassStorageApp* mass_storage) {
furi_assert(mass_storage); furi_assert(mass_storage);
// Input events and views are managed by file_select FuriString* file_path = furi_string_alloc();
bool res = dialog_file_select_show( DialogsFileBrowserOptions browser_options;
mass_storage->dialogs, dialog_file_browser_set_basic_options(&browser_options, "*", NULL);
MASS_STORAGE_APP_PATH_FOLDER, browser_options.base_path = MASS_STORAGE_APP_PATH_FOLDER;
"*", furi_string_set(file_path, MASS_STORAGE_APP_PATH_FOLDER);
mass_storage->file_name,
sizeof(mass_storage->file_name), bool res =
NULL); 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; 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) { bool mass_storage_scene_file_select_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
// MassStorageApp* mass_storage = context; // MassStorageApp* mass_storage = context;
return false; return false;
} }
void mass_storage_scene_file_select_on_exit(void* context) { void mass_storage_scene_file_select_on_exit(void* context) {
UNUSED(context);
// MassStorageApp* mass_storage = context; // MassStorageApp* mass_storage = context;
} }

View File

@@ -27,7 +27,7 @@ static bool file_write(void* ctx, uint32_t lba, uint16_t count, uint8_t* buf, ui
MassStorageApp* app = ctx; MassStorageApp* app = ctx;
// FURI_LOG_I(TAG, "file_write lba=%08lx count=%04x len=%04x", lba, count, len); // FURI_LOG_I(TAG, "file_write lba=%08lx count=%04x len=%04x", lba, count, len);
if(len != count * SCSI_BLOCK_SIZE) { 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; return false;
} }
if(!storage_file_seek(app->file, lba * SCSI_BLOCK_SIZE, true)) { 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) { static void file_eject(void* ctx) {
MassStorageApp* app = ctx; MassStorageApp* app = ctx;
FURI_LOG_I(TAG, "EJECT"); 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); mass_storage_usb_stop(app->usb);
app->usb = NULL; 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) { bool mass_storage_scene_work_on_event(void* context, SceneManagerEvent event) {
MassStorageApp* app = context; MassStorageApp* app = context;
if(event.type == SceneManagerEventTypeTick) { if(event.type == SceneManagerEventTypeTick) {
bool ejected; bool ejected;
furi_check(osMutexAcquire(app->usb_mutex, osWaitForever) == osOK); furi_check(furi_mutex_acquire(app->usb_mutex, FuriWaitForever) == FuriStatusOk);
ejected = app->usb == NULL; 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); if(ejected) scene_manager_previous_scene(app->scene_manager);
} }
return false; 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) { void mass_storage_scene_work_on_enter(void* context) {
MassStorageApp* app = context; MassStorageApp* app = context;
app->usb_mutex = osMutexNew(NULL); app->usb_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
string_t file_name; FuriString* file_name = furi_string_alloc();
string_init(file_name);
mass_storage_set_file_name(app->mass_storage_view, app->file_name); 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); app->file = storage_file_alloc(app->fs_api);
furi_assert(storage_file_open( furi_assert(storage_file_open(
app->file, string_get_cstr(file_name), FSAM_READ | FSAM_WRITE, FSOM_OPEN_EXISTING)); app->file, furi_string_get_cstr(file_name), FSAM_READ | FSAM_WRITE, FSOM_OPEN_EXISTING));
string_clear(file_name); furi_string_free(file_name);
SCSIDeviceFunc fn = { SCSIDeviceFunc fn = {
.ctx = app, .ctx = app,
@@ -93,7 +92,7 @@ void mass_storage_scene_work_on_enter(void* context) {
void mass_storage_scene_work_on_exit(void* context) { void mass_storage_scene_work_on_exit(void* context) {
MassStorageApp* app = context; MassStorageApp* app = context;
furi_assert(osMutexDelete(app->usb_mutex) == osOK); furi_mutex_free(app->usb_mutex);
if(app->usb) { if(app->usb) {
mass_storage_usb_stop(app->usb); mass_storage_usb_stop(app->usb);
app->usb = NULL; app->usb = NULL;

View File

@@ -1,5 +1,6 @@
#include "mass_storage_view.h" #include "mass_storage_view.h"
#include <gui/elements.h> #include <gui/elements.h>
#include <assets_icons.h>
struct MassStorage { struct MassStorage {
View* view; View* view;
@@ -12,16 +13,15 @@ typedef struct {
static void mass_storage_draw_callback(Canvas* canvas, void* _model) { static void mass_storage_draw_callback(Canvas* canvas, void* _model) {
MassStorageModel* model = _model; MassStorageModel* model = _model;
string_t disp_str; FuriString* disp_str = furi_string_alloc_set(model->file_name);
string_init_set_str(disp_str, model->file_name);
elements_string_fit_width(canvas, disp_str, 128 - 2); elements_string_fit_width(canvas, disp_str, 128 - 2);
canvas_set_font(canvas, FontSecondary); canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 2, 8, string_get_cstr(disp_str)); canvas_draw_str(canvas, 2, 8, furi_string_get_cstr(disp_str));
string_reset(disp_str); furi_string_reset(disp_str);
canvas_draw_icon(canvas, 40, 20, &I_UsbTree_48x22); canvas_draw_icon(canvas, 40, 20, &I_UsbTree_48x22);
string_clear(disp_str); furi_string_free(disp_str);
} }
MassStorage* mass_storage_alloc() { 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) { void mass_storage_set_file_name(MassStorage* mass_storage, char* name) {
furi_assert(name); furi_assert(name);
with_view_model( with_view_model(
mass_storage->view, (MassStorageModel * model) { mass_storage->view, MassStorageModel * model, { model->file_name = name; }, true);
model->file_name = name;
return true;
});
} }