From f37f43a8bc66e58a1f8b2ee1d44b5fc93ceba3a2 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 3 Aug 2023 14:40:51 +0200 Subject: [PATCH] Merge upstream mass storage changes --- .../mass_storage/helpers/mass_storage_scsi.c | 112 ++++++++++++------ .../mass_storage/helpers/mass_storage_usb.c | 29 ++--- .../external/mass_storage/mass_storage_app.c | 30 ++++- .../mass_storage/mass_storage_app_i.h | 15 +-- .../scenes/mass_storage_scene_create_image.c | 17 ++- .../mass_storage_scene_create_image_name.c | 2 +- .../scenes/mass_storage_scene_start.c | 2 +- .../scenes/mass_storage_scene_work.c | 39 ++++-- 8 files changed, 167 insertions(+), 79 deletions(-) diff --git a/applications/external/mass_storage/helpers/mass_storage_scsi.c b/applications/external/mass_storage/helpers/mass_storage_scsi.c index c7419d31c..c1efacf8e 100644 --- a/applications/external/mass_storage/helpers/mass_storage_scsi.c +++ b/applications/external/mass_storage/helpers/mass_storage_scsi.c @@ -7,7 +7,8 @@ #define SCSI_TEST_UNIT_READY (0x00) #define SCSI_REQUEST_SENSE (0x03) #define SCSI_INQUIRY (0x12) -#define SCSI_READ_CAPACITY_6 (0x25) +#define SCSI_READ_FORMAT_CAPACITIES (0x23) +#define SCSI_READ_CAPACITY_10 (0x25) #define SCSI_MODE_SENSE_6 (0x1A) #define SCSI_READ_10 (0x28) #define SCSI_PREVENT_MEDIUM_REMOVAL (0x1E) @@ -20,7 +21,7 @@ bool scsi_cmd_start(SCSISession* scsi, uint8_t* cmd, uint8_t len) { scsi->asc = SCSI_ASC_INVALID_COMMAND_OPERATION_CODE; return false; } - // FURI_LOG_I(TAG, "START %02x", cmd[0]); + FURI_LOG_T(TAG, "START %02X", cmd[0]); scsi->cmd = cmd; scsi->cmd_len = len; scsi->rx_done = false; @@ -30,14 +31,14 @@ bool scsi_cmd_start(SCSISession* scsi, uint8_t* cmd, uint8_t len) { if(len < 10) return false; scsi->write_10.lba = cmd[2] << 24 | cmd[3] << 16 | cmd[4] << 8 | cmd[5]; scsi->write_10.count = cmd[7] << 8 | cmd[8]; - FURI_LOG_I(TAG, "SCSI_WRITE_10 %08lx %04x", scsi->write_10.lba, scsi->write_10.count); + FURI_LOG_D(TAG, "SCSI_WRITE_10 %08lX %04X", scsi->write_10.lba, scsi->write_10.count); return true; }; break; case SCSI_READ_10: { if(len < 10) return false; scsi->read_10.lba = cmd[2] << 24 | cmd[3] << 16 | cmd[4] << 8 | cmd[5]; scsi->read_10.count = cmd[7] << 8 | cmd[8]; - FURI_LOG_I(TAG, "SCSI_READ_10 %08lx %04x", scsi->read_10.lba, scsi->read_10.count); + FURI_LOG_D(TAG, "SCSI_READ_10 %08lX %04X", scsi->read_10.lba, scsi->read_10.count); return true; }; break; } @@ -45,7 +46,7 @@ bool scsi_cmd_start(SCSISession* scsi, uint8_t* cmd, uint8_t len) { } bool scsi_cmd_rx_data(SCSISession* scsi, uint8_t* data, uint32_t len) { - // FURI_LOG_I(TAG, "RX %02x len %d", scsi->cmd[0], len); + FURI_LOG_T(TAG, "RX %02X len %lu", scsi->cmd[0], len); if(scsi->rx_done) return false; switch(scsi->cmd[0]) { case SCSI_WRITE_10: { @@ -61,7 +62,7 @@ bool scsi_cmd_rx_data(SCSISession* scsi, uint8_t* data, uint32_t len) { return result; }; break; default: { - FURI_LOG_W(TAG, "unexpected scsi rx data cmd=%02x", scsi->cmd[0]); + FURI_LOG_W(TAG, "unexpected scsi rx data cmd=%02X", scsi->cmd[0]); scsi->sk = SCSI_SK_ILLEGAL_REQUEST; scsi->asc = SCSI_ASC_INVALID_COMMAND_OPERATION_CODE; return false; @@ -70,11 +71,11 @@ bool scsi_cmd_rx_data(SCSISession* scsi, uint8_t* data, uint32_t len) { } bool scsi_cmd_tx_data(SCSISession* scsi, uint8_t* data, uint32_t* len, uint32_t cap) { - // FURI_LOG_I(TAG, "TX %02x cap %d", scsi->cmd[0], cap); + FURI_LOG_T(TAG, "TX %02X cap %lu", scsi->cmd[0], cap); if(scsi->tx_done) return false; switch(scsi->cmd[0]) { case SCSI_REQUEST_SENSE: { - FURI_LOG_I(TAG, "SCSI_REQUEST_SENSE"); + FURI_LOG_D(TAG, "SCSI_REQUEST_SENSE"); if(cap < 18) return false; memset(data, 0, cap); data[0] = 0x70; // fixed format sense data @@ -102,31 +103,73 @@ bool scsi_cmd_tx_data(SCSISession* scsi, uint8_t* data, uint32_t* len, uint32_t return true; }; break; case SCSI_INQUIRY: { - FURI_LOG_I(TAG, "SCSI_INQUIRY"); + FURI_LOG_D(TAG, "SCSI_INQUIRY"); if(scsi->cmd_len < 5) return false; + if(cap < 36) return false; + bool evpd = scsi->cmd[1] & 1; uint8_t page_code = scsi->cmd[2]; - // uint16_t alloc_len = scsi->cmd[3] << 8 | scsi->cmd[4]; - if(evpd) return false; - if(page_code) return false; - data[0] = 0x00; // device type: direct access block device - data[1] = 0x80; // removable: true - data[2] = 0x04; // version - data[3] = 0x02; // response data format - data[4] = 31; // additional length (len - 5) - data[5] = 0; // flags - data[6] = 0; // flags - data[7] = 0; // flags - memcpy(data + 8, "Flipper ", 8); // vendor id - memcpy(data + 16, "Mass Storage ", 16); // product id - memcpy(data + 32, "0001", 4); // product revision level - *len = 36; + if(evpd == 0) { + if(page_code != 0) return false; + + data[0] = 0x00; // device type: direct access block device + data[1] = 0x80; // removable: true + data[2] = 0x04; // version + data[3] = 0x02; // response data format + data[4] = 31; // additional length (len - 5) + data[5] = 0; // flags + data[6] = 0; // flags + data[7] = 0; // flags + memcpy(data + 8, "Flipper ", 8); // vendor id + memcpy(data + 16, "Mass Storage ", 16); // product id + memcpy(data + 32, "0001", 4); // product revision level + *len = 36; + scsi->tx_done = true; + return true; + } else { + if(page_code != 0x80) { + FURI_LOG_W(TAG, "Unsupported VPD code %02X", page_code); + return false; + } + data[0] = 0x00; + data[1] = 0x80; + data[2] = 0x00; + data[3] = 0x01; // Serial len + data[4] = '0'; + *len = 5; + scsi->tx_done = true; + return true; + } + }; break; + case SCSI_READ_FORMAT_CAPACITIES: { + FURI_LOG_D(TAG, "SCSI_READ_FORMAT_CAPACITIES"); + if(cap < 12) { + return false; + } + uint32_t n_blocks = scsi->fn.num_blocks(scsi->fn.ctx); + uint32_t block_size = SCSI_BLOCK_SIZE; + // Capacity List Header + data[0] = 0; + data[1] = 0; + data[2] = 0; + data[3] = 8; + + // Capacity Descriptor + data[4] = (n_blocks - 1) >> 24; + data[5] = (n_blocks - 1) >> 16; + data[6] = (n_blocks - 1) >> 8; + data[7] = (n_blocks - 1) & 0xFF; + data[8] = 0x02; // Formatted media + data[9] = block_size >> 16; + data[10] = block_size >> 8; + data[11] = block_size & 0xFF; + *len = 12; scsi->tx_done = true; return true; }; break; - case SCSI_READ_CAPACITY_6: { - FURI_LOG_I(TAG, "SCSI_READ_CAPACITY_6"); + case SCSI_READ_CAPACITY_10: { + FURI_LOG_D(TAG, "SCSI_READ_CAPACITY_10"); if(cap < 8) return false; uint32_t n_blocks = scsi->fn.num_blocks(scsi->fn.ctx); uint32_t block_size = SCSI_BLOCK_SIZE; @@ -143,7 +186,7 @@ bool scsi_cmd_tx_data(SCSISession* scsi, uint8_t* data, uint32_t* len, uint32_t return true; }; break; case SCSI_MODE_SENSE_6: { - FURI_LOG_I(TAG, "SCSI_MODE_SENSE_6 %lu", cap); + FURI_LOG_D(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 @@ -167,7 +210,7 @@ bool scsi_cmd_tx_data(SCSISession* scsi, uint8_t* data, uint32_t* len, uint32_t return result; }; break; default: { - FURI_LOG_W(TAG, "unexpected scsi tx data cmd=%02x", scsi->cmd[0]); + FURI_LOG_W(TAG, "unexpected scsi tx data cmd=%02X", scsi->cmd[0]); scsi->sk = SCSI_SK_ILLEGAL_REQUEST; scsi->asc = SCSI_ASC_INVALID_COMMAND_OPERATION_CODE; return false; @@ -176,7 +219,7 @@ bool scsi_cmd_tx_data(SCSISession* scsi, uint8_t* data, uint32_t* len, uint32_t } bool scsi_cmd_end(SCSISession* scsi) { - // FURI_LOG_I(TAG, "END %02x", scsi->cmd[0]); + FURI_LOG_T(TAG, "END %02X", scsi->cmd[0]); uint8_t* cmd = scsi->cmd; uint8_t len = scsi->cmd_len; scsi->cmd = NULL; @@ -187,33 +230,34 @@ bool scsi_cmd_end(SCSISession* scsi) { case SCSI_REQUEST_SENSE: case SCSI_INQUIRY: - case SCSI_READ_CAPACITY_6: + case SCSI_READ_FORMAT_CAPACITIES: + case SCSI_READ_CAPACITY_10: case SCSI_MODE_SENSE_6: case SCSI_READ_10: return scsi->tx_done; case SCSI_TEST_UNIT_READY: { - FURI_LOG_I(TAG, "SCSI_TEST_UNIT_READY"); + FURI_LOG_D(TAG, "SCSI_TEST_UNIT_READY"); return true; }; break; case SCSI_PREVENT_MEDIUM_REMOVAL: { if(len < 6) return false; bool prevent = cmd[5]; - FURI_LOG_I(TAG, "SCSI_PREVENT_MEDIUM_REMOVAL prevent=%d", prevent); + FURI_LOG_D(TAG, "SCSI_PREVENT_MEDIUM_REMOVAL prevent=%d", prevent); return !prevent; }; break; case SCSI_START_STOP_UNIT: { if(len < 6) return false; bool eject = (cmd[4] & 2) != 0; bool start = (cmd[4] & 1) != 0; - FURI_LOG_I(TAG, "SCSI_START_STOP_UNIT eject=%d start=%d", eject, start); + FURI_LOG_D(TAG, "SCSI_START_STOP_UNIT eject=%d start=%d", eject, start); if(eject) { scsi->fn.eject(scsi->fn.ctx); } return true; }; break; default: { - FURI_LOG_W(TAG, "unexpected scsi cmd=%02x", cmd[0]); + FURI_LOG_W(TAG, "unexpected scsi cmd=%02X", cmd[0]); scsi->sk = SCSI_SK_ILLEGAL_REQUEST; scsi->asc = SCSI_ASC_INVALID_COMMAND_OPERATION_CODE; return false; diff --git a/applications/external/mass_storage/helpers/mass_storage_usb.c b/applications/external/mass_storage/helpers/mass_storage_usb.c index b0a55a592..8e3e0f875 100644 --- a/applications/external/mass_storage/helpers/mass_storage_usb.c +++ b/applications/external/mass_storage/helpers/mass_storage_usb.c @@ -44,6 +44,7 @@ typedef struct { uint8_t cmd_len; uint8_t cmd[16]; } __attribute__((packed)) CBW; + typedef struct { uint32_t sig; uint32_t tag; @@ -80,11 +81,11 @@ static int32_t mass_thread_worker(void* context) { while(true) { uint32_t flags = furi_thread_flags_wait(EventAll, FuriFlagWaitAny, FuriWaitForever); if(flags & EventExit) { - FURI_LOG_I(TAG, "exit"); + FURI_LOG_D(TAG, "exit"); break; } if(flags & EventReset) { - FURI_LOG_I(TAG, "reset"); + FURI_LOG_D(TAG, "reset"); scsi.sk = 0; scsi.asc = 0; memset(&cbw, 0, sizeof(cbw)); @@ -99,10 +100,10 @@ static int32_t mass_thread_worker(void* context) { if(flags & EventRxTx) do { switch(state) { case StateReadCBW: { - // FURI_LOG_I(TAG, "StateReadCBW"); + FURI_LOG_T(TAG, "StateReadCBW"); int32_t len = usbd_ep_read(dev, USB_MSC_RX_EP, &cbw, sizeof(cbw)); if(len <= 0) { - // FURI_LOG_I(TAG, "cbw not ready"); + FURI_LOG_T(TAG, "cbw not ready"); break; } if(len != sizeof(cbw) || cbw.sig != CBW_SIG) { @@ -131,14 +132,14 @@ static int32_t mass_thread_worker(void* context) { continue; }; break; case StateReadData: { - // FURI_LOG_I(TAG, "StateReadData %d/%d", buf_len, cbw.len); + FURI_LOG_T(TAG, "StateReadData %lu/%lu", buf_len, cbw.len); if(!cbw.len) { state = StateBuildCSW; continue; } uint32_t buf_clamp = MIN(cbw.len, USB_MSC_BUF_MAX); if(buf_clamp > buf_cap) { - FURI_LOG_I(TAG, "growing buf %lu -> %lu", buf_cap, buf_clamp); + FURI_LOG_T(TAG, "growing buf %lu -> %lu", buf_cap, buf_clamp); if(buf) { free(buf); } @@ -149,10 +150,10 @@ static int32_t mass_thread_worker(void* context) { int32_t len = usbd_ep_read(dev, USB_MSC_RX_EP, buf + buf_len, buf_clamp - buf_len); if(len < 0) { - // FURI_LOG_I(TAG, "rx not ready %d", len); + FURI_LOG_T(TAG, "rx not ready %ld", len); break; } - // FURI_LOG_I(TAG, "clamp %ld len %d", buf_clamp, len); + FURI_LOG_T(TAG, "clamp %lu len %ld", buf_clamp, len); buf_len += len; } if(buf_len == buf_clamp) { @@ -172,14 +173,14 @@ static int32_t mass_thread_worker(void* context) { continue; }; break; case StateWriteData: { - // FURI_LOG_I(TAG, "StateWriteData %d", cbw.len); + FURI_LOG_T(TAG, "StateWriteData %lu", cbw.len); if(!cbw.len) { state = StateBuildCSW; continue; } uint32_t buf_clamp = MIN(cbw.len, USB_MSC_BUF_MAX); if(buf_clamp > buf_cap) { - FURI_LOG_I(TAG, "growing buf %lu -> %lu", buf_cap, buf_clamp); + FURI_LOG_T(TAG, "growing buf %lu -> %lu", buf_cap, buf_clamp); if(buf) { free(buf); } @@ -198,7 +199,7 @@ static int32_t mass_thread_worker(void* context) { buf + buf_sent, MIN(USB_MSC_TX_EP_SIZE, buf_len - buf_sent)); if(len < 0) { - // FURI_LOG_I(TAG, "tx not ready %d", len); + FURI_LOG_T(TAG, "tx not ready %ld", len); break; } buf_sent += len; @@ -210,7 +211,7 @@ static int32_t mass_thread_worker(void* context) { continue; }; break; case StateBuildCSW: { - // FURI_LOG_I(TAG, "StateBuildCSW"); + FURI_LOG_T(TAG, "StateBuildCSW"); csw.sig = CSW_SIG; csw.tag = cbw.tag; if(scsi_cmd_end(&scsi)) { @@ -223,7 +224,7 @@ static int32_t mass_thread_worker(void* context) { continue; }; break; case StateWriteCSW: { - // FURI_LOG_I(TAG, "StateWriteCSW"); + FURI_LOG_T(TAG, "StateWriteCSW"); if(csw.status) { FURI_LOG_W( TAG, @@ -235,7 +236,7 @@ static int32_t mass_thread_worker(void* context) { } int32_t len = usbd_ep_write(dev, USB_MSC_TX_EP, &csw, sizeof(csw)); if(len < 0) { - // FURI_LOG_I(TAG, "csw not ready"); + FURI_LOG_T(TAG, "csw not ready"); break; } if(len != sizeof(csw)) { diff --git a/applications/external/mass_storage/mass_storage_app.c b/applications/external/mass_storage/mass_storage_app.c index 53cc92bb5..083fe9073 100644 --- a/applications/external/mass_storage/mass_storage_app.c +++ b/applications/external/mass_storage/mass_storage_app.c @@ -21,6 +21,19 @@ static void mass_storage_app_tick_event_callback(void* context) { scene_manager_handle_tick_event(app->scene_manager); } +void mass_storage_app_show_loading_popup(MassStorageApp* app, bool show) { + TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); + + if(show) { + // Raise timer priority so that animations can play + vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1); + view_dispatcher_switch_to_view(app->view_dispatcher, MassStorageAppViewLoading); + } else { + // Restore default timer priority + vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY); + } +} + MassStorageApp* mass_storage_app_alloc(char* arg) { MassStorageApp* app = malloc(sizeof(MassStorageApp)); app->file_path = furi_string_alloc(); @@ -36,7 +49,6 @@ MassStorageApp* mass_storage_app_alloc(char* arg) { 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); app->view_dispatcher = view_dispatcher_alloc(); @@ -76,6 +88,10 @@ MassStorageApp* mass_storage_app_alloc(char* arg) { view_dispatcher_add_view( app->view_dispatcher, MassStorageAppViewPopup, popup_get_view(app->popup)); + app->loading = loading_alloc(); + view_dispatcher_add_view( + app->view_dispatcher, MassStorageAppViewLoading, loading_get_view(app->loading)); + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); scene_manager_set_scene_state( @@ -94,15 +110,18 @@ void mass_storage_app_free(MassStorageApp* app) { // Views view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewWork); - mass_storage_free(app->mass_storage_view); view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewVarItemList); - variable_item_list_free(app->var_item_list); view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewSubmenu); - submenu_free(app->submenu); view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewTextInput); - text_input_free(app->text_input); view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewPopup); + view_dispatcher_remove_view(app->view_dispatcher, MassStorageAppViewLoading); + + mass_storage_free(app->mass_storage_view); + variable_item_list_free(app->var_item_list); + submenu_free(app->submenu); + text_input_free(app->text_input); popup_free(app->popup); + loading_free(app->loading); // View dispatcher view_dispatcher_free(app->view_dispatcher); @@ -113,7 +132,6 @@ void mass_storage_app_free(MassStorageApp* app) { // Close records furi_record_close(RECORD_GUI); furi_record_close(RECORD_STORAGE); - furi_record_close(RECORD_NOTIFICATION); furi_record_close(RECORD_DIALOGS); free(app); diff --git a/applications/external/mass_storage/mass_storage_app_i.h b/applications/external/mass_storage/mass_storage_app_i.h index ca40df4f0..72aca8a1b 100644 --- a/applications/external/mass_storage/mass_storage_app_i.h +++ b/applications/external/mass_storage/mass_storage_app_i.h @@ -9,16 +9,16 @@ #include #include #include -#include -#include #include #include #include #include +#include #include #include "views/mass_storage_view.h" #define MASS_STORAGE_APP_PATH_FOLDER STORAGE_APP_DATA_PATH_PREFIX +#define MASS_STORAGE_APP_EXTENSION ".img" #define MASS_STORAGE_FILE_NAME_LEN 40 typedef enum { @@ -32,14 +32,12 @@ struct MassStorageApp { Storage* fs_api; ViewDispatcher* view_dispatcher; SceneManager* scene_manager; - NotificationApp* notifications; DialogsApp* dialogs; - Widget* widget; - MassStorage* mass_storage_view; VariableItemList* var_item_list; Submenu* submenu; TextInput* text_input; Popup* popup; + Loading* loading; uint32_t create_image_size; SizeUnit create_size_unit; @@ -47,16 +45,19 @@ struct MassStorageApp { FuriString* file_path; File* file; + MassStorage* mass_storage_view; FuriMutex* usb_mutex; MassStorageUsb* usb; }; typedef enum { - MassStorageAppViewError, - MassStorageAppViewWork, MassStorageAppViewVarItemList, MassStorageAppViewSubmenu, MassStorageAppViewTextInput, MassStorageAppViewPopup, + MassStorageAppViewLoading, + MassStorageAppViewWork, } MassStorageAppView; + +void mass_storage_app_show_loading_popup(MassStorageApp* app, bool show); diff --git a/applications/external/mass_storage/scenes/mass_storage_scene_create_image.c b/applications/external/mass_storage/scenes/mass_storage_scene_create_image.c index 861a9550d..f6a8eab37 100644 --- a/applications/external/mass_storage/scenes/mass_storage_scene_create_image.c +++ b/applications/external/mass_storage/scenes/mass_storage_scene_create_image.c @@ -100,14 +100,7 @@ bool mass_storage_scene_create_image_on_event(void* context, SceneManagerEvent e scene_manager_next_scene(app->scene_manager, MassStorageSceneCreateImageName); break; case VarItemListIndexCreate: { - popup_set_header(app->popup, "Creating Image...", 64, 32, AlignCenter, AlignCenter); - popup_set_text(app->popup, "", 0, 0, AlignLeft, AlignBottom); - popup_set_callback(app->popup, NULL); - popup_set_context(app->popup, NULL); - popup_set_timeout(app->popup, 0); - popup_disable_timeout(app->popup); - view_dispatcher_switch_to_view(app->view_dispatcher, MassStorageAppViewPopup); - + mass_storage_app_show_loading_popup(app, true); bool default_name = !strnlen(app->create_name, sizeof(app->create_name)); if(default_name) { snprintf( @@ -117,7 +110,12 @@ bool mass_storage_scene_create_image_on_event(void* context, SceneManagerEvent e app->create_image_size, size_unit_names[app->create_size_unit]); } - furi_string_printf(app->file_path, APP_DATA_PATH("%s.img"), app->create_name); + furi_string_printf( + app->file_path, + "%s/%s%s", + MASS_STORAGE_APP_PATH_FOLDER, + app->create_name, + MASS_STORAGE_APP_EXTENSION); app->file = storage_file_alloc(app->fs_api); const char* error = NULL; @@ -136,6 +134,7 @@ bool mass_storage_scene_create_image_on_event(void* context, SceneManagerEvent e } } storage_file_free(app->file); + mass_storage_app_show_loading_popup(app, false); if(error) { popup_set_header( diff --git a/applications/external/mass_storage/scenes/mass_storage_scene_create_image_name.c b/applications/external/mass_storage/scenes/mass_storage_scene_create_image_name.c index 8915900f2..48ae74327 100644 --- a/applications/external/mass_storage/scenes/mass_storage_scene_create_image_name.c +++ b/applications/external/mass_storage/scenes/mass_storage_scene_create_image_name.c @@ -13,7 +13,7 @@ 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, "Leave empty for default"); + text_input_set_header_text(text_input, "Image name, empty = default"); text_input_set_minimum_length(text_input, 0); diff --git a/applications/external/mass_storage/scenes/mass_storage_scene_start.c b/applications/external/mass_storage/scenes/mass_storage_scene_start.c index 57afc1130..8f3a7abdb 100644 --- a/applications/external/mass_storage/scenes/mass_storage_scene_start.c +++ b/applications/external/mass_storage/scenes/mass_storage_scene_start.c @@ -12,7 +12,7 @@ void mass_storage_scene_start_on_enter(void* context) { submenu_add_item( submenu, - "Emulate Image", + "Select Disc Image", MassStorageSceneFileSelect, mass_storage_scene_start_submenu_callback, app); diff --git a/applications/external/mass_storage/scenes/mass_storage_scene_work.c b/applications/external/mass_storage/scenes/mass_storage_scene_work.c index 9776e9f17..ad3630a48 100644 --- a/applications/external/mass_storage/scenes/mass_storage_scene_work.c +++ b/applications/external/mass_storage/scenes/mass_storage_scene_work.c @@ -13,20 +13,20 @@ static bool file_read( uint32_t* out_len, uint32_t out_cap) { MassStorageApp* app = ctx; - // FURI_LOG_I(TAG, "file_read lba=%08lx count=%04x out_cap=%04x", lba, count, out_cap); + 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_I(TAG, "%d/%d", *out_len, count * SCSI_BLOCK_SIZE); + FURI_LOG_T(TAG, "%lu/%lu", *out_len, count * SCSI_BLOCK_SIZE); 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_I(TAG, "file_write lba=%08lx count=%04x len=%04x", lba, count, len); + 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; @@ -45,7 +45,7 @@ static uint32_t file_num_blocks(void* ctx) { static void file_eject(void* ctx) { MassStorageApp* app = ctx; - FURI_LOG_I(TAG, "EJECT"); + FURI_LOG_D(TAG, "EJECT"); furi_check(furi_mutex_acquire(app->usb_mutex, FuriWaitForever) == FuriStatusOk); mass_storage_usb_stop(app->usb); app->usb = NULL; @@ -54,19 +54,38 @@ static void file_eject(void* ctx) { bool mass_storage_scene_work_on_event(void* context, SceneManagerEvent event) { MassStorageApp* app = context; + bool consumed = false; if(event.type == SceneManagerEventTypeTick) { bool ejected; furi_check(furi_mutex_acquire(app->usb_mutex, FuriWaitForever) == FuriStatusOk); ejected = app->usb == NULL; 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); + consumed = true; + } + } 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 false; + return consumed; } void mass_storage_scene_work_on_enter(void* context) { MassStorageApp* app = context; + 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(); @@ -92,13 +111,18 @@ void mass_storage_scene_work_on_enter(void* context) { 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); - furi_mutex_free(app->usb_mutex); + 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; @@ -107,4 +131,5 @@ void mass_storage_scene_work_on_exit(void* context) { storage_file_free(app->file); app->file = NULL; } + mass_storage_app_show_loading_popup(app, false); }