Ensure proper SD print completion (#16967)

This commit is contained in:
Scott Lahteine 2020-02-25 22:18:14 -06:00 committed by GitHub
parent 91cff02596
commit 5071fe82ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 106 additions and 68 deletions

View File

@ -390,8 +390,8 @@ void startOrResumeJob() {
#if ENABLED(SDSUPPORT) #if ENABLED(SDSUPPORT)
void abortSDPrinting() { inline void abortSDPrinting() {
card.stopSDPrint( card.endFilePrint(
#if SD_RESORT #if SD_RESORT
true true
#endif #endif
@ -412,10 +412,68 @@ void startOrResumeJob() {
#endif #endif
} }
#if ENABLED(PRINTER_EVENT_LEDS)
#include "feature/leds/printer_event_leds.h"
#endif #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 * - Check for Filament Runout
* - Keep the command buffer full * - Keep the command buffer full
* - Check for maximum inactive time between commands * - Check for maximum inactive time between commands
@ -1122,10 +1180,15 @@ void setup() {
/** /**
* The main Marlin program loop * The main Marlin program loop
* *
* - Save or log commands to SD * - Call idle() to handle all tasks between G-code commands
* - Process available commands (if not saving) * Note that no G-codes from the queue can be executed during idle()
* - Call endstop manager * but many G-codes can be called directly anytime like macros.
* - Call inactivity manager * - 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() { void loop() {
do { do {
@ -1135,6 +1198,7 @@ void loop() {
#if ENABLED(SDSUPPORT) #if ENABLED(SDSUPPORT)
card.checkautostart(); card.checkautostart();
if (card.flag.abort_sd_printing) abortSDPrinting(); if (card.flag.abort_sd_printing) abortSDPrinting();
if (card.sdprinting_done_state) finishSDPrinting();
#endif #endif
queue.advance(); queue.advance();

View File

@ -512,9 +512,10 @@ void GCodeQueue::get_serial_commands() {
#if ENABLED(SDSUPPORT) #if ENABLED(SDSUPPORT)
/** /**
* Get commands from the SD Card until the command buffer is full * Get lines from the SD Card until the command buffer is full
* or until the end of the file is reached. The special character '#' * or until the end of the file is reached. Because this method
* can also interrupt buffering. * always receives complete command-lines, they can go directly
* into the main command queue.
*/ */
inline void GCodeQueue::get_sdcard_commands() { inline void GCodeQueue::get_sdcard_commands() {
static uint8_t sd_input_state = PS_NORMAL; static uint8_t sd_input_state = PS_NORMAL;
@ -527,37 +528,21 @@ void GCodeQueue::get_serial_commands() {
const int16_t n = card.get(); const int16_t n = card.get();
card_eof = card.eof(); card_eof = card.eof();
if (n < 0 && !card_eof) { SERIAL_ERROR_MSG(MSG_SD_ERR_READ); continue; } if (n < 0 && !card_eof) { SERIAL_ERROR_MSG(MSG_SD_ERR_READ); continue; }
const char sd_char = (char)n; 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 // 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)) { 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) #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 #endif
} }
if (card_eof) { if (card_eof) card.fileHasFinished(); // Handle end of file reached
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
}
}
} }
else else
process_stream_char(sd_char, sd_input_state, command_buffer[index_w], sd_count); process_stream_char(sd_char, sd_input_state, command_buffer[index_w], sd_count);
@ -633,9 +618,7 @@ void GCodeQueue::advance() {
#endif // SDSUPPORT #endif // SDSUPPORT
// The queue may be reset by a command handler or by code invoked by idle() within a handler // The queue may be reset by a command handler or by code invoked by idle() within a handler
if (length) {
--length; --length;
if (++index_r >= BUFSIZE) index_r = 0; if (++index_r >= BUFSIZE) index_r = 0;
}
} }

View File

@ -117,6 +117,12 @@ public:
*/ */
static void flush_and_request_resend(); 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: private:
static uint8_t index_w; // Ring buffer write position static uint8_t index_w; // Ring buffer write position

View File

@ -324,9 +324,9 @@ void MarlinUI::_synchronize() {
if (should_draw()) MenuItem_static::draw(LCD_HEIGHT >= 4, sync_message); if (should_draw()) MenuItem_static::draw(LCD_HEIGHT >= 4, sync_message);
if (no_reentry) return; if (no_reentry) return;
// Make this the current handler till all moves are done // Make this the current handler till all moves are done
no_reentry = true;
const screenFunc_t old_screen = currentScreen; const screenFunc_t old_screen = currentScreen;
goto_screen(_synchronize); goto_screen(_synchronize);
no_reentry = true;
planner.synchronize(); // idle() is called until moves complete planner.synchronize(); // idle() is called until moves complete
no_reentry = false; no_reentry = false;
goto_screen(old_screen); goto_screen(old_screen);

View File

@ -403,7 +403,7 @@ void Endstops::event_handler() {
#if BOTH(SD_ABORT_ON_ENDSTOP_HIT, SDSUPPORT) #if BOTH(SD_ABORT_ON_ENDSTOP_HIT, SDSUPPORT)
if (planner.abort_on_endstop_hit) { if (planner.abort_on_endstop_hit) {
card.stopSDPrint(); card.endFilePrint();
quickstop_stepper(); quickstop_stepper();
thermalManager.disable_all_heaters(); thermalManager.disable_all_heaters();
print_job_timer.stop(); print_job_timer.stop();

View File

@ -28,7 +28,7 @@
#include "../MarlinCore.h" #include "../MarlinCore.h"
#include "../lcd/ultralcd.h" #include "../lcd/ultralcd.h"
#include "../module/planner.h" #include "../module/planner.h" // for synchronize
#include "../module/printcounter.h" #include "../module/printcounter.h"
#include "../core/language.h" #include "../core/language.h"
#include "../gcode/queue.h" #include "../gcode/queue.h"
@ -49,6 +49,7 @@
// public: // public:
card_flags_t CardReader::flag; card_flags_t CardReader::flag;
uint8_t CardReader::sdprinting_done_state;
char CardReader::filename[FILENAME_LENGTH], CardReader::longFilename[LONG_FILENAME_LENGTH]; char CardReader::filename[FILENAME_LENGTH], CardReader::longFilename[LONG_FILENAME_LENGTH];
int8_t CardReader::autostart_index; int8_t CardReader::autostart_index;
@ -379,7 +380,7 @@ void CardReader::mount() {
} }
void CardReader::release() { void CardReader::release() {
stopSDPrint(); endFilePrint();
flag.mounted = false; flag.mounted = false;
} }
@ -401,7 +402,7 @@ void CardReader::startFileprint() {
} }
} }
void CardReader::stopSDPrint( void CardReader::endFilePrint(
#if SD_RESORT #if SD_RESORT
const bool re_sort/*=false*/ const bool re_sort/*=false*/
#endif #endif
@ -501,7 +502,7 @@ void CardReader::openFileRead(char * const path, const uint8_t subcall_type/*=0*
break; break;
} }
stopSDPrint(); endFilePrint();
SdFile *curDir; SdFile *curDir;
const char * const fname = diveToFile(true, curDir, path); const char * const fname = diveToFile(true, curDir, path);
@ -529,7 +530,7 @@ void CardReader::openFileWrite(char * const path) {
announceOpen(2, path); announceOpen(2, path);
file_subcall_ctr = 0; file_subcall_ctr = 0;
stopSDPrint(); endFilePrint();
SdFile *curDir; SdFile *curDir;
const char * const fname = diveToFile(false, curDir, path); 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) { void CardReader::removeFile(const char * const name) {
if (!isMounted()) return; if (!isMounted()) return;
//stopSDPrint(); //endFilePrint();
SdFile *curDir; SdFile *curDir;
const char * const fname = diveToFile(false, curDir, name); const char * const fname = diveToFile(false, curDir, name);
@ -1073,30 +1074,13 @@ void CardReader::fileHasFinished() {
startFileprint(); startFileprint();
} }
else { else {
stopSDPrint(); endFilePrint();
#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"));
#if ENABLED(SDCARD_SORT_ALPHA) #if ENABLED(SDCARD_SORT_ALPHA)
presort(); presort();
#endif #endif
#if ENABLED(LCD_SET_PROGRESS_MANUALLY) sdprinting_done_state = 1;
ui.set_progress_done();
#endif
#if ENABLED(SD_REPRINT_LAST_SELECTED_FILE)
ui.reselect_last_file();
#endif
} }
} }

View File

@ -49,6 +49,7 @@ typedef struct {
class CardReader { class CardReader {
public: public:
static uint8_t sdprinting_done_state;
static card_flags_t flag; // Flags (above) static card_flags_t flag; // Flags (above)
static char filename[FILENAME_LENGTH], // DOS 8.3 filename of the selected item static char filename[FILENAME_LENGTH], // DOS 8.3 filename of the selected item
longFilename[LONG_FILENAME_LENGTH]; // Long name 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 openAndPrintFile(const char *name); // (working directory)
static void fileHasFinished(); static void fileHasFinished();
static void getAbsFilename(char *dst); static void getAbsFilename(char *dst);
static void startFileprint();
static void printFilename(); static void printFilename();
static void stopSDPrint( static void startFileprint();
static void endFilePrint(
#if SD_RESORT #if SD_RESORT
const bool re_sort=false const bool re_sort=false
#endif #endif