Skip to content

Commit f78aaf9

Browse files
committed
🚸 Detect multi-volume insert / remove
1 parent 38d6d61 commit f78aaf9

File tree

7 files changed

+168
-66
lines changed

7 files changed

+168
-66
lines changed

Marlin/src/MarlinCore.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,8 +1349,11 @@ void setup() {
13491349
#endif
13501350
#endif
13511351

1352-
#if HAS_MEDIA && ANY(SDCARD_EEPROM_EMULATION, POWER_LOSS_RECOVERY)
1353-
SETUP_RUN(card.mount()); // Mount media with settings before first_load
1352+
#if HAS_MEDIA
1353+
SETUP_RUN(card.init()); // Prepare for media usage
1354+
#if ANY(SDCARD_EEPROM_EMULATION, POWER_LOSS_RECOVERY)
1355+
SETUP_RUN(card.mount()); // Mount media with settings before first_load
1356+
#endif
13541357
#endif
13551358

13561359
// Prepare some LCDs to display early

Marlin/src/lcd/extui/anycubic_chiron/chiron_tft.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@ void ChironTFT::panelAction(uint8_t req) {
740740
break;
741741

742742
case 26: // A26 Refresh SD
743-
if (card.isMounted())card.release();
743+
card.release();
744744
card.mount();
745745
safe_delay(500);
746746
filenavigator.reset();

Marlin/src/lcd/extui/mks_ui/tft_lvgl_configuration.cpp

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -131,32 +131,16 @@ void tft_lvgl_init() {
131131
// Init TFT first!
132132
SPI_TFT.spiInit(SPI_FULL_SPEED);
133133
SPI_TFT.lcdInit();
134-
135134
hal.watchdog_refresh(); // LVGL init takes time
136135

137-
#if HAS_USB_FLASH_DRIVE
138-
#if HAS_MULTI_VOLUME && !HAS_SD_HOST_DRIVE
139-
if (card.isSDCardInserted())
140-
card.selectMediaSDCard();
141-
else
142-
card.selectMediaFlashDrive();
143-
#endif
144-
// Wait up to two seconds for USB Drive to mount
145-
for (uint16_t usb_flash_loop = 500; --usb_flash_loop;) {
146-
hal.watchdog_refresh();
147-
card.media_driver_usbFlash.idle();
148-
delay(4);
149-
if (card.media_driver_usbFlash.isInserted()) break;
150-
}
151-
card.mount();
152-
#elif HAS_LOGO_IN_FLASH
136+
#if HAS_LOGO_IN_FLASH
137+
// Leave the boot screen visible for a moment
153138
delay(1000);
154-
hal.watchdog_refresh();
139+
hal.watchdog_refresh(); // LVGL init takes time
155140
delay(1000);
141+
hal.watchdog_refresh(); // LVGL init takes time
156142
#endif
157143

158-
hal.watchdog_refresh(); // LVGL init takes time
159-
160144
#if HAS_MEDIA
161145
UpdateAssets();
162146
hal.watchdog_refresh(); // LVGL init takes time

Marlin/src/lcd/marlinui.cpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,40 +1891,60 @@ uint8_t expand_u8str_P(char * const outstr, PGM_P const ptpl, const int8_t ind,
18911891
#include "extui/ui_api.h"
18921892
#endif
18931893

1894-
void MarlinUI::media_changed(const uint8_t old_status, const uint8_t status) {
1894+
void MarlinUI::media_changed(const MediaPresence old_status, const MediaPresence status) {
18951895
TERN_(HAS_DISPLAY_SLEEP, refresh_screen_timeout());
18961896
if (old_status == status) {
18971897
TERN_(EXTENSIBLE_UI, ExtUI::onMediaError()); // Failed to mount/unmount
18981898
return;
18991899
}
19001900

1901-
if (old_status < 2) { // Skip this section on first boot check
1902-
if (status) { // Media Mounted
1901+
if (old_status > MEDIA_BOOT) { // Skip this section on first boot check
1902+
1903+
if (status > old_status) { // Media Mounted
1904+
19031905
#if ENABLED(EXTENSIBLE_UI)
1906+
19041907
ExtUI::onMediaMounted();
1908+
19051909
#elif ENABLED(BROWSE_MEDIA_ON_INSERT)
1910+
19061911
clear_menu_history();
19071912
quick_feedback();
19081913
goto_screen(MEDIA_MENU_GATEWAY);
1914+
19091915
#else
1916+
19101917
if (card.isSDCardSelected())
19111918
LCD_MESSAGE(MSG_MEDIA_INSERTED_SD);
19121919
else if (card.isFlashDriveSelected())
19131920
LCD_MESSAGE(MSG_MEDIA_INSERTED_USB);
19141921
else
19151922
LCD_MESSAGE(MSG_MEDIA_INSERTED);
1923+
19161924
#endif
19171925
}
19181926
else { // Media Removed
1927+
19191928
#if ENABLED(EXTENSIBLE_UI)
1929+
19201930
ExtUI::onMediaRemoved();
1921-
#elif HAS_SD_DETECT // Q: Does "Media Removed" need to be shown for manual release too?
1922-
LCD_MESSAGE(MSG_MEDIA_REMOVED);
1923-
#if HAS_MARLINUI_MENU
1924-
if (ENABLED(HAS_WIRED_LCD) || !defer_return_to_status) return_to_status();
1925-
#endif
1931+
1932+
#elif HAS_SD_DETECT || HAS_USB_FLASH_DRIVE // Q: Does "Media Removed" need to be shown for manual release too?
1933+
1934+
if ((old_status ^ status) & INSERT_SD)
1935+
LCD_MESSAGE(MSG_MEDIA_REMOVED_SD);
1936+
else if ((old_status ^ status) & INSERT_USB)
1937+
LCD_MESSAGE(MSG_MEDIA_REMOVED_USB);
1938+
else
1939+
LCD_MESSAGE(MSG_MEDIA_REMOVED);
1940+
1941+
if (ENABLED(HAS_WIRED_LCD) || !defer_return_to_status)
1942+
return_to_status();
1943+
19261944
#elif HAS_WIRED_LCD
1945+
19271946
return_to_status();
1947+
19281948
#endif
19291949
}
19301950
}

Marlin/src/lcd/marlinui.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ class MarlinUI {
256256

257257
#if HAS_MEDIA
258258
#define MEDIA_MENU_GATEWAY TERN(PASSWORD_ON_SD_PRINT_MENU, password.media_gatekeeper, menu_media)
259-
static void media_changed(const uint8_t old_stat, const uint8_t stat);
259+
static void media_changed(const MediaPresence old_stat, const MediaPresence stat);
260260
#endif
261261

262262
#if HAS_LCD_BRIGHTNESS

Marlin/src/sd/cardreader.cpp

Lines changed: 118 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ int16_t CardReader::nrItems = -1;
145145
#endif
146146

147147
DiskIODriver* CardReader::driver = nullptr;
148+
148149
MarlinVolume CardReader::volume;
149150
MediaFile CardReader::myfile;
150151

@@ -483,11 +484,15 @@ void CardReader::mount() {
483484
nrItems = -1;
484485
if (root.isOpen()) root.close();
485486

486-
if (!driver->init(SD_SPI_SPEED, SD_SS_PIN)
487+
const bool driver_init = (
488+
driver->init(SD_SPI_SPEED, SD_SS_PIN)
487489
#if PIN_EXISTS(LCD_SDSS) && (LCD_SDSS_PIN != SD_SS_PIN)
488-
&& !driver->init(SD_SPI_SPEED, LCD_SDSS_PIN)
490+
|| driver->init(SD_SPI_SPEED, LCD_SDSS_PIN)
489491
#endif
490-
) SERIAL_ECHO_MSG(STR_SD_INIT_FAIL);
492+
);
493+
494+
if (!driver_init)
495+
SERIAL_ECHO_MSG(STR_SD_INIT_FAIL);
491496
else if (!volume.init(driver))
492497
SERIAL_WARN_MSG(STR_SD_VOL_INIT_FAIL);
493498
else if (!root.openRoot(&volume))
@@ -519,69 +524,146 @@ void CardReader::mount() {
519524
#include "../module/stepper.h"
520525
#endif
521526

527+
// Provide a little time for drives to prepare
528+
void CardReader::init() {
529+
#if HAS_USB_FLASH_DRIVE
530+
for (uint8_t i = 10; --i;) {
531+
media_driver_usbFlash.idle();
532+
hal.watchdog_refresh();
533+
if (media_driver_usbFlash.isInserted()) break;
534+
delay(20);
535+
}
536+
#endif
537+
}
538+
522539
/**
523-
* Handle SD card events
540+
* Handle media insertion and removal events
541+
* based on SD Card detect and/or driver.isInserted()
542+
*
543+
* MULTI_VOLUME:
544+
* - Track insert/remove for both media drives.
545+
* - If the MOUNTED media is removed call release().
546+
* - If media is INSERTED when NO MEDIA is mounted, select and mount it.
524547
*/
525548
void CardReader::manage_media() {
526-
#if HAS_USB_FLASH_DRIVE // Wrap for optimal non-virtual?
527-
driver->idle(); // Handle device tasks (e.g., USB Drive insert / remove)
549+
/**
550+
* Handle device tasks (e.g., USB Drive insert / remove)
551+
* - USB Flash Drive needs to run even when not selected.
552+
* - SD Card currently has no background tasks.
553+
*/
554+
//driver->idle();
555+
#if HAS_USB_FLASH_DRIVE
556+
//if (!isFlashDriveSelected())
557+
media_driver_usbFlash.idle();
558+
#endif
559+
560+
// Prevent re-entry during Marlin::idle
561+
#if HAS_MULTI_VOLUME
562+
static bool no_reenter = false;
563+
if (no_reenter) return;
528564
#endif
529565

530-
static uint8_t prev_stat = 2; // At boot we don't know if media is present or not
531-
uint8_t stat = uint8_t(isInserted());
566+
static MediaPresence prev_stat = MEDIA_BOOT; // At boot we don't know if media is present or not
567+
568+
// Live status is based on available media flags
569+
MediaPresence stat = MediaPresence(
570+
#if HAS_MULTI_VOLUME
571+
(isSDCardInserted() ? INSERT_SD : 0) // Without SD Detect it's always "inserted"
572+
| (isFlashDriveInserted() ? INSERT_USB : 0)
573+
#else
574+
isInserted() ? INSERT_MEDIA : 0 // Without SD Detect it's always "inserted"
575+
#endif
576+
);
577+
532578
if (stat == prev_stat) return; // Already checked and still no change?
533579

534580
DEBUG_SECTION(cmm, "CardReader::manage_media()", true);
535581
DEBUG_ECHOLNPGM("Media present: ", prev_stat, " -> ", stat);
536582

537-
if (!ui.detected()) {
538-
DEBUG_ECHOLNPGM("SD: No UI Detected.");
539-
return;
540-
}
583+
// Without a UI there's no auto-mount or release
584+
if (!ui.detected()) { DEBUG_ECHOLNPGM("SD: No UI Detected."); return; }
541585

542-
flag.workDirIsRoot = true; // Return to root on mount/release/init
543-
544-
const uint8_t old_stat = prev_stat;
586+
const MediaPresence old_stat = prev_stat,
587+
old_real = old_stat == MEDIA_BOOT ? INSERT_NONE : old_stat;
545588
prev_stat = stat; // Change now to prevent re-entry in safe_delay
546589

547-
if (stat) { // Media Inserted
548-
safe_delay(500); // Some boards need a delay to get settled
590+
#if HAS_MULTI_VOLUME
591+
const int8_t vdiff = (old_real ^ stat), vadd = vdiff & stat;
592+
#endif
593+
const bool did_insert = TERN(HAS_MULTI_VOLUME, vadd, stat) != INSERT_NONE;
594+
595+
if (did_insert) { // Media Inserted
596+
597+
TERN_(HAS_MULTI_VOLUME, ui.refresh()); // Refresh for insert events without messages
598+
599+
// Some media is already mounted? Nothing to do.
600+
if (TERN0(HAS_MULTI_VOLUME, isMounted())) return;
549601

550-
// Try to mount the media (only later with SD_IGNORE_AT_STARTUP)
551-
if (TERN1(SD_IGNORE_AT_STARTUP, old_stat != 2)) mount();
552-
if (!isMounted()) stat = 0; // Not mounted?
602+
// Prevent re-entry during the following phases
603+
TERN_(HAS_MULTI_VOLUME, no_reenter = true);
604+
605+
// Try to mount the media (but not at boot if SD_IGNORE_AT_STARTUP)
606+
if (TERN1(SD_IGNORE_AT_STARTUP, old_stat > MEDIA_BOOT)) {
607+
#if HAS_MULTI_VOLUME
608+
if ((vadd & INSERT_SD) && !isSDCardSelected())
609+
selectMediaSDCard();
610+
if ((vadd & INSERT_USB) && !isFlashDriveSelected())
611+
selectMediaFlashDrive();
612+
#endif
613+
safe_delay(500); // Time for inserted media to settle. May re-enter for multiple media?
614+
mount();
615+
}
616+
617+
// If the selected media isn't mounted throw an alert in ui.media_changed
618+
if (!isMounted()) stat = old_real;
553619

554620
TERN_(RESET_STEPPERS_ON_MEDIA_INSERT, reset_stepper_drivers()); // Workaround for Cheetah bug
621+
622+
// Re-enable media detection logic
623+
TERN_(HAS_MULTI_VOLUME, no_reenter = false);
624+
}
625+
else if (
626+
// Media was removed from the device slot
627+
#if HAS_MULTI_VOLUME
628+
(isSDCardSelected() && (vdiff & INSERT_SD))
629+
|| (isFlashDriveSelected() && (vdiff & INSERT_USB))
630+
#else
631+
stat // == INSERT_MEDIA
632+
#endif
633+
) {
634+
flag.workDirIsRoot = true; // Return to root on release
635+
release();
636+
//TERN_(HAS_MULTI_VOLUME, prev_stat = INSERT_NONE); // HACK to try mounting any remaining media
555637
}
556638
else {
557-
TERN_(HAS_SD_DETECT, release()); // Card is released
639+
#if HAS_MULTI_VOLUME
640+
stat = old_real; // Ignore un-mounted media being ejected
641+
ui.refresh(); // Refresh for menus that show inserted unmounted media
642+
#endif
558643
}
559644

560-
ui.media_changed(old_stat, stat); // Update the UI or flag an error
645+
ui.media_changed(old_stat, stat); // Update the UI or flag an error
561646

562-
if (!stat) return; // Exit if no media is present
563-
564-
bool do_auto = true; UNUSED(do_auto);
647+
if (stat == INSERT_NONE) return; // Exit if no media is present
565648

566649
// First mount on boot? Load emulated EEPROM and look for PLR file.
567-
if (old_stat == 2) {
650+
if (old_stat <= MEDIA_BOOT) {
568651
DEBUG_ECHOLNPGM("First mount.");
569652

570653
// Load settings the first time media is inserted (not just during init)
571654
TERN_(SDCARD_EEPROM_EMULATION, settings.first_load());
572655

573-
// Check for PLR file. Skip One-Click and auto#.g if found
574-
TERN_(POWER_LOSS_RECOVERY, if (recovery.check()) do_auto = false);
656+
// Check for PLR file. If found skip other procedures!
657+
if (TERN0(POWER_LOSS_RECOVERY, recovery.check())) return;
575658
}
576659

577-
// Find the newest file and prompt to print it.
578-
TERN_(ONE_CLICK_PRINT, if (do_auto && one_click_check()) do_auto = false);
660+
// Find the newest file and prompt to print it. Skip other procedures!
661+
if (TERN0(ONE_CLICK_PRINT, one_click_check())) return;
579662

580-
// Also for the first mount run auto#.g for machine init.
581-
// (Skip if PLR or One-Click Print was invoked.)
582-
if (old_stat == 2) {
663+
// On first mount at boot run auto#.g for machine init.
664+
if (old_stat <= MEDIA_BOOT) {
583665
// Look for auto0.g on the next idle()
584-
IF_DISABLED(NO_SD_AUTOSTART, if (do_auto) autofile_begin());
666+
IF_DISABLED(NO_SD_AUTOSTART, autofile_begin());
585667
}
586668
}
587669

@@ -590,6 +672,8 @@ void CardReader::manage_media() {
590672
* Used by M22, "Release Media", manage_media.
591673
*/
592674
void CardReader::release() {
675+
if (!flag.mounted) return;
676+
593677
// Card removed while printing? Abort!
594678
if (isStillPrinting())
595679
abortFilePrintSoon();

Marlin/src/sd/cardreader.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ typedef struct {
7878
;
7979
} card_flags_t;
8080

81+
enum MediaPresence : int8_t {
82+
MEDIA_BOOT = -1,
83+
INSERT_NONE = 0x00,
84+
INSERT_MEDIA = 0x01,
85+
INSERT_SD = TERN(HAS_MULTI_VOLUME, 0x02, 0x00),
86+
INSERT_USB = TERN(HAS_MULTI_VOLUME, 0x04, 0x00)
87+
};
88+
8189
enum ListingFlags : uint8_t { LS_LONG_FILENAME, LS_ONLY_BIN, LS_TIMESTAMP };
8290
enum SortFlag : int8_t { AS_REV = -1, AS_OFF, AS_FWD, AS_ALSO_REV };
8391

@@ -102,6 +110,9 @@ class CardReader {
102110

103111
CardReader();
104112

113+
// Init at startup before mounting media
114+
static void init();
115+
105116
/**
106117
* Media Selection - Only one drive may be active at a time,
107118
* so switching drives (currently) returns to the root folder.

0 commit comments

Comments
 (0)