@@ -145,6 +145,7 @@ int16_t CardReader::nrItems = -1;
145145#endif
146146
147147DiskIODriver* CardReader::driver = nullptr ;
148+
148149MarlinVolume CardReader::volume;
149150MediaFile 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 */
525548void 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 */
592674void CardReader::release () {
675+ if (!flag.mounted ) return ;
676+
593677 // Card removed while printing? Abort!
594678 if (isStillPrinting ())
595679 abortFilePrintSoon ();
0 commit comments