Browse Source

Add M701/M702 Filament Load/Unload, M603

Scott Lahteine 6 years ago
parent
commit
7541316bb4

+ 1
- 1
.travis.yml View File

@@ -122,7 +122,7 @@ script:
122 122
   - opt_enable ULTIMAKERCONTROLLER SDSUPPORT
123 123
   - opt_enable PRINTCOUNTER NOZZLE_PARK_FEATURE NOZZLE_CLEAN_FEATURE PCA9632 USE_XMAX_PLUG
124 124
   - opt_enable_adv BEZIER_CURVE_SUPPORT EXPERIMENTAL_I2CBUS
125
-  - opt_enable_adv ADVANCED_PAUSE_FEATURE PARK_HEAD_ON_PAUSE LCD_INFO_MENU M114_DETAIL
125
+  - opt_enable_adv ADVANCED_PAUSE_FEATURE FILAMENT_LOAD_UNLOAD_GCODES PARK_HEAD_ON_PAUSE LCD_INFO_MENU M114_DETAIL
126 126
   - opt_set_adv PWM_MOTOR_CURRENT {1300,1300,1250}
127 127
   - opt_set_adv I2C_SLAVE_ADDRESS 63
128 128
   - build_marlin_pio ${TRAVIS_BUILD_DIR} ${TEST_PLATFORM}

+ 31
- 22
Marlin/Configuration_adv.h View File

@@ -881,29 +881,38 @@
881 881
  */
882 882
 //#define ADVANCED_PAUSE_FEATURE
883 883
 #if ENABLED(ADVANCED_PAUSE_FEATURE)
884
-  #define PAUSE_PARK_RETRACT_FEEDRATE 60      // Initial retract feedrate in mm/s
885
-  #define PAUSE_PARK_RETRACT_LENGTH 2         // Initial retract in mm
886
-                                              // It is a short retract used immediately after print interrupt before move to filament exchange position
887
-  #define FILAMENT_CHANGE_UNLOAD_FEEDRATE 10  // Unload filament feedrate in mm/s - filament unloading can be fast
888
-  #define FILAMENT_CHANGE_UNLOAD_LENGTH 100   // Unload filament length from hotend in mm
889
-                                              // Longer length for bowden printers to unload filament from whole bowden tube,
890
-                                              // shorter length for printers without bowden to unload filament from extruder only,
891
-                                              // 0 to disable unloading for manual unloading
892
-  #define FILAMENT_CHANGE_LOAD_FEEDRATE 6     // Load filament feedrate in mm/s - filament loading into the bowden tube can be fast
893
-  #define FILAMENT_CHANGE_LOAD_LENGTH 0       // Load filament length over hotend in mm
894
-                                              // Longer length for bowden printers to fast load filament into whole bowden tube over the hotend,
895
-                                              // Short or zero length for printers without bowden where loading is not used
896
-  #define ADVANCED_PAUSE_EXTRUDE_FEEDRATE 3   // Extrude filament feedrate in mm/s - must be slower than load feedrate
897
-  #define ADVANCED_PAUSE_EXTRUDE_LENGTH 50    // Extrude filament length in mm after filament is loaded over the hotend,
898
-                                              // 0 to disable for manual extrusion
899
-                                              // Filament can be extruded repeatedly from the filament exchange menu to fill the hotend,
900
-                                              // or until outcoming filament color is not clear for filament color change
901
-  #define PAUSE_PARK_NOZZLE_TIMEOUT 45        // Turn off nozzle if user doesn't change filament within this time limit in seconds
902
-  #define FILAMENT_CHANGE_NUMBER_OF_ALERT_BEEPS 5 // Number of alert beeps before printer goes quiet
903
-  #define PAUSE_PARK_NO_STEPPER_TIMEOUT       // Enable to have stepper motors hold position during filament change
904
-                                              // even if it takes longer than DEFAULT_STEPPER_DEACTIVE_TIME.
905
-  //#define PARK_HEAD_ON_PAUSE                // Go to filament change position on pause, return to print position on resume
884
+  #define PAUSE_PARK_RETRACT_FEEDRATE 60      // (mm/s) Initial retract feedrate.
885
+  #define PAUSE_PARK_RETRACT_LENGTH 2         // (mm) Initial retract.
886
+                                              // This short retract is done immediately, before parking the nozzle.
887
+  #define FILAMENT_CHANGE_UNLOAD_FEEDRATE 10  // (mm/s) Unload filament feedrate. This can be pretty fast.
888
+  #define FILAMENT_CHANGE_UNLOAD_LENGTH 100   // (mm) The length of filament for a complete unload.
889
+                                              //   For Bowden, the full length of the tube and nozzle.
890
+                                              //   For direct drive, the full length of the nozzle.
891
+                                              //   Set to 0 for manual unloading.
892
+  #define FILAMENT_CHANGE_LOAD_FEEDRATE 6     // (mm/s) Load filament feedrate. This can be pretty fast.
893
+  #define FILAMENT_CHANGE_LOAD_LENGTH 0       // (mm) Load length of filament, from extruder gear to nozzle.
894
+                                              //   For Bowden, the full length of the tube and nozzle.
895
+                                              //   For direct drive, the full length of the nozzle.
896
+  #define ADVANCED_PAUSE_EXTRUDE_FEEDRATE 3   // (mm/s) Extrude feedrate (after loading). Should be slower than load feedrate.
897
+  #define ADVANCED_PAUSE_EXTRUDE_LENGTH 50    // (mm) Length to extrude after loading.
898
+                                              //   Set to 0 for manual extrusion.
899
+                                              //   Filament can be extruded repeatedly from the Filament Change menu
900
+                                              //   until extrusion is consistent, and to purge old filament.
901
+
902
+                                              // Filament Unload does a Retract, Delay, and Purge first:
903
+  #define FILAMENT_UNLOAD_RETRACT_LENGTH 13   // (mm) Unload initial retract length.
904
+  #define FILAMENT_UNLOAD_DELAY 5000          // (ms) Delay for the filament to cool after retract.
905
+  #define FILAMENT_UNLOAD_PURGE_LENGTH 8      // (mm) An unretract is done, then this length is purged.
906
+
907
+  #define PAUSE_PARK_NOZZLE_TIMEOUT 45        // (seconds) Time limit before the nozzle is turned off for safety.
908
+  #define FILAMENT_CHANGE_ALERT_BEEPS 10      // Number of alert beeps to play when a response is needed.
909
+  #define PAUSE_PARK_NO_STEPPER_TIMEOUT       // Enable for XYZ steppers to stay powered on during filament change.
910
+
911
+  //#define PARK_HEAD_ON_PAUSE                // Park the nozzle during pause and filament change.
906 912
   //#define HOME_BEFORE_FILAMENT_CHANGE       // Ensure homing has been completed prior to parking for filament change
913
+
914
+  //#define FILAMENT_LOAD_UNLOAD_GCODES       // Add M701/M702 Load/Unload G-codes, plus Load/Unload in the LCD Prepare menu.
915
+  //#define FILAMENT_UNLOAD_ALL_EXTRUDERS     // Allow M702 to unload all extruders above a minimum target temp (as set by M302)
907 916
 #endif
908 917
 
909 918
 // @section tmc

+ 10
- 4
Marlin/src/Marlin.cpp View File

@@ -191,10 +191,6 @@ volatile bool wait_for_heatup = true;
191 191
 millis_t max_inactive_time = 0,
192 192
          stepper_inactive_time = (DEFAULT_STEPPER_DEACTIVE_TIME) * 1000UL;
193 193
 
194
-#if ENABLED(ADVANCED_PAUSE_FEATURE)
195
-  AdvancedPauseMenuResponse advanced_pause_menu_response;
196
-#endif
197
-
198 194
 #ifdef CHDK
199 195
   millis_t chdkHigh = 0;
200 196
   bool chdkActive = false;
@@ -308,6 +304,16 @@ void disable_e_steppers() {
308 304
   disable_E4();
309 305
 }
310 306
 
307
+void disable_e_stepper(const uint8_t e) {
308
+  switch (e) {
309
+    case 0: disable_E0(); break;
310
+    case 1: disable_E1(); break;
311
+    case 2: disable_E2(); break;
312
+    case 3: disable_E3(); break;
313
+    case 4: disable_E4(); break;
314
+  }
315
+}
316
+
311 317
 void disable_all_steppers() {
312 318
   disable_X();
313 319
   disable_Y();

+ 1
- 9
Marlin/src/Marlin.h View File

@@ -159,6 +159,7 @@ void manage_inactivity(bool ignore_stepper_queue = false);
159 159
 #define _AXIS(AXIS) AXIS ##_AXIS
160 160
 
161 161
 void enable_all_steppers();
162
+void disable_e_stepper(const uint8_t e);
162 163
 void disable_e_steppers();
163 164
 void disable_all_steppers();
164 165
 
@@ -198,15 +199,6 @@ extern millis_t max_inactive_time, stepper_inactive_time;
198 199
   #endif
199 200
 #endif
200 201
 
201
-#if ENABLED(ADVANCED_PAUSE_FEATURE)
202
-  enum AdvancedPauseMenuResponse {
203
-    ADVANCED_PAUSE_RESPONSE_WAIT_FOR,
204
-    ADVANCED_PAUSE_RESPONSE_EXTRUDE_MORE,
205
-    ADVANCED_PAUSE_RESPONSE_RESUME_PRINT
206
-  };
207
-  extern AdvancedPauseMenuResponse advanced_pause_menu_response;
208
-#endif
209
-
210 202
 #if ENABLED(PID_EXTRUSION_SCALING)
211 203
   extern int lpq_len;
212 204
 #endif

+ 9
- 1
Marlin/src/core/language.h View File

@@ -205,7 +205,15 @@
205 205
 #define MSG_ENDSTOPS_HIT                    "endstops hit: "
206 206
 #define MSG_ERR_COLD_EXTRUDE_STOP           " cold extrusion prevented"
207 207
 #define MSG_ERR_LONG_EXTRUDE_STOP           " too long extrusion prevented"
208
-#define MSG_TOO_COLD_FOR_M600               "M600 Hotend too cold to change filament"
208
+#define MSG_HOTEND_TOO_COLD                 "Hotend too cold"
209
+
210
+#define MSG_FILAMENT_CHANGE_HEAT            "Press button (or M108) to heat nozzle"
211
+#define MSG_FILAMENT_CHANGE_HEAT_LCD        "Press button to heat nozzle"
212
+#define MSG_FILAMENT_CHANGE_HEAT_M108       "Send M108 to heat nozzle"
213
+#define MSG_FILAMENT_CHANGE_INSERT          "Insert filament and press button (or M108)"
214
+#define MSG_FILAMENT_CHANGE_INSERT_LCD      "Insert filament and press button"
215
+#define MSG_FILAMENT_CHANGE_INSERT_M108     "Insert filament and send M108"
216
+
209 217
 #define MSG_SERIAL_ERROR_MENU_STRUCTURE     "Error in menu structure"
210 218
 
211 219
 #define MSG_ERR_EEPROM_WRITE                "Error writing to EEPROM!"

+ 212
- 138
Marlin/src/feature/pause.cpp View File

@@ -27,7 +27,7 @@
27 27
 
28 28
 #include "../inc/MarlinConfig.h"
29 29
 
30
-#if ENABLED(ADVANCED_PAUSE_FEATURE) || ENABLED(PARK_HEAD_ON_PAUSE)
30
+#if ENABLED(ADVANCED_PAUSE_FEATURE)
31 31
 
32 32
 #include "../Marlin.h"
33 33
 #include "../gcode/gcode.h"
@@ -56,6 +56,11 @@
56 56
 
57 57
 static float resume_position[XYZE];
58 58
 
59
+AdvancedPauseMenuResponse advanced_pause_menu_response;
60
+
61
+float filament_change_unload_length[EXTRUDERS],
62
+      filament_change_load_length[EXTRUDERS];
63
+
59 64
 #if ENABLED(SDSUPPORT)
60 65
   #include "../sd/cardreader.h"
61 66
 #endif
@@ -70,68 +75,197 @@ static float resume_position[XYZE];
70 75
     const millis_t ms = millis();
71 76
     if (ELAPSED(ms, next_buzz)) {
72 77
       if (max_beep_count < 0 || runout_beep < max_beep_count + 5) { // Only beep as long as we're supposed to
73
-        next_buzz = ms + ((max_beep_count < 0 || runout_beep < max_beep_count) ? 2500 : 400);
74
-        BUZZ(300, 2000);
78
+        next_buzz = ms + ((max_beep_count < 0 || runout_beep < max_beep_count) ? 1000 : 500);
79
+        BUZZ(50, 880 - (runout_beep & 1) * 220);
75 80
         runout_beep++;
76 81
       }
77 82
     }
78 83
   }
79 84
 #endif
80 85
 
81
-static void ensure_safe_temperature() {
82
-  bool heaters_heating = true;
83
-
84
-  wait_for_heatup = true;    // M108 will clear this
85
-  while (wait_for_heatup && heaters_heating) {
86
-    idle();
87
-    heaters_heating = false;
88
-    HOTEND_LOOP() {
89
-      if (thermalManager.degTargetHotend(e) && abs(thermalManager.degHotend(e) - thermalManager.degTargetHotend(e)) > TEMP_HYSTERESIS) {
90
-        heaters_heating = true;
91
-        #if ENABLED(ULTIPANEL)
92
-          lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT);
93
-        #endif
94
-        break;
95
-      }
86
+static bool ensure_safe_temperature(const AdvancedPauseMode mode=ADVANCED_PAUSE_MODE_PAUSE_PRINT) {
87
+
88
+  #if ENABLED(PREVENT_COLD_EXTRUSION)
89
+    if (!DEBUGGING(DRYRUN) && thermalManager.targetTooColdToExtrude(active_extruder)) {
90
+      SERIAL_ERROR_START();
91
+      SERIAL_ERRORLNPGM(MSG_HOTEND_TOO_COLD);
92
+      return false;
96 93
     }
97
-  }
94
+  #endif
95
+
96
+  #if ENABLED(ULTIPANEL)
97
+    lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT, mode);
98
+  #else
99
+    UNUSED(mode);
100
+  #endif
101
+
102
+  wait_for_heatup = true; // M108 will clear this
103
+  while (wait_for_heatup && thermalManager.wait_for_heating(active_extruder)) idle();
104
+  const bool status = wait_for_heatup;
105
+  wait_for_heatup = false;
106
+
107
+  return status;
98 108
 }
99 109
 
100
-void do_pause_e_move(const float &length, const float fr) {
101
-  current_position[E_AXIS] += length / planner.e_factor[active_extruder];
110
+static void do_pause_e_move(const float &length, const float &fr) {
102 111
   set_destination_from_current();
103
-  #if IS_KINEMATIC
104
-    planner.buffer_line_kinematic(destination, fr, active_extruder);
112
+  destination[E_AXIS] += length / planner.e_factor[active_extruder];
113
+  buffer_line_to_destination(fr);
114
+  stepper.synchronize();
115
+  set_current_from_destination();
116
+}
117
+
118
+bool load_filament(const float &load_length/*=0*/, const float &extrude_length/*=0*/, const int8_t max_beep_count/*=0*/,
119
+                          const bool show_lcd/*=false*/, const bool pause_for_user/*=false*/,
120
+                          const AdvancedPauseMode mode/*=ADVANCED_PAUSE_MODE_PAUSE_PRINT*/
121
+) {
122
+  #if DISABLED(ULTIPANEL)
123
+    UNUSED(show_lcd);
124
+  #endif
125
+
126
+  if (!ensure_safe_temperature(mode)) {
127
+    #if ENABLED(ULTIPANEL)
128
+      if (show_lcd) // Show status screen
129
+        lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS);
130
+    #endif
131
+
132
+    return false;
133
+  }
134
+
135
+  if (pause_for_user) {
136
+    #if ENABLED(ULTIPANEL)
137
+      if (show_lcd) // Show "insert filament"
138
+        lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INSERT, mode);
139
+    #endif
140
+    SERIAL_ECHO_START();
141
+    SERIAL_ECHOLNPGM(MSG_FILAMENT_CHANGE_INSERT);
142
+
143
+    #if HAS_BUZZER
144
+      filament_change_beep(max_beep_count, true);
145
+    #else
146
+      UNUSED(max_beep_count);
147
+    #endif
148
+
149
+    KEEPALIVE_STATE(PAUSED_FOR_USER);
150
+    wait_for_user = true;    // LCD click or M108 will clear this
151
+    while (wait_for_user) {
152
+      #if HAS_BUZZER
153
+        filament_change_beep(max_beep_count);
154
+      #endif
155
+      idle(true);
156
+    }
157
+    KEEPALIVE_STATE(IN_HANDLER);
158
+  }
159
+
160
+  #if ENABLED(ULTIPANEL)
161
+    if (show_lcd) // Show "load" message
162
+      lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_LOAD, mode);
163
+  #endif
164
+
165
+  // Load filament
166
+  do_pause_e_move(load_length, FILAMENT_CHANGE_LOAD_FEEDRATE);
167
+
168
+  do {
169
+    if (extrude_length > 0) {
170
+      // "Wait for filament purge"
171
+      #if ENABLED(ULTIPANEL)
172
+        if (show_lcd)
173
+          lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_PURGE, mode);
174
+      #endif
175
+
176
+      // Extrude filament to get into hotend
177
+      do_pause_e_move(extrude_length, ADVANCED_PAUSE_EXTRUDE_FEEDRATE);
178
+    }
179
+
180
+    // Show "Extrude More" / "Resume" menu and wait for reply
181
+    #if ENABLED(ULTIPANEL)
182
+      if (show_lcd) {
183
+        KEEPALIVE_STATE(PAUSED_FOR_USER);
184
+        wait_for_user = false;
185
+        lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_OPTION, mode);
186
+        while (advanced_pause_menu_response == ADVANCED_PAUSE_RESPONSE_WAIT_FOR) idle(true);
187
+        KEEPALIVE_STATE(IN_HANDLER);
188
+      }
189
+    #endif
190
+
191
+    // Keep looping if "Extrude More" was selected
192
+  } while (
193
+    #if ENABLED(ULTIPANEL)
194
+      show_lcd && advanced_pause_menu_response == ADVANCED_PAUSE_RESPONSE_EXTRUDE_MORE
195
+    #else
196
+      0
197
+    #endif
198
+  );
199
+
200
+  return true;
201
+}
202
+
203
+bool unload_filament(const float &unload_length, const bool show_lcd/*=false*/,
204
+                            const AdvancedPauseMode mode/*=ADVANCED_PAUSE_MODE_PAUSE_PRINT*/
205
+) {
206
+  if (!ensure_safe_temperature(mode)) {
207
+    #if ENABLED(ULTIPANEL)
208
+      if (show_lcd) // Show status screen
209
+        lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS);
210
+    #endif
211
+
212
+    return false;
213
+  }
214
+
215
+  #if DISABLED(ULTIPANEL)
216
+    UNUSED(show_lcd);
105 217
   #else
106
-    buffer_line_to_destination(fr);
218
+    if (show_lcd)
219
+      lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_UNLOAD, mode);
107 220
   #endif
108
-  stepper.synchronize();
221
+
222
+  // Retract filament
223
+  do_pause_e_move(-FILAMENT_UNLOAD_RETRACT_LENGTH, PAUSE_PARK_RETRACT_FEEDRATE);
224
+
225
+  // Wait for filament to cool
226
+  safe_delay(FILAMENT_UNLOAD_DELAY);
227
+
228
+  // Quickly purge
229
+  do_pause_e_move(FILAMENT_UNLOAD_RETRACT_LENGTH + FILAMENT_UNLOAD_PURGE_LENGTH, planner.max_feedrate_mm_s[E_AXIS]);
230
+
231
+  // Unload filament
232
+  do_pause_e_move(unload_length, FILAMENT_CHANGE_UNLOAD_FEEDRATE);
233
+
234
+  // Disable extruders steppers for manual filament changing (only on boards that have separate ENABLE_PINS)
235
+  #if E0_ENABLE_PIN != X_ENABLE_PIN && E1_ENABLE_PIN != Y_ENABLE_PIN
236
+    disable_e_stepper(active_extruder);
237
+    safe_delay(100);
238
+  #endif
239
+
240
+  return true;
109 241
 }
110 242
 
111 243
 // public:
112 244
 
113 245
 uint8_t did_pause_print = 0;
114 246
 
115
-bool pause_print(const float &retract, const point_t &park_point, const float &unload_length/*=0*/,
116
-                 const int8_t max_beep_count/*=0*/, const bool show_lcd/*=false*/
117
-) {
247
+bool pause_print(const float &retract, const point_t &park_point, const float &unload_length/*=0*/, const bool show_lcd/*=false*/) {
118 248
   if (did_pause_print) return false; // already paused
119 249
 
120 250
   #ifdef ACTION_ON_PAUSE
121 251
     SERIAL_ECHOLNPGM("//action:" ACTION_ON_PAUSE);
122 252
   #endif
123 253
 
124
-  if (!DEBUGGING(DRYRUN) && unload_length != 0) {
125
-    #if ENABLED(PREVENT_COLD_EXTRUSION)
126
-      if (!thermalManager.allow_cold_extrude &&
127
-          thermalManager.degTargetHotend(active_extruder) < thermalManager.extrude_min_temp) {
128
-        SERIAL_ERROR_START();
129
-        SERIAL_ERRORLNPGM(MSG_TOO_COLD_FOR_M600);
130
-        return false;
131
-      }
254
+  #if ENABLED(ULTIPANEL)
255
+    if (show_lcd) // Show initial message
256
+      lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INIT);
257
+  #endif
258
+
259
+  if (!DEBUGGING(DRYRUN) && unload_length && thermalManager.targetTooColdToExtrude(active_extruder)) {
260
+    SERIAL_ERROR_START();
261
+    SERIAL_ERRORLNPGM(MSG_HOTEND_TOO_COLD);
262
+
263
+    #if ENABLED(ULTIPANEL)
264
+      if (show_lcd) // Show status screen
265
+        lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS);
132 266
     #endif
133 267
 
134
-    ensure_safe_temperature(); // wait for extruder to heat up before unloading
268
+    return false; // unable to reach safe temperature
135 269
   }
136 270
 
137 271
   // Indicate that the printer is paused
@@ -139,22 +273,18 @@ bool pause_print(const float &retract, const point_t &park_point, const float &u
139 273
 
140 274
   // Pause the print job and timer
141 275
   #if ENABLED(SDSUPPORT)
142
-    if (IS_SD_PRINTING) {
276
+    if (card.sdprinting) {
143 277
       card.pauseSDPrint();
144 278
       ++did_pause_print;
145 279
     }
146 280
   #endif
147 281
   print_job_timer.pause();
148 282
 
149
-  // Show initial message and wait for synchronize steppers
150
-  if (show_lcd) {
151
-    #if ENABLED(ULTIPANEL)
152
-      lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INIT);
153
-    #endif
154
-  }
155
-
283
+  // Wait for synchronize steppers
156 284
   stepper.synchronize();
157
-  COPY(resume_position, current_position); // Save current position for later
285
+
286
+  // Save current position
287
+  COPY(resume_position, current_position);
158 288
 
159 289
   // Initial retract before move to filament change position
160 290
   if (retract && !thermalManager.tooColdToExtrude(active_extruder))
@@ -163,34 +293,24 @@ bool pause_print(const float &retract, const point_t &park_point, const float &u
163 293
   // Park the nozzle by moving up by z_lift and then moving to (x_pos, y_pos)
164 294
   Nozzle::park(2, park_point);
165 295
 
166
-  if (unload_length != 0) {
167
-    if (show_lcd) {
168
-      #if ENABLED(ULTIPANEL)
169
-        lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_UNLOAD);
170
-        idle();
171
-      #endif
172
-    }
296
+  // Unload the filament
297
+  if (unload_length)
298
+    unload_filament(unload_length, show_lcd);
173 299
 
174
-    // Unload filament
175
-    do_pause_e_move(unload_length, FILAMENT_CHANGE_UNLOAD_FEEDRATE);
176
-  }
300
+  return true;
301
+}
177 302
 
178
-  if (show_lcd) {
179
-    #if ENABLED(ULTIPANEL)
180
-      lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INSERT);
181
-    #endif
182
-  }
303
+void wait_for_filament_reload(const int8_t max_beep_count/*=0*/) {
304
+  bool nozzle_timed_out = false;
183 305
 
184
-  #if HAS_BUZZER
185
-    filament_change_beep(max_beep_count, true);
306
+  #if ENABLED(ULTIPANEL)
307
+    lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INSERT);
186 308
   #endif
309
+  SERIAL_ECHO_START();
310
+  SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_INSERT);
187 311
 
188
-  idle();
189
-
190
-  // Disable extruders steppers for manual filament changing (only on boards that have separate ENABLE_PINS)
191
-  #if E0_ENABLE_PIN != X_ENABLE_PIN && E1_ENABLE_PIN != Y_ENABLE_PIN
192
-    disable_e_steppers();
193
-    safe_delay(100);
312
+  #if HAS_BUZZER
313
+    filament_change_beep(max_beep_count, true);
194 314
   #endif
195 315
 
196 316
   // Start the heater idle timers
@@ -199,12 +319,6 @@ bool pause_print(const float &retract, const point_t &park_point, const float &u
199 319
   HOTEND_LOOP()
200 320
     thermalManager.start_heater_idle_timer(e, nozzle_timeout);
201 321
 
202
-  return true;
203
-}
204
-
205
-void wait_for_filament_reload(const int8_t max_beep_count/*=0*/) {
206
-  bool nozzle_timed_out = false;
207
-
208 322
   // Wait for filament insert by user and press button
209 323
   KEEPALIVE_STATE(PAUSED_FOR_USER);
210 324
   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*/) {
223 337
       #if ENABLED(ULTIPANEL)
224 338
         lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_CLICK_TO_HEAT_NOZZLE);
225 339
       #endif
340
+      SERIAL_ECHO_START();
341
+      #if ENABLED(ULTIPANEL) && ENABLED(EMERGENCY_PARSER)
342
+        SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_HEAT);
343
+      #elif ENABLED(EMERGENCY_PARSER)
344
+        SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_HEAT_M108);
345
+      #else
346
+        SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_HEAT_LCD);
347
+      #endif
226 348
 
227 349
       // Wait for LCD click or M108
228 350
       while (wait_for_user) idle(true);
@@ -236,6 +358,14 @@ void wait_for_filament_reload(const int8_t max_beep_count/*=0*/) {
236 358
       #if ENABLED(ULTIPANEL)
237 359
         lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INSERT);
238 360
       #endif
361
+      SERIAL_ECHO_START();
362
+      #if ENABLED(ULTIPANEL) && ENABLED(EMERGENCY_PARSER)
363
+        SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_INSERT);
364
+      #elif ENABLED(EMERGENCY_PARSER)
365
+        SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_INSERT_M108);
366
+      #else
367
+        SERIAL_ERRORLNPGM(MSG_FILAMENT_CHANGE_INSERT_LCD);
368
+      #endif
239 369
 
240 370
       // Start the heater idle timers
241 371
       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*/) {
243 373
       HOTEND_LOOP()
244 374
         thermalManager.start_heater_idle_timer(e, nozzle_timeout);
245 375
 
246
-      wait_for_user = true; /* Wait for user to load filament */
376
+      wait_for_user = true; // Wait for user to load filament
247 377
       nozzle_timed_out = false;
248 378
 
249 379
       #if HAS_BUZZER
@@ -256,7 +386,7 @@ void wait_for_filament_reload(const int8_t max_beep_count/*=0*/) {
256 386
   KEEPALIVE_STATE(IN_HANDLER);
257 387
 }
258 388
 
259
-void resume_print(const float &load_length/*=0*/, const float &initial_extrude_length/*=0*/, const int8_t max_beep_count/*=0*/) {
389
+void resume_print(const float &load_length/*=0*/, const float &extrude_length/*=ADVANCED_PAUSE_EXTRUDE_LENGTH*/, const int8_t max_beep_count/*=0*/) {
260 390
   bool nozzle_timed_out = false;
261 391
 
262 392
   if (!did_pause_print) return;
@@ -267,67 +397,11 @@ void resume_print(const float &load_length/*=0*/, const float &initial_extrude_l
267 397
     thermalManager.reset_heater_idle_timer(e);
268 398
   }
269 399
 
270
-  if (nozzle_timed_out) ensure_safe_temperature();
271
-
272
-  #if HAS_BUZZER
273
-    filament_change_beep(max_beep_count, true);
274
-  #endif
275
-
276
-  if (load_length != 0) {
277
-    #if ENABLED(ULTIPANEL)
278
-      // Show "insert filament"
279
-      if (nozzle_timed_out)
280
-        lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INSERT);
281
-    #endif
282
-
283
-    KEEPALIVE_STATE(PAUSED_FOR_USER);
284
-    wait_for_user = true;    // LCD click or M108 will clear this
285
-    while (wait_for_user && nozzle_timed_out) {
286
-      #if HAS_BUZZER
287
-        filament_change_beep(max_beep_count);
288
-      #endif
289
-      idle(true);
290
-    }
291
-    KEEPALIVE_STATE(IN_HANDLER);
292
-
293
-    #if ENABLED(ULTIPANEL)
294
-      // Show "load" message
295
-      lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_LOAD);
296
-    #endif
297
-
298
-    // Load filament
299
-    do_pause_e_move(load_length, FILAMENT_CHANGE_LOAD_FEEDRATE);
400
+  if (nozzle_timed_out || !thermalManager.tooColdToExtrude(active_extruder)) {
401
+    // Load the new filament
402
+    load_filament(load_length, extrude_length, max_beep_count, true, nozzle_timed_out);
300 403
   }
301 404
 
302
-  #if ENABLED(ULTIPANEL) && ADVANCED_PAUSE_EXTRUDE_LENGTH > 0
303
-
304
-    if (!thermalManager.tooColdToExtrude(active_extruder)) {
305
-      float extrude_length = initial_extrude_length;
306
-
307
-      do {
308
-        if (extrude_length > 0) {
309
-          // "Wait for filament extrude"
310
-          lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_EXTRUDE);
311
-
312
-          // Extrude filament to get into hotend
313
-          do_pause_e_move(extrude_length, ADVANCED_PAUSE_EXTRUDE_FEEDRATE);
314
-        }
315
-
316
-        // Show "Extrude More" / "Resume" menu and wait for reply
317
-        KEEPALIVE_STATE(PAUSED_FOR_USER);
318
-        wait_for_user = false;
319
-        lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_OPTION);
320
-        while (advanced_pause_menu_response == ADVANCED_PAUSE_RESPONSE_WAIT_FOR) idle(true);
321
-        KEEPALIVE_STATE(IN_HANDLER);
322
-
323
-        extrude_length = ADVANCED_PAUSE_EXTRUDE_LENGTH;
324
-
325
-        // Keep looping if "Extrude More" was selected
326
-      } while (advanced_pause_menu_response == ADVANCED_PAUSE_RESPONSE_EXTRUDE_MORE);
327
-    }
328
-
329
-  #endif
330
-
331 405
   #if ENABLED(ULTIPANEL)
332 406
     // "Wait for print to resume"
333 407
     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
358 432
   #endif
359 433
 
360 434
   #if ENABLED(ULTIPANEL)
361
-    // Show pause status screen
435
+    // Show status screen
362 436
     lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS);
363 437
   #endif
364 438
 
@@ -376,4 +450,4 @@ void resume_print(const float &load_length/*=0*/, const float &initial_extrude_l
376 450
   #endif
377 451
 }
378 452
 
379
-#endif // ADVANCED_PAUSE_FEATURE || PARK_HEAD_ON_PAUSE
453
+#endif // ADVANCED_PAUSE_FEATURE

+ 39
- 4
Marlin/src/feature/pause.h View File

@@ -30,14 +30,49 @@
30 30
 
31 31
 #include "../libs/nozzle.h"
32 32
 
33
+#include "../inc/MarlinConfigPre.h"
34
+
35
+enum AdvancedPauseMode {
36
+  ADVANCED_PAUSE_MODE_PAUSE_PRINT,
37
+  ADVANCED_PAUSE_MODE_LOAD_FILAMENT,
38
+  ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT
39
+};
40
+
41
+enum AdvancedPauseMessage {
42
+  ADVANCED_PAUSE_MESSAGE_INIT,
43
+  ADVANCED_PAUSE_MESSAGE_UNLOAD,
44
+  ADVANCED_PAUSE_MESSAGE_INSERT,
45
+  ADVANCED_PAUSE_MESSAGE_LOAD,
46
+  ADVANCED_PAUSE_MESSAGE_PURGE,
47
+  ADVANCED_PAUSE_MESSAGE_OPTION,
48
+  ADVANCED_PAUSE_MESSAGE_RESUME,
49
+  ADVANCED_PAUSE_MESSAGE_STATUS,
50
+  ADVANCED_PAUSE_MESSAGE_CLICK_TO_HEAT_NOZZLE,
51
+  ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT
52
+};
53
+
54
+enum AdvancedPauseMenuResponse {
55
+  ADVANCED_PAUSE_RESPONSE_WAIT_FOR,
56
+  ADVANCED_PAUSE_RESPONSE_EXTRUDE_MORE,
57
+  ADVANCED_PAUSE_RESPONSE_RESUME_PRINT
58
+};
59
+
60
+extern AdvancedPauseMenuResponse advanced_pause_menu_response;
61
+
62
+extern float filament_change_unload_length[EXTRUDERS],
63
+             filament_change_load_length[EXTRUDERS];
64
+
33 65
 extern uint8_t did_pause_print;
34 66
 
35
-bool pause_print(const float &retract, const point_t &park_point, const float &unload_length=0,
36
-                 const int8_t max_beep_count=0, const bool show_lcd=false
37
-);
67
+bool pause_print(const float &retract, const point_t &park_point, const float &unload_length=0, const bool show_lcd=false);
38 68
 
39 69
 void wait_for_filament_reload(const int8_t max_beep_count=0);
40 70
 
41
-void resume_print(const float &load_length=0, const float &initial_extrude_length=0, const int8_t max_beep_count=0);
71
+void resume_print(const float &load_length=0, const float &extrude_length=ADVANCED_PAUSE_EXTRUDE_LENGTH, const int8_t max_beep_count=0);
72
+
73
+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,
74
+                          const bool pause_for_user=false, const AdvancedPauseMode mode=ADVANCED_PAUSE_MODE_PAUSE_PRINT);
75
+
76
+bool unload_filament(const float &unload_length, const bool show_lcd=false, const AdvancedPauseMode mode=ADVANCED_PAUSE_MODE_PAUSE_PRINT);
42 77
 
43 78
 #endif // _PAUSE_H_

+ 1
- 1
Marlin/src/gcode/control/M17_M18_M84.cpp View File

@@ -54,7 +54,7 @@ void GcodeSuite::M18_M84() {
54 54
       if (parser.seen('X')) disable_X();
55 55
       if (parser.seen('Y')) disable_Y();
56 56
       if (parser.seen('Z')) disable_Z();
57
-      #if E0_ENABLE_PIN != X_ENABLE_PIN && E1_ENABLE_PIN != Y_ENABLE_PIN // Only enable on boards that have separate ENABLE_PINS
57
+      #if E0_ENABLE_PIN != X_ENABLE_PIN && E1_ENABLE_PIN != Y_ENABLE_PIN // Only disable on boards that have separate ENABLE_PINS
58 58
         if (parser.seen('E')) disable_e_steppers();
59 59
       #endif
60 60
     }

+ 28
- 29
Marlin/src/gcode/feature/pause/M600.cpp View File

@@ -33,24 +33,34 @@
33 33
   #include "../../../module/tool_change.h"
34 34
 #endif
35 35
 
36
+#if ENABLED(ULTIPANEL)
37
+  #include "../../../lcd/ultralcd.h"
38
+#endif
39
+
36 40
 /**
37 41
  * M600: Pause for filament change
38 42
  *
39
- *  E[distance] - Retract the filament this far (negative value)
43
+ *  E[distance] - Retract the filament this far
40 44
  *  Z[distance] - Move the Z axis by this distance
41 45
  *  X[position] - Move to this X position, with Y
42 46
  *  Y[position] - Move to this Y position, with X
43
- *  U[distance] - Retract distance for removal (negative value) (manual reload)
44
- *  L[distance] - Extrude distance for insertion (positive value) (manual reload)
47
+ *  U[distance] - Retract distance for removal (manual reload)
48
+ *  L[distance] - Extrude distance for insertion (manual reload)
45 49
  *  B[count]    - Number of times to beep, -1 for indefinite (if equipped with a buzzer)
46 50
  *  T[toolhead] - Select extruder for filament change
47 51
  *
48 52
  *  Default values are used for omitted arguments.
49
- *
50 53
  */
51 54
 void GcodeSuite::M600() {
52 55
   point_t park_point = NOZZLE_PARK_POINT;
53 56
 
57
+  if (get_target_extruder_from_command()) return;
58
+
59
+  // Show initial message
60
+  #if ENABLED(ULTIPANEL)
61
+    lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INIT, ADVANCED_PAUSE_MODE_PAUSE_PRINT, target_extruder);
62
+  #endif
63
+
54 64
   #if ENABLED(HOME_BEFORE_FILAMENT_CHANGE)
55 65
     // Don't allow filament change without homing first
56 66
     if (axis_unhomed_error()) home_all_axes();
@@ -58,22 +68,17 @@ void GcodeSuite::M600() {
58 68
 
59 69
   #if EXTRUDERS > 1
60 70
     // Change toolhead if specified
61
-    uint8_t active_extruder_before_filament_change = -1;
62
-    if (parser.seen('T')) {
63
-      const uint8_t extruder = parser.value_byte();
64
-      if (active_extruder != extruder) {
65
-        active_extruder_before_filament_change = active_extruder;
66
-        tool_change(extruder, 0, true);
67
-      }
68
-    }
71
+    uint8_t active_extruder_before_filament_change = active_extruder;
72
+    if (active_extruder != target_extruder)
73
+      tool_change(target_extruder, 0, true);
69 74
   #endif
70 75
 
71 76
   // Initial retract before move to filament change position
72
-  const float retract = parser.seen('E') ? parser.value_axis_units(E_AXIS) : 0
77
+  const float retract = -FABS(parser.seen('E') ? parser.value_axis_units(E_AXIS) : 0
73 78
     #ifdef PAUSE_PARK_RETRACT_LENGTH
74
-      - (PAUSE_PARK_RETRACT_LENGTH)
79
+      + (PAUSE_PARK_RETRACT_LENGTH)
75 80
     #endif
76
-  ;
81
+  );
77 82
 
78 83
   // Move XY axes to filament change position or given position
79 84
   if (parser.seenval('X')) park_point.x = parser.linearval('X');
@@ -88,22 +93,16 @@ void GcodeSuite::M600() {
88 93
   #endif
89 94
 
90 95
   // Unload filament
91
-  const float unload_length = parser.seen('U') ? parser.value_axis_units(E_AXIS) : 0
92
-    #if defined(FILAMENT_CHANGE_UNLOAD_LENGTH) && FILAMENT_CHANGE_UNLOAD_LENGTH > 0
93
-      - (FILAMENT_CHANGE_UNLOAD_LENGTH)
94
-    #endif
95
-  ;
96
+  const float unload_length = -FABS(parser.seen('U') ? parser.value_axis_units(E_AXIS)
97
+                                                     : filament_change_unload_length[active_extruder]);
96 98
 
97 99
   // Load filament
98
-  const float load_length = parser.seen('L') ? parser.value_axis_units(E_AXIS) : 0
99
-    #ifdef FILAMENT_CHANGE_LOAD_LENGTH
100
-      + FILAMENT_CHANGE_LOAD_LENGTH
101
-    #endif
102
-  ;
100
+  const float load_length = FABS(parser.seen('L') ? parser.value_axis_units(E_AXIS)
101
+                                                  : filament_change_load_length[active_extruder]);
103 102
 
104 103
   const int beep_count = parser.intval('B',
105
-    #ifdef FILAMENT_CHANGE_NUMBER_OF_ALERT_BEEPS
106
-      FILAMENT_CHANGE_NUMBER_OF_ALERT_BEEPS
104
+    #ifdef FILAMENT_CHANGE_ALERT_BEEPS
105
+      FILAMENT_CHANGE_ALERT_BEEPS
107 106
     #else
108 107
       -1
109 108
     #endif
@@ -111,14 +110,14 @@ void GcodeSuite::M600() {
111 110
 
112 111
   const bool job_running = print_job_timer.isRunning();
113 112
 
114
-  if (pause_print(retract, park_point, unload_length, beep_count, true)) {
113
+  if (pause_print(retract, park_point, unload_length, true)) {
115 114
     wait_for_filament_reload(beep_count);
116 115
     resume_print(load_length, ADVANCED_PAUSE_EXTRUDE_LENGTH, beep_count);
117 116
   }
118 117
 
119 118
   #if EXTRUDERS > 1
120 119
     // Restore toolhead if it was changed
121
-    if (active_extruder_before_filament_change >= 0)
120
+    if (active_extruder_before_filament_change != active_extruder)
122 121
       tool_change(active_extruder_before_filament_change, 0, true);
123 122
   #endif
124 123
 

+ 65
- 0
Marlin/src/gcode/feature/pause/M603.cpp View File

@@ -0,0 +1,65 @@
1
+/**
2
+ * Marlin 3D Printer Firmware
3
+ * Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
4
+ *
5
+ * Based on Sprinter and grbl.
6
+ * Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
7
+ *
8
+ * This program is free software: you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation, either version 3 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+
23
+#include "../../../inc/MarlinConfig.h"
24
+
25
+#if ENABLED(ADVANCED_PAUSE_FEATURE)
26
+
27
+#include "../../gcode.h"
28
+#include "../../../feature/pause.h"
29
+#include "../../../module/motion.h"
30
+#include "../../../module/printcounter.h"
31
+
32
+#if EXTRUDERS > 1
33
+  #include "../../../module/tool_change.h"
34
+#endif
35
+
36
+/**
37
+ * M603: Configure filament change
38
+ *
39
+ *  T[toolhead] - Select extruder to configure, active extruder if not specified
40
+ *  U[distance] - Retract distance for removal, for the specified extruder
41
+ *  L[distance] - Extrude distance for insertion, for the specified extruder
42
+ *
43
+ */
44
+inline void GcodeSuite::M603() {
45
+
46
+  if (get_target_extruder_from_command()) return;
47
+
48
+  // Unload length
49
+  if (parser.seen('U')) {
50
+    filament_change_unload_length[target_extruder] = FABS(parser.value_axis_units(E_AXIS));
51
+    #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
52
+      NOMORE(filament_change_unload_length[target_extruder], EXTRUDE_MAXLENGTH);
53
+    #endif
54
+  }
55
+
56
+  // Load length
57
+  if (parser.seen('L')) {
58
+    filament_change_load_length[target_extruder] = FABS(parser.value_axis_units(E_AXIS));
59
+    #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
60
+      NOMORE(filament_change_load_length[target_extruder], EXTRUDE_MAXLENGTH);
61
+    #endif
62
+  }
63
+}
64
+
65
+#endif // ADVANCED_PAUSE_FEATURE

+ 132
- 19
Marlin/src/gcode/feature/snmm/M702.cpp View File

@@ -20,33 +20,146 @@
20 20
  *
21 21
  */
22 22
 
23
-#include "../../../inc/MarlinConfig.h"
23
+#include "../../../inc/MarlinConfigPre.h"
24 24
 
25
-#if ENABLED(MK2_MULTIPLEXER)
25
+#if ENABLED(FILAMENT_LOAD_UNLOAD_GCODES)
26 26
 
27 27
 #include "../../gcode.h"
28
-#include "../../../module/motion.h"
29
-#include "../../../feature/snmm.h"
30 28
 #include "../../../Marlin.h"
29
+#include "../../../module/motion.h"
30
+#include "../../../module/temperature.h"
31
+#include "../../../libs/point_t.h"
32
+
33
+#if EXTRUDERS > 1
34
+  #include "../../../module/tool_change.h"
35
+#endif
36
+
37
+#if ENABLED(ULTIPANEL)
38
+  #include "../../../lcd/ultralcd.h"
39
+#endif
40
+
41
+/**
42
+ * M701: Load filament
43
+ *
44
+ *  T[extruder] - Optional extruder number. Current extruder if omitted.
45
+ *  Z[distance] - Move the Z axis by this distance
46
+ *  L[distance] - Extrude distance for insertion (positive value) (manual reload)
47
+ *
48
+ *  Default values are used for omitted arguments.
49
+ */
50
+void GcodeSuite::M701() {
51
+  point_t park_point = NOZZLE_PARK_POINT;
52
+
53
+  if (get_target_extruder_from_command()) return;
54
+
55
+  // Z axis lift
56
+  if (parser.seenval('Z')) park_point.z = parser.linearval('Z');
57
+
58
+  // Load filament
59
+  const float load_length = FABS(parser.seen('L') ? parser.value_axis_units(E_AXIS) :
60
+                                                    filament_change_load_length[target_extruder]);
61
+
62
+  // Show initial message
63
+  #if ENABLED(ULTIPANEL)
64
+    lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_LOAD, ADVANCED_PAUSE_MODE_LOAD_FILAMENT, target_extruder);
65
+  #endif
66
+
67
+  #if EXTRUDERS > 1
68
+    // Change toolhead if specified
69
+    uint8_t active_extruder_before_filament_change = active_extruder;
70
+    if (active_extruder != target_extruder)
71
+      tool_change(target_extruder, 0, true);
72
+  #endif
73
+
74
+  // Lift Z axis
75
+  if (park_point.z > 0)
76
+    do_blocking_move_to_z(min(current_position[Z_AXIS] + park_point.z, Z_MAX_POS), NOZZLE_PARK_Z_FEEDRATE);
77
+
78
+  load_filament(load_length, ADVANCED_PAUSE_EXTRUDE_LENGTH, FILAMENT_CHANGE_ALERT_BEEPS, true,
79
+                thermalManager.wait_for_heating(target_extruder), ADVANCED_PAUSE_MODE_LOAD_FILAMENT);
80
+
81
+  // Restore Z axis
82
+  if (park_point.z > 0)
83
+    do_blocking_move_to_z(max(current_position[Z_AXIS] - park_point.z, Z_MIN_POS), NOZZLE_PARK_Z_FEEDRATE);
84
+
85
+  #if EXTRUDERS > 1
86
+    // Restore toolhead if it was changed
87
+    if (active_extruder_before_filament_change != active_extruder)
88
+      tool_change(active_extruder_before_filament_change, 0, true);
89
+  #endif
90
+
91
+  // Show status screen
92
+  #if ENABLED(ULTIPANEL)
93
+    lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS);
94
+  #endif
95
+}
31 96
 
32 97
 /**
33
- * M702: Unload all extruders
98
+ * M702: Unload filament
99
+ *
100
+ *  T[extruder] - Optional extruder number. If omitted, current extruder
101
+ *                (or ALL extruders with FILAMENT_UNLOAD_ALL_EXTRUDERS).
102
+ *  Z[distance] - Move the Z axis by this distance
103
+ *  U[distance] - Retract distance for removal (manual reload)
104
+ *
105
+ *  Default values are used for omitted arguments.
34 106
  */
35 107
 void GcodeSuite::M702() {
36
-  for (uint8_t s = 0; s < E_STEPPERS; s++) {
37
-    select_multiplexed_stepper(s);
38
-    // TODO: standard unload filament function
39
-    // MK2 firmware behavior:
40
-    //  - Make sure temperature is high enough
41
-    //  - Raise Z to at least 15 to make room
42
-    //  - Extrude 1cm of filament in 1 second
43
-    //  - Under 230C quickly purge ~12mm, over 230C purge ~10mm
44
-    //  - Change E max feedrate to 80, eject the filament from the tube. Sync.
45
-    //  - Restore E max feedrate to 50
108
+  point_t park_point = NOZZLE_PARK_POINT;
109
+
110
+  if (get_target_extruder_from_command()) return;
111
+
112
+  // Z axis lift
113
+  if (parser.seenval('Z')) park_point.z = parser.linearval('Z');
114
+
115
+  // Show initial message
116
+  #if ENABLED(ULTIPANEL)
117
+    lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_UNLOAD, ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, target_extruder);
118
+  #endif
119
+
120
+  #if EXTRUDERS > 1
121
+    // Change toolhead if specified
122
+    uint8_t active_extruder_before_filament_change = active_extruder;
123
+    if (active_extruder != target_extruder)
124
+      tool_change(target_extruder, 0, true);
125
+  #endif
126
+
127
+  // Lift Z axis
128
+  if (park_point.z > 0)
129
+    do_blocking_move_to_z(min(current_position[Z_AXIS] + park_point.z, Z_MAX_POS), NOZZLE_PARK_Z_FEEDRATE);
130
+
131
+  // Unload filament
132
+  #if EXTRUDERS > 1 && ENABLED(FILAMENT_UNLOAD_ALL_EXTRUDERS)
133
+    if (!parser.seenval('T')) {
134
+      HOTEND_LOOP() {
135
+        if (e != active_extruder) tool_change(e, 0, true);
136
+        unload_filament(-filament_change_unload_length[e], true, ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT);
137
+      }
138
+    }
139
+    else
140
+  #endif
141
+  {
142
+    // Unload length
143
+    const float unload_length = -FABS(parser.seen('U') ? parser.value_axis_units(E_AXIS) :
144
+                                                        filament_change_unload_length[target_extruder]);
145
+
146
+    unload_filament(unload_length, true, ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT);
46 147
   }
47
-  // Go back to the last active extruder
48
-  select_multiplexed_stepper(active_extruder);
49
-  disable_e_steppers();
148
+
149
+  // Restore Z axis
150
+  if (park_point.z > 0)
151
+    do_blocking_move_to_z(max(current_position[Z_AXIS] - park_point.z, Z_MIN_POS), NOZZLE_PARK_Z_FEEDRATE);
152
+
153
+  #if EXTRUDERS > 1
154
+    // Restore toolhead if it was changed
155
+    if (active_extruder_before_filament_change != active_extruder)
156
+      tool_change(active_extruder_before_filament_change, 0, true);
157
+  #endif
158
+
159
+  // Show status screen
160
+  #if ENABLED(ULTIPANEL)
161
+    lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_STATUS);
162
+  #endif
50 163
 }
51 164
 
52
-#endif // MK2_MULTIPLEXER
165
+#endif // ADVANCED_PAUSE_FEATURE

+ 1
- 2
Marlin/src/gcode/gcode.cpp View File

@@ -399,8 +399,7 @@ void GcodeSuite::process_parsed_command() {
399 399
       #endif
400 400
 
401 401
       #if ENABLED(PARK_HEAD_ON_PAUSE)
402
-        case 125: // M125: Store current position and move to filament change position
403
-          M125(); break;
402
+        case 125: M125(); break;  // M125: Store current position and move to filament change position
404 403
       #endif
405 404
 
406 405
       #if ENABLED(BARICUDA)

+ 7
- 2
Marlin/src/gcode/gcode.h View File

@@ -198,9 +198,12 @@
198 198
  * M503 - Print the current settings (in memory): "M503 S<verbose>". S0 specifies compact output.
199 199
  * M540 - Enable/disable SD card abort on endstop hit: "M540 S<state>". (Requires ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED)
200 200
  * M600 - Pause for filament change: "M600 X<pos> Y<pos> Z<raise> E<first_retract> L<later_retract>". (Requires ADVANCED_PAUSE_FEATURE)
201
+ * M603 - Configure filament change: "M603 T<tool> U<unload_length> L<load_length>". (Requires ADVANCED_PAUSE_FEATURE)
202
+ * M605 - Set Dual X-Carriage movement mode: "M605 S<mode> [X<x_offset>] [R<temp_offset>]". (Requires DUAL_X_CARRIAGE)
201 203
  * M665 - Set delta configurations: "M665 L<diagonal rod> R<delta radius> S<segments/s> A<rod A trim mm> B<rod B trim mm> C<rod C trim mm> I<tower A trim angle> J<tower B trim angle> K<tower C trim angle>" (Requires DELTA)
202 204
  * M666 - Set delta endstop adjustment. (Requires DELTA)
203
- * M605 - Set dual x-carriage movement mode: "M605 S<mode> [X<x_offset>] [R<temp_offset>]". (Requires DUAL_X_CARRIAGE)
205
+ * M701 - Load filament (requires FILAMENT_LOAD_UNLOAD_GCODES)
206
+ * M702 - Unload filament (requires FILAMENT_LOAD_UNLOAD_GCODES)
204 207
  * M851 - Set Z probe's Z offset in current units. (Negative = below the nozzle.)
205 208
  * M852 - Set skew factors: "M852 [I<xy>] [J<xz>] [K<yz>]". (Requires SKEW_CORRECTION_GCODE, and SKEW_CORRECTION_FOR_Z for IJ)
206 209
  * M860 - Report the position of position encoder modules.
@@ -685,6 +688,7 @@ private:
685 688
 
686 689
   #if ENABLED(ADVANCED_PAUSE_FEATURE)
687 690
     static void M600();
691
+    static void M603();
688 692
   #endif
689 693
 
690 694
   #if ENABLED(DUAL_X_CARRIAGE) || ENABLED(DUAL_NOZZLE_DUPLICATION_MODE)
@@ -699,7 +703,8 @@ private:
699 703
     static void M666();
700 704
   #endif
701 705
 
702
-  #if ENABLED(MK2_MULTIPLEXER)
706
+  #if ENABLED(FILAMENT_LOAD_UNLOAD_GCODES)
707
+    static void M701();
703 708
     static void M702();
704 709
   #endif
705 710
 

+ 10
- 6
Marlin/src/inc/SanityCheck.h View File

@@ -131,6 +131,8 @@
131 131
   #error "FILAMENT_CHANGE_EXTRUDE_LENGTH is now ADVANCED_PAUSE_EXTRUDE_LENGTH. Please update your configuration."
132 132
 #elif defined(FILAMENT_CHANGE_NOZZLE_TIMEOUT)
133 133
   #error "FILAMENT_CHANGE_NOZZLE_TIMEOUT is now PAUSE_PARK_NOZZLE_TIMEOUT. Please update your configuration."
134
+#elif defined(FILAMENT_CHANGE_NUMBER_OF_ALERT_BEEPS)
135
+  #error "FILAMENT_CHANGE_NUMBER_OF_ALERT_BEEPS is now FILAMENT_CHANGE_ALERT_BEEPS. Please update your configuration."
134 136
 #elif ENABLED(FILAMENT_CHANGE_NO_STEPPER_TIMEOUT)
135 137
   #error "FILAMENT_CHANGE_NO_STEPPER_TIMEOUT is now PAUSE_PARK_NO_STEPPER_TIMEOUT. Please update your configuration."
136 138
 #elif defined(PLA_PREHEAT_HOTEND_TEMP)
@@ -406,16 +408,20 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE,
406 408
  * Advanced Pause
407 409
  */
408 410
 #if ENABLED(ADVANCED_PAUSE_FEATURE)
409
-  #if DISABLED(NEWPANEL)
410
-    #error "ADVANCED_PAUSE_FEATURE currently requires an LCD controller."
411
+  #if !HAS_RESUME_CONTINUE
412
+    #error "ADVANCED_PAUSE_FEATURE currently requires an LCD controller or EMERGENCY_PARSER."
411 413
   #elif ENABLED(EXTRUDER_RUNOUT_PREVENT)
412 414
     #error "EXTRUDER_RUNOUT_PREVENT is incompatible with ADVANCED_PAUSE_FEATURE."
413 415
   #elif ENABLED(PARK_HEAD_ON_PAUSE) && DISABLED(SDSUPPORT) && DISABLED(NEWPANEL) && DISABLED(EMERGENCY_PARSER)
414 416
     #error "PARK_HEAD_ON_PAUSE requires SDSUPPORT, EMERGENCY_PARSER, or an LCD controller."
415 417
   #elif ENABLED(HOME_BEFORE_FILAMENT_CHANGE) && DISABLED(PAUSE_PARK_NO_STEPPER_TIMEOUT)
416
-    #error "HOME_BEFORE_FILAMENT_CHANGE requires PAUSE_PARK_NO_STEPPER_TIMEOUT"
418
+    #error "HOME_BEFORE_FILAMENT_CHANGE requires PAUSE_PARK_NO_STEPPER_TIMEOUT."
417 419
   #elif DISABLED(NOZZLE_PARK_FEATURE)
418
-    #error "ADVANCED_PAUSE_FEATURE requires NOZZLE_PARK_FEATURE"
420
+    #error "ADVANCED_PAUSE_FEATURE requires NOZZLE_PARK_FEATURE."
421
+  #elif ENABLED(PREVENT_LENGTHY_EXTRUDE) && FILAMENT_CHANGE_UNLOAD_LENGTH > EXTRUDE_MAXLENGTH
422
+    #error "FILAMENT_CHANGE_UNLOAD_LENGTH must be less than or equal to EXTRUDE_MAXLENGTH."
423
+  #elif ENABLED(PREVENT_LENGTHY_EXTRUDE) && FILAMENT_CHANGE_LOAD_LENGTH > EXTRUDE_MAXLENGTH
424
+    #error "FILAMENT_CHANGE_LOAD_LENGTH must be less than or equal to EXTRUDE_MAXLENGTH."
419 425
   #endif
420 426
 #endif
421 427
 
@@ -454,8 +460,6 @@ static_assert(X_MAX_LENGTH >= X_BED_SIZE && Y_MAX_LENGTH >= Y_BED_SIZE,
454 460
  */
455 461
 #ifdef SNMM
456 462
   #error "SNMM is now MK2_MULTIPLEXER. Please update your configuration."
457
-#elif ENABLED(MK2_MULTIPLEXER) && DISABLED(ADVANCED_PAUSE_FEATURE)
458
-  #error "ADVANCED_PAUSE_FEATURE is required with MK2_MULTIPLEXER."
459 463
 #endif
460 464
 
461 465
 /**

+ 378
- 183
Marlin/src/lcd/ultralcd.cpp View File

@@ -39,6 +39,10 @@
39 39
 
40 40
 #include "../Marlin.h"
41 41
 
42
+#if ENABLED(ADVANCED_PAUSE_FEATURE)
43
+  #include "../feature/pause.h"
44
+#endif
45
+
42 46
 #if ENABLED(PRINTCOUNTER) && ENABLED(LCD_INFO_MENU)
43 47
   #include "../libs/duration_t.h"
44 48
 #endif
@@ -183,7 +187,7 @@ uint16_t max_display_update_time = 0;
183 187
     void lcd_control_temperature_preheat_material2_settings_menu();
184 188
   #endif
185 189
 
186
-  #if DISABLED(NO_VOLUMETRICS)
190
+  #if DISABLED(NO_VOLUMETRICS) || ENABLED(ADVANCED_PAUSE_FEATURE)
187 191
     void lcd_control_filament_menu();
188 192
   #endif
189 193
 
@@ -201,14 +205,18 @@ uint16_t max_display_update_time = 0;
201 205
   #endif
202 206
 
203 207
   #if ENABLED(ADVANCED_PAUSE_FEATURE)
204
-    void lcd_advanced_pause_toocold_menu();
208
+    #if E_STEPPERS > 1 || ENABLED(FILAMENT_LOAD_UNLOAD_GCODES)
209
+      void lcd_change_filament_menu();
210
+    #else
211
+      void lcd_temp_menu_e0_filament_change();
212
+    #endif
205 213
     void lcd_advanced_pause_option_menu();
206 214
     void lcd_advanced_pause_init_message();
207 215
     void lcd_advanced_pause_unload_message();
208 216
     void lcd_advanced_pause_insert_message();
209 217
     void lcd_advanced_pause_load_message();
210 218
     void lcd_advanced_pause_heat_nozzle();
211
-    void lcd_advanced_pause_extrude_message();
219
+    void lcd_advanced_pause_purge_message();
212 220
     void lcd_advanced_pause_resume_message();
213 221
   #endif
214 222
 
@@ -1249,61 +1257,6 @@ void kill_screen(const char* lcd_msg) {
1249 1257
     #endif
1250 1258
   }
1251 1259
 
1252
-  #if ENABLED(ADVANCED_PAUSE_FEATURE)
1253
-
1254
-    void lcd_enqueue_filament_change(
1255
-      #if EXTRUDERS > 1
1256
-        const uint8_t extruder
1257
-      #endif
1258
-    ) {
1259
-
1260
-      #if ENABLED(PREVENT_COLD_EXTRUSION)
1261
-        if (!DEBUGGING(DRYRUN) && thermalManager.tooColdToExtrude(active_extruder)) {
1262
-          lcd_save_previous_screen();
1263
-          lcd_goto_screen(lcd_advanced_pause_toocold_menu);
1264
-          return;
1265
-        }
1266
-      #endif
1267
-
1268
-      lcd_advanced_pause_show_message(ADVANCED_PAUSE_MESSAGE_INIT);
1269
-
1270
-      #if EXTRUDERS <= 1
1271
-        enqueue_and_echo_commands_P(PSTR("M600 B0"));
1272
-      #else
1273
-        char *command_M600;
1274
-        switch (extruder) {
1275
-          case 0: command_M600 = PSTR("M600 B0 T0"); break;
1276
-          case 1: command_M600 = PSTR("M600 B0 T1"); break;
1277
-          #if EXTRUDERS > 2
1278
-            case 2: command_M600 = PSTR("M600 B0 T2"); break;
1279
-            #if EXTRUDERS > 3
1280
-              case 3: command_M600 = PSTR("M600 B0 T3"); break;
1281
-              #if EXTRUDERS > 4
1282
-                case 4: command_M600 = PSTR("M600 B0 T4"); break;
1283
-              #endif // EXTRUDERS > 4
1284
-            #endif // EXTRUDERS > 3
1285
-          #endif // EXTRUDERS > 2
1286
-        }
1287
-        enqueue_and_echo_commands_P(command_M600);
1288
-      #endif // EXTRUDERS > 1
1289
-    }
1290
-
1291
-    #if EXTRUDERS > 1
1292
-      void lcd_enqueue_filament_change_e0() { lcd_enqueue_filament_change(0); }
1293
-      void lcd_enqueue_filament_change_e1() { lcd_enqueue_filament_change(1); }
1294
-      #if EXTRUDERS > 2
1295
-        void lcd_enqueue_filament_change_e2() { lcd_enqueue_filament_change(2); }
1296
-        #if EXTRUDERS > 3
1297
-          void lcd_enqueue_filament_change_e3() { lcd_enqueue_filament_change(3); }
1298
-          #if EXTRUDERS > 4
1299
-            void lcd_enqueue_filament_change_e4() { lcd_enqueue_filament_change(4); }
1300
-          #endif // EXTRUDERS > 4
1301
-        #endif // EXTRUDERS > 3
1302
-      #endif // EXTRUDERS > 2
1303
-    #endif // EXTRUDERS > 1
1304
-
1305
-  #endif // ADVANCED_PAUSE_FEATURE
1306
-
1307 1260
   // First Fan Speed title in "Tune" and "Control>Temperature" menus
1308 1261
   #if FAN_COUNT > 0 && HAS_FAN0
1309 1262
     #if FAN_COUNT > 1
@@ -1445,26 +1398,13 @@ void kill_screen(const char* lcd_msg) {
1445 1398
     // Change filament
1446 1399
     //
1447 1400
     #if ENABLED(ADVANCED_PAUSE_FEATURE)
1448
-      #if EXTRUDERS > 1
1449
-        if (!thermalManager.tooColdToExtrude(0))
1450
-          MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E1, lcd_enqueue_filament_change_e0);
1451
-        if (!thermalManager.tooColdToExtrude(1))
1452
-          MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E2, lcd_enqueue_filament_change_e1);
1453
-        #if EXTRUDERS > 2
1454
-          if (!thermalManager.tooColdToExtrude(2))
1455
-            MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E3, lcd_enqueue_filament_change_e2);
1456
-          #if EXTRUDERS > 3
1457
-            if (!thermalManager.tooColdToExtrude(3))
1458
-              MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E4, lcd_enqueue_filament_change_e3);
1459
-            #if EXTRUDERS > 4
1460
-              if (!thermalManager.tooColdToExtrude(4))
1461
-                MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E5, lcd_enqueue_filament_change_e4);
1462
-            #endif // EXTRUDERS > 4
1463
-          #endif // EXTRUDERS > 3
1464
-        #endif // EXTRUDERS > 2
1401
+      #if E_STEPPERS == 1 && !ENABLED(FILAMENT_LOAD_UNLOAD_GCODES)
1402
+        if (!thermalManager.targetTooColdToExtrude(active_extruder))
1403
+          MENU_ITEM(gcode, MSG_FILAMENTCHANGE, PSTR("M600 B0"));
1404
+        else
1405
+          MENU_ITEM(submenu, MSG_FILAMENTCHANGE, lcd_temp_menu_e0_filament_change);
1465 1406
       #else
1466
-        if (!thermalManager.tooColdToExtrude(active_extruder))
1467
-          MENU_ITEM(function, MSG_FILAMENTCHANGE, lcd_enqueue_filament_change);
1407
+        MENU_ITEM(submenu, MSG_FILAMENTCHANGE, lcd_change_filament_menu);
1468 1408
       #endif
1469 1409
     #endif
1470 1410
 
@@ -2651,7 +2591,6 @@ void kill_screen(const char* lcd_msg) {
2651 2591
       // Set Home Offsets
2652 2592
       //
2653 2593
       MENU_ITEM(function, MSG_SET_HOME_OFFSETS, lcd_set_home_offsets);
2654
-      //MENU_ITEM(gcode, MSG_SET_ORIGIN, PSTR("G92 X0 Y0 Z0"));
2655 2594
     #endif
2656 2595
 
2657 2596
     //
@@ -2664,26 +2603,13 @@ void kill_screen(const char* lcd_msg) {
2664 2603
     //
2665 2604
     #if ENABLED(ADVANCED_PAUSE_FEATURE)
2666 2605
       if (!IS_SD_FILE_OPEN) {
2667
-        #if EXTRUDERS > 1
2668
-          if (!thermalManager.tooColdToExtrude(0))
2669
-            MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E1, lcd_enqueue_filament_change_e0);
2670
-          if (!thermalManager.tooColdToExtrude(1))
2671
-            MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E2, lcd_enqueue_filament_change_e1);
2672
-          #if EXTRUDERS > 2
2673
-            if (!thermalManager.tooColdToExtrude(2))
2674
-              MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E3, lcd_enqueue_filament_change_e2);
2675
-            #if EXTRUDERS > 3
2676
-              if (!thermalManager.tooColdToExtrude(3))
2677
-                MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E4, lcd_enqueue_filament_change_e3);
2678
-              #if EXTRUDERS > 4
2679
-                if (!thermalManager.tooColdToExtrude(4))
2680
-                  MENU_ITEM(function, MSG_FILAMENTCHANGE " " MSG_E5, lcd_enqueue_filament_change_e4);
2681
-              #endif // EXTRUDERS > 4
2682
-            #endif // EXTRUDERS > 3
2683
-          #endif // EXTRUDERS > 2
2606
+        #if E_STEPPERS == 1 && !ENABLED(FILAMENT_LOAD_UNLOAD_GCODES)
2607
+          if (!thermalManager.targetTooColdToExtrude(active_extruder))
2608
+            MENU_ITEM(gcode, MSG_FILAMENTCHANGE, PSTR("M600 B0"));
2609
+          else
2610
+            MENU_ITEM(submenu, MSG_FILAMENTCHANGE, lcd_temp_menu_e0_filament_change);
2684 2611
         #else
2685
-          if (!thermalManager.tooColdToExtrude(active_extruder))
2686
-            MENU_ITEM(function, MSG_FILAMENTCHANGE, lcd_enqueue_filament_change);
2612
+          MENU_ITEM(submenu, MSG_FILAMENTCHANGE, lcd_change_filament_menu);
2687 2613
         #endif
2688 2614
       }
2689 2615
     #endif // ADVANCED_PAUSE_FEATURE
@@ -3232,14 +3158,14 @@ void kill_screen(const char* lcd_msg) {
3232 3158
     MENU_ITEM(submenu, MSG_TEMPERATURE, lcd_control_temperature_menu);
3233 3159
     MENU_ITEM(submenu, MSG_MOTION, lcd_control_motion_menu);
3234 3160
 
3235
-    #if DISABLED(NO_VOLUMETRICS)
3161
+    #if DISABLED(NO_VOLUMETRICS) || ENABLED(ADVANCED_PAUSE_FEATURE)
3236 3162
       MENU_ITEM(submenu, MSG_FILAMENT, lcd_control_filament_menu);
3237 3163
     #elif ENABLED(LIN_ADVANCE)
3238 3164
       MENU_ITEM_EDIT(float3, MSG_ADVANCE_K, &planner.extruder_advance_k, 0, 999);
3239 3165
     #endif
3240 3166
 
3241 3167
     #if HAS_LCD_CONTRAST
3242
-      MENU_ITEM_EDIT_CALLBACK(int3, MSG_CONTRAST, (int16_t*) &lcd_contrast, LCD_CONTRAST_MIN, LCD_CONTRAST_MAX, lcd_callback_set_contrast, true);
3168
+      MENU_ITEM_EDIT_CALLBACK(int3, MSG_CONTRAST, &lcd_contrast, LCD_CONTRAST_MIN, LCD_CONTRAST_MAX, lcd_callback_set_contrast, true);
3243 3169
     #endif
3244 3170
     #if ENABLED(FWRETRACT)
3245 3171
       MENU_ITEM(submenu, MSG_RETRACT, lcd_control_retract_menu);
@@ -3491,7 +3417,7 @@ void kill_screen(const char* lcd_msg) {
3491 3417
 
3492 3418
   #if DISABLED(SLIM_LCD_MENUS)
3493 3419
 
3494
-    void _lcd_control_temperature_preheat_settings_menu(uint8_t material) {
3420
+    void _lcd_control_temperature_preheat_settings_menu(const uint8_t material) {
3495 3421
       #if HOTENDS > 4
3496 3422
         #define MINTEMP_ALL MIN5(HEATER_0_MINTEMP, HEATER_1_MINTEMP, HEATER_2_MINTEMP, HEATER_3_MINTEMP, HEATER_4_MINTEMP)
3497 3423
         #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) {
3737 3663
     END_MENU();
3738 3664
   }
3739 3665
 
3740
-  #if DISABLED(NO_VOLUMETRICS)
3666
+  #if DISABLED(NO_VOLUMETRICS) || ENABLED(ADVANCED_PAUSE_FEATURE)
3741 3667
     /**
3742 3668
      *
3743 3669
      * "Control" > "Filament" submenu
@@ -3751,30 +3677,76 @@ void kill_screen(const char* lcd_msg) {
3751 3677
         MENU_ITEM_EDIT(float3, MSG_ADVANCE_K, &planner.extruder_advance_k, 0, 999);
3752 3678
       #endif
3753 3679
 
3754
-      MENU_ITEM_EDIT_CALLBACK(bool, MSG_VOLUMETRIC_ENABLED, &parser.volumetric_enabled, planner.calculate_volumetric_multipliers);
3680
+      #if DISABLED(NO_VOLUMETRICS)
3681
+        MENU_ITEM_EDIT_CALLBACK(bool, MSG_VOLUMETRIC_ENABLED, &parser.volumetric_enabled, planner.calculate_volumetric_multipliers);
3682
+
3683
+        if (parser.volumetric_enabled) {
3684
+          #if EXTRUDERS == 1
3685
+            MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM, &planner.filament_size[0], 1.5, 3.25, planner.calculate_volumetric_multipliers);
3686
+          #else // EXTRUDERS > 1
3687
+            MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM, &planner.filament_size[active_extruder], 1.5, 3.25, planner.calculate_volumetric_multipliers);
3688
+            MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E1, &planner.filament_size[0], 1.5, 3.25, planner.calculate_volumetric_multipliers);
3689
+            MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E2, &planner.filament_size[1], 1.5, 3.25, planner.calculate_volumetric_multipliers);
3690
+            #if EXTRUDERS > 2
3691
+              MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E3, &planner.filament_size[2], 1.5, 3.25, planner.calculate_volumetric_multipliers);
3692
+            #if EXTRUDERS > 3
3693
+              MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E4, &planner.filament_size[3], 1.5, 3.25, planner.calculate_volumetric_multipliers);
3694
+              #if EXTRUDERS > 4
3695
+                  MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E5, &planner.filament_size[4], 1.5, 3.25, planner.calculate_volumetric_multipliers);
3696
+                #endif // EXTRUDERS > 4
3697
+              #endif // EXTRUDERS > 3
3698
+            #endif // EXTRUDERS > 2
3699
+          #endif // EXTRUDERS > 1
3700
+        }
3701
+      #endif
3702
+
3703
+      #if ENABLED(ADVANCED_PAUSE_FEATURE)
3704
+        const float extrude_maxlength =
3705
+          #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
3706
+            EXTRUDE_MAXLENGTH
3707
+          #else
3708
+            999.0f
3709
+          #endif
3710
+        ;
3755 3711
 
3756
-      if (parser.volumetric_enabled) {
3757 3712
         #if EXTRUDERS == 1
3758
-          MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM, &planner.filament_size[0], 1.5, 3.25, planner.calculate_volumetric_multipliers);
3713
+          MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD, &filament_change_unload_length[0], 0.0, extrude_maxlength);
3759 3714
         #else // EXTRUDERS > 1
3760
-          MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM, &planner.filament_size[active_extruder], 1.5, 3.25, planner.calculate_volumetric_multipliers);
3761
-          MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E1, &planner.filament_size[0], 1.5, 3.25, planner.calculate_volumetric_multipliers);
3762
-          MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E2, &planner.filament_size[1], 1.5, 3.25, planner.calculate_volumetric_multipliers);
3715
+          MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD, &filament_change_unload_length[active_extruder], 0.0, extrude_maxlength);
3716
+          MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD MSG_DIAM_E1, &filament_change_unload_length[0], 0.0, extrude_maxlength);
3717
+          MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD MSG_DIAM_E2, &filament_change_unload_length[1], 0.0, extrude_maxlength);
3763 3718
           #if EXTRUDERS > 2
3764
-            MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E3, &planner.filament_size[2], 1.5, 3.25, planner.calculate_volumetric_multipliers);
3765
-            #if EXTRUDERS > 3
3766
-              MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E4, &planner.filament_size[3], 1.5, 3.25, planner.calculate_volumetric_multipliers);
3767
-              #if EXTRUDERS > 4
3768
-                MENU_MULTIPLIER_ITEM_EDIT_CALLBACK(float43, MSG_FILAMENT_DIAM MSG_DIAM_E5, &planner.filament_size[4], 1.5, 3.25, planner.calculate_volumetric_multipliers);
3719
+            MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD MSG_DIAM_E3, &filament_change_unload_length[2], 0.0, extrude_maxlength);
3720
+          #if EXTRUDERS > 3
3721
+            MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD MSG_DIAM_E4, &filament_change_unload_length[3], 0.0, extrude_maxlength);
3722
+            #if EXTRUDERS > 4
3723
+                MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_UNLOAD MSG_DIAM_E5, &filament_change_unload_length[4], 0.0, extrude_maxlength);
3769 3724
               #endif // EXTRUDERS > 4
3770 3725
             #endif // EXTRUDERS > 3
3771 3726
           #endif // EXTRUDERS > 2
3772 3727
         #endif // EXTRUDERS > 1
3773
-      }
3728
+
3729
+        #if EXTRUDERS == 1
3730
+          MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD, &filament_change_load_length[0], 0.0, extrude_maxlength);
3731
+        #else // EXTRUDERS > 1
3732
+          MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD, &filament_change_load_length[active_extruder], 0.0, extrude_maxlength);
3733
+          MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD MSG_DIAM_E1, &filament_change_load_length[0], 0.0, extrude_maxlength);
3734
+          MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD MSG_DIAM_E2, &filament_change_load_length[1], 0.0, extrude_maxlength);
3735
+          #if EXTRUDERS > 2
3736
+            MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD MSG_DIAM_E3, &filament_change_load_length[2], 0.0, extrude_maxlength);
3737
+          #if EXTRUDERS > 3
3738
+            MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD MSG_DIAM_E4, &filament_change_load_length[3], 0.0, extrude_maxlength);
3739
+            #if EXTRUDERS > 4
3740
+                MENU_MULTIPLIER_ITEM_EDIT(float3, MSG_FILAMENT_LOAD MSG_DIAM_E5, &filament_change_load_length[4], 0.0, extrude_maxlength);
3741
+              #endif // EXTRUDERS > 4
3742
+            #endif // EXTRUDERS > 3
3743
+          #endif // EXTRUDERS > 2
3744
+        #endif // EXTRUDERS > 1
3745
+      #endif
3774 3746
 
3775 3747
       END_MENU();
3776 3748
     }
3777
-  #endif // !NO_VOLUMETRICS
3749
+  #endif // !NO_VOLUMETRICS || ADVANCED_PAUSE_FEATURE
3778 3750
 
3779 3751
   /**
3780 3752
    *
@@ -4131,12 +4103,258 @@ void kill_screen(const char* lcd_msg) {
4131 4103
    */
4132 4104
   #if ENABLED(ADVANCED_PAUSE_FEATURE)
4133 4105
 
4106
+    /**
4107
+     *
4108
+     * "Change Filament" > "Change/Unload/Load Filament" submenu
4109
+     *
4110
+     */
4111
+    static AdvancedPauseMode _change_filament_temp_mode;
4112
+    static int8_t _change_filament_temp_extruder;
4113
+
4114
+    static const char* _change_filament_temp_command() {
4115
+      switch (_change_filament_temp_mode) {
4116
+        case ADVANCED_PAUSE_MODE_LOAD_FILAMENT:
4117
+          return PSTR("M701 T%d");
4118
+        case ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT:
4119
+          return _change_filament_temp_extruder >= 0 ? PSTR("M702 T%d") : PSTR("M702 ;%d");
4120
+        case ADVANCED_PAUSE_MODE_PAUSE_PRINT:
4121
+        default:
4122
+          return PSTR("M600 B0 T%d");
4123
+      }
4124
+      return PSTR(MSG_FILAMENTCHANGE);
4125
+    }
4126
+
4127
+    void _change_filament_temp(const uint8_t index) {
4128
+      char cmd[11];
4129
+      sprintf_P(cmd, _change_filament_temp_command(), _change_filament_temp_extruder);
4130
+      thermalManager.setTargetHotend(index == 1 ? PREHEAT_1_TEMP_HOTEND : PREHEAT_2_TEMP_HOTEND, _change_filament_temp_extruder);
4131
+      lcd_enqueue_command(cmd);
4132
+    }
4133
+    void _lcd_change_filament_temp_1_menu() { _change_filament_temp(1); }
4134
+    void _lcd_change_filament_temp_2_menu() { _change_filament_temp(2); }
4135
+
4136
+    static const char* change_filament_header(const AdvancedPauseMode mode) {
4137
+      switch (mode) {
4138
+        case ADVANCED_PAUSE_MODE_LOAD_FILAMENT:
4139
+          return PSTR(MSG_FILAMENTLOAD);
4140
+        case ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT:
4141
+          return PSTR(MSG_FILAMENTUNLOAD);
4142
+        default: break;
4143
+      }
4144
+      return PSTR(MSG_FILAMENTCHANGE);
4145
+    }
4146
+
4147
+    void _lcd_temp_menu_filament_op(const AdvancedPauseMode mode, const int8_t extruder) {
4148
+      _change_filament_temp_mode = mode;
4149
+      _change_filament_temp_extruder = extruder;
4150
+      START_MENU();
4151
+      if (LCD_HEIGHT >= 4) STATIC_ITEM_P(change_filament_header(mode), true, true);
4152
+      MENU_BACK(MSG_FILAMENTCHANGE);
4153
+      MENU_ITEM(submenu, MSG_PREHEAT_1, _lcd_change_filament_temp_1_menu);
4154
+      MENU_ITEM(submenu, MSG_PREHEAT_2, _lcd_change_filament_temp_2_menu);
4155
+      END_MENU();
4156
+    }
4157
+    void lcd_temp_menu_e0_filament_change()  { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 0); }
4158
+    void lcd_temp_menu_e0_filament_load()    { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 0); }
4159
+    void lcd_temp_menu_e0_filament_unload()  { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 0); }
4160
+    #if E_STEPPERS > 1
4161
+      void lcd_temp_menu_e1_filament_change()  { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 1); }
4162
+      void lcd_temp_menu_e1_filament_load()    { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 1); }
4163
+      void lcd_temp_menu_e1_filament_unload()  { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 1); }
4164
+      #if ENABLED(FILAMENT_UNLOAD_ALL_EXTRUDERS)
4165
+        void lcd_unload_filament_all_temp_menu() { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, -1); }
4166
+      #endif
4167
+      #if E_STEPPERS > 2
4168
+        void lcd_temp_menu_e2_filament_change()  { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 2); }
4169
+        void lcd_temp_menu_e2_filament_load()    { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 2); }
4170
+        void lcd_temp_menu_e2_filament_unload()  { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 2); }
4171
+        #if E_STEPPERS > 3
4172
+          void lcd_temp_menu_e3_filament_change()  { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 3); }
4173
+          void lcd_temp_menu_e3_filament_load()    { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 3); }
4174
+          void lcd_temp_menu_e3_filament_unload()  { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 3); }
4175
+          #if E_STEPPERS > 4
4176
+            void lcd_temp_menu_e4_filament_change()  { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_PAUSE_PRINT, 4); }
4177
+            void lcd_temp_menu_e4_filament_load()    { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_LOAD_FILAMENT, 4); }
4178
+            void lcd_temp_menu_e4_filament_unload()  { _lcd_temp_menu_filament_op(ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT, 4); }
4179
+          #endif // E_STEPPERS > 4
4180
+        #endif // E_STEPPERS > 3
4181
+      #endif // E_STEPPERS > 2
4182
+    #endif // E_STEPPERS > 1
4183
+
4184
+    /**
4185
+     *
4186
+     * "Change Filament" submenu
4187
+     *
4188
+     */
4189
+    #if E_STEPPERS > 1 || ENABLED(FILAMENT_LOAD_UNLOAD_GCODES)
4190
+      void lcd_change_filament_menu() {
4191
+        START_MENU();
4192
+        MENU_BACK(MSG_PREPARE);
4193
+
4194
+        // Change filament
4195
+        #if E_STEPPERS == 1
4196
+          PGM_P msg0 = PSTR(MSG_FILAMENTCHANGE);
4197
+          if (thermalManager.targetTooColdToExtrude(active_extruder))
4198
+            MENU_ITEM_P(submenu, msg0, lcd_temp_menu_e0_filament_change);
4199
+          else
4200
+            MENU_ITEM_P(gcode, msg0, PSTR("M600 B0"));
4201
+        #else
4202
+          PGM_P msg0 = PSTR(MSG_FILAMENTCHANGE " " MSG_E1);
4203
+          PGM_P msg1 = PSTR(MSG_FILAMENTCHANGE " " MSG_E2);
4204
+          if (thermalManager.targetTooColdToExtrude(0))
4205
+            MENU_ITEM_P(submenu, msg0, lcd_temp_menu_e0_filament_change);
4206
+          else
4207
+            MENU_ITEM_P(gcode, msg0, PSTR("M600 B0 T0"));
4208
+          if (thermalManager.targetTooColdToExtrude(1))
4209
+            MENU_ITEM_P(submenu, msg1, lcd_temp_menu_e1_filament_change);
4210
+          else
4211
+            MENU_ITEM_P(gcode, msg1, PSTR("M600 B0 T1"));
4212
+          #if E_STEPPERS > 2
4213
+            PGM_P msg2 = PSTR(MSG_FILAMENTCHANGE " " MSG_E3);
4214
+            if (thermalManager.targetTooColdToExtrude(2))
4215
+              MENU_ITEM_P(submenu, msg2, lcd_temp_menu_e2_filament_change);
4216
+            else
4217
+              MENU_ITEM_P(gcode, msg2, PSTR("M600 B0 T2"));
4218
+            #if E_STEPPERS > 3
4219
+              PGM_P msg3 = PSTR(MSG_FILAMENTCHANGE " " MSG_E4);
4220
+              if (thermalManager.targetTooColdToExtrude(3))
4221
+                MENU_ITEM_P(submenu, msg3, lcd_temp_menu_e3_filament_change);
4222
+              else
4223
+                MENU_ITEM_P(gcode, msg3, PSTR("M600 B0 T3"));
4224
+              #if E_STEPPERS > 4
4225
+                PGM_P msg4 = PSTR(MSG_FILAMENTCHANGE " " MSG_E5);
4226
+                if (thermalManager.targetTooColdToExtrude(4))
4227
+                  MENU_ITEM_P(submenu, msg4, lcd_temp_menu_e4_filament_change);
4228
+                else
4229
+                  MENU_ITEM_P(gcode, msg4, PSTR("M600 B0 T4"));
4230
+              #endif // E_STEPPERS > 4
4231
+            #endif // E_STEPPERS > 3
4232
+          #endif // E_STEPPERS > 2
4233
+        #endif // E_STEPPERS == 1
4234
+
4235
+        #if ENABLED(FILAMENT_LOAD_UNLOAD_GCODES)
4236
+          if (!planner.movesplanned() && !IS_SD_FILE_OPEN) {
4237
+            // Load filament
4238
+            #if E_STEPPERS == 1
4239
+              PGM_P msg0 = PSTR(MSG_FILAMENTLOAD);
4240
+              if (thermalManager.targetTooColdToExtrude(active_extruder))
4241
+                MENU_ITEM_P(submenu, msg0, lcd_temp_menu_e0_filament_load);
4242
+              else
4243
+                MENU_ITEM_P(gcode, msg0, PSTR("M701"));
4244
+            #else
4245
+              PGM_P msg0 = PSTR(MSG_FILAMENTLOAD " " MSG_E1);
4246
+              PGM_P msg1 = PSTR(MSG_FILAMENTLOAD " " MSG_E2);
4247
+              if (thermalManager.targetTooColdToExtrude(0))
4248
+                MENU_ITEM_P(submenu, msg0, lcd_temp_menu_e0_filament_load);
4249
+              else
4250
+                MENU_ITEM_P(gcode, msg0, PSTR("M701 T0"));
4251
+              if (thermalManager.targetTooColdToExtrude(1))
4252
+                MENU_ITEM_P(submenu, msg1, lcd_temp_menu_e1_filament_load);
4253
+              else
4254
+                MENU_ITEM_P(gcode, msg1, PSTR("M701 T1"));
4255
+              #if E_STEPPERS > 2
4256
+                PGM_P msg2 = PSTR(MSG_FILAMENTLOAD " " MSG_E3);
4257
+                if (thermalManager.targetTooColdToExtrude(2))
4258
+                  MENU_ITEM_P(submenu, msg2, lcd_temp_menu_e2_filament_load);
4259
+                else
4260
+                  MENU_ITEM_P(gcode, msg2, PSTR("M701 T2"));
4261
+                #if E_STEPPERS > 3
4262
+                  PGM_P msg3 = PSTR(MSG_FILAMENTLOAD " " MSG_E4);
4263
+                  if (thermalManager.targetTooColdToExtrude(3))
4264
+                    MENU_ITEM_P(submenu, msg3, lcd_temp_menu_e3_filament_load);
4265
+                  else
4266
+                    MENU_ITEM_P(gcode, msg3, PSTR("M701 T3"));
4267
+                  #if E_STEPPERS > 4
4268
+                    PGM_P msg4 = PSTR(MSG_FILAMENTLOAD " " MSG_E5);
4269
+                    if (thermalManager.targetTooColdToExtrude(4))
4270
+                      MENU_ITEM_P(submenu, msg4, lcd_temp_menu_e4_filament_load);
4271
+                    else
4272
+                      MENU_ITEM_P(gcode, msg4, PSTR("M701 T4"));
4273
+                  #endif // E_STEPPERS > 4
4274
+                #endif // E_STEPPERS > 3
4275
+              #endif // E_STEPPERS > 2
4276
+            #endif // E_STEPPERS == 1
4277
+
4278
+            // Unload filament
4279
+            #if E_STEPPERS == 1
4280
+              if (!thermalManager.targetTooColdToExtrude(active_extruder))
4281
+                MENU_ITEM(gcode, MSG_FILAMENTUNLOAD, PSTR("M702"));
4282
+              else
4283
+                MENU_ITEM(submenu, MSG_FILAMENTUNLOAD, lcd_temp_menu_e0_filament_unload);
4284
+            #else
4285
+              #if ENABLED(FILAMENT_UNLOAD_ALL_EXTRUDERS)
4286
+                if (!thermalManager.targetTooColdToExtrude(0)
4287
+                  #if E_STEPPERS > 1
4288
+                    && !thermalManager.targetTooColdToExtrude(1)
4289
+                    #if E_STEPPERS > 2
4290
+                      && !thermalManager.targetTooColdToExtrude(2)
4291
+                      #if E_STEPPERS > 3
4292
+                        && !thermalManager.targetTooColdToExtrude(3)
4293
+                        #if E_STEPPERS > 4
4294
+                          && !thermalManager.targetTooColdToExtrude(4)
4295
+                        #endif // E_STEPPERS > 4
4296
+                      #endif // E_STEPPERS > 3
4297
+                    #endif // E_STEPPERS > 2
4298
+                  #endif // E_STEPPERS > 1
4299
+                )
4300
+                  MENU_ITEM(gcode, MSG_FILAMENTUNLOAD_ALL, PSTR("M702"));
4301
+              else
4302
+                MENU_ITEM(submenu, MSG_FILAMENTUNLOAD_ALL, lcd_unload_filament_all_temp_menu);
4303
+              #endif
4304
+              if (!thermalManager.targetTooColdToExtrude(0))
4305
+                MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E1, PSTR("M702 T0"));
4306
+              else
4307
+                MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E1, lcd_temp_menu_e0_filament_unload);
4308
+              if (!thermalManager.targetTooColdToExtrude(1))
4309
+                MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E2, PSTR("M702 T1"));
4310
+              else
4311
+                MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E2, lcd_temp_menu_e1_filament_unload);
4312
+              #if E_STEPPERS > 2
4313
+                if (!thermalManager.targetTooColdToExtrude(2))
4314
+                  MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E3, PSTR("M702 T2"));
4315
+                else
4316
+                  MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E3, lcd_temp_menu_e2_filament_unload);
4317
+                #if E_STEPPERS > 3
4318
+                  if (!thermalManager.targetTooColdToExtrude(3))
4319
+                    MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E4, PSTR("M702 T3"));
4320
+                  else
4321
+                    MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E4, lcd_temp_menu_e3_filament_unload);
4322
+                  #if E_STEPPERS > 4
4323
+                    if (!thermalManager.targetTooColdToExtrude(4))
4324
+                      MENU_ITEM(gcode, MSG_FILAMENTUNLOAD " " MSG_E5, PSTR("M702 T4"));
4325
+                    else
4326
+                      MENU_ITEM(submenu, MSG_FILAMENTUNLOAD " " MSG_E5, lcd_temp_menu_e4_filament_unload);
4327
+                  #endif // E_STEPPERS > 4
4328
+                #endif // E_STEPPERS > 3
4329
+              #endif // E_STEPPERS > 2
4330
+            #endif // E_STEPPERS == 1
4331
+          }
4332
+        #endif
4333
+
4334
+        END_MENU();
4335
+      }
4336
+    #endif
4337
+
4338
+    static AdvancedPauseMode advanced_pause_mode = ADVANCED_PAUSE_MODE_PAUSE_PRINT;
4339
+    static uint8_t hotend_status_extruder = 0;
4340
+
4341
+    static const char* advanced_pause_header() {
4342
+      switch (advanced_pause_mode) {
4343
+        case ADVANCED_PAUSE_MODE_LOAD_FILAMENT:
4344
+          return PSTR(MSG_FILAMENT_CHANGE_HEADER_LOAD);
4345
+        case ADVANCED_PAUSE_MODE_UNLOAD_FILAMENT:
4346
+          return PSTR(MSG_FILAMENT_CHANGE_HEADER_UNLOAD);
4347
+        default: break;
4348
+      }
4349
+      return PSTR(MSG_FILAMENT_CHANGE_HEADER_PAUSE);
4350
+    }
4351
+
4134 4352
     // Portions from STATIC_ITEM...
4135 4353
     #define HOTEND_STATUS_ITEM() do { \
4136 4354
       if (_menuLineNr == _thisItemNr) { \
4137 4355
         if (lcdDrawUpdate) { \
4138 4356
           lcd_implementation_drawmenu_static(_lcdLineNr, PSTR(MSG_FILAMENT_CHANGE_NOZZLE), false, true); \
4139
-          lcd_implementation_hotend_status(_lcdLineNr); \
4357
+          lcd_implementation_hotend_status(_lcdLineNr, hotend_status_extruder); \
4140 4358
         } \
4141 4359
         if (_skipStatic && encoderLine <= _thisItemNr) { \
4142 4360
           encoderPosition += ENCODER_STEPS_PER_MENU_ITEM; \
@@ -4147,18 +4365,6 @@ void kill_screen(const char* lcd_msg) {
4147 4365
       ++_thisItemNr; \
4148 4366
     }while(0)
4149 4367
 
4150
-    void lcd_advanced_pause_toocold_menu() {
4151
-      START_MENU();
4152
-      STATIC_ITEM(MSG_HEATING_FAILED_LCD, true, true);
4153
-      STATIC_ITEM(MSG_FILAMENT_CHANGE_MINTEMP STRINGIFY(EXTRUDE_MINTEMP) ".", false, false);
4154
-      MENU_BACK(MSG_BACK);
4155
-      #if LCD_HEIGHT > 4
4156
-        STATIC_ITEM(" ");
4157
-      #endif
4158
-      HOTEND_STATUS_ITEM();
4159
-      END_MENU();
4160
-    }
4161
-
4162 4368
     void lcd_advanced_pause_resume_print() {
4163 4369
       advanced_pause_menu_response = ADVANCED_PAUSE_RESPONSE_RESUME_PRINT;
4164 4370
     }
@@ -4173,13 +4379,13 @@ void kill_screen(const char* lcd_msg) {
4173 4379
         STATIC_ITEM(MSG_FILAMENT_CHANGE_OPTION_HEADER, true, false);
4174 4380
       #endif
4175 4381
       MENU_ITEM(function, MSG_FILAMENT_CHANGE_OPTION_RESUME, lcd_advanced_pause_resume_print);
4176
-      MENU_ITEM(function, MSG_FILAMENT_CHANGE_OPTION_EXTRUDE, lcd_advanced_pause_extrude_more);
4382
+      MENU_ITEM(function, MSG_FILAMENT_CHANGE_OPTION_PURGE, lcd_advanced_pause_extrude_more);
4177 4383
       END_MENU();
4178 4384
     }
4179 4385
 
4180 4386
     void lcd_advanced_pause_init_message() {
4181 4387
       START_SCREEN();
4182
-      STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true);
4388
+      STATIC_ITEM_P(advanced_pause_header(), true, true);
4183 4389
       STATIC_ITEM(MSG_FILAMENT_CHANGE_INIT_1);
4184 4390
       #ifdef MSG_FILAMENT_CHANGE_INIT_2
4185 4391
         STATIC_ITEM(MSG_FILAMENT_CHANGE_INIT_2);
@@ -4202,7 +4408,7 @@ void kill_screen(const char* lcd_msg) {
4202 4408
 
4203 4409
     void lcd_advanced_pause_unload_message() {
4204 4410
       START_SCREEN();
4205
-      STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true);
4411
+      STATIC_ITEM_P(advanced_pause_header(), true, true);
4206 4412
       STATIC_ITEM(MSG_FILAMENT_CHANGE_UNLOAD_1);
4207 4413
       #ifdef MSG_FILAMENT_CHANGE_UNLOAD_2
4208 4414
         STATIC_ITEM(MSG_FILAMENT_CHANGE_UNLOAD_2);
@@ -4225,7 +4431,7 @@ void kill_screen(const char* lcd_msg) {
4225 4431
 
4226 4432
     void lcd_advanced_pause_wait_for_nozzles_to_heat() {
4227 4433
       START_SCREEN();
4228
-      STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true);
4434
+      STATIC_ITEM_P(advanced_pause_header(), true, true);
4229 4435
       STATIC_ITEM(MSG_FILAMENT_CHANGE_HEATING_1);
4230 4436
       #ifdef MSG_FILAMENT_CHANGE_HEATING_2
4231 4437
         STATIC_ITEM(MSG_FILAMENT_CHANGE_HEATING_2);
@@ -4242,7 +4448,7 @@ void kill_screen(const char* lcd_msg) {
4242 4448
 
4243 4449
     void lcd_advanced_pause_heat_nozzle() {
4244 4450
       START_SCREEN();
4245
-      STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true);
4451
+      STATIC_ITEM_P(advanced_pause_header(), true, true);
4246 4452
       STATIC_ITEM(MSG_FILAMENT_CHANGE_HEAT_1);
4247 4453
       #ifdef MSG_FILAMENT_CHANGE_INSERT_2
4248 4454
         STATIC_ITEM(MSG_FILAMENT_CHANGE_HEAT_2);
@@ -4259,7 +4465,7 @@ void kill_screen(const char* lcd_msg) {
4259 4465
 
4260 4466
     void lcd_advanced_pause_insert_message() {
4261 4467
       START_SCREEN();
4262
-      STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true);
4468
+      STATIC_ITEM_P(advanced_pause_header(), true, true);
4263 4469
       STATIC_ITEM(MSG_FILAMENT_CHANGE_INSERT_1);
4264 4470
       #ifdef MSG_FILAMENT_CHANGE_INSERT_2
4265 4471
         STATIC_ITEM(MSG_FILAMENT_CHANGE_INSERT_2);
@@ -4282,7 +4488,7 @@ void kill_screen(const char* lcd_msg) {
4282 4488
 
4283 4489
     void lcd_advanced_pause_load_message() {
4284 4490
       START_SCREEN();
4285
-      STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true);
4491
+      STATIC_ITEM_P(advanced_pause_header(), true, true);
4286 4492
       STATIC_ITEM(MSG_FILAMENT_CHANGE_LOAD_1);
4287 4493
       #ifdef MSG_FILAMENT_CHANGE_LOAD_2
4288 4494
         STATIC_ITEM(MSG_FILAMENT_CHANGE_LOAD_2);
@@ -4303,18 +4509,18 @@ void kill_screen(const char* lcd_msg) {
4303 4509
       END_SCREEN();
4304 4510
     }
4305 4511
 
4306
-    void lcd_advanced_pause_extrude_message() {
4512
+    void lcd_advanced_pause_purge_message() {
4307 4513
       START_SCREEN();
4308
-      STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true);
4309
-      STATIC_ITEM(MSG_FILAMENT_CHANGE_EXTRUDE_1);
4310
-      #ifdef MSG_FILAMENT_CHANGE_EXTRUDE_2
4311
-        STATIC_ITEM(MSG_FILAMENT_CHANGE_EXTRUDE_2);
4514
+      STATIC_ITEM_P(advanced_pause_header(), true, true);
4515
+      STATIC_ITEM(MSG_FILAMENT_CHANGE_PURGE_1);
4516
+      #ifdef MSG_FILAMENT_CHANGE_PURGE_2
4517
+        STATIC_ITEM(MSG_FILAMENT_CHANGE_PURGE_2);
4312 4518
         #define __FC_LINES_G 3
4313 4519
       #else
4314 4520
         #define __FC_LINES_G 2
4315 4521
       #endif
4316
-      #ifdef MSG_FILAMENT_CHANGE_EXTRUDE_3
4317
-        STATIC_ITEM(MSG_FILAMENT_CHANGE_EXTRUDE_3);
4522
+      #ifdef MSG_FILAMENT_CHANGE_PURGE_3
4523
+        STATIC_ITEM(MSG_FILAMENT_CHANGE_PURGE_3);
4318 4524
         #define _FC_LINES_G (__FC_LINES_G + 1)
4319 4525
       #else
4320 4526
         #define _FC_LINES_G __FC_LINES_G
@@ -4328,7 +4534,7 @@ void kill_screen(const char* lcd_msg) {
4328 4534
 
4329 4535
     void lcd_advanced_pause_resume_message() {
4330 4536
       START_SCREEN();
4331
-      STATIC_ITEM(MSG_FILAMENT_CHANGE_HEADER, true, true);
4537
+      STATIC_ITEM_P(advanced_pause_header(), true, true);
4332 4538
       STATIC_ITEM(MSG_FILAMENT_CHANGE_RESUME_1);
4333 4539
       #ifdef MSG_FILAMENT_CHANGE_RESUME_2
4334 4540
         STATIC_ITEM(MSG_FILAMENT_CHANGE_RESUME_2);
@@ -4339,49 +4545,38 @@ void kill_screen(const char* lcd_msg) {
4339 4545
       END_SCREEN();
4340 4546
     }
4341 4547
 
4342
-    void lcd_advanced_pause_show_message(const AdvancedPauseMessage message) {
4548
+    FORCE_INLINE screenFunc_t ap_message_screen(const AdvancedPauseMessage message) {
4343 4549
       switch (message) {
4344
-        case ADVANCED_PAUSE_MESSAGE_INIT:
4345
-          defer_return_to_status = true;
4346
-          lcd_goto_screen(lcd_advanced_pause_init_message);
4347
-          break;
4348
-        case ADVANCED_PAUSE_MESSAGE_UNLOAD:
4349
-          defer_return_to_status = true;
4350
-          lcd_goto_screen(lcd_advanced_pause_unload_message);
4351
-          break;
4352
-        case ADVANCED_PAUSE_MESSAGE_INSERT:
4353
-          defer_return_to_status = true;
4354
-          lcd_goto_screen(lcd_advanced_pause_insert_message);
4355
-          break;
4356
-        case ADVANCED_PAUSE_MESSAGE_LOAD:
4357
-          defer_return_to_status = true;
4358
-          lcd_goto_screen(lcd_advanced_pause_load_message);
4359
-          break;
4360
-        case ADVANCED_PAUSE_MESSAGE_EXTRUDE:
4361
-          defer_return_to_status = true;
4362
-          lcd_goto_screen(lcd_advanced_pause_extrude_message);
4363
-          break;
4364
-        case ADVANCED_PAUSE_MESSAGE_CLICK_TO_HEAT_NOZZLE:
4365
-          defer_return_to_status = true;
4366
-          lcd_goto_screen(lcd_advanced_pause_heat_nozzle);
4367
-          break;
4368
-        case ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT:
4369
-          defer_return_to_status = true;
4370
-          lcd_goto_screen(lcd_advanced_pause_wait_for_nozzles_to_heat);
4371
-          break;
4372
-        case ADVANCED_PAUSE_MESSAGE_OPTION:
4373
-          defer_return_to_status = true;
4374
-          advanced_pause_menu_response = ADVANCED_PAUSE_RESPONSE_WAIT_FOR;
4375
-          lcd_goto_screen(lcd_advanced_pause_option_menu);
4376
-          break;
4377
-        case ADVANCED_PAUSE_MESSAGE_RESUME:
4378
-          defer_return_to_status = true;
4379
-          lcd_goto_screen(lcd_advanced_pause_resume_message);
4380
-          break;
4550
+        case ADVANCED_PAUSE_MESSAGE_INIT: return lcd_advanced_pause_init_message;
4551
+        case ADVANCED_PAUSE_MESSAGE_UNLOAD: return lcd_advanced_pause_unload_message;
4552
+        case ADVANCED_PAUSE_MESSAGE_INSERT: return lcd_advanced_pause_insert_message;
4553
+        case ADVANCED_PAUSE_MESSAGE_LOAD: return lcd_advanced_pause_load_message;
4554
+        case ADVANCED_PAUSE_MESSAGE_PURGE: return lcd_advanced_pause_purge_message;
4555
+        case ADVANCED_PAUSE_MESSAGE_RESUME: return lcd_advanced_pause_resume_message;
4556
+        case ADVANCED_PAUSE_MESSAGE_CLICK_TO_HEAT_NOZZLE: return lcd_advanced_pause_heat_nozzle;
4557
+        case ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT: return lcd_advanced_pause_wait_for_nozzles_to_heat;
4558
+        case ADVANCED_PAUSE_MESSAGE_OPTION: advanced_pause_menu_response = ADVANCED_PAUSE_RESPONSE_WAIT_FOR;
4559
+                                            return lcd_advanced_pause_option_menu;
4381 4560
         case ADVANCED_PAUSE_MESSAGE_STATUS:
4382
-          lcd_return_to_status();
4383
-          break;
4561
+        default: break;
4384 4562
       }
4563
+      return NULL;
4564
+    }
4565
+
4566
+    void lcd_advanced_pause_show_message(
4567
+      const AdvancedPauseMessage message,
4568
+      const AdvancedPauseMode mode/*=ADVANCED_PAUSE_MODE_PAUSE_PRINT*/,
4569
+      const uint8_t extruder/*=active_extruder*/
4570
+    ) {
4571
+      advanced_pause_mode = mode;
4572
+      hotend_status_extruder = extruder;
4573
+      const screenFunc_t next_screen = ap_message_screen(message);
4574
+      if (next_screen) {
4575
+        defer_return_to_status = true;
4576
+        lcd_goto_screen(next_screen);
4577
+      }
4578
+      else
4579
+        lcd_return_to_status();
4385 4580
     }
4386 4581
 
4387 4582
   #endif // ADVANCED_PAUSE_FEATURE
@@ -4742,7 +4937,7 @@ void lcd_update() {
4742 4937
     if (UBL_CONDITION && LCD_CLICKED) {
4743 4938
       if (!wait_for_unclick) {           // If not waiting for a debounce release:
4744 4939
         wait_for_unclick = true;         //  Set debounce flag to ignore continous clicks
4745
-        lcd_clicked = !wait_for_user && !no_reentry; // Flag the click if allowed
4940
+        lcd_clicked = !wait_for_user && !no_reentry; //  Keep the click if not waiting for a user-click
4746 4941
         wait_for_user = false;           //  Any click clears wait for user
4747 4942
         lcd_quick_feedback();            //  Always make a click sound
4748 4943
       }

+ 9
- 14
Marlin/src/lcd/ultralcd.h View File

@@ -29,6 +29,10 @@
29 29
 
30 30
   #include "../Marlin.h"
31 31
 
32
+  #if ENABLED(ADVANCED_PAUSE_FEATURE)
33
+    #include "../feature/pause.h"
34
+  #endif
35
+
32 36
   #if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION)
33 37
     extern bool lcd_external_control;
34 38
   #else
@@ -116,20 +120,11 @@
116 120
     void lcd_completion_feedback(const bool good=true);
117 121
 
118 122
     #if ENABLED(ADVANCED_PAUSE_FEATURE)
119
-      enum AdvancedPauseMessage {
120
-        ADVANCED_PAUSE_MESSAGE_INIT,
121
-        ADVANCED_PAUSE_MESSAGE_UNLOAD,
122
-        ADVANCED_PAUSE_MESSAGE_INSERT,
123
-        ADVANCED_PAUSE_MESSAGE_LOAD,
124
-        ADVANCED_PAUSE_MESSAGE_EXTRUDE,
125
-        ADVANCED_PAUSE_MESSAGE_OPTION,
126
-        ADVANCED_PAUSE_MESSAGE_RESUME,
127
-        ADVANCED_PAUSE_MESSAGE_STATUS,
128
-        ADVANCED_PAUSE_MESSAGE_CLICK_TO_HEAT_NOZZLE,
129
-        ADVANCED_PAUSE_MESSAGE_WAIT_FOR_NOZZLES_TO_HEAT
130
-      };
131
-      void lcd_advanced_pause_show_message(const AdvancedPauseMessage message);
132
-    #endif
123
+      extern uint8_t active_extruder;
124
+      void lcd_advanced_pause_show_message(const AdvancedPauseMessage message,
125
+                                           const AdvancedPauseMode mode=ADVANCED_PAUSE_MODE_PAUSE_PRINT,
126
+                                           const uint8_t extruder=active_extruder);
127
+    #endif // ADVANCED_PAUSE_FEATURE
133 128
 
134 129
     #if ENABLED(G26_MESH_VALIDATION)
135 130
       void lcd_chirp();

+ 5
- 5
Marlin/src/lcd/ultralcd_impl_DOGM.h View File

@@ -773,7 +773,7 @@ static void lcd_implementation_status_screen() {
773 773
 
774 774
   #if ENABLED(ADVANCED_PAUSE_FEATURE)
775 775
 
776
-    static void lcd_implementation_hotend_status(const uint8_t row) {
776
+    static void lcd_implementation_hotend_status(const uint8_t row, const uint8_t extruder=active_extruder) {
777 777
       row_y1 = row * row_height + 1;
778 778
       row_y2 = row_y1 + row_height - 1;
779 779
 
@@ -781,13 +781,13 @@ static void lcd_implementation_status_screen() {
781 781
 
782 782
       u8g.setPrintPos(LCD_PIXEL_WIDTH - 11 * (DOG_CHAR_WIDTH), row_y2);
783 783
       lcd_print('E');
784
-      lcd_print((char)('1' + active_extruder));
784
+      lcd_print((char)('1' + extruder));
785 785
       lcd_print(' ');
786
-      lcd_print(itostr3(thermalManager.degHotend(active_extruder)));
786
+      lcd_print(itostr3(thermalManager.degHotend(extruder)));
787 787
       lcd_print('/');
788 788
 
789
-      if (lcd_blink() || !thermalManager.is_heater_idle(active_extruder))
790
-        lcd_print(itostr3(thermalManager.degTargetHotend(active_extruder)));
789
+      if (lcd_blink() || !thermalManager.is_heater_idle(extruder))
790
+        lcd_print(itostr3(thermalManager.degTargetHotend(extruder)));
791 791
     }
792 792
 
793 793
   #endif // ADVANCED_PAUSE_FEATURE

+ 2
- 3
Marlin/src/lcd/ultralcd_impl_HD44780.h View File

@@ -803,7 +803,6 @@ static void lcd_implementation_status_screen() {
803 803
 
804 804
       // If the first line has two extruder temps,
805 805
       // show more temperatures on the next line
806
-      // instead of 
807 806
 
808 807
       #if HOTENDS > 2 || (HOTENDS > 1 && TEMP_SENSOR_BED)
809 808
 
@@ -954,10 +953,10 @@ static void lcd_implementation_status_screen() {
954 953
 
955 954
   #if ENABLED(ADVANCED_PAUSE_FEATURE)
956 955
 
957
-    static void lcd_implementation_hotend_status(const uint8_t row) {
956
+    static void lcd_implementation_hotend_status(const uint8_t row, const uint8_t extruder=active_extruder) {
958 957
       if (row < LCD_HEIGHT) {
959 958
         lcd.setCursor(LCD_WIDTH - 9, row);
960
-        _draw_heater_status(active_extruder, LCD_STR_THERMOMETER[0], lcd_blink());
959
+        _draw_heater_status(extruder, LCD_STR_THERMOMETER[0], lcd_blink());
961 960
       }
962 961
     }
963 962
 

+ 88
- 7
Marlin/src/module/configuration_store.cpp View File

@@ -36,13 +36,13 @@
36 36
  *
37 37
  */
38 38
 
39
-#define EEPROM_VERSION "V47"
39
+#define EEPROM_VERSION "V48"
40 40
 
41 41
 // Change EEPROM version if these are changed:
42 42
 #define EEPROM_OFFSET 100
43 43
 
44 44
 /**
45
- * V47 EEPROM Layout:
45
+ * V48 EEPROM Layout:
46 46
  *
47 47
  *  100  Version                                    (char x4)
48 48
  *  104  EEPROM CRC16                               (uint16_t)
@@ -139,7 +139,7 @@
139 139
  *
140 140
  * Volumetric Extrusion:                            21 bytes
141 141
  *  539  M200 D    parser.volumetric_enabled        (bool)
142
- *  540  M200 T D  planner.filament_size            (float x5) (T0..3)
142
+ *  540  M200 T D  planner.filament_size            (float x5) (T0..4)
143 143
  *
144 144
  * HAS_TRINAMIC:                                    22 bytes
145 145
  *  560  M906 X    Stepper X current                (uint16_t)
@@ -154,7 +154,7 @@
154 154
  *  578  M906 E3   Stepper E3 current               (uint16_t)
155 155
  *  580  M906 E4   Stepper E4 current               (uint16_t)
156 156
  *
157
- * SENSORLESS HOMING                                4 bytes
157
+ * SENSORLESS_HOMING:                               4 bytes
158 158
  *  582  M914 X    Stepper X and X2 threshold       (int16_t)
159 159
  *  584  M914 Y    Stepper Y and Y2 threshold       (int16_t)
160 160
  *
@@ -167,7 +167,7 @@
167 167
  *  598  M907 Z    Stepper Z current                (uint32_t)
168 168
  *  602  M907 E    Stepper E current                (uint32_t)
169 169
  *
170
- * CNC_COORDINATE_SYSTEMS                           108 bytes
170
+ * CNC_COORDINATE_SYSTEMS:                          108 bytes
171 171
  *  606  G54-G59.3 coordinate_system                (float x 27)
172 172
  *
173 173
  * SKEW_CORRECTION:                                 12 bytes
@@ -175,8 +175,12 @@
175 175
  *  718  M852 J    planner.xz_skew_factor           (float)
176 176
  *  722  M852 K    planner.yz_skew_factor           (float)
177 177
  *
178
- *  726                                   Minimum end-point
179
- * 2255 (726 + 208 + 36 + 9 + 288 + 988)  Maximum end-point
178
+ * ADVANCED_PAUSE_FEATURE:                          40 bytes
179
+ *  726  M603 T U  filament_change_unload_length    (float x 5) (T0..4)
180
+ *  746  M603 T L  filament_change_load_length      (float x 5) (T0..4)
181
+ *
182
+ *  766                                   Minimum end-point
183
+ * 2295 (766 + 208 + 36 + 9 + 288 + 988)  Maximum end-point
180 184
  *
181 185
  * ========================================================================
182 186
  * meshes_begin (between max and min end-point, directly above)
@@ -698,6 +702,23 @@ void MarlinSettings::postprocess() {
698 702
       for (uint8_t q = 3; q--;) EEPROM_WRITE(dummy);
699 703
     #endif
700 704
 
705
+    //
706
+    // Advanced Pause filament load & unload lengths
707
+    //
708
+    #if ENABLED(ADVANCED_PAUSE_FEATURE)
709
+      for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) {
710
+        if (q < COUNT(filament_change_unload_length)) dummy = filament_change_unload_length[q];
711
+        EEPROM_WRITE(dummy);
712
+      }
713
+      for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) {
714
+        if (q < COUNT(filament_change_load_length)) dummy = filament_change_load_length[q];
715
+        EEPROM_WRITE(dummy);
716
+      }
717
+    #else
718
+      dummy = 0.0f;
719
+      for (uint8_t q = MAX_EXTRUDERS * 2; q--;) EEPROM_WRITE(dummy);
720
+    #endif
721
+
701 722
     if (!eeprom_error) {
702 723
       #if ENABLED(EEPROM_CHITCHAT)
703 724
         const int eeprom_size = eeprom_index;
@@ -1183,6 +1204,23 @@ void MarlinSettings::postprocess() {
1183 1204
         for (uint8_t q = 3; q--;) EEPROM_READ(dummy);
1184 1205
       #endif
1185 1206
 
1207
+      //
1208
+      // Advanced Pause filament load & unload lengths
1209
+      //
1210
+
1211
+      #if ENABLED(ADVANCED_PAUSE_FEATURE)
1212
+        for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) {
1213
+          EEPROM_READ(dummy);
1214
+          if (q < COUNT(filament_change_unload_length)) filament_change_unload_length[q] = dummy;
1215
+        }
1216
+        for (uint8_t q = 0; q < MAX_EXTRUDERS; q++) {
1217
+          EEPROM_READ(dummy);
1218
+          if (q < COUNT(filament_change_load_length)) filament_change_load_length[q] = dummy;
1219
+        }
1220
+      #else
1221
+        for (uint8_t q = MAX_EXTRUDERS * 2; q--;) EEPROM_READ(dummy);
1222
+      #endif
1223
+
1186 1224
       if (working_crc == stored_crc) {
1187 1225
         postprocess();
1188 1226
         #if ENABLED(EEPROM_CHITCHAT)
@@ -1593,6 +1631,13 @@ void MarlinSettings::reset() {
1593 1631
     #endif
1594 1632
   #endif
1595 1633
 
1634
+  #if ENABLED(ADVANCED_PAUSE_FEATURE)
1635
+    for (uint8_t e = 0; e < E_STEPPERS; e++) {
1636
+      filament_change_unload_length[e] = FILAMENT_CHANGE_UNLOAD_LENGTH;
1637
+      filament_change_load_length[e] = FILAMENT_CHANGE_LOAD_LENGTH;
1638
+    }
1639
+  #endif
1640
+
1596 1641
   postprocess();
1597 1642
 
1598 1643
   #if ENABLED(EEPROM_CHITCHAT)
@@ -2136,6 +2181,42 @@ void MarlinSettings::reset() {
2136 2181
       SERIAL_ECHOPAIR(" E", stepper.motor_current_setting[2]);
2137 2182
       SERIAL_EOL();
2138 2183
     #endif
2184
+
2185
+    /**
2186
+     * Advanced Pause filament load & unload lengths
2187
+     */
2188
+    #if ENABLED(ADVANCED_PAUSE_FEATURE)
2189
+      if (!forReplay) {
2190
+        CONFIG_ECHO_START;
2191
+        SERIAL_ECHOLNPGM("Filament load/unload lengths:");
2192
+      }
2193
+      CONFIG_ECHO_START;
2194
+      #if EXTRUDERS == 1
2195
+        SERIAL_ECHOPAIR("  M603 L", LINEAR_UNIT(filament_change_load_length[0]));
2196
+        SERIAL_ECHOLNPAIR(" U", LINEAR_UNIT(filament_change_unload_length[0]));
2197
+      #else
2198
+        SERIAL_ECHOPAIR("  M603 T0 L", LINEAR_UNIT(filament_change_load_length[0]));
2199
+        SERIAL_ECHOLNPAIR(" U", LINEAR_UNIT(filament_change_unload_length[0]));
2200
+        CONFIG_ECHO_START;
2201
+        SERIAL_ECHOPAIR("  M603 T1 L", LINEAR_UNIT(filament_change_load_length[1]));
2202
+        SERIAL_ECHOLNPAIR(" U", LINEAR_UNIT(filament_change_unload_length[1]));
2203
+        #if EXTRUDERS > 2
2204
+          CONFIG_ECHO_START;
2205
+          SERIAL_ECHOPAIR("  M603 T2 L", LINEAR_UNIT(filament_change_load_length[2]));
2206
+          SERIAL_ECHOLNPAIR(" U", LINEAR_UNIT(filament_change_unload_length[2]));
2207
+          #if EXTRUDERS > 3
2208
+            CONFIG_ECHO_START;
2209
+            SERIAL_ECHOPAIR("  M603 T3 L", LINEAR_UNIT(filament_change_load_length[3]));
2210
+            SERIAL_ECHOLNPAIR(" U", LINEAR_UNIT(filament_change_unload_length[3]));
2211
+            #if EXTRUDERS > 4
2212
+              CONFIG_ECHO_START;
2213
+              SERIAL_ECHOPAIR("  M603 T4 L", LINEAR_UNIT(filament_change_load_length[4]));
2214
+              SERIAL_ECHOLNPAIR(" U", LINEAR_UNIT(filament_change_unload_length[4]));
2215
+            #endif // EXTRUDERS > 4
2216
+          #endif // EXTRUDERS > 3
2217
+        #endif // EXTRUDERS > 2
2218
+      #endif // EXTRUDERS == 1
2219
+    #endif // ADVANCED_PAUSE_FEATURE
2139 2220
   }
2140 2221
 
2141 2222
 #endif // !DISABLE_M503

Loading…
Cancel
Save