diff options
Diffstat (limited to 'Marlin/src/gcode/feature/pause')
-rw-r--r-- | Marlin/src/gcode/feature/pause/G27.cpp | 41 | ||||
-rw-r--r-- | Marlin/src/gcode/feature/pause/G60.cpp | 58 | ||||
-rw-r--r-- | Marlin/src/gcode/feature/pause/G61.cpp | 73 | ||||
-rw-r--r-- | Marlin/src/gcode/feature/pause/M125.cpp | 90 | ||||
-rw-r--r-- | Marlin/src/gcode/feature/pause/M600.cpp | 172 | ||||
-rw-r--r-- | Marlin/src/gcode/feature/pause/M603.cpp | 65 | ||||
-rw-r--r-- | Marlin/src/gcode/feature/pause/M701_M702.cpp | 235 |
7 files changed, 734 insertions, 0 deletions
diff --git a/Marlin/src/gcode/feature/pause/G27.cpp b/Marlin/src/gcode/feature/pause/G27.cpp new file mode 100644 index 0000000..3ce618d --- /dev/null +++ b/Marlin/src/gcode/feature/pause/G27.cpp @@ -0,0 +1,41 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>. + * + */ + + +#include "../../../inc/MarlinConfig.h" + +#if ENABLED(NOZZLE_PARK_FEATURE) + +#include "../../gcode.h" +#include "../../../libs/nozzle.h" +#include "../../../module/motion.h" + +/** + * G27: Park the nozzle + */ +void GcodeSuite::G27() { + // Don't allow nozzle parking without homing first + if (homing_needed_error()) return; + nozzle.park(parser.ushortval('P')); +} + +#endif // NOZZLE_PARK_FEATURE diff --git a/Marlin/src/gcode/feature/pause/G60.cpp b/Marlin/src/gcode/feature/pause/G60.cpp new file mode 100644 index 0000000..6f695b9 --- /dev/null +++ b/Marlin/src/gcode/feature/pause/G60.cpp @@ -0,0 +1,58 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>. + * + */ + +#include "../../../inc/MarlinConfig.h" + +#if SAVED_POSITIONS + +#include "../../gcode.h" +#include "../../../module/motion.h" + +#define DEBUG_OUT ENABLED(SAVED_POSITIONS_DEBUG) +#include "../../../core/debug_out.h" + +/** + * G60: Save current position + * + * S<slot> - Memory slot # (0-based) to save into (default 0) + */ +void GcodeSuite::G60() { + const uint8_t slot = parser.byteval('S'); + + if (slot >= SAVED_POSITIONS) { + SERIAL_ERROR_MSG(STR_INVALID_POS_SLOT STRINGIFY(SAVED_POSITIONS)); + return; + } + + stored_position[slot] = current_position; + SBI(saved_slots[slot >> 3], slot & 0x07); + + #if ENABLED(SAVED_POSITIONS_DEBUG) + const xyze_pos_t &pos = stored_position[slot]; + DEBUG_ECHOPAIR_F(STR_SAVED_POS " S", slot); + DEBUG_ECHOPAIR_F(" : X", pos.x); + DEBUG_ECHOPAIR_F_P(SP_Y_STR, pos.y); + DEBUG_ECHOLNPAIR_F_P(SP_Z_STR, pos.z); + #endif +} + +#endif // SAVED_POSITIONS diff --git a/Marlin/src/gcode/feature/pause/G61.cpp b/Marlin/src/gcode/feature/pause/G61.cpp new file mode 100644 index 0000000..5d89af0 --- /dev/null +++ b/Marlin/src/gcode/feature/pause/G61.cpp @@ -0,0 +1,73 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>. + * + */ + +#include "../../../inc/MarlinConfig.h" + +#if SAVED_POSITIONS + +#include "../../../module/planner.h" +#include "../../gcode.h" +#include "../../../module/motion.h" + +/** + * G61: Return to saved position + * + * F<rate> - Feedrate (optional) for the move back. + * S<slot> - Slot # (0-based) to restore from (default 0). + * X Y Z - Axes to restore. At least one is required. + */ +void GcodeSuite::G61(void) { + + const uint8_t slot = parser.byteval('S'); + + #if SAVED_POSITIONS < 256 + if (slot >= SAVED_POSITIONS) { + SERIAL_ERROR_MSG(STR_INVALID_POS_SLOT STRINGIFY(SAVED_POSITIONS)); + return; + } + #endif + + // No saved position? No axes being restored? + if (!TEST(saved_slots[slot >> 3], slot & 0x07) || !parser.seen("XYZ")) return; + + SERIAL_ECHOPAIR(STR_RESTORING_POS " S", int(slot)); + LOOP_XYZ(i) { + destination[i] = parser.seen(XYZ_CHAR(i)) + ? stored_position[slot][i] + parser.value_axis_units((AxisEnum)i) + : current_position[i]; + SERIAL_CHAR(' ', XYZ_CHAR(i)); + SERIAL_ECHO_F(destination[i]); + } + SERIAL_EOL(); + + // Apply any given feedrate over 0.0 + feedRate_t saved_feedrate = feedrate_mm_s; + const float fr = parser.linearval('F'); + if (fr > 0.0) feedrate_mm_s = MMM_TO_MMS(fr); + + // Move to the saved position + prepare_line_to_destination(); + + feedrate_mm_s = saved_feedrate; +} + +#endif // SAVED_POSITIONS diff --git a/Marlin/src/gcode/feature/pause/M125.cpp b/Marlin/src/gcode/feature/pause/M125.cpp new file mode 100644 index 0000000..9391b86 --- /dev/null +++ b/Marlin/src/gcode/feature/pause/M125.cpp @@ -0,0 +1,90 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>. + * + */ + +#include "../../../inc/MarlinConfig.h" + +#if ENABLED(PARK_HEAD_ON_PAUSE) + +#include "../../gcode.h" +#include "../../parser.h" +#include "../../../feature/pause.h" +#include "../../../lcd/marlinui.h" +#include "../../../module/motion.h" +#include "../../../module/printcounter.h" +#include "../../../sd/cardreader.h" + +#if ENABLED(POWER_LOSS_RECOVERY) + #include "../../../feature/powerloss.h" +#endif + +/** + * M125: Store current position and move to parking position. + * Called on pause (by M25) to prevent material leaking onto the + * object. On resume (M24) the head will be moved back and the + * print will resume. + * + * When not actively SD printing, M125 simply moves to the park + * position and waits, resuming with a button click or M108. + * Without PARK_HEAD_ON_PAUSE the M125 command does nothing. + * + * L<linear> = Override retract Length + * X<pos> = Override park position X + * Y<pos> = Override park position Y + * Z<linear> = Override Z raise + * + * With an LCD menu: + * P<bool> = Always show a prompt and await a response + */ +void GcodeSuite::M125() { + // Initial retract before move to filament change position + const float retract = -ABS(parser.seen('L') ? parser.value_axis_units(E_AXIS) : (PAUSE_PARK_RETRACT_LENGTH)); + + xyz_pos_t park_point = NOZZLE_PARK_POINT; + + // Move XY axes to filament change position or given position + if (parser.seenval('X')) park_point.x = RAW_X_POSITION(parser.linearval('X')); + if (parser.seenval('Y')) park_point.y = RAW_X_POSITION(parser.linearval('Y')); + + // Lift Z axis + if (parser.seenval('Z')) park_point.z = parser.linearval('Z'); + + #if HAS_HOTEND_OFFSET && NONE(DUAL_X_CARRIAGE, DELTA) + park_point += hotend_offset[active_extruder]; + #endif + + const bool sd_printing = TERN0(SDSUPPORT, IS_SD_PRINTING()); + + ui.pause_show_message(PAUSE_MESSAGE_PARKING, PAUSE_MODE_PAUSE_PRINT); + + // If possible, show an LCD prompt with the 'P' flag + const bool show_lcd = TERN0(HAS_LCD_MENU, parser.boolval('P')); + + if (pause_print(retract, park_point, 0, show_lcd)) { + TERN_(POWER_LOSS_RECOVERY, if (recovery.enabled) recovery.save(true)); + if (ENABLED(EXTENSIBLE_UI) || !sd_printing || show_lcd) { + wait_for_confirmation(false, 0); + resume_print(0, 0, -retract, 0); + } + } +} + +#endif // PARK_HEAD_ON_PAUSE diff --git a/Marlin/src/gcode/feature/pause/M600.cpp b/Marlin/src/gcode/feature/pause/M600.cpp new file mode 100644 index 0000000..1c282f2 --- /dev/null +++ b/Marlin/src/gcode/feature/pause/M600.cpp @@ -0,0 +1,172 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>. + * + */ + +#include "../../../inc/MarlinConfig.h" + +#if ENABLED(ADVANCED_PAUSE_FEATURE) + +#include "../../gcode.h" +#include "../../../feature/pause.h" +#include "../../../module/motion.h" +#include "../../../module/printcounter.h" +#include "../../../lcd/marlinui.h" + +#if HAS_MULTI_EXTRUDER + #include "../../../module/tool_change.h" +#endif + +#if ENABLED(MMU2_MENUS) + #include "../../../lcd/menu/menu_mmu2.h" +#endif + +#if ENABLED(MIXING_EXTRUDER) + #include "../../../feature/mixing.h" +#endif + +#if HAS_FILAMENT_SENSOR + #include "../../../feature/runout.h" +#endif + +/** + * M600: Pause for filament change + * + * 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 (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 + * R[temp] - Resume temperature (in current units) + * + * Default values are used for omitted arguments. + */ +void GcodeSuite::M600() { + + #if ENABLED(MIXING_EXTRUDER) + const int8_t target_e_stepper = get_target_e_stepper_from_command(); + if (target_e_stepper < 0) return; + + const uint8_t old_mixing_tool = mixer.get_current_vtool(); + mixer.T(MIXER_DIRECT_SET_TOOL); + + MIXER_STEPPER_LOOP(i) mixer.set_collector(i, i == uint8_t(target_e_stepper) ? 1.0 : 0.0); + mixer.normalize(); + + const int8_t target_extruder = active_extruder; + #else + const int8_t target_extruder = get_target_extruder_from_command(); + if (target_extruder < 0) return; + #endif + + #if ENABLED(DUAL_X_CARRIAGE) + int8_t DXC_ext = target_extruder; + if (!parser.seen('T')) { // If no tool index is specified, M600 was (probably) sent in response to filament runout. + // In this case, for duplicating modes set DXC_ext to the extruder that ran out. + #if HAS_FILAMENT_SENSOR && NUM_RUNOUT_SENSORS > 1 + if (idex_is_duplicating()) + DXC_ext = (READ(FIL_RUNOUT2_PIN) == FIL_RUNOUT2_STATE) ? 1 : 0; + #else + DXC_ext = active_extruder; + #endif + } + #endif + + // Show initial "wait for start" message + #if DISABLED(MMU2_MENUS) + ui.pause_show_message(PAUSE_MESSAGE_CHANGING, PAUSE_MODE_PAUSE_PRINT, target_extruder); + #endif + + #if ENABLED(HOME_BEFORE_FILAMENT_CHANGE) + // If needed, home before parking for filament change + if (!all_axes_trusted()) home_all_axes(true); + #endif + + #if HAS_MULTI_EXTRUDER + // Change toolhead if specified + const uint8_t active_extruder_before_filament_change = active_extruder; + if (active_extruder != target_extruder && TERN1(DUAL_X_CARRIAGE, !idex_is_duplicating())) + tool_change(target_extruder, false); + #endif + + // Initial retract before move to filament change position + const float retract = -ABS(parser.seen('E') ? parser.value_axis_units(E_AXIS) : (PAUSE_PARK_RETRACT_LENGTH)); + + xyz_pos_t park_point NOZZLE_PARK_POINT; + + // Lift Z axis + if (parser.seenval('Z')) park_point.z = parser.linearval('Z'); + + // Move XY axes to filament change position or given position + if (parser.seenval('X')) park_point.x = parser.linearval('X'); + if (parser.seenval('Y')) park_point.y = parser.linearval('Y'); + + #if HAS_HOTEND_OFFSET && NONE(DUAL_X_CARRIAGE, DELTA) + park_point += hotend_offset[active_extruder]; + #endif + + #if ENABLED(MMU2_MENUS) + // For MMU2 reset retract and load/unload values so they don't mess with MMU filament handling + constexpr float unload_length = 0.5f, + slow_load_length = 0.0f, + fast_load_length = 0.0f; + #else + // Unload filament + const float unload_length = -ABS(parser.seen('U') ? parser.value_axis_units(E_AXIS) + : fc_settings[active_extruder].unload_length); + + // Slow load filament + constexpr float slow_load_length = FILAMENT_CHANGE_SLOW_LOAD_LENGTH; + + // Fast load filament + const float fast_load_length = ABS(parser.seen('L') ? parser.value_axis_units(E_AXIS) + : fc_settings[active_extruder].load_length); + #endif + + const int beep_count = parser.intval('B', -1 + #ifdef FILAMENT_CHANGE_ALERT_BEEPS + + 1 + FILAMENT_CHANGE_ALERT_BEEPS + #endif + ); + + if (pause_print(retract, park_point, unload_length, true DXC_PASS)) { + #if ENABLED(MMU2_MENUS) + mmu2_M600(); + resume_print(slow_load_length, fast_load_length, 0, beep_count DXC_PASS); + #else + wait_for_confirmation(true, beep_count DXC_PASS); + resume_print(slow_load_length, fast_load_length, ADVANCED_PAUSE_PURGE_LENGTH, + beep_count, (parser.seenval('R') ? parser.value_celsius() : 0) DXC_PASS); + #endif + } + + #if HAS_MULTI_EXTRUDER + // Restore toolhead if it was changed + if (active_extruder_before_filament_change != active_extruder) + tool_change(active_extruder_before_filament_change, false); + #endif + + TERN_(MIXING_EXTRUDER, mixer.T(old_mixing_tool)); // Restore original mixing tool +} + +#endif // ADVANCED_PAUSE_FEATURE diff --git a/Marlin/src/gcode/feature/pause/M603.cpp b/Marlin/src/gcode/feature/pause/M603.cpp new file mode 100644 index 0000000..9c3b774 --- /dev/null +++ b/Marlin/src/gcode/feature/pause/M603.cpp @@ -0,0 +1,65 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>. + * + */ + +#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 HAS_MULTI_EXTRUDER + #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 + */ +void GcodeSuite::M603() { + + const int8_t target_extruder = get_target_extruder_from_command(); + if (target_extruder < 0) return; + + // Unload length + if (parser.seen('U')) { + fc_settings[target_extruder].unload_length = ABS(parser.value_axis_units(E_AXIS)); + #if ENABLED(PREVENT_LENGTHY_EXTRUDE) + NOMORE(fc_settings[target_extruder].unload_length, EXTRUDE_MAXLENGTH); + #endif + } + + // Load length + if (parser.seen('L')) { + fc_settings[target_extruder].load_length = ABS(parser.value_axis_units(E_AXIS)); + #if ENABLED(PREVENT_LENGTHY_EXTRUDE) + NOMORE(fc_settings[target_extruder].load_length, EXTRUDE_MAXLENGTH); + #endif + } +} + +#endif // ADVANCED_PAUSE_FEATURE diff --git a/Marlin/src/gcode/feature/pause/M701_M702.cpp b/Marlin/src/gcode/feature/pause/M701_M702.cpp new file mode 100644 index 0000000..9a2b774 --- /dev/null +++ b/Marlin/src/gcode/feature/pause/M701_M702.cpp @@ -0,0 +1,235 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2020 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 <https://www.gnu.org/licenses/>. + * + */ + +#include "../../../inc/MarlinConfigPre.h" + +#if ENABLED(FILAMENT_LOAD_UNLOAD_GCODES) + +#include "../../gcode.h" +#include "../../../MarlinCore.h" +#include "../../../module/motion.h" +#include "../../../module/temperature.h" +#include "../../../feature/pause.h" +#include "../../../lcd/marlinui.h" + +#if HAS_MULTI_EXTRUDER + #include "../../../module/tool_change.h" +#endif + +#if HAS_PRUSA_MMU2 + #include "../../../feature/mmu/mmu2.h" +#endif + +#if ENABLED(MIXING_EXTRUDER) + #include "../../../feature/mixing.h" +#endif + +/** + * M701: Load filament + * + * T<extruder> - Extruder number. Required for mixing extruder. + * For non-mixing, 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::M701() { + xyz_pos_t park_point = NOZZLE_PARK_POINT; + + // Don't raise Z if the machine isn't homed + if (TERN0(NO_MOTION_BEFORE_HOMING, axes_should_home())) park_point.z = 0; + + #if ENABLED(MIXING_EXTRUDER) + const int8_t target_e_stepper = get_target_e_stepper_from_command(); + if (target_e_stepper < 0) return; + + const uint8_t old_mixing_tool = mixer.get_current_vtool(); + mixer.T(MIXER_DIRECT_SET_TOOL); + + MIXER_STEPPER_LOOP(i) mixer.set_collector(i, (i == (uint8_t)target_e_stepper) ? 1.0 : 0.0); + mixer.normalize(); + + const int8_t target_extruder = active_extruder; + #else + const int8_t target_extruder = get_target_extruder_from_command(); + if (target_extruder < 0) return; + #endif + + // Z axis lift + if (parser.seenval('Z')) park_point.z = parser.linearval('Z'); + + // Show initial "wait for load" message + ui.pause_show_message(PAUSE_MESSAGE_LOAD, PAUSE_MODE_LOAD_FILAMENT, target_extruder); + + #if HAS_MULTI_EXTRUDER && (HAS_PRUSA_MMU1 || !HAS_MMU) + // Change toolhead if specified + uint8_t active_extruder_before_filament_change = active_extruder; + if (active_extruder != target_extruder) + tool_change(target_extruder, false); + #endif + + // Lift Z axis + if (park_point.z > 0) + do_blocking_move_to_z(_MIN(current_position.z + park_point.z, Z_MAX_POS), feedRate_t(NOZZLE_PARK_Z_FEEDRATE)); + + // Load filament + #if HAS_PRUSA_MMU2 + mmu2.load_filament_to_nozzle(target_extruder); + #else + constexpr float purge_length = ADVANCED_PAUSE_PURGE_LENGTH, + slow_load_length = FILAMENT_CHANGE_SLOW_LOAD_LENGTH; + const float fast_load_length = ABS(parser.seen('L') ? parser.value_axis_units(E_AXIS) + : fc_settings[active_extruder].load_length); + load_filament( + slow_load_length, fast_load_length, purge_length, + FILAMENT_CHANGE_ALERT_BEEPS, + true, // show_lcd + thermalManager.still_heating(target_extruder), // pause_for_user + PAUSE_MODE_LOAD_FILAMENT // pause_mode + #if ENABLED(DUAL_X_CARRIAGE) + , target_extruder // Dual X target + #endif + ); + #endif + + // Restore Z axis + if (park_point.z > 0) + do_blocking_move_to_z(_MAX(current_position.z - park_point.z, 0), feedRate_t(NOZZLE_PARK_Z_FEEDRATE)); + + #if HAS_MULTI_EXTRUDER && (HAS_PRUSA_MMU1 || !HAS_MMU) + // Restore toolhead if it was changed + if (active_extruder_before_filament_change != active_extruder) + tool_change(active_extruder_before_filament_change, false); + #endif + + TERN_(MIXING_EXTRUDER, mixer.T(old_mixing_tool)); // Restore original mixing tool + + // Show status screen + ui.pause_show_message(PAUSE_MESSAGE_STATUS); +} + +/** + * M702: Unload filament + * + * T<extruder> - Extruder number. Required for mixing extruder. + * For non-mixing, 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() { + xyz_pos_t park_point = NOZZLE_PARK_POINT; + + // Don't raise Z if the machine isn't homed + if (TERN0(NO_MOTION_BEFORE_HOMING, axes_should_home())) park_point.z = 0; + + #if ENABLED(MIXING_EXTRUDER) + const uint8_t old_mixing_tool = mixer.get_current_vtool(); + + #if ENABLED(FILAMENT_UNLOAD_ALL_EXTRUDERS) + float mix_multiplier = 1.0; + const bool seenT = parser.seenval('T'); + if (!seenT) { + mixer.T(MIXER_AUTORETRACT_TOOL); + mix_multiplier = MIXING_STEPPERS; + } + #else + constexpr bool seenT = true; + #endif + + if (seenT) { + const int8_t target_e_stepper = get_target_e_stepper_from_command(); + if (target_e_stepper < 0) return; + mixer.T(MIXER_DIRECT_SET_TOOL); + MIXER_STEPPER_LOOP(i) mixer.set_collector(i, (i == (uint8_t)target_e_stepper) ? 1.0 : 0.0); + mixer.normalize(); + } + + const int8_t target_extruder = active_extruder; + #else + const int8_t target_extruder = get_target_extruder_from_command(); + if (target_extruder < 0) return; + #endif + + // Z axis lift + if (parser.seenval('Z')) park_point.z = parser.linearval('Z'); + + // Show initial "wait for unload" message + ui.pause_show_message(PAUSE_MESSAGE_UNLOAD, PAUSE_MODE_UNLOAD_FILAMENT, target_extruder); + + #if HAS_MULTI_EXTRUDER && (HAS_PRUSA_MMU1 || !HAS_MMU) + // Change toolhead if specified + uint8_t active_extruder_before_filament_change = active_extruder; + if (active_extruder != target_extruder) + tool_change(target_extruder, false); + #endif + + // Lift Z axis + if (park_point.z > 0) + do_blocking_move_to_z(_MIN(current_position.z + park_point.z, Z_MAX_POS), feedRate_t(NOZZLE_PARK_Z_FEEDRATE)); + + // Unload filament + #if HAS_PRUSA_MMU2 + mmu2.unload(); + #else + #if BOTH(HAS_MULTI_EXTRUDER, FILAMENT_UNLOAD_ALL_EXTRUDERS) + if (!parser.seenval('T')) { + HOTEND_LOOP() { + if (e != active_extruder) tool_change(e, false); + unload_filament(-fc_settings[e].unload_length, true, PAUSE_MODE_UNLOAD_FILAMENT); + } + } + else + #endif + { + // Unload length + const float unload_length = -ABS(parser.seen('U') ? parser.value_axis_units(E_AXIS) + : fc_settings[target_extruder].unload_length); + + unload_filament(unload_length, true, PAUSE_MODE_UNLOAD_FILAMENT + #if ALL(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) + , mix_multiplier + #endif + ); + } + #endif + + // Restore Z axis + if (park_point.z > 0) + do_blocking_move_to_z(_MAX(current_position.z - park_point.z, 0), feedRate_t(NOZZLE_PARK_Z_FEEDRATE)); + + #if HAS_MULTI_EXTRUDER && (HAS_PRUSA_MMU1 || !HAS_MMU) + // Restore toolhead if it was changed + if (active_extruder_before_filament_change != active_extruder) + tool_change(active_extruder_before_filament_change, false); + #endif + + TERN_(MIXING_EXTRUDER, mixer.T(old_mixing_tool)); // Restore original mixing tool + + // Show status screen + ui.pause_show_message(PAUSE_MESSAGE_STATUS); +} + +#endif // ADVANCED_PAUSE_FEATURE |