From 7541316bb49303ce97e062da601e26426321c4ba Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Thu, 4 Jan 2018 05:06:34 -0600 Subject: [PATCH] Add M701/M702 Filament Load/Unload, M603 --- .travis.yml | 2 +- Marlin/Configuration_adv.h | 53 +- Marlin/src/Marlin.cpp | 14 +- Marlin/src/Marlin.h | 10 +- Marlin/src/core/language.h | 10 +- Marlin/src/feature/pause.cpp | 350 ++++++++------ Marlin/src/feature/pause.h | 43 +- Marlin/src/gcode/control/M17_M18_M84.cpp | 2 +- Marlin/src/gcode/feature/pause/M600.cpp | 57 ++- Marlin/src/gcode/feature/pause/M603.cpp | 65 +++ Marlin/src/gcode/feature/snmm/M702.cpp | 155 +++++- Marlin/src/gcode/gcode.cpp | 3 +- Marlin/src/gcode/gcode.h | 9 +- Marlin/src/inc/SanityCheck.h | 16 +- Marlin/src/lcd/ultralcd.cpp | 561 +++++++++++++++------- Marlin/src/lcd/ultralcd.h | 23 +- Marlin/src/lcd/ultralcd_impl_DOGM.h | 10 +- Marlin/src/lcd/ultralcd_impl_HD44780.h | 5 +- Marlin/src/module/configuration_store.cpp | 95 +++- 19 files changed, 1031 insertions(+), 452 deletions(-) create mode 100644 Marlin/src/gcode/feature/pause/M603.cpp diff --git a/.travis.yml b/.travis.yml index fc51921a0..4cb03f69e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -122,7 +122,7 @@ script: - opt_enable ULTIMAKERCONTROLLER SDSUPPORT - opt_enable PRINTCOUNTER NOZZLE_PARK_FEATURE NOZZLE_CLEAN_FEATURE PCA9632 USE_XMAX_PLUG - opt_enable_adv BEZIER_CURVE_SUPPORT EXPERIMENTAL_I2CBUS - - opt_enable_adv ADVANCED_PAUSE_FEATURE PARK_HEAD_ON_PAUSE LCD_INFO_MENU M114_DETAIL + - opt_enable_adv ADVANCED_PAUSE_FEATURE FILAMENT_LOAD_UNLOAD_GCODES PARK_HEAD_ON_PAUSE LCD_INFO_MENU M114_DETAIL - opt_set_adv PWM_MOTOR_CURRENT {1300,1300,1250} - opt_set_adv I2C_SLAVE_ADDRESS 63 - build_marlin_pio ${TRAVIS_BUILD_DIR} ${TEST_PLATFORM} diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 764d75744..8cc0eb4b3 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -881,29 +881,38 @@ */ //#define ADVANCED_PAUSE_FEATURE #if ENABLED(ADVANCED_PAUSE_FEATURE) - #define PAUSE_PARK_RETRACT_FEEDRATE 60 // Initial retract feedrate in mm/s - #define PAUSE_PARK_RETRACT_LENGTH 2 // Initial retract in mm - // It is a short retract used immediately after print interrupt before move to filament exchange position - #define FILAMENT_CHANGE_UNLOAD_FEEDRATE 10 // Unload filament feedrate in mm/s - filament unloading can be fast - #define FILAMENT_CHANGE_UNLOAD_LENGTH 100 // Unload filament length from hotend in mm - // Longer length for bowden printers to unload filament from whole bowden tube, - // shorter length for printers without bowden to unload filament from extruder only, - // 0 to disable unloading for manual unloading - #define FILAMENT_CHANGE_LOAD_FEEDRATE 6 // Load filament feedrate in mm/s - filament loading into the bowden tube can be fast - #define FILAMENT_CHANGE_LOAD_LENGTH 0 // Load filament length over hotend in mm - // Longer length for bowden printers to fast load filament into whole bowden tube over the hotend, - // Short or zero length for printers without bowden where loading is not used - #define ADVANCED_PAUSE_EXTRUDE_FEEDRATE 3 // Extrude filament feedrate in mm/s - must be slower than load feedrate - #define ADVANCED_PAUSE_EXTRUDE_LENGTH 50 // Extrude filament length in mm after filament is loaded over the hotend, - // 0 to disable for manual extrusion - // Filament can be extruded repeatedly from the filament exchange menu to fill the hotend, - // or until outcoming filament color is not clear for filament color change - #define PAUSE_PARK_NOZZLE_TIMEOUT 45 // Turn off nozzle if user doesn't change filament within this time limit in seconds - #define FILAMENT_CHANGE_NUMBER_OF_ALERT_BEEPS 5 // Number of alert beeps before printer goes quiet - #define PAUSE_PARK_NO_STEPPER_TIMEOUT // Enable to have stepper motors hold position during filament change - // even if it takes longer than DEFAULT_STEPPER_DEACTIVE_TIME. - //#define PARK_HEAD_ON_PAUSE // Go to filament change position on pause, return to print position on resume + #define PAUSE_PARK_RETRACT_FEEDRATE 60 // (mm/s) Initial retract feedrate. + #define PAUSE_PARK_RETRACT_LENGTH 2 // (mm) Initial retract. + // This short retract is done immediately, before parking the nozzle. + #define FILAMENT_CHANGE_UNLOAD_FEEDRATE 10 // (mm/s) Unload filament feedrate. This can be pretty fast. + #define FILAMENT_CHANGE_UNLOAD_LENGTH 100 // (mm) The length of filament for a complete unload. + // For Bowden, the full length of the tube and nozzle. + // For direct drive, the full length of the nozzle. + // Set to 0 for manual unloading. + #define FILAMENT_CHANGE_LOAD_FEEDRATE 6 // (mm/s) Load filament feedrate. This can be pretty fast. + #define FILAMENT_CHANGE_LOAD_LENGTH 0 // (mm) Load length of filament, from extruder gear to nozzle. + // For Bowden, the full length of the tube and nozzle. + // For direct drive, the full length of the nozzle. + #define ADVANCED_PAUSE_EXTRUDE_FEEDRATE 3 // (mm/s) Extrude feedrate (after loading). Should be slower than load feedrate. + #define ADVANCED_PAUSE_EXTRUDE_LENGTH 50 // (mm) Length to extrude after loading. + // Set to 0 for manual extrusion. + // Filament can be extruded repeatedly from the Filament Change menu + // until extrusion is consistent, and to purge old filament. + + // Filament Unload does a Retract, Delay, and Purge first: + #define FILAMENT_UNLOAD_RETRACT_LENGTH 13 // (mm) Unload initial retract length. + #define FILAMENT_UNLOAD_DELAY 5000 // (ms) Delay for the filament to cool after retract. + #define FILAMENT_UNLOAD_PURGE_LENGTH 8 // (mm) An unretract is done, then this length is purged. + + #define PAUSE_PARK_NOZZLE_TIMEOUT 45 // (seconds) Time limit before the nozzle is turned off for safety. + #define FILAMENT_CHANGE_ALERT_BEEPS 10 // Number of alert beeps to play when a response is needed. + #define PAUSE_PARK_NO_STEPPER_TIMEOUT // Enable for XYZ steppers to stay powered on during filament change. + + //#define PARK_HEAD_ON_PAUSE // Park the nozzle during pause and filament change. //#define HOME_BEFORE_FILAMENT_CHANGE // Ensure homing has been completed prior to parking for filament change + + //#define FILAMENT_LOAD_UNLOAD_GCODES // Add M701/M702 Load/Unload G-codes, plus Load/Unload in the LCD Prepare menu. + //#define FILAMENT_UNLOAD_ALL_EXTRUDERS // Allow M702 to unload all extruders above a minimum target temp (as set by M302) #endif // @section tmc diff --git a/Marlin/src/Marlin.cpp b/Marlin/src/Marlin.cpp index a12cbdb25..b801281dd 100644 --- a/Marlin/src/Marlin.cpp +++ b/Marlin/src/Marlin.cpp @@ -191,10 +191,6 @@ volatile bool wait_for_heatup = true; millis_t max_inactive_time = 0, stepper_inactive_time = (DEFAULT_STEPPER_DEACTIVE_TIME) * 1000UL; -#if ENABLED(ADVANCED_PAUSE_FEATURE) - AdvancedPauseMenuResponse advanced_pause_menu_response; -#endif - #ifdef CHDK millis_t chdkHigh = 0; bool chdkActive = false; @@ -308,6 +304,16 @@ void disable_e_steppers() { disable_E4(); } +void disable_e_stepper(const uint8_t e) { + switch (e) { + case 0: disable_E0(); break; + case 1: disable_E1(); break; + case 2: disable_E2(); break; + case 3: disable_E3(); break; + case 4: disable_E4(); break; + } +} + void disable_all_steppers() { disable_X(); disable_Y(); diff --git a/Marlin/src/Marlin.h b/Marlin/src/Marlin.h index a1b6741b9..3f1ad9357 100644 --- a/Marlin/src/Marlin.h +++ b/Marlin/src/Marlin.h @@ -159,6 +159,7 @@ void manage_inactivity(bool ignore_stepper_queue = false); #define _AXIS(AXIS) AXIS ##_AXIS void enable_all_steppers(); +void disable_e_stepper(const uint8_t e); void disable_e_steppers(); void disable_all_steppers(); @@ -198,15 +199,6 @@ extern millis_t max_inactive_time, stepper_inactive_time; #endif #endif -#if ENABLED(ADVANCED_PAUSE_FEATURE) - enum AdvancedPauseMenuResponse { - ADVANCED_PAUSE_RESPONSE_WAIT_FOR, - ADVANCED_PAUSE_RESPONSE_EXTRUDE_MORE, - ADVANCED_PAUSE_RESPONSE_RESUME_PRINT - }; - extern AdvancedPauseMenuResponse advanced_pause_menu_response; -#endif - #if ENABLED(PID_EXTRUSION_SCALING) extern int lpq_len; #endif diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h index 49f78c404..8cd650b05 100644 --- a/Marlin/src/core/language.h +++ b/Marlin/src/core/language.h @@ -205,7 +205,15 @@ #define MSG_ENDSTOPS_HIT "endstops hit: " #define MSG_ERR_COLD_EXTRUDE_STOP " cold extrusion prevented" #define MSG_ERR_LONG_EXTRUDE_STOP " too long extrusion prevented" -#define MSG_TOO_COLD_FOR_M600 "M600 Hotend too cold to change filament" +#define MSG_HOTEND_TOO_COLD "Hotend too cold" + +#define MSG_FILAMENT_CHANGE_HEAT "Press button (or M108) to heat nozzle" +#define MSG_FILAMENT_CHANGE_HEAT_LCD "Press button to heat nozzle" +#define MSG_FILAMENT_CHANGE_HEAT_M108 "Send M108 to heat nozzle" +#define MSG_FILAMENT_CHANGE_INSERT "Insert filament and press button (or M108)" +#define MSG_FILAMENT_CHANGE_INSERT_LCD "Insert filament and press button" +#define MSG_FILAMENT_CHANGE_INSERT_M108 "Insert filament and send M108" + #define MSG_SERIAL_ERROR_MENU_STRUCTURE "Error in menu structure" #define MSG_ERR_EEPROM_WRITE "Error writing to EEPROM!" diff --git a/Marlin/src/feature/pause.cpp b/Marlin/src/feature/pause.cpp index ccdeb429d..43244acbc 100644 --- a/Marlin/src/feature/pause.cpp +++ b/Marlin/src/feature/pause.cpp @@ -27,7 +27,7 @@ #include "../inc/MarlinConfig.h" -#if ENABLED(ADVANCED_PAUSE_FEATURE) || ENABLED(PARK_HEAD_ON_PAUSE) +#if ENABLED(ADVANCED_PAUSE_FEATURE) #include "../Marlin.h" #include "../gcode/gcode.h" @@ -56,6 +56,11 @@ static float resume_position[XYZE]; +AdvancedPauseMenuResponse advanced_pause_menu_response; + +float filament_change_unload_length[EXTRUDERS], + filament_change_load_length[EXTRUDERS]; + #if ENABLED(SDSUPPORT) #include "../sd/cardreader.h" #endif @@ -70,68 +75,197 @@ static float resume_position[XYZE]; const millis_t ms = millis(); if (ELAPSED(ms, next_buzz)) { if (max_beep_count < 0 || runout_beep < max_beep_count + 5) { // Only beep as long as we're supposed to - next_buzz = ms + ((max_beep_count < 0 || runout_beep < max_beep_count) ? 2500 : 400); - BUZZ(300, 2000); + next_buzz = ms + ((max_beep_count < 0 || runout_beep < max_beep_count) ? 1000 : 500); + BUZZ(50, 880 - (runout_beep & 1) * 220); runout_beep++; } } } #endif -static void ensure_safe_temperature() { - bool heaters_heating = true; +static bool ensure_safe_temperature(const AdvancedPauseMode mode=ADVANCED_PAUSE_MODE_PAUSE_PRINT) { - wait_for_heatup = true; // M108 will clear this - while (wait_for_heatup && heaters_heating) { - idle(); - heaters_heating = false; - HOTEND_LOOP() { - if (thermalManager.degTargetHotend(e) && abs(thermalManager.degHotend(e) - thermalManager.degTargetHotend(e)) > TEMP_HYSTERESIS) { - heaters_heating = true; - #if ENABLED(ULTIPANEL) - lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT); - #endif - break; - } + #if ENABLED(PREVENT_COLD_EXTRUSION) + if (!DEBUGGING(DRYRUN) && thermalManager.targetTooColdToExtrude(active_extruder)) { + SERIAL_ERROR_START(); + SERIAL_ERRORLNPGM(MSG_HOTEND_TOO_COLD); + return false; } - } + #endif + + #if ENABLED(ULTIPANEL) + lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT, mode); + #else + UNUSED(mode); + #endif + + wait_for_heatup = true; // M108 will clear this + while (wait_for_heatup && thermalManager.wait_for_heating(active_extruder)) idle(); + const bool status = wait_for_heatup; + wait_for_heatup = false; + + return status; } -void do_pause_e_move(const float &length, const float fr) { - current_position[E_AXIS] += length / planner.e_factor[active_extruder]; +static void do_pause_e_move(const float &length, const float &fr) { set_destination_from_current(); - #if IS_KINEMATIC - planner.buffer_line_kinematic(destination, fr, active_extruder); - #else - buffer_line_to_destination(fr); - #endif + destination[E_AXIS] += length / planner.e_factor[active_extruder]; + buffer_line_to_destination(fr); stepper.synchronize(); + set_current_from_destination(); +} + +bool load_filament(const float &load_length/*=0*/, const float &extrude_length/*=0*/, const int8_t max_beep_count/*=0*/, + const bool show_lcd/*=false*/, const bool pause_for_user/*=false*/, + const AdvancedPauseMode mode/*=ADVANCED_PAUSE_MODE_PAUSE_PRINT*/ +) { + #if DISABLED(ULTIPANEL) + UNUSED(show_lcd); + #endif + + if (!ensure_safe_temperature(mode)) { + #if ENABLED(ULTIPANEL) + if (show_lcd) // Show status screen + lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS); + #endif + + return false; + } + + if (pause_for_user) { + #if ENABLED(ULTIPANEL) + if (show_lcd) // Show "insert filament" + lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INSERT, mode); + #endif + SERIAL_ECHO_START(); + SERIAL_ECHOLNPGM(MSG_FILAMENT_CHANGE_INSERT); + + #if HAS_BUZZER + filament_change_beep(max_beep_count, true); + #else + UNUSED(max_beep_count); + #endif + + KEEPALIVE_STATE(PAUSED_FOR_USER); + wait_for_user = true; // LCD click or M108 will clear this + while (wait_for_user) { + #if HAS_BUZZER + filament_change_beep(max_beep_count); + #endif + idle(true); + } + KEEPALIVE_STATE(IN_HANDLER); + } + + #if ENABLED(ULTIPANEL) + if (show_lcd) // Show "load" message + lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_LOAD, mode); + #endif + + // Load filament + do_pause_e_move(load_length, FILAMENT_CHANGE_LOAD_FEEDRATE); + + do { + if (extrude_length > 0) { + // "Wait for filament purge" + #if ENABLED(ULTIPANEL) + if (show_lcd) + lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_PURGE, mode); + #endif + + // Extrude filament to get into hotend + do_pause_e_move(extrude_length, ADVANCED_PAUSE_EXTRUDE_FEEDRATE); + } + + // Show "Extrude More" / "Resume" menu and wait for reply + #if ENABLED(ULTIPANEL) + if (show_lcd) { + KEEPALIVE_STATE(PAUSED_FOR_USER); + wait_for_user = false; + lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_OPTION, mode); + while (advanced_pause_menu_response == ADVANCED_PAUSE_RESPONSE_WAIT_FOR) idle(true); + KEEPALIVE_STATE(IN_HANDLER); + } + #endif + + // Keep looping if "Extrude More" was selected + } while ( + #if ENABLED(ULTIPANEL) + show_lcd && advanced_pause_menu_response == ADVANCED_PAUSE_RESPONSE_EXTRUDE_MORE + #else + 0 + #endif + ); + + return true; +} + +bool unload_filament(const float &unload_length, const bool show_lcd/*=false*/, + const AdvancedPauseMode mode/*=ADVANCED_PAUSE_MODE_PAUSE_PRINT*/ +) { + if (!ensure_safe_temperature(mode)) { + #if ENABLED(ULTIPANEL) + if (show_lcd) // Show status screen + lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS); + #endif + + return false; + } + + #if DISABLED(ULTIPANEL) + UNUSED(show_lcd); + #else + if (show_lcd) + lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_UNLOAD, mode); + #endif + + // Retract filament + do_pause_e_move(-FILAMENT_UNLOAD_RETRACT_LENGTH, PAUSE_PARK_RETRACT_FEEDRATE); + + // Wait for filament to cool + safe_delay(FILAMENT_UNLOAD_DELAY); + + // Quickly purge + do_pause_e_move(FILAMENT_UNLOAD_RETRACT_LENGTH + FILAMENT_UNLOAD_PURGE_LENGTH, planner.max_feedrate_mm_s[E_AXIS]); + + // Unload filament + do_pause_e_move(unload_length, FILAMENT_CHANGE_UNLOAD_FEEDRATE); + + // Disable extruders steppers for manual filament changing (only on boards that have separate ENABLE_PINS) + #if E0_ENABLE_PIN != X_ENABLE_PIN && E1_ENABLE_PIN != Y_ENABLE_PIN + disable_e_stepper(active_extruder); + safe_delay(100); + #endif + + return true; } // public: uint8_t did_pause_print = 0; -bool pause_print(const float &retract, const point_t &park_point, const float &unload_length/*=0*/, - const int8_t max_beep_count/*=0*/, const bool show_lcd/*=false*/ -) { +bool pause_print(const float &retract, const point_t &park_point, const float &unload_length/*=0*/, const bool show_lcd/*=false*/) { if (did_pause_print) return false; // already paused #ifdef ACTION_ON_PAUSE SERIAL_ECHOLNPGM("//action:" ACTION_ON_PAUSE); #endif - if (!DEBUGGING(DRYRUN) && unload_length != 0) { - #if ENABLED(PREVENT_COLD_EXTRUSION) - if (!thermalManager.allow_cold_extrude && - thermalManager.degTargetHotend(active_extruder) < thermalManager.extrude_min_temp) { - SERIAL_ERROR_START(); - SERIAL_ERRORLNPGM(MSG_TOO_COLD_FOR_M600); - return false; - } + #if ENABLED(ULTIPANEL) + if (show_lcd) // Show initial message + lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INIT); + #endif + + if (!DEBUGGING(DRYRUN) && unload_length && thermalManager.targetTooColdToExtrude(active_extruder)) { + SERIAL_ERROR_START(); + SERIAL_ERRORLNPGM(MSG_HOTEND_TOO_COLD); + + #if ENABLED(ULTIPANEL) + if (show_lcd) // Show status screen + lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS); #endif - ensure_safe_temperature(); // wait for extruder to heat up before unloading + return false; // unable to reach safe temperature } // Indicate that the printer is paused @@ -139,22 +273,18 @@ bool pause_print(const float &retract, const point_t &park_point, const float &u // Pause the print job and timer #if ENABLED(SDSUPPORT) - if (IS_SD_PRINTING) { + if (card.sdprinting) { card.pauseSDPrint(); ++did_pause_print; } #endif print_job_timer.pause(); - // Show initial message and wait for synchronize steppers - if (show_lcd) { - #if ENABLED(ULTIPANEL) - lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INIT); - #endif - } - + // Wait for synchronize steppers stepper.synchronize(); - COPY(resume_position, current_position); // Save current position for later + + // Save current position + COPY(resume_position, current_position); // Initial retract before move to filament change position if (retract && !thermalManager.tooColdToExtrude(active_extruder)) @@ -163,48 +293,32 @@ bool pause_print(const float &retract, const point_t &park_point, const float &u // Park the nozzle by moving up by z_lift and then moving to (x_pos, y_pos) Nozzle::park(2, park_point); - if (unload_length != 0) { - if (show_lcd) { - #if ENABLED(ULTIPANEL) - lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_UNLOAD); - idle(); - #endif - } + // Unload the filament + if (unload_length) + unload_filament(unload_length, show_lcd); - // Unload filament - do_pause_e_move(unload_length, FILAMENT_CHANGE_UNLOAD_FEEDRATE); - } + return true; +} - if (show_lcd) { - #if ENABLED(ULTIPANEL) - lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INSERT); - #endif - } +void wait_for_filament_reload(const int8_t max_beep_count/*=0*/) { + bool nozzle_timed_out = false; + + #if ENABLED(ULTIPANEL) + lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INSERT); + #endif + SERIAL_ECHO_START(); + SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_INSERT); #if HAS_BUZZER filament_change_beep(max_beep_count, true); #endif - idle(); - - // Disable extruders steppers for manual filament changing (only on boards that have separate ENABLE_PINS) - #if E0_ENABLE_PIN != X_ENABLE_PIN && E1_ENABLE_PIN != Y_ENABLE_PIN - disable_e_steppers(); - safe_delay(100); - #endif - // Start the heater idle timers const millis_t nozzle_timeout = (millis_t)(PAUSE_PARK_NOZZLE_TIMEOUT) * 1000UL; HOTEND_LOOP() thermalManager.start_heater_idle_timer(e, nozzle_timeout); - return true; -} - -void wait_for_filament_reload(const int8_t max_beep_count/*=0*/) { - bool nozzle_timed_out = false; - // Wait for filament insert by user and press button KEEPALIVE_STATE(PAUSED_FOR_USER); wait_for_user = true; // LCD click or M108 will clear this @@ -223,6 +337,14 @@ void wait_for_filament_reload(const int8_t max_beep_count/*=0*/) { #if ENABLED(ULTIPANEL) lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_CLICK_TO_HEAT_NOZZLE); #endif + SERIAL_ECHO_START(); + #if ENABLED(ULTIPANEL) && ENABLED(EMERGENCY_PARSER) + SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_HEAT); + #elif ENABLED(EMERGENCY_PARSER) + SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_HEAT_M108); + #else + SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_HEAT_LCD); + #endif // Wait for LCD click or M108 while (wait_for_user) idle(true); @@ -236,6 +358,14 @@ void wait_for_filament_reload(const int8_t max_beep_count/*=0*/) { #if ENABLED(ULTIPANEL) lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INSERT); #endif + SERIAL_ECHO_START(); + #if ENABLED(ULTIPANEL) && ENABLED(EMERGENCY_PARSER) + SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_INSERT); + #elif ENABLED(EMERGENCY_PARSER) + SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_INSERT_M108); + #else + SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_INSERT_LCD); + #endif // Start the heater idle timers const millis_t nozzle_timeout = (millis_t)(PAUSE_PARK_NOZZLE_TIMEOUT) * 1000UL; @@ -243,7 +373,7 @@ void wait_for_filament_reload(const int8_t max_beep_count/*=0*/) { HOTEND_LOOP() thermalManager.start_heater_idle_timer(e, nozzle_timeout); - wait_for_user = true; /* Wait for user to load filament */ + wait_for_user = true; // Wait for user to load filament nozzle_timed_out = false; #if HAS_BUZZER @@ -256,7 +386,7 @@ void wait_for_filament_reload(const int8_t max_beep_count/*=0*/) { KEEPALIVE_STATE(IN_HANDLER); } -void resume_print(const float &load_length/*=0*/, const float &initial_extrude_length/*=0*/, const int8_t max_beep_count/*=0*/) { +void resume_print(const float &load_length/*=0*/, const float &extrude_length/*=ADVANCED_PAUSE_EXTRUDE_LENGTH*/, const int8_t max_beep_count/*=0*/) { bool nozzle_timed_out = false; if (!did_pause_print) return; @@ -267,67 +397,11 @@ void resume_print(const float &load_length/*=0*/, const float &initial_extrude_l thermalManager.reset_heater_idle_timer(e); } - if (nozzle_timed_out) ensure_safe_temperature(); - - #if HAS_BUZZER - filament_change_beep(max_beep_count, true); - #endif - - if (load_length != 0) { - #if ENABLED(ULTIPANEL) - // Show "insert filament" - if (nozzle_timed_out) - lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INSERT); - #endif - - KEEPALIVE_STATE(PAUSED_FOR_USER); - wait_for_user = true; // LCD click or M108 will clear this - while (wait_for_user && nozzle_timed_out) { - #if HAS_BUZZER - filament_change_beep(max_beep_count); - #endif - idle(true); - } - KEEPALIVE_STATE(IN_HANDLER); - - #if ENABLED(ULTIPANEL) - // Show "load" message - lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_LOAD); - #endif - - // Load filament - do_pause_e_move(load_length, FILAMENT_CHANGE_LOAD_FEEDRATE); + if (nozzle_timed_out || !thermalManager.tooColdToExtrude(active_extruder)) { + // Load the new filament + load_filament(load_length, extrude_length, max_beep_count, true, nozzle_timed_out); } - #if ENABLED(ULTIPANEL) && ADVANCED_PAUSE_EXTRUDE_LENGTH > 0 - - if (!thermalManager.tooColdToExtrude(active_extruder)) { - float extrude_length = initial_extrude_length; - - do { - if (extrude_length > 0) { - // "Wait for filament extrude" - lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_EXTRUDE); - - // Extrude filament to get into hotend - do_pause_e_move(extrude_length, ADVANCED_PAUSE_EXTRUDE_FEEDRATE); - } - - // Show "Extrude More" / "Resume" menu and wait for reply - KEEPALIVE_STATE(PAUSED_FOR_USER); - wait_for_user = false; - lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_OPTION); - while (advanced_pause_menu_response == ADVANCED_PAUSE_RESPONSE_WAIT_FOR) idle(true); - KEEPALIVE_STATE(IN_HANDLER); - - extrude_length = ADVANCED_PAUSE_EXTRUDE_LENGTH; - - // Keep looping if "Extrude More" was selected - } while (advanced_pause_menu_response == ADVANCED_PAUSE_RESPONSE_EXTRUDE_MORE); - } - - #endif - #if ENABLED(ULTIPANEL) // "Wait for print to resume" lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_RESUME); @@ -358,7 +432,7 @@ void resume_print(const float &load_length/*=0*/, const float &initial_extrude_l #endif #if ENABLED(ULTIPANEL) - // Show pause status screen + // Show status screen lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS); #endif @@ -376,4 +450,4 @@ void resume_print(const float &load_length/*=0*/, const float &initial_extrude_l #endif } -#endif // ADVANCED_PAUSE_FEATURE || PARK_HEAD_ON_PAUSE +#endif // ADVANCED_PAUSE_FEATURE diff --git a/Marlin/src/feature/pause.h b/Marlin/src/feature/pause.h index 2bceaa291..16f338947 100644 --- a/Marlin/src/feature/pause.h +++ b/Marlin/src/feature/pause.h @@ -30,14 +30,49 @@ #include "../libs/nozzle.h" +#include "../inc/MarlinConfigPre.h" + +enum AdvancedPauseMode { + ADVANCED_PAUSE_MODE_PAUSE_PRINT, + ADVANCED_PAUSE_MODE_LOAD_FILAMENT, + ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT +}; + +enum AdvancedPauseMessage { + ADVANCED_PAUSE_MESSAGE_INIT, + ADVANCED_PAUSE_MESSAGE_UNLOAD, + ADVANCED_PAUSE_MESSAGE_INSERT, + ADVANCED_PAUSE_MESSAGE_LOAD, + ADVANCED_PAUSE_MESSAGE_PURGE, + ADVANCED_PAUSE_MESSAGE_OPTION, + ADVANCED_PAUSE_MESSAGE_RESUME, + ADVANCED_PAUSE_MESSAGE_STATUS, + ADVANCED_PAUSE_MESSAGE_CLICK_TO_HEAT_NOZZLE, + ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT +}; + +enum AdvancedPauseMenuResponse { + ADVANCED_PAUSE_RESPONSE_WAIT_FOR, + ADVANCED_PAUSE_RESPONSE_EXTRUDE_MORE, + ADVANCED_PAUSE_RESPONSE_RESUME_PRINT +}; + +extern AdvancedPauseMenuResponse advanced_pause_menu_response; + +extern float filament_change_unload_length[EXTRUDERS], + filament_change_load_length[EXTRUDERS]; + extern uint8_t did_pause_print; -bool pause_print(const float &retract, const point_t &park_point, const float &unload_length=0, - const int8_t max_beep_count=0, const bool show_lcd=false -); +bool pause_print(const float &retract, const point_t &park_point, const float &unload_length=0, const bool show_lcd=false); void wait_for_filament_reload(const int8_t max_beep_count=0); -void resume_print(const float &load_length=0, const float &initial_extrude_length=0, const int8_t max_beep_count=0); +void resume_print(const float &load_length=0, const float &extrude_length=ADVANCED_PAUSE_EXTRUDE_LENGTH, const int8_t max_beep_count=0); + +bool load_filament(const float &load_length=0, const float &extrude_length=0, const int8_t max_beep_count=0, const bool show_lcd=false, + const bool pause_for_user=false, const AdvancedPauseMode mode=ADVANCED_PAUSE_MODE_PAUSE_PRINT); + +bool unload_filament(const float &unload_length, const bool show_lcd=false, const AdvancedPauseMode mode=ADVANCED_PAUSE_MODE_PAUSE_PRINT); #endif // _PAUSE_H_ diff --git a/Marlin/src/gcode/control/M17_M18_M84.cpp b/Marlin/src/gcode/control/M17_M18_M84.cpp index 003687c2c..2049aebae 100644 --- a/Marlin/src/gcode/control/M17_M18_M84.cpp +++ b/Marlin/src/gcode/control/M17_M18_M84.cpp @@ -54,7 +54,7 @@ void GcodeSuite::M18_M84() { if (parser.seen('X')) disable_X(); if (parser.seen('Y')) disable_Y(); if (parser.seen('Z')) disable_Z(); - #if E0_ENABLE_PIN != X_ENABLE_PIN && E1_ENABLE_PIN != Y_ENABLE_PIN // Only enable on boards that have separate ENABLE_PINS + #if E0_ENABLE_PIN != X_ENABLE_PIN && E1_ENABLE_PIN != Y_ENABLE_PIN // Only disable on boards that have separate ENABLE_PINS if (parser.seen('E')) disable_e_steppers(); #endif } diff --git a/Marlin/src/gcode/feature/pause/M600.cpp b/Marlin/src/gcode/feature/pause/M600.cpp index c1793f6fa..8589a48d9 100644 --- a/Marlin/src/gcode/feature/pause/M600.cpp +++ b/Marlin/src/gcode/feature/pause/M600.cpp @@ -33,24 +33,34 @@ #include "../../../module/tool_change.h" #endif +#if ENABLED(ULTIPANEL) + #include "../../../lcd/ultralcd.h" +#endif + /** * M600: Pause for filament change * - * E[distance] - Retract the filament this far (negative value) + * E[distance] - Retract the filament this far * Z[distance] - Move the Z axis by this distance * X[position] - Move to this X position, with Y * Y[position] - Move to this Y position, with X - * U[distance] - Retract distance for removal (negative value) (manual reload) - * L[distance] - Extrude distance for insertion (positive value) (manual reload) + * U[distance] - Retract distance for removal (manual reload) + * L[distance] - Extrude distance for insertion (manual reload) * B[count] - Number of times to beep, -1 for indefinite (if equipped with a buzzer) * T[toolhead] - Select extruder for filament change * * Default values are used for omitted arguments. - * */ void GcodeSuite::M600() { point_t park_point = NOZZLE_PARK_POINT; + if (get_target_extruder_from_command()) return; + + // Show initial message + #if ENABLED(ULTIPANEL) + lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INIT, ADVANCED_PAUSE_MODE_PAUSE_PRINT, target_extruder); + #endif + #if ENABLED(HOME_BEFORE_FILAMENT_CHANGE) // Don't allow filament change without homing first if (axis_unhomed_error()) home_all_axes(); @@ -58,22 +68,17 @@ void GcodeSuite::M600() { #if EXTRUDERS > 1 // Change toolhead if specified - uint8_t active_extruder_before_filament_change = -1; - if (parser.seen('T')) { - const uint8_t extruder = parser.value_byte(); - if (active_extruder != extruder) { - active_extruder_before_filament_change = active_extruder; - tool_change(extruder, 0, true); - } - } + uint8_t active_extruder_before_filament_change = active_extruder; + if (active_extruder != target_extruder) + tool_change(target_extruder, 0, true); #endif // Initial retract before move to filament change position - const float retract = parser.seen('E') ? parser.value_axis_units(E_AXIS) : 0 + const float retract = -FABS(parser.seen('E') ? parser.value_axis_units(E_AXIS) : 0 #ifdef PAUSE_PARK_RETRACT_LENGTH - - (PAUSE_PARK_RETRACT_LENGTH) + + (PAUSE_PARK_RETRACT_LENGTH) #endif - ; + ); // Move XY axes to filament change position or given position if (parser.seenval('X')) park_point.x = parser.linearval('X'); @@ -88,22 +93,16 @@ void GcodeSuite::M600() { #endif // Unload filament - const float unload_length = parser.seen('U') ? parser.value_axis_units(E_AXIS) : 0 - #if defined(FILAMENT_CHANGE_UNLOAD_LENGTH) && FILAMENT_CHANGE_UNLOAD_LENGTH > 0 - - (FILAMENT_CHANGE_UNLOAD_LENGTH) - #endif - ; + const float unload_length = -FABS(parser.seen('U') ? parser.value_axis_units(E_AXIS) + : filament_change_unload_length[active_extruder]); // Load filament - const float load_length = parser.seen('L') ? parser.value_axis_units(E_AXIS) : 0 - #ifdef FILAMENT_CHANGE_LOAD_LENGTH - + FILAMENT_CHANGE_LOAD_LENGTH - #endif - ; + const float load_length = FABS(parser.seen('L') ? parser.value_axis_units(E_AXIS) + : filament_change_load_length[active_extruder]); const int beep_count = parser.intval('B', - #ifdef FILAMENT_CHANGE_NUMBER_OF_ALERT_BEEPS - FILAMENT_CHANGE_NUMBER_OF_ALERT_BEEPS + #ifdef FILAMENT_CHANGE_ALERT_BEEPS + FILAMENT_CHANGE_ALERT_BEEPS #else -1 #endif @@ -111,14 +110,14 @@ void GcodeSuite::M600() { const bool job_running = print_job_timer.isRunning(); - if (pause_print(retract, park_point, unload_length, beep_count, true)) { + if (pause_print(retract, park_point, unload_length, true)) { wait_for_filament_reload(beep_count); resume_print(load_length, ADVANCED_PAUSE_EXTRUDE_LENGTH, beep_count); } #if EXTRUDERS > 1 // Restore toolhead if it was changed - if (active_extruder_before_filament_change >= 0) + if (active_extruder_before_filament_change != active_extruder) tool_change(active_extruder_before_filament_change, 0, true); #endif diff --git a/Marlin/src/gcode/feature/pause/M603.cpp b/Marlin/src/gcode/feature/pause/M603.cpp new file mode 100644 index 000000000..feabe2b92 --- /dev/null +++ b/Marlin/src/gcode/feature/pause/M603.cpp @@ -0,0 +1,65 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include "../../../inc/MarlinConfig.h" + +#if ENABLED(ADVANCED_PAUSE_FEATURE) + +#include "../../gcode.h" +#include "../../../feature/pause.h" +#include "../../../module/motion.h" +#include "../../../module/printcounter.h" + +#if EXTRUDERS > 1 + #include "../../../module/tool_change.h" +#endif + +/** + * M603: Configure filament change + * + * T[toolhead] - Select extruder to configure, active extruder if not specified + * U[distance] - Retract distance for removal, for the specified extruder + * L[distance] - Extrude distance for insertion, for the specified extruder + * + */ +inline void GcodeSuite::M603() { + + if (get_target_extruder_from_command()) return; + + // Unload length + if (parser.seen('U')) { + filament_change_unload_length[target_extruder] = FABS(parser.value_axis_units(E_AXIS)); + #if ENABLED(PREVENT_LENGTHY_EXTRUDE) + NOMORE(filament_change_unload_length[target_extruder], EXTRUDE_MAXLENGTH); + #endif + } + + // Load length + if (parser.seen('L')) { + filament_change_load_length[target_extruder] = FABS(parser.value_axis_units(E_AXIS)); + #if ENABLED(PREVENT_LENGTHY_EXTRUDE) + NOMORE(filament_change_load_length[target_extruder], EXTRUDE_MAXLENGTH); + #endif + } +} + +#endif // ADVANCED_PAUSE_FEATURE diff --git a/Marlin/src/gcode/feature/snmm/M702.cpp b/Marlin/src/gcode/feature/snmm/M702.cpp index ff8ee062e..d032107bc 100644 --- a/Marlin/src/gcode/feature/snmm/M702.cpp +++ b/Marlin/src/gcode/feature/snmm/M702.cpp @@ -20,33 +20,146 @@ * */ -#include "../../../inc/MarlinConfig.h" +#include "../../../inc/MarlinConfigPre.h" -#if ENABLED(MK2_MULTIPLEXER) +#if ENABLED(FILAMENT_LOAD_UNLOAD_GCODES) #include "../../gcode.h" -#include "../../../module/motion.h" -#include "../../../feature/snmm.h" #include "../../../Marlin.h" +#include "../../../module/motion.h" +#include "../../../module/temperature.h" +#include "../../../libs/point_t.h" + +#if EXTRUDERS > 1 + #include "../../../module/tool_change.h" +#endif + +#if ENABLED(ULTIPANEL) + #include "../../../lcd/ultralcd.h" +#endif /** - * M702: Unload all extruders + * M701: Load filament + * + * T[extruder] - Optional extruder number. Current extruder if omitted. + * Z[distance] - Move the Z axis by this distance + * L[distance] - Extrude distance for insertion (positive value) (manual reload) + * + * Default values are used for omitted arguments. */ -void GcodeSuite::M702() { - for (uint8_t s = 0; s < E_STEPPERS; s++) { - select_multiplexed_stepper(s); - // TODO: standard unload filament function - // MK2 firmware behavior: - // - Make sure temperature is high enough - // - Raise Z to at least 15 to make room - // - Extrude 1cm of filament in 1 second - // - Under 230C quickly purge ~12mm, over 230C purge ~10mm - // - Change E max feedrate to 80, eject the filament from the tube. Sync. - // - Restore E max feedrate to 50 - } - // Go back to the last active extruder - select_multiplexed_stepper(active_extruder); - disable_e_steppers(); +void GcodeSuite::M701() { + point_t park_point = NOZZLE_PARK_POINT; + + if (get_target_extruder_from_command()) return; + + // Z axis lift + if (parser.seenval('Z')) park_point.z = parser.linearval('Z'); + + // Load filament + const float load_length = FABS(parser.seen('L') ? parser.value_axis_units(E_AXIS) : + filament_change_load_length[target_extruder]); + + // Show initial message + #if ENABLED(ULTIPANEL) + lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_LOAD, ADVANCED_PAUSE_MODE_LOAD_FILAMENT, target_extruder); + #endif + + #if EXTRUDERS > 1 + // Change toolhead if specified + uint8_t active_extruder_before_filament_change = active_extruder; + if (active_extruder != target_extruder) + tool_change(target_extruder, 0, true); + #endif + + // Lift Z axis + if (park_point.z > 0) + do_blocking_move_to_z(min(current_position[Z_AXIS] + park_point.z, Z_MAX_POS), NOZZLE_PARK_Z_FEEDRATE); + + load_filament(load_length, ADVANCED_PAUSE_EXTRUDE_LENGTH, FILAMENT_CHANGE_ALERT_BEEPS, true, + thermalManager.wait_for_heating(target_extruder), ADVANCED_PAUSE_MODE_LOAD_FILAMENT); + + // Restore Z axis + if (park_point.z > 0) + do_blocking_move_to_z(max(current_position[Z_AXIS] - park_point.z, Z_MIN_POS), NOZZLE_PARK_Z_FEEDRATE); + + #if EXTRUDERS > 1 + // Restore toolhead if it was changed + if (active_extruder_before_filament_change != active_extruder) + tool_change(active_extruder_before_filament_change, 0, true); + #endif + + // Show status screen + #if ENABLED(ULTIPANEL) + lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS); + #endif } -#endif // MK2_MULTIPLEXER +/** + * M702: Unload filament + * + * T[extruder] - Optional extruder number. If omitted, current extruder + * (or ALL extruders with FILAMENT_UNLOAD_ALL_EXTRUDERS). + * Z[distance] - Move the Z axis by this distance + * U[distance] - Retract distance for removal (manual reload) + * + * Default values are used for omitted arguments. + */ +void GcodeSuite::M702() { + point_t park_point = NOZZLE_PARK_POINT; + + if (get_target_extruder_from_command()) return; + + // Z axis lift + if (parser.seenval('Z')) park_point.z = parser.linearval('Z'); + + // Show initial message + #if ENABLED(ULTIPANEL) + lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_UNLOAD, ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, target_extruder); + #endif + + #if EXTRUDERS > 1 + // Change toolhead if specified + uint8_t active_extruder_before_filament_change = active_extruder; + if (active_extruder != target_extruder) + tool_change(target_extruder, 0, true); + #endif + + // Lift Z axis + if (park_point.z > 0) + do_blocking_move_to_z(min(current_position[Z_AXIS] + park_point.z, Z_MAX_POS), NOZZLE_PARK_Z_FEEDRATE); + + // Unload filament + #if EXTRUDERS > 1 && ENABLED(FILAMENT_UNLOAD_ALL_EXTRUDERS) + if (!parser.seenval('T')) { + HOTEND_LOOP() { + if (e != active_extruder) tool_change(e, 0, true); + unload_filament(-filament_change_unload_length[e], true, ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT); + } + } + else + #endif + { + // Unload length + const float unload_length = -FABS(parser.seen('U') ? parser.value_axis_units(E_AXIS) : + filament_change_unload_length[target_extruder]); + + unload_filament(unload_length, true, ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT); + } + + // Restore Z axis + if (park_point.z > 0) + do_blocking_move_to_z(max(current_position[Z_AXIS] - park_point.z, Z_MIN_POS), NOZZLE_PARK_Z_FEEDRATE); + + #if EXTRUDERS > 1 + // Restore toolhead if it was changed + if (active_extruder_before_filament_change != active_extruder) + tool_change(active_extruder_before_filament_change, 0, true); + #endif + + // Show status screen + #if ENABLED(ULTIPANEL) + lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS); + #endif +} + +#endif // ADVANCED_PAUSE_FEATURE diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 35305df7b..31d628d85 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -399,8 +399,7 @@ void GcodeSuite::process_parsed_command() { #endif #if ENABLED(PARK_HEAD_ON_PAUSE) - case 125: // M125: Store current position and move to filament change position - M125(); break; + case 125: M125(); break; // M125: Store current position and move to filament change position #endif #if ENABLED(BARICUDA) diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index 648a27392..377c948b6 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -198,9 +198,12 @@ * M503 - Print the current settings (in memory): "M503 S". S0 specifies compact output. * M540 - Enable/disable SD card abort on endstop hit: "M540 S". (Requires ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED) * M600 - Pause for filament change: "M600 X Y Z E L". (Requires ADVANCED_PAUSE_FEATURE) + * M603 - Configure filament change: "M603 T U L". (Requires ADVANCED_PAUSE_FEATURE) + * M605 - Set Dual X-Carriage movement mode: "M605 S [X] [R]". (Requires DUAL_X_CARRIAGE) * M665 - Set delta configurations: "M665 L R S A B C I J K" (Requires DELTA) * M666 - Set delta endstop adjustment. (Requires DELTA) - * M605 - Set dual x-carriage movement mode: "M605 S [X] [R]". (Requires DUAL_X_CARRIAGE) + * M701 - Load filament (requires FILAMENT_LOAD_UNLOAD_GCODES) + * M702 - Unload filament (requires FILAMENT_LOAD_UNLOAD_GCODES) * M851 - Set Z probe's Z offset in current units. (Negative = below the nozzle.) * M852 - Set skew factors: "M852 [I] [J] [K]". (Requires SKEW_CORRECTION_GCODE, and SKEW_CORRECTION_FOR_Z for IJ) * M860 - Report the position of position encoder modules. @@ -685,6 +688,7 @@ private: #if ENABLED(ADVANCED_PAUSE_FEATURE) static void M600(); + static void M603(); #endif #if ENABLED(DUAL_X_CARRIAGE) || ENABLED(DUAL_NOZZLE_DUPLICATION_MODE) @@ -699,7 +703,8 @@ private: static void M666(); #endif - #if ENABLED(MK2_MULTIPLEXER) + #if ENABLED(FILAMENT_LOAD_UNLOAD_GCODES) + static void M701(); static void M702(); #endif diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index fd03c4d12..fe69cf92e 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -131,6 +131,8 @@ #error "FILAMENT_CHANGE_EXTRUDE_LENGTH is now ADVANCED_PAUSE_EXTRUDE_LENGTH. Please update your configuration." #elif defined(FILAMENT_CHANGE_NOZZLE_TIMEOUT) #error "FILAMENT_CHANGE_NOZZLE_TIMEOUT is now PAUSE_PARK_NOZZLE_TIMEOUT. Please update your configuration." +#elif defined(FILAMENT_CHANGE_NUMBER_OF_ALERT_BEEPS) + #error "FILAMENT_CHANGE_NUMBER_OF_ALERT_BEEPS is now FILAMENT_CHANGE_ALERT_BEEPS. Please update your configuration." #elif ENABLED(FILAMENT_CHANGE_NO_STEPPER_TIMEOUT) #error "FILAMENT_CHANGE_NO_STEPPER_TIMEOUT is now PAUSE_PARK_NO_STEPPER_TIMEOUT. Please update your configuration." #elif defined(PLA_PREHEAT_HOTEND_TEMP) @@ -406,16 +408,20 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE, * Advanced Pause */ #if ENABLED(ADVANCED_PAUSE_FEATURE) - #if DISABLED(NEWPANEL) - #error "ADVANCED_PAUSE_FEATURE currently requires an LCD controller." + #if !HAS_RESUME_CONTINUE + #error "ADVANCED_PAUSE_FEATURE currently requires an LCD controller or EMERGENCY_PARSER." #elif ENABLED(EXTRUDER_RUNOUT_PREVENT) #error "EXTRUDER_RUNOUT_PREVENT is incompatible with ADVANCED_PAUSE_FEATURE." #elif ENABLED(PARK_HEAD_ON_PAUSE) && DISABLED(SDSUPPORT) && DISABLED(NEWPANEL) && DISABLED(EMERGENCY_PARSER) #error "PARK_HEAD_ON_PAUSE requires SDSUPPORT, EMERGENCY_PARSER, or an LCD controller." #elif ENABLED(HOME_BEFORE_FILAMENT_CHANGE) && DISABLED(PAUSE_PARK_NO_STEPPER_TIMEOUT) - #error "HOME_BEFORE_FILAMENT_CHANGE requires PAUSE_PARK_NO_STEPPER_TIMEOUT" + #error "HOME_BEFORE_FILAMENT_CHANGE requires PAUSE_PARK_NO_STEPPER_TIMEOUT." #elif DISABLED(NOZZLE_PARK_FEATURE) - #error "ADVANCED_PAUSE_FEATURE requires NOZZLE_PARK_FEATURE" + #error "ADVANCED_PAUSE_FEATURE requires NOZZLE_PARK_FEATURE." + #elif ENABLED(PREVENT_LENGTHY_EXTRUDE) && FILAMENT_CHANGE_UNLOAD_LENGTH > EXTRUDE_MAXLENGTH + #error "FILAMENT_CHANGE_UNLOAD_LENGTH must be less than or equal to EXTRUDE_MAXLENGTH." + #elif ENABLED(PREVENT_LENGTHY_EXTRUDE) && FILAMENT_CHANGE_LOAD_LENGTH > EXTRUDE_MAXLENGTH + #error "FILAMENT_CHANGE_LOAD_LENGTH must be less than or equal to EXTRUDE_MAXLENGTH." #endif #endif @@ -454,8 +460,6 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE, */ #ifdef SNMM #error "SNMM is now MK2_MULTIPLEXER. Please update your configuration." -#elif ENABLED(MK2_MULTIPLEXER) && DISABLED(ADVANCED_PAUSE_FEATURE) - #error "ADVANCED_PAUSE_FEATURE is required with MK2_MULTIPLEXER." #endif /** diff --git a/Marlin/src/lcd/ultralcd.cpp b/Marlin/src/lcd/ultralcd.cpp index cace6dd59..550c71263 100644 --- a/Marlin/src/lcd/ultralcd.cpp +++ b/Marlin/src/lcd/ultralcd.cpp @@ -39,6 +39,10 @@ #include "../Marlin.h" +#if ENABLED(ADVANCED_PAUSE_FEATURE) + #include "../feature/pause.h" +#endif + #if ENABLED(PRINTCOUNTER) && ENABLED(LCD_INFO_MENU) #include "../libs/duration_t.h" #endif @@ -183,7 +187,7 @@ uint16_t max_display_update_time = 0; void lcd_control_temperature_preheat_material2_settings_menu(); #endif - #if DISABLED(NO_VOLUMETRICS) + #if DISABLED(NO_VOLUMETRICS) || ENABLED(ADVANCED_PAUSE_FEATURE) void lcd_control_filament_menu(); #endif @@ -201,14 +205,18 @@ uint16_t max_display_update_time = 0; #endif #if ENABLED(ADVANCED_PAUSE_FEATURE) - void lcd_advanced_pause_toocold_menu(); + #if E_STEPPERS > 1 || ENABLED(FILAMENT_LOAD_UNLOAD_GCODES) + void lcd_change_filament_menu(); + #else + void lcd_temp_menu_e0_filament_change(); + #endif void lcd_advanced_pause_option_menu(); void lcd_advanced_pause_init_message(); void lcd_advanced_pause_unload_message(); void lcd_advanced_pause_insert_message(); void lcd_advanced_pause_load_message(); void lcd_advanced_pause_heat_nozzle(); - void lcd_advanced_pause_extrude_message(); + void lcd_advanced_pause_purge_message(); void lcd_advanced_pause_resume_message(); #endif @@ -1249,61 +1257,6 @@ void kill_screen(const char* lcd_msg) { #endif } - #if ENABLED(ADVANCED_PAUSE_FEATURE) - - void lcd_enqueue_filament_change( - #if EXTRUDERS > 1 - const uint8_t extruder - #endif - ) { - - #if ENABLED(PREVENT_COLD_EXTRUSION) - if (!DEBUGGING(DRYRUN) && thermalManager.tooColdToExtrude(active_extruder)) { - lcd_save_previous_screen(); - lcd_goto_screen(lcd_advanced_pause_toocold_menu); - return; - } - #endif - - lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INIT); - - #if EXTRUDERS <= 1 - enqueue_and_echo_commands_P(PSTR("M600 B0")); - #else - char *command_M600; - switch (extruder) { - case 0: command_M600 = PSTR("M600 B0 T0"); break; - case 1: command_M600 = PSTR("M600 B0 T1"); break; - #if EXTRUDERS > 2 - case 2: command_M600 = PSTR("M600 B0 T2"); break; - #if EXTRUDERS > 3 - case 3: command_M600 = PSTR("M600 B0 T3"); break; - #if EXTRUDERS > 4 - case 4: command_M600 = PSTR("M600 B0 T4"); break; - #endif // EXTRUDERS > 4 - #endif // EXTRUDERS > 3 - #endif // EXTRUDERS > 2 - } - enqueue_and_echo_commands_P(command_M600); - #endif // EXTRUDERS > 1 - } - - #if EXTRUDERS > 1 - void lcd_enqueue_filament_change_e0() { lcd_enqueue_filament_change(0); } - void lcd_enqueue_filament_change_e1() { lcd_enqueue_filament_change(1); } - #if EXTRUDERS > 2 - void lcd_enqueue_filament_change_e2() { lcd_enqueue_filament_change(2); } - #if EXTRUDERS > 3 - void lcd_enqueue_filament_change_e3() { lcd_enqueue_filament_change(3); } - #if EXTRUDERS > 4 - void lcd_enqueue_filament_change_e4() { lcd_enqueue_filament_change(4); } - #endif // EXTRUDERS > 4 - #endif // EXTRUDERS > 3 - #endif // EXTRUDERS > 2 - #endif // EXTRUDERS > 1 - - #endif // ADVANCED_PAUSE_FEATURE - // First Fan Speed title in "Tune" and "Control>Temperature" menus #if FAN_COUNT > 0 && HAS_FAN0 #if FAN_COUNT > 1 @@ -1445,26 +1398,13 @@ void kill_screen(const char* lcd_msg) { // Change filament // #if ENABLED(ADVANCED_PAUSE_FEATURE) - #if EXTRUDERS > 1 - if (!thermalManager.tooColdToExtrude(0)) - MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E1, lcd_enqueue_filament_change_e0); - if (!thermalManager.tooColdToExtrude(1)) - MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E2, lcd_enqueue_filament_change_e1); - #if EXTRUDERS > 2 - if (!thermalManager.tooColdToExtrude(2)) - MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E3, lcd_enqueue_filament_change_e2); - #if EXTRUDERS > 3 - if (!thermalManager.tooColdToExtrude(3)) - MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E4, lcd_enqueue_filament_change_e3); - #if EXTRUDERS > 4 - if (!thermalManager.tooColdToExtrude(4)) - MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E5, lcd_enqueue_filament_change_e4); - #endif // EXTRUDERS > 4 - #endif // EXTRUDERS > 3 - #endif // EXTRUDERS > 2 + #if E_STEPPERS == 1 && !ENABLED(FILAMENT_LOAD_UNLOAD_GCODES) + if (!thermalManager.targetTooColdToExtrude(active_extruder)) + MENU_ITEM(gcode, MSG_FILAMENTCHANGE, PSTR("M600 B0")); + else + MENU_ITEM(submenu, MSG_FILAMENTCHANGE, lcd_temp_menu_e0_filament_change); #else - if (!thermalManager.tooColdToExtrude(active_extruder)) - MENU_ITEM(function, MSG_FILAMENTCHANGE, lcd_enqueue_filament_change); + MENU_ITEM(submenu, MSG_FILAMENTCHANGE, lcd_change_filament_menu); #endif #endif @@ -2651,7 +2591,6 @@ void kill_screen(const char* lcd_msg) { // Set Home Offsets // MENU_ITEM(function, MSG_SET_HOME_OFFSETS, lcd_set_home_offsets); - //MENU_ITEM(gcode, MSG_SET_ORIGIN, PSTR("G92 X0 Y0 Z0")); #endif // @@ -2664,26 +2603,13 @@ void kill_screen(const char* lcd_msg) { // #if ENABLED(ADVANCED_PAUSE_FEATURE) if (!IS_SD_FILE_OPEN) { - #if EXTRUDERS > 1 - if (!thermalManager.tooColdToExtrude(0)) - MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E1, lcd_enqueue_filament_change_e0); - if (!thermalManager.tooColdToExtrude(1)) - MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E2, lcd_enqueue_filament_change_e1); - #if EXTRUDERS > 2 - if (!thermalManager.tooColdToExtrude(2)) - MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E3, lcd_enqueue_filament_change_e2); - #if EXTRUDERS > 3 - if (!thermalManager.tooColdToExtrude(3)) - MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E4, lcd_enqueue_filament_change_e3); - #if EXTRUDERS > 4 - if (!thermalManager.tooColdToExtrude(4)) - MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E5, lcd_enqueue_filament_change_e4); - #endif // EXTRUDERS > 4 - #endif // EXTRUDERS > 3 - #endif // EXTRUDERS > 2 + #if E_STEPPERS == 1 && !ENABLED(FILAMENT_LOAD_UNLOAD_GCODES) + if (!thermalManager.targetTooColdToExtrude(active_extruder)) + MENU_ITEM(gcode, MSG_FILAMENTCHANGE, PSTR("M600 B0")); + else + MENU_ITEM(submenu, MSG_FILAMENTCHANGE, lcd_temp_menu_e0_filament_change); #else - if (!thermalManager.tooColdToExtrude(active_extruder)) - MENU_ITEM(function, MSG_FILAMENTCHANGE, lcd_enqueue_filament_change); + MENU_ITEM(submenu, MSG_FILAMENTCHANGE, lcd_change_filament_menu); #endif } #endif // ADVANCED_PAUSE_FEATURE @@ -3232,14 +3158,14 @@ void kill_screen(const char* lcd_msg) { MENU_ITEM(submenu, MSG_TEMPERATURE, lcd_control_temperature_menu); MENU_ITEM(submenu, MSG_MOTION, lcd_control_motion_menu); - #if DISABLED(NO_VOLUMETRICS) + #if DISABLED(NO_VOLUMETRICS) || ENABLED(ADVANCED_PAUSE_FEATURE) MENU_ITEM(submenu, MSG_FILAMENT, lcd_control_filament_menu); #elif ENABLED(LIN_ADVANCE) MENU_ITEM_EDIT(float3, MSG_ADVANCE_K, &planner.extruder_advance_k, 0, 999); #endif #if HAS_LCD_CONTRAST - MENU_ITEM_EDIT_CALLBACK(int3, MSG_CONTRAST, (int16_t*) &lcd_contrast, LCD_CONTRAST_MIN, LCD_CONTRAST_MAX, lcd_callback_set_contrast, true); + MENU_ITEM_EDIT_CALLBACK(int3, MSG_CONTRAST, &lcd_contrast, LCD_CONTRAST_MIN, LCD_CONTRAST_MAX, lcd_callback_set_contrast, true); #endif #if ENABLED(FWRETRACT) MENU_ITEM(submenu, MSG_RETRACT, lcd_control_retract_menu); @@ -3491,7 +3417,7 @@ void kill_screen(const char* lcd_msg) { #if DISABLED(SLIM_LCD_MENUS) - void _lcd_control_temperature_preheat_settings_menu(uint8_t material) { + void _lcd_control_temperature_preheat_settings_menu(const uint8_t material) { #if HOTENDS > 4 #define MINTEMP_ALL MIN5(HEATER_0_MINTEMP, HEATER_1_MINTEMP, HEATER_2_MINTEMP, HEATER_3_MINTEMP, HEATER_4_MINTEMP) #define MAXTEMP_ALL MAX5(HEATER_0_MAXTEMP, HEATER_1_MAXTEMP, HEATER_2_MAXTEMP, HEATER_3_MAXTEMP, HEATER_4_MAXTEMP) @@ -3737,7 +3663,7 @@ void kill_screen(const char* lcd_msg) { END_MENU(); } - #if DISABLED(NO_VOLUMETRICS) + #if DISABLED(NO_VOLUMETRICS) || ENABLED(ADVANCED_PAUSE_FEATURE) /** * * "Control" > "Filament" submenu @@ -3751,30 +3677,76 @@ void kill_screen(const char* lcd_msg) { MENU_ITEM_EDIT(float3, MSG_ADVANCE_K, &planner.extruder_advance_k, 0, 999); #endif - MENU_ITEM_EDIT_CALLBACK(bool, MSG_VOLUMETRIC_ENABLED, &parser.volumetric_enabled, planner.calculate_volumetric_multipliers); + #if DISABLED(NO_VOLUMETRICS) + MENU_ITEM_EDIT_CALLBACK(bool, MSG_VOLUMETRIC_ENABLED, &parser.volumetric_enabled, planner.calculate_volumetric_multipliers); - if (parser.volumetric_enabled) { - #if EXTRUDERS == 1 - MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM, &planner.filament_size[0], 1.5, 3.25, planner.calculate_volumetric_multipliers); - #else // EXTRUDERS > 1 - MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM, &planner.filament_size[active_extruder], 1.5, 3.25, planner.calculate_volumetric_multipliers); - MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E1, &planner.filament_size[0], 1.5, 3.25, planner.calculate_volumetric_multipliers); - MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E2, &planner.filament_size[1], 1.5, 3.25, planner.calculate_volumetric_multipliers); - #if EXTRUDERS > 2 - MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E3, &planner.filament_size[2], 1.5, 3.25, planner.calculate_volumetric_multipliers); + if (parser.volumetric_enabled) { + #if EXTRUDERS == 1 + MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM, &planner.filament_size[0], 1.5, 3.25, planner.calculate_volumetric_multipliers); + #else // EXTRUDERS > 1 + MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM, &planner.filament_size[active_extruder], 1.5, 3.25, planner.calculate_volumetric_multipliers); + MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E1, &planner.filament_size[0], 1.5, 3.25, planner.calculate_volumetric_multipliers); + MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E2, &planner.filament_size[1], 1.5, 3.25, planner.calculate_volumetric_multipliers); + #if EXTRUDERS > 2 + MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E3, &planner.filament_size[2], 1.5, 3.25, planner.calculate_volumetric_multipliers); #if EXTRUDERS > 3 MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E4, &planner.filament_size[3], 1.5, 3.25, planner.calculate_volumetric_multipliers); #if EXTRUDERS > 4 - MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E5, &planner.filament_size[4], 1.5, 3.25, planner.calculate_volumetric_multipliers); + MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E5, &planner.filament_size[4], 1.5, 3.25, planner.calculate_volumetric_multipliers); + #endif // EXTRUDERS > 4 + #endif // EXTRUDERS > 3 + #endif // EXTRUDERS > 2 + #endif // EXTRUDERS > 1 + } + #endif + + #if ENABLED(ADVANCED_PAUSE_FEATURE) + const float extrude_maxlength = + #if ENABLED(PREVENT_LENGTHY_EXTRUDE) + EXTRUDE_MAXLENGTH + #else + 999.0f + #endif + ; + + #if EXTRUDERS == 1 + MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD, &filament_change_unload_length[0], 0.0, extrude_maxlength); + #else // EXTRUDERS > 1 + MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD, &filament_change_unload_length[active_extruder], 0.0, extrude_maxlength); + MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD MSG_DIAM_E1, &filament_change_unload_length[0], 0.0, extrude_maxlength); + MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD MSG_DIAM_E2, &filament_change_unload_length[1], 0.0, extrude_maxlength); + #if EXTRUDERS > 2 + MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD MSG_DIAM_E3, &filament_change_unload_length[2], 0.0, extrude_maxlength); + #if EXTRUDERS > 3 + MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD MSG_DIAM_E4, &filament_change_unload_length[3], 0.0, extrude_maxlength); + #if EXTRUDERS > 4 + MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD MSG_DIAM_E5, &filament_change_unload_length[4], 0.0, extrude_maxlength); #endif // EXTRUDERS > 4 #endif // EXTRUDERS > 3 #endif // EXTRUDERS > 2 #endif // EXTRUDERS > 1 - } + + #if EXTRUDERS == 1 + MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD, &filament_change_load_length[0], 0.0, extrude_maxlength); + #else // EXTRUDERS > 1 + MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD, &filament_change_load_length[active_extruder], 0.0, extrude_maxlength); + MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD MSG_DIAM_E1, &filament_change_load_length[0], 0.0, extrude_maxlength); + MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD MSG_DIAM_E2, &filament_change_load_length[1], 0.0, extrude_maxlength); + #if EXTRUDERS > 2 + MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD MSG_DIAM_E3, &filament_change_load_length[2], 0.0, extrude_maxlength); + #if EXTRUDERS > 3 + MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD MSG_DIAM_E4, &filament_change_load_length[3], 0.0, extrude_maxlength); + #if EXTRUDERS > 4 + MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD MSG_DIAM_E5, &filament_change_load_length[4], 0.0, extrude_maxlength); + #endif // EXTRUDERS > 4 + #endif // EXTRUDERS > 3 + #endif // EXTRUDERS > 2 + #endif // EXTRUDERS > 1 + #endif END_MENU(); } - #endif // !NO_VOLUMETRICS + #endif // !NO_VOLUMETRICS || ADVANCED_PAUSE_FEATURE /** * @@ -4131,12 +4103,258 @@ void kill_screen(const char* lcd_msg) { */ #if ENABLED(ADVANCED_PAUSE_FEATURE) + /** + * + * "Change Filament" > "Change/Unload/Load Filament" submenu + * + */ + static AdvancedPauseMode _change_filament_temp_mode; + static int8_t _change_filament_temp_extruder; + + static const char* _change_filament_temp_command() { + switch (_change_filament_temp_mode) { + case ADVANCED_PAUSE_MODE_LOAD_FILAMENT: + return PSTR("M701 T%d"); + case ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT: + return _change_filament_temp_extruder >= 0 ? PSTR("M702 T%d") : PSTR("M702 ;%d"); + case ADVANCED_PAUSE_MODE_PAUSE_PRINT: + default: + return PSTR("M600 B0 T%d"); + } + return PSTR(MSG_FILAMENTCHANGE); + } + + void _change_filament_temp(const uint8_t index) { + char cmd[11]; + sprintf_P(cmd, _change_filament_temp_command(), _change_filament_temp_extruder); + thermalManager.setTargetHotend(index == 1 ? PREHEAT_1_TEMP_HOTEND : PREHEAT_2_TEMP_HOTEND, _change_filament_temp_extruder); + lcd_enqueue_command(cmd); + } + void _lcd_change_filament_temp_1_menu() { _change_filament_temp(1); } + void _lcd_change_filament_temp_2_menu() { _change_filament_temp(2); } + + static const char* change_filament_header(const AdvancedPauseMode mode) { + switch (mode) { + case ADVANCED_PAUSE_MODE_LOAD_FILAMENT: + return PSTR(MSG_FILAMENTLOAD); + case ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT: + return PSTR(MSG_FILAMENTUNLOAD); + default: break; + } + return PSTR(MSG_FILAMENTCHANGE); + } + + void _lcd_temp_menu_filament_op(const AdvancedPauseMode mode, const int8_t extruder) { + _change_filament_temp_mode = mode; + _change_filament_temp_extruder = extruder; + START_MENU(); + if (LCD_HEIGHT >= 4) STATIC_ITEM_P(change_filament_header(mode), true, true); + MENU_BACK(MSG_FILAMENTCHANGE); + MENU_ITEM(submenu, MSG_PREHEAT_1, _lcd_change_filament_temp_1_menu); + MENU_ITEM(submenu, MSG_PREHEAT_2, _lcd_change_filament_temp_2_menu); + END_MENU(); + } + void lcd_temp_menu_e0_filament_change() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 0); } + void lcd_temp_menu_e0_filament_load() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 0); } + void lcd_temp_menu_e0_filament_unload() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 0); } + #if E_STEPPERS > 1 + void lcd_temp_menu_e1_filament_change() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 1); } + void lcd_temp_menu_e1_filament_load() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 1); } + void lcd_temp_menu_e1_filament_unload() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 1); } + #if ENABLED(FILAMENT_UNLOAD_ALL_EXTRUDERS) + void lcd_unload_filament_all_temp_menu() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, -1); } + #endif + #if E_STEPPERS > 2 + void lcd_temp_menu_e2_filament_change() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 2); } + void lcd_temp_menu_e2_filament_load() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 2); } + void lcd_temp_menu_e2_filament_unload() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 2); } + #if E_STEPPERS > 3 + void lcd_temp_menu_e3_filament_change() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 3); } + void lcd_temp_menu_e3_filament_load() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 3); } + void lcd_temp_menu_e3_filament_unload() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 3); } + #if E_STEPPERS > 4 + void lcd_temp_menu_e4_filament_change() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 4); } + void lcd_temp_menu_e4_filament_load() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 4); } + void lcd_temp_menu_e4_filament_unload() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 4); } + #endif // E_STEPPERS > 4 + #endif // E_STEPPERS > 3 + #endif // E_STEPPERS > 2 + #endif // E_STEPPERS > 1 + + /** + * + * "Change Filament" submenu + * + */ + #if E_STEPPERS > 1 || ENABLED(FILAMENT_LOAD_UNLOAD_GCODES) + void lcd_change_filament_menu() { + START_MENU(); + MENU_BACK(MSG_PREPARE); + + // Change filament + #if E_STEPPERS == 1 + PGM_P msg0 = PSTR(MSG_FILAMENTCHANGE); + if (thermalManager.targetTooColdToExtrude(active_extruder)) + MENU_ITEM_P(submenu, msg0, lcd_temp_menu_e0_filament_change); + else + MENU_ITEM_P(gcode, msg0, PSTR("M600 B0")); + #else + PGM_P msg0 = PSTR(MSG_FILAMENTCHANGE " " MSG_E1); + PGM_P msg1 = PSTR(MSG_FILAMENTCHANGE " " MSG_E2); + if (thermalManager.targetTooColdToExtrude(0)) + MENU_ITEM_P(submenu, msg0, lcd_temp_menu_e0_filament_change); + else + MENU_ITEM_P(gcode, msg0, PSTR("M600 B0 T0")); + if (thermalManager.targetTooColdToExtrude(1)) + MENU_ITEM_P(submenu, msg1, lcd_temp_menu_e1_filament_change); + else + MENU_ITEM_P(gcode, msg1, PSTR("M600 B0 T1")); + #if E_STEPPERS > 2 + PGM_P msg2 = PSTR(MSG_FILAMENTCHANGE " " MSG_E3); + if (thermalManager.targetTooColdToExtrude(2)) + MENU_ITEM_P(submenu, msg2, lcd_temp_menu_e2_filament_change); + else + MENU_ITEM_P(gcode, msg2, PSTR("M600 B0 T2")); + #if E_STEPPERS > 3 + PGM_P msg3 = PSTR(MSG_FILAMENTCHANGE " " MSG_E4); + if (thermalManager.targetTooColdToExtrude(3)) + MENU_ITEM_P(submenu, msg3, lcd_temp_menu_e3_filament_change); + else + MENU_ITEM_P(gcode, msg3, PSTR("M600 B0 T3")); + #if E_STEPPERS > 4 + PGM_P msg4 = PSTR(MSG_FILAMENTCHANGE " " MSG_E5); + if (thermalManager.targetTooColdToExtrude(4)) + MENU_ITEM_P(submenu, msg4, lcd_temp_menu_e4_filament_change); + else + MENU_ITEM_P(gcode, msg4, PSTR("M600 B0 T4")); + #endif // E_STEPPERS > 4 + #endif // E_STEPPERS > 3 + #endif // E_STEPPERS > 2 + #endif // E_STEPPERS == 1 + + #if ENABLED(FILAMENT_LOAD_UNLOAD_GCODES) + if (!planner.movesplanned() && !IS_SD_FILE_OPEN) { + // Load filament + #if E_STEPPERS == 1 + PGM_P msg0 = PSTR(MSG_FILAMENTLOAD); + if (thermalManager.targetTooColdToExtrude(active_extruder)) + MENU_ITEM_P(submenu, msg0, lcd_temp_menu_e0_filament_load); + else + MENU_ITEM_P(gcode, msg0, PSTR("M701")); + #else + PGM_P msg0 = PSTR(MSG_FILAMENTLOAD " " MSG_E1); + PGM_P msg1 = PSTR(MSG_FILAMENTLOAD " " MSG_E2); + if (thermalManager.targetTooColdToExtrude(0)) + MENU_ITEM_P(submenu, msg0, lcd_temp_menu_e0_filament_load); + else + MENU_ITEM_P(gcode, msg0, PSTR("M701 T0")); + if (thermalManager.targetTooColdToExtrude(1)) + MENU_ITEM_P(submenu, msg1, lcd_temp_menu_e1_filament_load); + else + MENU_ITEM_P(gcode, msg1, PSTR("M701 T1")); + #if E_STEPPERS > 2 + PGM_P msg2 = PSTR(MSG_FILAMENTLOAD " " MSG_E3); + if (thermalManager.targetTooColdToExtrude(2)) + MENU_ITEM_P(submenu, msg2, lcd_temp_menu_e2_filament_load); + else + MENU_ITEM_P(gcode, msg2, PSTR("M701 T2")); + #if E_STEPPERS > 3 + PGM_P msg3 = PSTR(MSG_FILAMENTLOAD " " MSG_E4); + if (thermalManager.targetTooColdToExtrude(3)) + MENU_ITEM_P(submenu, msg3, lcd_temp_menu_e3_filament_load); + else + MENU_ITEM_P(gcode, msg3, PSTR("M701 T3")); + #if E_STEPPERS > 4 + PGM_P msg4 = PSTR(MSG_FILAMENTLOAD " " MSG_E5); + if (thermalManager.targetTooColdToExtrude(4)) + MENU_ITEM_P(submenu, msg4, lcd_temp_menu_e4_filament_load); + else + MENU_ITEM_P(gcode, msg4, PSTR("M701 T4")); + #endif // E_STEPPERS > 4 + #endif // E_STEPPERS > 3 + #endif // E_STEPPERS > 2 + #endif // E_STEPPERS == 1 + + // Unload filament + #if E_STEPPERS == 1 + if (!thermalManager.targetTooColdToExtrude(active_extruder)) + MENU_ITEM(gcode, MSG_FILAMENTUNLOAD, PSTR("M702")); + else + MENU_ITEM(submenu, MSG_FILAMENTUNLOAD, lcd_temp_menu_e0_filament_unload); + #else + #if ENABLED(FILAMENT_UNLOAD_ALL_EXTRUDERS) + if (!thermalManager.targetTooColdToExtrude(0) + #if E_STEPPERS > 1 + && !thermalManager.targetTooColdToExtrude(1) + #if E_STEPPERS > 2 + && !thermalManager.targetTooColdToExtrude(2) + #if E_STEPPERS > 3 + && !thermalManager.targetTooColdToExtrude(3) + #if E_STEPPERS > 4 + && !thermalManager.targetTooColdToExtrude(4) + #endif // E_STEPPERS > 4 + #endif // E_STEPPERS > 3 + #endif // E_STEPPERS > 2 + #endif // E_STEPPERS > 1 + ) + MENU_ITEM(gcode, MSG_FILAMENTUNLOAD_ALL, PSTR("M702")); + else + MENU_ITEM(submenu, MSG_FILAMENTUNLOAD_ALL, lcd_unload_filament_all_temp_menu); + #endif + if (!thermalManager.targetTooColdToExtrude(0)) + MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E1, PSTR("M702 T0")); + else + MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E1, lcd_temp_menu_e0_filament_unload); + if (!thermalManager.targetTooColdToExtrude(1)) + MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E2, PSTR("M702 T1")); + else + MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E2, lcd_temp_menu_e1_filament_unload); + #if E_STEPPERS > 2 + if (!thermalManager.targetTooColdToExtrude(2)) + MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E3, PSTR("M702 T2")); + else + MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E3, lcd_temp_menu_e2_filament_unload); + #if E_STEPPERS > 3 + if (!thermalManager.targetTooColdToExtrude(3)) + MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E4, PSTR("M702 T3")); + else + MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E4, lcd_temp_menu_e3_filament_unload); + #if E_STEPPERS > 4 + if (!thermalManager.targetTooColdToExtrude(4)) + MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E5, PSTR("M702 T4")); + else + MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E5, lcd_temp_menu_e4_filament_unload); + #endif // E_STEPPERS > 4 + #endif // E_STEPPERS > 3 + #endif // E_STEPPERS > 2 + #endif // E_STEPPERS == 1 + } + #endif + + END_MENU(); + } + #endif + + static AdvancedPauseMode advanced_pause_mode = ADVANCED_PAUSE_MODE_PAUSE_PRINT; + static uint8_t hotend_status_extruder = 0; + + static const char* advanced_pause_header() { + switch (advanced_pause_mode) { + case ADVANCED_PAUSE_MODE_LOAD_FILAMENT: + return PSTR(MSG_FILAMENT_CHANGE_HEADER_LOAD); + case ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT: + return PSTR(MSG_FILAMENT_CHANGE_HEADER_UNLOAD); + default: break; + } + return PSTR(MSG_FILAMENT_CHANGE_HEADER_PAUSE); + } + // Portions from STATIC_ITEM... #define HOTEND_STATUS_ITEM() do { \ if (_menuLineNr == _thisItemNr) { \ if (lcdDrawUpdate) { \ lcd_implementation_drawmenu_static(_lcdLineNr, PSTR(MSG_FILAMENT_CHANGE_NOZZLE), false, true); \ - lcd_implementation_hotend_status(_lcdLineNr); \ + lcd_implementation_hotend_status(_lcdLineNr, hotend_status_extruder); \ } \ if (_skipStatic && encoderLine <= _thisItemNr) { \ encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; \ @@ -4147,18 +4365,6 @@ void kill_screen(const char* lcd_msg) { ++_thisItemNr; \ }while(0) - void lcd_advanced_pause_toocold_menu() { - START_MENU(); - STATIC_ITEM(MSG_HEATING_FAILED_LCD, true, true); - STATIC_ITEM(MSG_FILAMENT_CHANGE_MINTEMP STRINGIFY(EXTRUDE_MINTEMP) ".", false, false); - MENU_BACK(MSG_BACK); - #if LCD_HEIGHT > 4 - STATIC_ITEM(" "); - #endif - HOTEND_STATUS_ITEM(); - END_MENU(); - } - void lcd_advanced_pause_resume_print() { advanced_pause_menu_response = ADVANCED_PAUSE_RESPONSE_RESUME_PRINT; } @@ -4173,13 +4379,13 @@ void kill_screen(const char* lcd_msg) { STATIC_ITEM(MSG_FILAMENT_CHANGE_OPTION_HEADER, true, false); #endif MENU_ITEM(function, MSG_FILAMENT_CHANGE_OPTION_RESUME, lcd_advanced_pause_resume_print); - MENU_ITEM(function, MSG_FILAMENT_CHANGE_OPTION_EXTRUDE, lcd_advanced_pause_extrude_more); + MENU_ITEM(function, MSG_FILAMENT_CHANGE_OPTION_PURGE, lcd_advanced_pause_extrude_more); END_MENU(); } void lcd_advanced_pause_init_message() { START_SCREEN(); - STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true); + STATIC_ITEM_P(advanced_pause_header(), true, true); STATIC_ITEM(MSG_FILAMENT_CHANGE_INIT_1); #ifdef MSG_FILAMENT_CHANGE_INIT_2 STATIC_ITEM(MSG_FILAMENT_CHANGE_INIT_2); @@ -4202,7 +4408,7 @@ void kill_screen(const char* lcd_msg) { void lcd_advanced_pause_unload_message() { START_SCREEN(); - STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true); + STATIC_ITEM_P(advanced_pause_header(), true, true); STATIC_ITEM(MSG_FILAMENT_CHANGE_UNLOAD_1); #ifdef MSG_FILAMENT_CHANGE_UNLOAD_2 STATIC_ITEM(MSG_FILAMENT_CHANGE_UNLOAD_2); @@ -4225,7 +4431,7 @@ void kill_screen(const char* lcd_msg) { void lcd_advanced_pause_wait_for_nozzles_to_heat() { START_SCREEN(); - STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true); + STATIC_ITEM_P(advanced_pause_header(), true, true); STATIC_ITEM(MSG_FILAMENT_CHANGE_HEATING_1); #ifdef MSG_FILAMENT_CHANGE_HEATING_2 STATIC_ITEM(MSG_FILAMENT_CHANGE_HEATING_2); @@ -4242,7 +4448,7 @@ void kill_screen(const char* lcd_msg) { void lcd_advanced_pause_heat_nozzle() { START_SCREEN(); - STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true); + STATIC_ITEM_P(advanced_pause_header(), true, true); STATIC_ITEM(MSG_FILAMENT_CHANGE_HEAT_1); #ifdef MSG_FILAMENT_CHANGE_INSERT_2 STATIC_ITEM(MSG_FILAMENT_CHANGE_HEAT_2); @@ -4259,7 +4465,7 @@ void kill_screen(const char* lcd_msg) { void lcd_advanced_pause_insert_message() { START_SCREEN(); - STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true); + STATIC_ITEM_P(advanced_pause_header(), true, true); STATIC_ITEM(MSG_FILAMENT_CHANGE_INSERT_1); #ifdef MSG_FILAMENT_CHANGE_INSERT_2 STATIC_ITEM(MSG_FILAMENT_CHANGE_INSERT_2); @@ -4282,7 +4488,7 @@ void kill_screen(const char* lcd_msg) { void lcd_advanced_pause_load_message() { START_SCREEN(); - STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true); + STATIC_ITEM_P(advanced_pause_header(), true, true); STATIC_ITEM(MSG_FILAMENT_CHANGE_LOAD_1); #ifdef MSG_FILAMENT_CHANGE_LOAD_2 STATIC_ITEM(MSG_FILAMENT_CHANGE_LOAD_2); @@ -4303,18 +4509,18 @@ void kill_screen(const char* lcd_msg) { END_SCREEN(); } - void lcd_advanced_pause_extrude_message() { + void lcd_advanced_pause_purge_message() { START_SCREEN(); - STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true); - STATIC_ITEM(MSG_FILAMENT_CHANGE_EXTRUDE_1); - #ifdef MSG_FILAMENT_CHANGE_EXTRUDE_2 - STATIC_ITEM(MSG_FILAMENT_CHANGE_EXTRUDE_2); + STATIC_ITEM_P(advanced_pause_header(), true, true); + STATIC_ITEM(MSG_FILAMENT_CHANGE_PURGE_1); + #ifdef MSG_FILAMENT_CHANGE_PURGE_2 + STATIC_ITEM(MSG_FILAMENT_CHANGE_PURGE_2); #define __FC_LINES_G 3 #else #define __FC_LINES_G 2 #endif - #ifdef MSG_FILAMENT_CHANGE_EXTRUDE_3 - STATIC_ITEM(MSG_FILAMENT_CHANGE_EXTRUDE_3); + #ifdef MSG_FILAMENT_CHANGE_PURGE_3 + STATIC_ITEM(MSG_FILAMENT_CHANGE_PURGE_3); #define _FC_LINES_G (__FC_LINES_G + 1) #else #define _FC_LINES_G __FC_LINES_G @@ -4328,7 +4534,7 @@ void kill_screen(const char* lcd_msg) { void lcd_advanced_pause_resume_message() { START_SCREEN(); - STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true); + STATIC_ITEM_P(advanced_pause_header(), true, true); STATIC_ITEM(MSG_FILAMENT_CHANGE_RESUME_1); #ifdef MSG_FILAMENT_CHANGE_RESUME_2 STATIC_ITEM(MSG_FILAMENT_CHANGE_RESUME_2); @@ -4339,49 +4545,38 @@ void kill_screen(const char* lcd_msg) { END_SCREEN(); } - void lcd_advanced_pause_show_message(const AdvancedPauseMessage message) { + FORCE_INLINE screenFunc_t ap_message_screen(const AdvancedPauseMessage message) { switch (message) { - case ADVANCED_PAUSE_MESSAGE_INIT: - defer_return_to_status = true; - lcd_goto_screen(lcd_advanced_pause_init_message); - break; - case ADVANCED_PAUSE_MESSAGE_UNLOAD: - defer_return_to_status = true; - lcd_goto_screen(lcd_advanced_pause_unload_message); - break; - case ADVANCED_PAUSE_MESSAGE_INSERT: - defer_return_to_status = true; - lcd_goto_screen(lcd_advanced_pause_insert_message); - break; - case ADVANCED_PAUSE_MESSAGE_LOAD: - defer_return_to_status = true; - lcd_goto_screen(lcd_advanced_pause_load_message); - break; - case ADVANCED_PAUSE_MESSAGE_EXTRUDE: - defer_return_to_status = true; - lcd_goto_screen(lcd_advanced_pause_extrude_message); - break; - case ADVANCED_PAUSE_MESSAGE_CLICK_TO_HEAT_NOZZLE: - defer_return_to_status = true; - lcd_goto_screen(lcd_advanced_pause_heat_nozzle); - break; - case ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT: - defer_return_to_status = true; - lcd_goto_screen(lcd_advanced_pause_wait_for_nozzles_to_heat); - break; - case ADVANCED_PAUSE_MESSAGE_OPTION: - defer_return_to_status = true; - advanced_pause_menu_response = ADVANCED_PAUSE_RESPONSE_WAIT_FOR; - lcd_goto_screen(lcd_advanced_pause_option_menu); - break; - case ADVANCED_PAUSE_MESSAGE_RESUME: - defer_return_to_status = true; - lcd_goto_screen(lcd_advanced_pause_resume_message); - break; + case ADVANCED_PAUSE_MESSAGE_INIT: return lcd_advanced_pause_init_message; + case ADVANCED_PAUSE_MESSAGE_UNLOAD: return lcd_advanced_pause_unload_message; + case ADVANCED_PAUSE_MESSAGE_INSERT: return lcd_advanced_pause_insert_message; + case ADVANCED_PAUSE_MESSAGE_LOAD: return lcd_advanced_pause_load_message; + case ADVANCED_PAUSE_MESSAGE_PURGE: return lcd_advanced_pause_purge_message; + case ADVANCED_PAUSE_MESSAGE_RESUME: return lcd_advanced_pause_resume_message; + case ADVANCED_PAUSE_MESSAGE_CLICK_TO_HEAT_NOZZLE: return lcd_advanced_pause_heat_nozzle; + case ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT: return lcd_advanced_pause_wait_for_nozzles_to_heat; + case ADVANCED_PAUSE_MESSAGE_OPTION: advanced_pause_menu_response = ADVANCED_PAUSE_RESPONSE_WAIT_FOR; + return lcd_advanced_pause_option_menu; case ADVANCED_PAUSE_MESSAGE_STATUS: - lcd_return_to_status(); - break; + default: break; } + return NULL; + } + + void lcd_advanced_pause_show_message( + const AdvancedPauseMessage message, + const AdvancedPauseMode mode/*=ADVANCED_PAUSE_MODE_PAUSE_PRINT*/, + const uint8_t extruder/*=active_extruder*/ + ) { + advanced_pause_mode = mode; + hotend_status_extruder = extruder; + const screenFunc_t next_screen = ap_message_screen(message); + if (next_screen) { + defer_return_to_status = true; + lcd_goto_screen(next_screen); + } + else + lcd_return_to_status(); } #endif // ADVANCED_PAUSE_FEATURE @@ -4742,7 +4937,7 @@ void lcd_update() { if (UBL_CONDITION && LCD_CLICKED) { if (!wait_for_unclick) { // If not waiting for a debounce release: wait_for_unclick = true; // Set debounce flag to ignore continous clicks - lcd_clicked = !wait_for_user && !no_reentry; // Flag the click if allowed + lcd_clicked = !wait_for_user && !no_reentry; // Keep the click if not waiting for a user-click wait_for_user = false; // Any click clears wait for user lcd_quick_feedback(); // Always make a click sound } diff --git a/Marlin/src/lcd/ultralcd.h b/Marlin/src/lcd/ultralcd.h index 23148ae35..98e8ffa13 100644 --- a/Marlin/src/lcd/ultralcd.h +++ b/Marlin/src/lcd/ultralcd.h @@ -29,6 +29,10 @@ #include "../Marlin.h" + #if ENABLED(ADVANCED_PAUSE_FEATURE) + #include "../feature/pause.h" + #endif + #if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION) extern bool lcd_external_control; #else @@ -116,20 +120,11 @@ void lcd_completion_feedback(const bool good=true); #if ENABLED(ADVANCED_PAUSE_FEATURE) - enum AdvancedPauseMessage { - ADVANCED_PAUSE_MESSAGE_INIT, - ADVANCED_PAUSE_MESSAGE_UNLOAD, - ADVANCED_PAUSE_MESSAGE_INSERT, - ADVANCED_PAUSE_MESSAGE_LOAD, - ADVANCED_PAUSE_MESSAGE_EXTRUDE, - ADVANCED_PAUSE_MESSAGE_OPTION, - ADVANCED_PAUSE_MESSAGE_RESUME, - ADVANCED_PAUSE_MESSAGE_STATUS, - ADVANCED_PAUSE_MESSAGE_CLICK_TO_HEAT_NOZZLE, - ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT - }; - void lcd_advanced_pause_show_message(const AdvancedPauseMessage message); - #endif + extern uint8_t active_extruder; + void lcd_advanced_pause_show_message(const AdvancedPauseMessage message, + const AdvancedPauseMode mode=ADVANCED_PAUSE_MODE_PAUSE_PRINT, + const uint8_t extruder=active_extruder); + #endif // ADVANCED_PAUSE_FEATURE #if ENABLED(G26_MESH_VALIDATION) void lcd_chirp(); diff --git a/Marlin/src/lcd/ultralcd_impl_DOGM.h b/Marlin/src/lcd/ultralcd_impl_DOGM.h index 27cfc8d4f..cf1719297 100644 --- a/Marlin/src/lcd/ultralcd_impl_DOGM.h +++ b/Marlin/src/lcd/ultralcd_impl_DOGM.h @@ -773,7 +773,7 @@ static void lcd_implementation_status_screen() { #if ENABLED(ADVANCED_PAUSE_FEATURE) - static void lcd_implementation_hotend_status(const uint8_t row) { + static void lcd_implementation_hotend_status(const uint8_t row, const uint8_t extruder=active_extruder) { row_y1 = row * row_height + 1; row_y2 = row_y1 + row_height - 1; @@ -781,13 +781,13 @@ static void lcd_implementation_status_screen() { u8g.setPrintPos(LCD_PIXEL_WIDTH - 11 * (DOG_CHAR_WIDTH), row_y2); lcd_print('E'); - lcd_print((char)('1' + active_extruder)); + lcd_print((char)('1' + extruder)); lcd_print(' '); - lcd_print(itostr3(thermalManager.degHotend(active_extruder))); + lcd_print(itostr3(thermalManager.degHotend(extruder))); lcd_print('/'); - if (lcd_blink() || !thermalManager.is_heater_idle(active_extruder)) - lcd_print(itostr3(thermalManager.degTargetHotend(active_extruder))); + if (lcd_blink() || !thermalManager.is_heater_idle(extruder)) + lcd_print(itostr3(thermalManager.degTargetHotend(extruder))); } #endif // ADVANCED_PAUSE_FEATURE diff --git a/Marlin/src/lcd/ultralcd_impl_HD44780.h b/Marlin/src/lcd/ultralcd_impl_HD44780.h index 72f2574b8..0331af681 100644 --- a/Marlin/src/lcd/ultralcd_impl_HD44780.h +++ b/Marlin/src/lcd/ultralcd_impl_HD44780.h @@ -803,7 +803,6 @@ static void lcd_implementation_status_screen() { // If the first line has two extruder temps, // show more temperatures on the next line - // instead of #if HOTENDS > 2 || (HOTENDS > 1 && TEMP_SENSOR_BED) @@ -954,10 +953,10 @@ static void lcd_implementation_status_screen() { #if ENABLED(ADVANCED_PAUSE_FEATURE) - static void lcd_implementation_hotend_status(const uint8_t row) { + static void lcd_implementation_hotend_status(const uint8_t row, const uint8_t extruder=active_extruder) { if (row < LCD_HEIGHT) { lcd.setCursor(LCD_WIDTH - 9, row); - _draw_heater_status(active_extruder, LCD_STR_THERMOMETER[0], lcd_blink()); + _draw_heater_status(extruder, LCD_STR_THERMOMETER[0], lcd_blink()); } } diff --git a/Marlin/src/module/configuration_store.cpp b/Marlin/src/module/configuration_store.cpp index dc1fc3792..ee7e75563 100644 --- a/Marlin/src/module/configuration_store.cpp +++ b/Marlin/src/module/configuration_store.cpp @@ -36,13 +36,13 @@ * */ -#define EEPROM_VERSION "V47" +#define EEPROM_VERSION "V48" // Change EEPROM version if these are changed: #define EEPROM_OFFSET 100 /** - * V47 EEPROM Layout: + * V48 EEPROM Layout: * * 100 Version (char x4) * 104 EEPROM CRC16 (uint16_t) @@ -139,7 +139,7 @@ * * Volumetric Extrusion: 21 bytes * 539 M200 D parser.volumetric_enabled (bool) - * 540 M200 T D planner.filament_size (float x5) (T0..3) + * 540 M200 T D planner.filament_size (float x5) (T0..4) * * HAS_TRINAMIC: 22 bytes * 560 M906 X Stepper X current (uint16_t) @@ -154,7 +154,7 @@ * 578 M906 E3 Stepper E3 current (uint16_t) * 580 M906 E4 Stepper E4 current (uint16_t) * - * SENSORLESS HOMING 4 bytes + * SENSORLESS_HOMING: 4 bytes * 582 M914 X Stepper X and X2 threshold (int16_t) * 584 M914 Y Stepper Y and Y2 threshold (int16_t) * @@ -167,7 +167,7 @@ * 598 M907 Z Stepper Z current (uint32_t) * 602 M907 E Stepper E current (uint32_t) * - * CNC_COORDINATE_SYSTEMS 108 bytes + * CNC_COORDINATE_SYSTEMS: 108 bytes * 606 G54-G59.3 coordinate_system (float x 27) * * SKEW_CORRECTION: 12 bytes @@ -175,8 +175,12 @@ * 718 M852 J planner.xz_skew_factor (float) * 722 M852 K planner.yz_skew_factor (float) * - * 726 Minimum end-point - * 2255 (726 + 208 + 36 + 9 + 288 + 988) Maximum end-point + * ADVANCED_PAUSE_FEATURE: 40 bytes + * 726 M603 T U filament_change_unload_length (float x 5) (T0..4) + * 746 M603 T L filament_change_load_length (float x 5) (T0..4) + * + * 766 Minimum end-point + * 2295 (766 + 208 + 36 + 9 + 288 + 988) Maximum end-point * * ======================================================================== * meshes_begin (between max and min end-point, directly above) @@ -698,6 +702,23 @@ void MarlinSettings::postprocess() { for (uint8_t q = 3; q--;) EEPROM_WRITE(dummy); #endif + // + // Advanced Pause filament load & unload lengths + // + #if ENABLED(ADVANCED_PAUSE_FEATURE) + for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) { + if (q < COUNT(filament_change_unload_length)) dummy = filament_change_unload_length[q]; + EEPROM_WRITE(dummy); + } + for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) { + if (q < COUNT(filament_change_load_length)) dummy = filament_change_load_length[q]; + EEPROM_WRITE(dummy); + } + #else + dummy = 0.0f; + for (uint8_t q = MAX_EXTRUDERS * 2; q--;) EEPROM_WRITE(dummy); + #endif + if (!eeprom_error) { #if ENABLED(EEPROM_CHITCHAT) const int eeprom_size = eeprom_index; @@ -1183,6 +1204,23 @@ void MarlinSettings::postprocess() { for (uint8_t q = 3; q--;) EEPROM_READ(dummy); #endif + // + // Advanced Pause filament load & unload lengths + // + + #if ENABLED(ADVANCED_PAUSE_FEATURE) + for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) { + EEPROM_READ(dummy); + if (q < COUNT(filament_change_unload_length)) filament_change_unload_length[q] = dummy; + } + for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) { + EEPROM_READ(dummy); + if (q < COUNT(filament_change_load_length)) filament_change_load_length[q] = dummy; + } + #else + for (uint8_t q = MAX_EXTRUDERS * 2; q--;) EEPROM_READ(dummy); + #endif + if (working_crc == stored_crc) { postprocess(); #if ENABLED(EEPROM_CHITCHAT) @@ -1593,6 +1631,13 @@ void MarlinSettings::reset() { #endif #endif + #if ENABLED(ADVANCED_PAUSE_FEATURE) + for (uint8_t e = 0; e < E_STEPPERS; e++) { + filament_change_unload_length[e] = FILAMENT_CHANGE_UNLOAD_LENGTH; + filament_change_load_length[e] = FILAMENT_CHANGE_LOAD_LENGTH; + } + #endif + postprocess(); #if ENABLED(EEPROM_CHITCHAT) @@ -2136,6 +2181,42 @@ void MarlinSettings::reset() { SERIAL_ECHOPAIR(" E", stepper.motor_current_setting[2]); SERIAL_EOL(); #endif + + /** + * Advanced Pause filament load & unload lengths + */ + #if ENABLED(ADVANCED_PAUSE_FEATURE) + if (!forReplay) { + CONFIG_ECHO_START; + SERIAL_ECHOLNPGM("Filament load/unload lengths:"); + } + CONFIG_ECHO_START; + #if EXTRUDERS == 1 + SERIAL_ECHOPAIR(" M603 L", LINEAR_UNIT(filament_change_load_length[0])); + SERIAL_ECHOLNPAIR(" U", LINEAR_UNIT(filament_change_unload_length[0])); + #else + SERIAL_ECHOPAIR(" M603 T0 L", LINEAR_UNIT(filament_change_load_length[0])); + SERIAL_ECHOLNPAIR(" U", LINEAR_UNIT(filament_change_unload_length[0])); + CONFIG_ECHO_START; + SERIAL_ECHOPAIR(" M603 T1 L", LINEAR_UNIT(filament_change_load_length[1])); + SERIAL_ECHOLNPAIR(" U", LINEAR_UNIT(filament_change_unload_length[1])); + #if EXTRUDERS > 2 + CONFIG_ECHO_START; + SERIAL_ECHOPAIR(" M603 T2 L", LINEAR_UNIT(filament_change_load_length[2])); + SERIAL_ECHOLNPAIR(" U", LINEAR_UNIT(filament_change_unload_length[2])); + #if EXTRUDERS > 3 + CONFIG_ECHO_START; + SERIAL_ECHOPAIR(" M603 T3 L", LINEAR_UNIT(filament_change_load_length[3])); + SERIAL_ECHOLNPAIR(" U", LINEAR_UNIT(filament_change_unload_length[3])); + #if EXTRUDERS > 4 + CONFIG_ECHO_START; + SERIAL_ECHOPAIR(" M603 T4 L", LINEAR_UNIT(filament_change_load_length[4])); + SERIAL_ECHOLNPAIR(" U", LINEAR_UNIT(filament_change_unload_length[4])); + #endif // EXTRUDERS > 4 + #endif // EXTRUDERS > 3 + #endif // EXTRUDERS > 2 + #endif // EXTRUDERS == 1 + #endif // ADVANCED_PAUSE_FEATURE } #endif // !DISABLE_M503