Ensure proper SD print completion (#16967)
This commit is contained in:
		@@ -390,8 +390,8 @@ void startOrResumeJob() {
 | 
			
		||||
 | 
			
		||||
#if ENABLED(SDSUPPORT)
 | 
			
		||||
 | 
			
		||||
  void abortSDPrinting() {
 | 
			
		||||
    card.stopSDPrint(
 | 
			
		||||
  inline void abortSDPrinting() {
 | 
			
		||||
    card.endFilePrint(
 | 
			
		||||
      #if SD_RESORT
 | 
			
		||||
        true
 | 
			
		||||
      #endif
 | 
			
		||||
@@ -412,10 +412,68 @@ void startOrResumeJob() {
 | 
			
		||||
    #endif
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  #if ENABLED(PRINTER_EVENT_LEDS)
 | 
			
		||||
    #include "feature/leds/printer_event_leds.h"
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  inline void finishSDPrinting() {
 | 
			
		||||
    bool did_state = true;
 | 
			
		||||
    switch (card.sdprinting_done_state) {
 | 
			
		||||
 | 
			
		||||
      #if ENABLED(PRINTER_EVENT_LEDS)
 | 
			
		||||
        case 1:
 | 
			
		||||
          printerEventLEDs.onPrintCompleted();  // Change LED color for Print Completed
 | 
			
		||||
          break;
 | 
			
		||||
      #endif
 | 
			
		||||
 | 
			
		||||
      #if HAS_RESUME_CONTINUE                   // Display "Click to Continue..."
 | 
			
		||||
        case 2:
 | 
			
		||||
          did_state = queue.enqueue_P(PSTR("M0 S"
 | 
			
		||||
            #if HAS_LCD_MENU
 | 
			
		||||
              "1800"                            // ...for 30 minutes with LCD
 | 
			
		||||
            #else
 | 
			
		||||
              "60"                              // ...for 1 minute with no LCD
 | 
			
		||||
            #endif
 | 
			
		||||
          ));
 | 
			
		||||
          break;
 | 
			
		||||
      #endif
 | 
			
		||||
 | 
			
		||||
      case 3: print_job_timer.stop(); break;
 | 
			
		||||
 | 
			
		||||
      case 4:
 | 
			
		||||
        did_state = print_job_timer.duration() < 60 || queue.enqueue_P(PSTR("M31"));
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      case 5:
 | 
			
		||||
        #if ENABLED(POWER_LOSS_RECOVERY)
 | 
			
		||||
          recovery.purge();
 | 
			
		||||
        #endif
 | 
			
		||||
 | 
			
		||||
        #if ENABLED(SD_FINISHED_STEPPERRELEASE) && defined(SD_FINISHED_RELEASECOMMAND)
 | 
			
		||||
          planner.finish_and_disable();
 | 
			
		||||
        #endif
 | 
			
		||||
 | 
			
		||||
        #if ENABLED(LCD_SET_PROGRESS_MANUALLY)
 | 
			
		||||
          ui.set_progress_done();
 | 
			
		||||
        #endif
 | 
			
		||||
 | 
			
		||||
        #if ENABLED(SD_REPRINT_LAST_SELECTED_FILE)
 | 
			
		||||
          ui.reselect_last_file();
 | 
			
		||||
        #endif
 | 
			
		||||
 | 
			
		||||
        SERIAL_ECHOLNPGM(MSG_FILE_PRINTED);
 | 
			
		||||
 | 
			
		||||
      default:
 | 
			
		||||
        did_state = false;
 | 
			
		||||
        card.sdprinting_done_state = 0;
 | 
			
		||||
    }
 | 
			
		||||
    if (did_state) ++card.sdprinting_done_state;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
#endif // SDSUPPORT
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Manage several activities:
 | 
			
		||||
 * Minimal management of Marlin's core activities:
 | 
			
		||||
 *  - Check for Filament Runout
 | 
			
		||||
 *  - Keep the command buffer full
 | 
			
		||||
 *  - Check for maximum inactive time between commands
 | 
			
		||||
@@ -1122,10 +1180,15 @@ void setup() {
 | 
			
		||||
/**
 | 
			
		||||
 * The main Marlin program loop
 | 
			
		||||
 *
 | 
			
		||||
 *  - Save or log commands to SD
 | 
			
		||||
 *  - Process available commands (if not saving)
 | 
			
		||||
 *  - Call endstop manager
 | 
			
		||||
 *  - Call inactivity manager
 | 
			
		||||
 *  - Call idle() to handle all tasks between G-code commands
 | 
			
		||||
 *      Note that no G-codes from the queue can be executed during idle()
 | 
			
		||||
 *      but many G-codes can be called directly anytime like macros.
 | 
			
		||||
 *  - Check whether SD card auto-start is needed now.
 | 
			
		||||
 *  - Check whether SD print finishing is needed now.
 | 
			
		||||
 *  - Run one G-code command from the immediate or main command queue
 | 
			
		||||
 *    and open up one space. Commands in the main queue may come from sd
 | 
			
		||||
 *    card, host, or by direct injection. The queue will continue to fill
 | 
			
		||||
 *    as long as idle() or manage_inactivity() are being called.
 | 
			
		||||
 */
 | 
			
		||||
void loop() {
 | 
			
		||||
  do {
 | 
			
		||||
@@ -1135,6 +1198,7 @@ void loop() {
 | 
			
		||||
    #if ENABLED(SDSUPPORT)
 | 
			
		||||
      card.checkautostart();
 | 
			
		||||
      if (card.flag.abort_sd_printing) abortSDPrinting();
 | 
			
		||||
      if (card.sdprinting_done_state) finishSDPrinting();
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    queue.advance();
 | 
			
		||||
 
 | 
			
		||||
@@ -512,9 +512,10 @@ void GCodeQueue::get_serial_commands() {
 | 
			
		||||
#if ENABLED(SDSUPPORT)
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Get commands from the SD Card until the command buffer is full
 | 
			
		||||
   * or until the end of the file is reached. The special character '#'
 | 
			
		||||
   * can also interrupt buffering.
 | 
			
		||||
   * Get lines from the SD Card until the command buffer is full
 | 
			
		||||
   * or until the end of the file is reached. Because this method
 | 
			
		||||
   * always receives complete command-lines, they can go directly
 | 
			
		||||
   * into the main command queue.
 | 
			
		||||
   */
 | 
			
		||||
  inline void GCodeQueue::get_sdcard_commands() {
 | 
			
		||||
    static uint8_t sd_input_state = PS_NORMAL;
 | 
			
		||||
@@ -527,37 +528,21 @@ void GCodeQueue::get_serial_commands() {
 | 
			
		||||
      const int16_t n = card.get();
 | 
			
		||||
      card_eof = card.eof();
 | 
			
		||||
      if (n < 0 && !card_eof) { SERIAL_ERROR_MSG(MSG_SD_ERR_READ); continue; }
 | 
			
		||||
 | 
			
		||||
      const char sd_char = (char)n;
 | 
			
		||||
      if (sd_char == '\n' || sd_char == '\r' || card_eof) {
 | 
			
		||||
      const bool is_eol = sd_char == '\n' || sd_char == '\r';
 | 
			
		||||
      if (is_eol || card_eof) {
 | 
			
		||||
 | 
			
		||||
        // Reset stream state, terminate the buffer, and commit a non-empty command
 | 
			
		||||
        if (!is_eol && sd_count) ++sd_count;          // End of file with no newline
 | 
			
		||||
        if (!process_line_done(sd_input_state, command_buffer[index_w], sd_count)) {
 | 
			
		||||
          _commit_command(false);                     // Can handle last line missing a newline terminator
 | 
			
		||||
          _commit_command(false);
 | 
			
		||||
          #if ENABLED(POWER_LOSS_RECOVERY)
 | 
			
		||||
            recovery.cmd_sdpos = card.getIndex();     // Prime for the next _commit_command
 | 
			
		||||
            recovery.cmd_sdpos = card.getIndex();     // Prime for the NEXT _commit_command
 | 
			
		||||
          #endif
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (card_eof) {
 | 
			
		||||
 | 
			
		||||
          card.fileHasFinished();                     // Handle end of file reached
 | 
			
		||||
 | 
			
		||||
          if (!IS_SD_PRINTING()) {                    // Was it the main job file?
 | 
			
		||||
            SERIAL_ECHOLNPGM(MSG_FILE_PRINTED);       // Tell the host the file is printed.
 | 
			
		||||
            #if ENABLED(PRINTER_EVENT_LEDS)
 | 
			
		||||
              printerEventLEDs.onPrintCompleted();    // Change LED color for Print Completed
 | 
			
		||||
              #if HAS_RESUME_CONTINUE
 | 
			
		||||
                enqueue_now_P(PSTR("M0 S"             // Display "Click to Continue..."
 | 
			
		||||
                  #if HAS_LCD_MENU
 | 
			
		||||
                    "1800"                            // ...for 30 minutes with LCD
 | 
			
		||||
                  #else
 | 
			
		||||
                    "60"                              // ...for 1 minute with no LCD
 | 
			
		||||
                  #endif
 | 
			
		||||
                ));
 | 
			
		||||
              #endif
 | 
			
		||||
            #endif
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        if (card_eof) card.fileHasFinished();         // Handle end of file reached
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
        process_stream_char(sd_char, sd_input_state, command_buffer[index_w], sd_count);
 | 
			
		||||
@@ -633,9 +618,7 @@ void GCodeQueue::advance() {
 | 
			
		||||
  #endif // SDSUPPORT
 | 
			
		||||
 | 
			
		||||
  // The queue may be reset by a command handler or by code invoked by idle() within a handler
 | 
			
		||||
  if (length) {
 | 
			
		||||
  --length;
 | 
			
		||||
  if (++index_r >= BUFSIZE) index_r = 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -117,6 +117,12 @@ public:
 | 
			
		||||
   */
 | 
			
		||||
  static void flush_and_request_resend();
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Attempt to enqueue a single G-code command
 | 
			
		||||
   * and return 'true' if successful.
 | 
			
		||||
   */
 | 
			
		||||
  FORCE_INLINE static bool enqueue_P(const char* cmd) { return _enqueue(cmd); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
  static uint8_t index_w;  // Ring buffer write position
 | 
			
		||||
 
 | 
			
		||||
@@ -324,9 +324,9 @@ void MarlinUI::_synchronize() {
 | 
			
		||||
  if (should_draw()) MenuItem_static::draw(LCD_HEIGHT >= 4, sync_message);
 | 
			
		||||
  if (no_reentry) return;
 | 
			
		||||
  // Make this the current handler till all moves are done
 | 
			
		||||
  no_reentry = true;
 | 
			
		||||
  const screenFunc_t old_screen = currentScreen;
 | 
			
		||||
  goto_screen(_synchronize);
 | 
			
		||||
  no_reentry = true;
 | 
			
		||||
  planner.synchronize(); // idle() is called until moves complete
 | 
			
		||||
  no_reentry = false;
 | 
			
		||||
  goto_screen(old_screen);
 | 
			
		||||
 
 | 
			
		||||
@@ -403,7 +403,7 @@ void Endstops::event_handler() {
 | 
			
		||||
 | 
			
		||||
    #if BOTH(SD_ABORT_ON_ENDSTOP_HIT, SDSUPPORT)
 | 
			
		||||
      if (planner.abort_on_endstop_hit) {
 | 
			
		||||
        card.stopSDPrint();
 | 
			
		||||
        card.endFilePrint();
 | 
			
		||||
        quickstop_stepper();
 | 
			
		||||
        thermalManager.disable_all_heaters();
 | 
			
		||||
        print_job_timer.stop();
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@
 | 
			
		||||
 | 
			
		||||
#include "../MarlinCore.h"
 | 
			
		||||
#include "../lcd/ultralcd.h"
 | 
			
		||||
#include "../module/planner.h"
 | 
			
		||||
#include "../module/planner.h"        // for synchronize
 | 
			
		||||
#include "../module/printcounter.h"
 | 
			
		||||
#include "../core/language.h"
 | 
			
		||||
#include "../gcode/queue.h"
 | 
			
		||||
@@ -49,6 +49,7 @@
 | 
			
		||||
// public:
 | 
			
		||||
 | 
			
		||||
card_flags_t CardReader::flag;
 | 
			
		||||
uint8_t CardReader::sdprinting_done_state;
 | 
			
		||||
char CardReader::filename[FILENAME_LENGTH], CardReader::longFilename[LONG_FILENAME_LENGTH];
 | 
			
		||||
int8_t CardReader::autostart_index;
 | 
			
		||||
 | 
			
		||||
@@ -379,7 +380,7 @@ void CardReader::mount() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CardReader::release() {
 | 
			
		||||
  stopSDPrint();
 | 
			
		||||
  endFilePrint();
 | 
			
		||||
  flag.mounted = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -401,7 +402,7 @@ void CardReader::startFileprint() {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CardReader::stopSDPrint(
 | 
			
		||||
void CardReader::endFilePrint(
 | 
			
		||||
  #if SD_RESORT
 | 
			
		||||
    const bool re_sort/*=false*/
 | 
			
		||||
  #endif
 | 
			
		||||
@@ -501,7 +502,7 @@ void CardReader::openFileRead(char * const path, const uint8_t subcall_type/*=0*
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  stopSDPrint();
 | 
			
		||||
  endFilePrint();
 | 
			
		||||
 | 
			
		||||
  SdFile *curDir;
 | 
			
		||||
  const char * const fname = diveToFile(true, curDir, path);
 | 
			
		||||
@@ -529,7 +530,7 @@ void CardReader::openFileWrite(char * const path) {
 | 
			
		||||
  announceOpen(2, path);
 | 
			
		||||
  file_subcall_ctr = 0;
 | 
			
		||||
 | 
			
		||||
  stopSDPrint();
 | 
			
		||||
  endFilePrint();
 | 
			
		||||
 | 
			
		||||
  SdFile *curDir;
 | 
			
		||||
  const char * const fname = diveToFile(false, curDir, path);
 | 
			
		||||
@@ -554,7 +555,7 @@ void CardReader::openFileWrite(char * const path) {
 | 
			
		||||
void CardReader::removeFile(const char * const name) {
 | 
			
		||||
  if (!isMounted()) return;
 | 
			
		||||
 | 
			
		||||
  //stopSDPrint();
 | 
			
		||||
  //endFilePrint();
 | 
			
		||||
 | 
			
		||||
  SdFile *curDir;
 | 
			
		||||
  const char * const fname = diveToFile(false, curDir, name);
 | 
			
		||||
@@ -1073,30 +1074,13 @@ void CardReader::fileHasFinished() {
 | 
			
		||||
    startFileprint();
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    stopSDPrint();
 | 
			
		||||
 | 
			
		||||
    #if ENABLED(POWER_LOSS_RECOVERY)
 | 
			
		||||
      recovery.purge();
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    #if ENABLED(SD_FINISHED_STEPPERRELEASE) && defined(SD_FINISHED_RELEASECOMMAND)
 | 
			
		||||
      planner.finish_and_disable();
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    print_job_timer.stop();
 | 
			
		||||
    queue.enqueue_now_P(print_job_timer.duration() > 60 ? PSTR("M31") : PSTR("M117"));
 | 
			
		||||
    endFilePrint();
 | 
			
		||||
 | 
			
		||||
    #if ENABLED(SDCARD_SORT_ALPHA)
 | 
			
		||||
      presort();
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    #if ENABLED(LCD_SET_PROGRESS_MANUALLY)
 | 
			
		||||
      ui.set_progress_done();
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    #if ENABLED(SD_REPRINT_LAST_SELECTED_FILE)
 | 
			
		||||
      ui.reselect_last_file();
 | 
			
		||||
    #endif
 | 
			
		||||
    sdprinting_done_state = 1;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,7 @@ typedef struct {
 | 
			
		||||
 | 
			
		||||
class CardReader {
 | 
			
		||||
public:
 | 
			
		||||
  static uint8_t sdprinting_done_state;
 | 
			
		||||
  static card_flags_t flag;                         // Flags (above)
 | 
			
		||||
  static char filename[FILENAME_LENGTH],            // DOS 8.3 filename of the selected item
 | 
			
		||||
              longFilename[LONG_FILENAME_LENGTH];   // Long name of the selected item
 | 
			
		||||
@@ -108,9 +109,9 @@ public:
 | 
			
		||||
  static void openAndPrintFile(const char *name);   // (working directory)
 | 
			
		||||
  static void fileHasFinished();
 | 
			
		||||
  static void getAbsFilename(char *dst);
 | 
			
		||||
  static void startFileprint();
 | 
			
		||||
  static void printFilename();
 | 
			
		||||
  static void stopSDPrint(
 | 
			
		||||
  static void startFileprint();
 | 
			
		||||
  static void endFilePrint(
 | 
			
		||||
    #if SD_RESORT
 | 
			
		||||
      const bool re_sort=false
 | 
			
		||||
    #endif
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user