This commit is contained in:
Sil
2023-07-22 10:03:31 +02:00
19 changed files with 98 additions and 155 deletions

View File

@@ -1,12 +0,0 @@
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="USB",
)

View File

@@ -1,54 +0,0 @@
#include "../mass_storage_app_i.h"
#include <assets_icons.h>
typedef enum {
SubghzCustomEventErrorBack,
} MassStorageCustomEvent;
static void
mass_storage_scene_error_event_callback(GuiButtonType result, InputType type, void* context) {
furi_assert(context);
MassStorageApp* app = context;
if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
view_dispatcher_send_custom_event(app->view_dispatcher, SubghzCustomEventErrorBack);
}
}
void mass_storage_scene_error_on_enter(void* context) {
MassStorageApp* app = context;
widget_add_icon_element(app->widget, 0, 0, &I_SDQuestion_35x43);
widget_add_string_multiline_element(
app->widget,
81,
4,
AlignCenter,
AlignTop,
FontSecondary,
"No SD card or\napp data found.\nThis app requires a\nmass_storage/\ndirectory.");
widget_add_button_element(
app->widget, GuiButtonTypeLeft, "Back", mass_storage_scene_error_event_callback, app);
view_dispatcher_switch_to_view(app->view_dispatcher, MassStorageAppViewError);
}
bool mass_storage_scene_error_on_event(void* context, SceneManagerEvent event) {
MassStorageApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubghzCustomEventErrorBack) {
view_dispatcher_stop(app->view_dispatcher);
consumed = true;
}
}
return consumed;
}
void mass_storage_scene_error_on_exit(void* context) {
MassStorageApp* app = context;
widget_reset(app->widget);
}

View File

@@ -0,0 +1,15 @@
App(
appid="mass_storage",
name="Mass Storage",
apptype=FlipperAppType.EXTERNAL,
entry_point="mass_storage_app",
requires=[
"gui",
"dialogs",
],
stack_size=2 * 1024,
order=20,
fap_icon="assets/mass_storage_10px.png",
fap_icon_assets="assets",
fap_category="USB",
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

View File

@@ -1,5 +1,7 @@
#include "mass_storage_scsi.h"
#include <core/log.h>
#define TAG "MassStorageSCSI"
#define SCSI_TEST_UNIT_READY (0x00)
@@ -131,17 +133,17 @@ bool scsi_cmd_tx_data(SCSISession* scsi, uint8_t* data, uint32_t* len, uint32_t
data[0] = (n_blocks - 1) >> 24;
data[1] = (n_blocks - 1) >> 16;
data[2] = (n_blocks - 1) >> 8;
data[3] = (n_blocks - 1);
data[3] = (n_blocks - 1) & 0xFF;
data[4] = block_size >> 24;
data[5] = block_size >> 16;
data[6] = block_size >> 8;
data[7] = block_size;
data[7] = block_size & 0xFF;
*len = 8;
scsi->tx_done = true;
return true;
}; break;
case SCSI_MODE_SENSE_6: {
FURI_LOG_I(TAG, "SCSI_MODE_SENSE_6 %ld", cap);
FURI_LOG_I(TAG, "SCSI_MODE_SENSE_6 %lu", cap);
if(cap < 4) return false;
data[0] = 3; // mode data length (len - 1)
data[1] = 0; // medium type

View File

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

View File

@@ -1,5 +1,4 @@
#include "mass_storage_usb.h"
#include <furi_hal.h>
#define TAG "MassStorageUsb"
@@ -7,8 +6,8 @@
#define USB_MSC_RX_EP (0x01)
#define USB_MSC_TX_EP (0x82)
#define USB_MSC_RX_EP_SIZE (64)
#define USB_MSC_TX_EP_SIZE (64u)
#define USB_MSC_RX_EP_SIZE (64UL)
#define USB_MSC_TX_EP_SIZE (64UL)
#define USB_MSC_BOT_GET_MAX_LUN (0xFE)
#define USB_MSC_BOT_RESET (0xFF)
@@ -23,7 +22,7 @@
// must be SCSI_BLOCK_SIZE aligned
// larger than 0x10000 exceeds size_t, storage_file_* ops fail
#define USB_MSC_BUF_MAX (0x10000u - SCSI_BLOCK_SIZE)
#define USB_MSC_BUF_MAX (0x10000UL - 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,11 +78,10 @@ static int32_t mass_thread_worker(void* context) {
StateWriteCSW,
} state = StateReadCBW;
while(true) {
uint32_t flags = furi_thread_flags_wait(EventAll, FuriFlagWaitAny, FuriFlagWaitAny);
uint32_t flags = furi_thread_flags_wait(EventAll, FuriFlagWaitAny, FuriWaitForever);
if(flags & EventExit) {
FURI_LOG_I(TAG, "exit");
free(buf);
return 0;
break;
}
if(flags & EventReset) {
FURI_LOG_I(TAG, "reset");
@@ -91,8 +89,10 @@ static int32_t mass_thread_worker(void* context) {
scsi.asc = 0;
memset(&cbw, 0, sizeof(cbw));
memset(&csw, 0, sizeof(csw));
free(buf);
buf = NULL;
if(buf) {
free(buf);
buf = NULL;
}
buf_len = buf_cap = buf_sent = 0;
state = StateReadCBW;
}
@@ -138,8 +138,10 @@ static int32_t mass_thread_worker(void* context) {
}
uint32_t buf_clamp = MIN(cbw.len, USB_MSC_BUF_MAX);
if(buf_clamp > buf_cap) {
// FURI_LOG_I(TAG, "growing buf %d -> %d", buf_cap, buf_clamp);
free(buf);
FURI_LOG_I(TAG, "growing buf %lu -> %lu", buf_cap, buf_clamp);
if(buf) {
free(buf);
}
buf_cap = buf_clamp;
buf = malloc(buf_cap);
}
@@ -177,8 +179,10 @@ static int32_t mass_thread_worker(void* context) {
}
uint32_t buf_clamp = MIN(cbw.len, USB_MSC_BUF_MAX);
if(buf_clamp > buf_cap) {
// FURI_LOG_I(TAG, "growing buf %d -> %d", buf_cap, buf_clamp);
free(buf);
FURI_LOG_I(TAG, "growing buf %lu -> %lu", buf_cap, buf_clamp);
if(buf) {
free(buf);
}
buf_cap = buf_clamp;
buf = malloc(buf_cap);
}
@@ -248,6 +252,10 @@ static int32_t mass_thread_worker(void* context) {
break;
} while(true);
}
if(buf) {
free(buf);
}
return 0;
}
// needed in usb_deinit, usb_suspend, usb_rxtx_ep_callback, usb_control,
@@ -307,8 +315,8 @@ static void usb_suspend(usbd_device* dev) {
}
static void usb_rxtx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) {
UNUSED(event);
UNUSED(ep);
UNUSED(event);
MassStorageUsb* mass = mass_cur;
if(!mass || mass->dev != dev) return;
furi_thread_flags_set(furi_thread_get_id(mass->thread), EventRxTx);

View File

@@ -21,31 +21,14 @@ static void mass_storage_app_tick_event_callback(void* context) {
scene_manager_handle_tick_event(app->scene_manager);
}
static bool mass_storage_check_assets(Storage* fs_api) {
File* dir = storage_file_alloc(fs_api);
bool ret = false;
if(storage_dir_open(dir, MASS_STORAGE_APP_PATH_FOLDER)) {
ret = true;
}
storage_dir_close(dir);
storage_file_free(dir);
return ret;
}
MassStorageApp* mass_storage_app_alloc(char* arg) {
MassStorageApp* app = malloc(sizeof(MassStorageApp));
memset(app, 0, sizeof(MassStorageApp));
app->file_path = furi_string_alloc();
if(arg != NULL) {
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);
}
strlcpy(app->file_name, furi_string_get_cstr(filename), MASS_STORAGE_FILE_NAME_LEN);
furi_string_free(filename);
furi_string_set_str(app->file_path, arg);
} else {
furi_string_set_str(app->file_path, MASS_STORAGE_APP_PATH_FOLDER);
}
app->gui = furi_record_open(RECORD_GUI);
@@ -53,8 +36,6 @@ MassStorageApp* mass_storage_app_alloc(char* arg) {
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);
@@ -68,11 +49,6 @@ MassStorageApp* mass_storage_app_alloc(char* arg) {
view_dispatcher_set_navigation_event_callback(
app->view_dispatcher, mass_storage_app_back_event_callback);
// Custom Widget
app->widget = widget_alloc();
view_dispatcher_add_view(
app->view_dispatcher, MassStorageAppViewError, widget_get_view(app->widget));
app->mass_storage_view = mass_storage_alloc();
view_dispatcher_add_view(
app->view_dispatcher,
@@ -81,12 +57,10 @@ MassStorageApp* mass_storage_app_alloc(char* arg) {
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
if(*app->file_name != '\0') {
if(storage_file_exists(app->fs_api, furi_string_get_cstr(app->file_path))) {
scene_manager_next_scene(app->scene_manager, MassStorageSceneWork);
} else if(mass_storage_check_assets(app->fs_api)) {
scene_manager_next_scene(app->scene_manager, MassStorageSceneFileSelect);
} else {
scene_manager_next_scene(app->scene_manager, MassStorageSceneError);
scene_manager_next_scene(app->scene_manager, MassStorageSceneFileSelect);
}
return app;
@@ -99,14 +73,12 @@ void mass_storage_app_free(MassStorageApp* app) {
view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewWork);
mass_storage_free(app->mass_storage_view);
// Custom Widget
view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewError);
widget_free(app->widget);
// View dispatcher
view_dispatcher_free(app->view_dispatcher);
scene_manager_free(app->scene_manager);
furi_string_free(app->file_path);
// Close records
furi_record_close(RECORD_GUI);
furi_record_close(RECORD_STORAGE);

View File

@@ -17,7 +17,7 @@
#include "views/mass_storage_view.h"
#define MASS_STORAGE_APP_PATH_FOLDER STORAGE_APP_DATA_PATH_PREFIX
// #define MASS_STORAGE_APP_EXTENSION ".iso"
#define MASS_STORAGE_APP_EXTENSION ".img"
#define MASS_STORAGE_FILE_NAME_LEN 40
struct MassStorageApp {
@@ -29,7 +29,7 @@ struct MassStorageApp {
DialogsApp* dialogs;
Widget* widget;
char file_name[MASS_STORAGE_FILE_NAME_LEN];
FuriString* file_path;
File* file;
MassStorage* mass_storage_view;
@@ -39,6 +39,5 @@ struct MassStorageApp {
typedef enum {
MassStorageAppViewError,
MassStorageAppViewFileSelect,
MassStorageAppViewWork,
} MassStorageAppView;

View File

@@ -1,3 +1,2 @@
ADD_SCENE(mass_storage, file_select, FileSelect)
ADD_SCENE(mass_storage, work, Work)
ADD_SCENE(mass_storage, error, Error)

View File

@@ -1,25 +1,18 @@
#include "../mass_storage_app_i.h"
#include "furi_hal_power.h"
#include <mass_storage_icons.h>
static bool mass_storage_file_select(MassStorageApp* mass_storage) {
furi_assert(mass_storage);
FuriString* file_path = furi_string_alloc();
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, "*", NULL);
dialog_file_browser_set_basic_options(
&browser_options, MASS_STORAGE_APP_EXTENSION, &I_mass_storage_10px);
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);
// 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;
}

View File

@@ -1,6 +1,7 @@
#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"
@@ -27,7 +28,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=%ld", count, len);
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)) {
@@ -69,13 +70,15 @@ void mass_storage_scene_work_on_enter(void* context) {
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, app->file_name);
furi_string_printf(file_name, "%s/%s", MASS_STORAGE_APP_PATH_FOLDER, app->file_name);
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(file_name), FSAM_READ | FSAM_WRITE, FSOM_OPEN_EXISTING));
furi_string_free(file_name);
app->file,
furi_string_get_cstr(app->file_path),
FSAM_READ | FSAM_WRITE,
FSOM_OPEN_EXISTING));
SCSIDeviceFunc fn = {
.ctx = app,
@@ -84,7 +87,10 @@ void mass_storage_scene_work_on_enter(void* context) {
.num_blocks = file_num_blocks,
.eject = file_eject,
};
app->usb = mass_storage_usb_start(app->file_name, fn);
app->usb = mass_storage_usb_start(furi_string_get_cstr(file_name), fn);
furi_string_free(file_name);
view_dispatcher_switch_to_view(app->view_dispatcher, MassStorageAppViewWork);
}

View File

@@ -1,5 +1,6 @@
#include "mass_storage_view.h"
#include <gui/elements.h>
#include <mass_storage_icons.h>
#include <assets_icons.h>
struct MassStorage {
@@ -7,21 +8,22 @@ struct MassStorage {
};
typedef struct {
char* file_name;
FuriString* file_name;
} MassStorageModel;
static void mass_storage_draw_callback(Canvas* canvas, void* _model) {
MassStorageModel* model = _model;
FuriString* disp_str = furi_string_alloc_set(model->file_name);
elements_string_fit_width(canvas, disp_str, 128 - 2);
canvas_draw_icon(canvas, 8, 14, &I_Drive_112x35);
canvas_set_font(canvas, FontPrimary);
canvas_draw_str_aligned(
canvas, canvas_width(canvas) / 2, 0, AlignCenter, AlignTop, "USB Mass Storage");
elements_string_fit_width(canvas, model->file_name, 87 - 2);
canvas_set_font(canvas, FontSecondary);
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);
furi_string_free(disp_str);
canvas_draw_str(canvas, 12, 25, "Disc image:");
canvas_draw_str(canvas, 12, 40, furi_string_get_cstr(model->file_name));
}
MassStorage* mass_storage_alloc() {
@@ -29,6 +31,11 @@ MassStorage* mass_storage_alloc() {
mass_storage->view = view_alloc();
view_allocate_model(mass_storage->view, ViewModelTypeLocking, sizeof(MassStorageModel));
with_view_model(
mass_storage->view,
MassStorageModel * model,
{ model->file_name = furi_string_alloc(); },
false);
view_set_context(mass_storage->view, mass_storage);
view_set_draw_callback(mass_storage->view, mass_storage_draw_callback);
@@ -37,6 +44,11 @@ MassStorage* mass_storage_alloc() {
void mass_storage_free(MassStorage* mass_storage) {
furi_assert(mass_storage);
with_view_model(
mass_storage->view,
MassStorageModel * model,
{ furi_string_free(model->file_name); },
false);
view_free(mass_storage->view);
free(mass_storage);
}
@@ -46,8 +58,11 @@ View* mass_storage_get_view(MassStorage* mass_storage) {
return mass_storage->view;
}
void mass_storage_set_file_name(MassStorage* mass_storage, char* name) {
void mass_storage_set_file_name(MassStorage* mass_storage, FuriString* name) {
furi_assert(name);
with_view_model(
mass_storage->view, MassStorageModel * model, { model->file_name = name; }, true);
mass_storage->view,
MassStorageModel * model,
{ furi_string_set(model->file_name, name); },
true);
}

View File

@@ -10,4 +10,4 @@ void mass_storage_free(MassStorage* mass_storage);
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, FuriString* name);

Binary file not shown.