From ee243e4edfe45fa855d4ff71abf8a9a118b66369 Mon Sep 17 00:00:00 2001
From: Thomas Moore <tcm0116@users.noreply.github.com>
Date: Wed, 1 May 2019 22:55:58 -0400
Subject: [PATCH] Fix mixing extruder filament change (#13803)

---
 .../src/HAL/shared/backtrace/unwarm_arm.cpp   |  6 +-
 Marlin/src/core/language.h                    |  2 +
 Marlin/src/feature/mixing.cpp                 |  6 +-
 Marlin/src/feature/mixing.h                   | 18 ++---
 Marlin/src/feature/pause.cpp                  | 15 ++--
 Marlin/src/feature/pause.h                    |  6 +-
 Marlin/src/gcode/feature/pause/M600.cpp       | 25 ++++++-
 Marlin/src/gcode/feature/pause/M701_M702.cpp  | 68 +++++++++++++++++--
 Marlin/src/gcode/gcode.cpp                    | 29 ++++++--
 Marlin/src/gcode/gcode.h                      |  1 +
 Marlin/src/lcd/menu/menu_mixer.cpp            |  4 +-
 Marlin/src/lcd/menu/menu_ubl.cpp              |  4 +-
 Marlin/src/module/motion.cpp                  | 18 ++++-
 Marlin/src/module/planner.cpp                 | 25 +++++--
 Marlin/src/module/temperature.cpp             |  7 +-
 15 files changed, 182 insertions(+), 52 deletions(-)

diff --git a/Marlin/src/HAL/shared/backtrace/unwarm_arm.cpp b/Marlin/src/HAL/shared/backtrace/unwarm_arm.cpp
index 3c9c5aaeec..0ec9bd56af 100644
--- a/Marlin/src/HAL/shared/backtrace/unwarm_arm.cpp
+++ b/Marlin/src/HAL/shared/backtrace/unwarm_arm.cpp
@@ -124,13 +124,11 @@ UnwResult UnwStartArm(UnwState * const state) {
 
     /* MRS */
     else if ((instr & 0xFFBF0FFF) == 0xE10F0000) {
+      uint8_t rd = (instr & 0x0000F000) >> 12;
       #ifdef UNW_DEBUG
         const bool R = !!(instr & 0x00400000);
-      #else
-        constexpr bool R = false;
+        UnwPrintd4("MRS r%d,%s\t; r%d invalidated", rd, R ? "SPSR" : "CPSR", rd);
       #endif
-      uint8_t rd = (instr & 0x0000F000) >> 12;
-      UnwPrintd4("MRS r%d,%s\t; r%d invalidated", rd, R ? "SPSR" : "CPSR", rd);
 
       /* Status registers untracked */
       state->regData[rd].o = REG_VAL_INVALID;
diff --git a/Marlin/src/core/language.h b/Marlin/src/core/language.h
index 14dcf8bd30..a8d214fba2 100644
--- a/Marlin/src/core/language.h
+++ b/Marlin/src/core/language.h
@@ -162,6 +162,8 @@
 #define MSG_BEGIN_FILE_LIST                 "Begin file list"
 #define MSG_END_FILE_LIST                   "End file list"
 #define MSG_INVALID_EXTRUDER                "Invalid extruder"
+#define MSG_INVALID_E_STEPPER               "Invalid E stepper"
+#define MSG_E_STEPPER_NOT_SPECIFIED         "E stepper not specified"
 #define MSG_INVALID_SOLENOID                "Invalid solenoid"
 #define MSG_ERR_NO_THERMISTORS              "No thermistors - no temperature"
 #define MSG_M115_REPORT                     "FIRMWARE_NAME:Marlin " DETAILED_BUILD_VERSION " SOURCE_CODE_URL:" SOURCE_CODE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID
diff --git a/Marlin/src/feature/mixing.cpp b/Marlin/src/feature/mixing.cpp
index 98b26e29ce..21d1ee433e 100644
--- a/Marlin/src/feature/mixing.cpp
+++ b/Marlin/src/feature/mixing.cpp
@@ -132,7 +132,7 @@ void Mixer::init() {
   #endif
 }
 
-void Mixer::refresh_collector(const float proportion/*=1.0*/, const uint8_t t/*=selected_vtool*/) {
+void Mixer::refresh_collector(const float proportion/*=1.0*/, const uint8_t t/*=selected_vtool*/, float (&c)[MIXING_STEPPERS]/*=collector*/) {
   float csum = 0, cmax = 0;
   MIXER_STEPPER_LOOP(i) {
     const float v = color[t][i];
@@ -142,8 +142,8 @@ void Mixer::refresh_collector(const float proportion/*=1.0*/, const uint8_t t/*=
   //SERIAL_ECHOPAIR("Mixer::refresh_collector(", proportion, ", ", int(t), ") cmax=", cmax, "  csum=", csum, "  color");
   const float inv_prop = proportion / csum;
   MIXER_STEPPER_LOOP(i) {
-    collector[i] = color[t][i] * inv_prop;
-    //SERIAL_ECHOPAIR(" [", int(t), "][", int(i), "] = ", int(color[t][i]), " (", collector[i], ")  ");
+    c[i] = color[t][i] * inv_prop;
+    //SERIAL_ECHOPAIR(" [", int(t), "][", int(i), "] = ", int(color[t][i]), " (", c[i], ")  ");
   }
   //SERIAL_EOL();
 }
diff --git a/Marlin/src/feature/mixing.h b/Marlin/src/feature/mixing.h
index bb069c97d7..12bf091fd7 100644
--- a/Marlin/src/feature/mixing.h
+++ b/Marlin/src/feature/mixing.h
@@ -51,19 +51,19 @@ enum MixTool {
   FIRST_USER_VIRTUAL_TOOL = 0,
   LAST_USER_VIRTUAL_TOOL = MIXING_VIRTUAL_TOOLS - 1,
   NR_USER_VIRTUAL_TOOLS,
-  #ifdef RETRACT_SYNC_MIXING
-    MIXER_AUTORETRACT_TOOL = NR_USER_VIRTUAL_TOOLS,
-    NR_MIXING_VIRTUAL_TOOLS
-  #else
-    NR_MIXING_VIRTUAL_TOOLS = NR_USER_VIRTUAL_TOOLS
+  MIXER_DIRECT_SET_TOOL = NR_USER_VIRTUAL_TOOLS,
+  #if ENABLED(RETRACT_SYNC_MIXING)
+    MIXER_AUTORETRACT_TOOL,
   #endif
+  NR_MIXING_VIRTUAL_TOOLS
 };
 
-#ifdef RETRACT_SYNC_MIXING
-  static_assert(NR_MIXING_VIRTUAL_TOOLS <= 254, "MIXING_VIRTUAL_TOOLS must be <= 254!");
+#if ENABLED(RETRACT_SYNC_MIXING)
+  #define MAX_VTOOLS 254
 #else
-  static_assert(NR_MIXING_VIRTUAL_TOOLS <= 255, "MIXING_VIRTUAL_TOOLS must be <= 255!");
+  #define MAX_VTOOLS 255
 #endif
+static_assert(NR_MIXING_VIRTUAL_TOOLS <= MAX_VTOOLS, "MIXING_VIRTUAL_TOOLS must be <= " STRINGIFY(MAX_VTOOLS) "!");
 
 #define MIXER_STEPPER_LOOP(VAR) \
   for (uint_fast8_t VAR = 0; VAR < MIXING_STEPPERS; VAR++)
@@ -100,7 +100,7 @@ class Mixer {
   static void init(); // Populate colors at boot time
 
   static void reset_vtools();
-  static void refresh_collector(const float proportion=1.0, const uint8_t t=selected_vtool);
+  static void refresh_collector(const float proportion=1.0, const uint8_t t=selected_vtool, float (&c)[MIXING_STEPPERS]=collector);
 
   // Used up to Planner level
   FORCE_INLINE static void set_collector(const uint8_t c, const float f) { collector[c] = MAX(f, 0.0f); }
diff --git a/Marlin/src/feature/pause.cpp b/Marlin/src/feature/pause.cpp
index 99dbb380e5..7d5135151c 100644
--- a/Marlin/src/feature/pause.cpp
+++ b/Marlin/src/feature/pause.cpp
@@ -302,16 +302,22 @@ bool load_filament(const float &slow_load_length/*=0*/, const float &fast_load_l
  */
 bool unload_filament(const float &unload_length, const bool show_lcd/*=false*/,
                      const PauseMode mode/*=PAUSE_MODE_PAUSE_PRINT*/
+                     #if BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER)
+                       , const float &mix_multiplier/*=1.0*/
+                     #endif
 ) {
   #if !HAS_LCD_MENU
     UNUSED(show_lcd);
   #endif
 
+  #if !BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER)
+    constexpr float mix_multiplier = 1.0;
+  #endif
+
   if (!ensure_safe_temperature(mode)) {
     #if HAS_LCD_MENU
       if (show_lcd) lcd_pause_show_message(PAUSE_MESSAGE_STATUS);
     #endif
-
     return false;
   }
 
@@ -320,13 +326,14 @@ bool unload_filament(const float &unload_length, const bool show_lcd/*=false*/,
   #endif
 
   // Retract filament
-  do_pause_e_move(-FILAMENT_UNLOAD_RETRACT_LENGTH, PAUSE_PARK_RETRACT_FEEDRATE);
+  do_pause_e_move(-(FILAMENT_UNLOAD_RETRACT_LENGTH) * mix_multiplier, (PAUSE_PARK_RETRACT_FEEDRATE) * mix_multiplier);
 
   // Wait for filament to cool
   safe_delay(FILAMENT_UNLOAD_DELAY);
 
   // Quickly purge
-  do_pause_e_move(FILAMENT_UNLOAD_RETRACT_LENGTH + FILAMENT_UNLOAD_PURGE_LENGTH, planner.settings.max_feedrate_mm_s[E_AXIS]);
+  do_pause_e_move((FILAMENT_UNLOAD_RETRACT_LENGTH + FILAMENT_UNLOAD_PURGE_LENGTH) * mix_multiplier,
+                  planner.settings.max_feedrate_mm_s[E_AXIS] * mix_multiplier);
 
   // Unload filament
   #if FILAMENT_CHANGE_UNLOAD_ACCEL > 0
@@ -334,7 +341,7 @@ bool unload_filament(const float &unload_length, const bool show_lcd/*=false*/,
     planner.settings.retract_acceleration = FILAMENT_CHANGE_UNLOAD_ACCEL;
   #endif
 
-  do_pause_e_move(unload_length, FILAMENT_CHANGE_UNLOAD_FEEDRATE);
+  do_pause_e_move(unload_length * mix_multiplier, (FILAMENT_CHANGE_UNLOAD_FEEDRATE) * mix_multiplier);
 
   #if FILAMENT_CHANGE_FAST_LOAD_ACCEL > 0
     planner.settings.retract_acceleration = saved_acceleration;
diff --git a/Marlin/src/feature/pause.h b/Marlin/src/feature/pause.h
index 8a0653b2bd..36a2a2cc0c 100644
--- a/Marlin/src/feature/pause.h
+++ b/Marlin/src/feature/pause.h
@@ -92,6 +92,10 @@ void resume_print(const float &slow_load_length=0, const float &fast_load_length
 bool load_filament(const float &slow_load_length=0, const float &fast_load_length=0, const float &extrude_length=0, const int8_t max_beep_count=0, const bool show_lcd=false,
                           const bool pause_for_user=false, const PauseMode mode=PAUSE_MODE_PAUSE_PRINT DXC_PARAMS);
 
-bool unload_filament(const float &unload_length, const bool show_lcd=false, const PauseMode mode=PAUSE_MODE_PAUSE_PRINT);
+bool unload_filament(const float &unload_length, const bool show_lcd=false, const PauseMode mode=PAUSE_MODE_PAUSE_PRINT
+  #if BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER)
+    , const float &mix_multiplier=1.0
+  #endif
+);
 
 #endif // ADVANCED_PAUSE_FEATURE
diff --git a/Marlin/src/gcode/feature/pause/M600.cpp b/Marlin/src/gcode/feature/pause/M600.cpp
index 78e7e8e658..147cc9c573 100644
--- a/Marlin/src/gcode/feature/pause/M600.cpp
+++ b/Marlin/src/gcode/feature/pause/M600.cpp
@@ -41,6 +41,10 @@
   #include "../../../lcd/menu/menu_mmu2.h"
 #endif
 
+#if ENABLED(MIXING_EXTRUDER)
+  #include "../../../feature/mixing.h"
+#endif
+
 /**
  * M600: Pause for filament change
  *
@@ -58,8 +62,21 @@
 void GcodeSuite::M600() {
   point_t park_point = NOZZLE_PARK_POINT;
 
-  const int8_t target_extruder = get_target_extruder_from_command();
-  if (target_extruder < 0) return;
+  #if ENABLED(MIXING_EXTRUDER)
+    const int8_t target_e_stepper = get_target_e_stepper_from_command();
+    if (target_e_stepper < 0) return;
+
+    const uint8_t old_mixing_tool = mixer.get_current_vtool();
+    mixer.T(MIXER_DIRECT_SET_TOOL);
+
+    MIXER_STEPPER_LOOP(i) mixer.set_collector(i, i == uint8_t(target_e_stepper) ? 1.0 : 0.0);
+    mixer.normalize();
+
+    const int8_t target_extruder = active_extruder;
+  #else
+    const int8_t target_extruder = get_target_extruder_from_command();
+    if (target_extruder < 0) return;
+  #endif
 
   #if ENABLED(DUAL_X_CARRIAGE)
     int8_t DXC_ext = target_extruder;
@@ -155,6 +172,10 @@ void GcodeSuite::M600() {
     if (active_extruder_before_filament_change != active_extruder)
       tool_change(active_extruder_before_filament_change, 0, false);
   #endif
+
+  #if ENABLED(MIXING_EXTRUDER)
+    mixer.T(old_mixing_tool); // Restore original mixing tool
+  #endif
 }
 
 #endif // ADVANCED_PAUSE_FEATURE
diff --git a/Marlin/src/gcode/feature/pause/M701_M702.cpp b/Marlin/src/gcode/feature/pause/M701_M702.cpp
index a09d8aa710..19c6eed209 100644
--- a/Marlin/src/gcode/feature/pause/M701_M702.cpp
+++ b/Marlin/src/gcode/feature/pause/M701_M702.cpp
@@ -42,10 +42,15 @@
   #include "../../../feature/prusa_MMU2/mmu2.h"
 #endif
 
+#if ENABLED(MIXING_EXTRUDER)
+  #include "../../../feature/mixing.h"
+#endif
+
 /**
  * M701: Load filament
  *
- *  T<extruder> - Optional extruder number. Current extruder if omitted.
+ *  T<extruder> - Extruder number. Required for mixing extruder.
+ *                For non-mixing, current extruder if omitted.
  *  Z<distance> - Move the Z axis by this distance
  *  L<distance> - Extrude distance for insertion (positive value) (manual reload)
  *
@@ -59,9 +64,21 @@ void GcodeSuite::M701() {
     if (axis_unhomed_error()) park_point.z = 0;
   #endif
 
-  const int8_t target_extruder = get_target_extruder_from_command();
-  if (target_extruder < 0) return;
+  #if ENABLED(MIXING_EXTRUDER)
+    const int8_t target_e_stepper = get_target_e_stepper_from_command();
+    if (target_e_stepper < 0) return;
+
+    const uint8_t old_mixing_tool = mixer.get_current_vtool();
+    mixer.T(MIXER_DIRECT_SET_TOOL);
 
+    MIXER_STEPPER_LOOP(i) mixer.set_collector(i, (i == (uint8_t)target_e_stepper) ? 1.0 : 0.0);
+    mixer.normalize();
+
+    const int8_t target_extruder = active_extruder;
+  #else
+    const int8_t target_extruder = get_target_extruder_from_command();
+    if (target_extruder < 0) return;
+  #endif
 
   // Z axis lift
   if (parser.seenval('Z')) park_point.z = parser.linearval('Z');
@@ -107,6 +124,10 @@ void GcodeSuite::M701() {
       tool_change(active_extruder_before_filament_change, 0, false);
   #endif
 
+  #if ENABLED(MIXING_EXTRUDER)
+    mixer.T(old_mixing_tool); // Restore original mixing tool
+  #endif
+
   // Show status screen
   #if HAS_LCD_MENU
     lcd_pause_show_message(PAUSE_MESSAGE_STATUS);
@@ -116,7 +137,8 @@ void GcodeSuite::M701() {
 /**
  * M702: Unload filament
  *
- *  T<extruder> - Optional extruder number. If omitted, current extruder
+ *  T<extruder> - Extruder number. Required for mixing extruder.
+ *                For non-mixing, if omitted, current extruder
  *                (or ALL extruders with FILAMENT_UNLOAD_ALL_EXTRUDERS).
  *  Z<distance> - Move the Z axis by this distance
  *  U<distance> - Retract distance for removal (manual reload)
@@ -131,8 +153,32 @@ void GcodeSuite::M702() {
     if (axis_unhomed_error()) park_point.z = 0;
   #endif
 
-  const int8_t target_extruder = get_target_extruder_from_command();
-  if (target_extruder < 0) return;
+  #if ENABLED(MIXING_EXTRUDER)
+    const uint8_t old_mixing_tool = mixer.get_current_vtool();
+
+    #if ENABLED(FILAMENT_UNLOAD_ALL_EXTRUDERS)
+      float mix_multiplier = 1.0;
+      if (!parser.seenval('T')) {
+        mixer.T(MIXER_AUTORETRACT_TOOL);
+        mix_multiplier = MIXING_STEPPERS;
+      }
+      else
+    #endif
+    {
+      const int8_t target_e_stepper = get_target_e_stepper_from_command();
+      if (target_e_stepper < 0) return;
+
+      mixer.T(MIXER_DIRECT_SET_TOOL);
+      MIXER_STEPPER_LOOP(i) mixer.set_collector(i, (i == (uint8_t)target_e_stepper) ? 1.0 : 0.0);
+      mixer.normalize();
+    }
+
+    const int8_t target_extruder = active_extruder;
+  #else
+    const float unload_length_multiplier = 1.0;
+    const int8_t target_extruder = get_target_extruder_from_command();
+    if (target_extruder < 0) return;
+  #endif
 
   // Z axis lift
   if (parser.seenval('Z')) park_point.z = parser.linearval('Z');
@@ -171,7 +217,11 @@ void GcodeSuite::M702() {
       const float unload_length = -ABS(parser.seen('U') ? parser.value_axis_units(E_AXIS)
                                                         : fc_settings[target_extruder].unload_length);
 
-      unload_filament(unload_length, true, PAUSE_MODE_UNLOAD_FILAMENT);
+      unload_filament(unload_length, true, PAUSE_MODE_UNLOAD_FILAMENT
+        #if ALL(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER)
+          , mix_multiplier
+        #endif
+      );
     }
   #endif
 
@@ -185,6 +235,10 @@ void GcodeSuite::M702() {
       tool_change(active_extruder_before_filament_change, 0, false);
   #endif
 
+  #if ENABLED(MIXING_EXTRUDER)
+    mixer.T(old_mixing_tool); // Restore original mixing tool
+  #endif
+
   // Show status screen
   #if HAS_LCD_MENU
     lcd_pause_show_message(PAUSE_MESSAGE_STATUS);
diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp
index 5b179dcaf0..45f00b7ddc 100644
--- a/Marlin/src/gcode/gcode.cpp
+++ b/Marlin/src/gcode/gcode.cpp
@@ -72,17 +72,32 @@ bool GcodeSuite::axis_relative_modes[] = AXIS_RELATIVE_MODES;
 int8_t GcodeSuite::get_target_extruder_from_command() {
   if (parser.seenval('T')) {
     const int8_t e = parser.value_byte();
-    if (e >= EXTRUDERS) {
-      SERIAL_ECHO_START();
-      SERIAL_CHAR('M'); SERIAL_ECHO(parser.codenum);
-      SERIAL_ECHOLNPAIR(" " MSG_INVALID_EXTRUDER " ", int(e));
-      return -1;
-    }
-    return e;
+    if (e < EXTRUDERS) return e;
+    SERIAL_ECHO_START();
+    SERIAL_CHAR('M'); SERIAL_ECHO(parser.codenum);
+    SERIAL_ECHOLNPAIR(" " MSG_INVALID_EXTRUDER " ", int(e));
+    return -1;
   }
   return active_extruder;
 }
 
+/**
+ * Get the target e stepper from the T parameter
+ * Return -1 if the T parameter is out of range or unspecified
+ */
+int8_t GcodeSuite::get_target_e_stepper_from_command() {
+  const int8_t e = parser.intval('T', -1);
+  if (WITHIN(e, 0, E_STEPPERS - 1)) return e;
+
+  SERIAL_ECHO_START();
+  SERIAL_CHAR('M'); SERIAL_ECHO(parser.codenum);
+  if (e == -1)
+    SERIAL_ECHOLNPGM(" " MSG_E_STEPPER_NOT_SPECIFIED);
+  else
+    SERIAL_ECHOLNPAIR(" " MSG_INVALID_E_STEPPER " ", int(e));
+  return -1;
+}
+
 /**
  * Set XYZE destination and feedrate from the current GCode command
  *
diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h
index af99e4fbed..e6cd1f59f7 100644
--- a/Marlin/src/gcode/gcode.h
+++ b/Marlin/src/gcode/gcode.h
@@ -298,6 +298,7 @@ public:
   FORCE_INLINE static void reset_stepper_timeout() { previous_move_ms = millis(); }
 
   static int8_t get_target_extruder_from_command();
+  static int8_t get_target_e_stepper_from_command();
   static void get_destination_from_command();
 
   static void process_parsed_command(
diff --git a/Marlin/src/lcd/menu/menu_mixer.cpp b/Marlin/src/lcd/menu/menu_mixer.cpp
index 77124d1146..cbc375a3a3 100644
--- a/Marlin/src/lcd/menu/menu_mixer.cpp
+++ b/Marlin/src/lcd/menu/menu_mixer.cpp
@@ -101,7 +101,7 @@
       MENU_ITEM_EDIT_CALLBACK(int8, MSG_GRADIENT_ALIAS, &mixer.gradient.vtool_index, 0, MIXING_VIRTUAL_TOOLS - 1, mixer.refresh_gradient);
     #endif
 
-    char tmp[10];
+    char tmp[18];
 
     MENU_ITEM(submenu, MSG_START_Z ":", lcd_mixer_gradient_z_start_edit);
     MENU_ITEM_ADDON_START(9);
@@ -298,7 +298,7 @@ void menu_mixer() {
 
   #if ENABLED(GRADIENT_MIX)
   {
-    char tmp[10];
+    char tmp[13];
     MENU_ITEM(submenu, MSG_GRADIENT, lcd_mixer_edit_gradient_menu);
     MENU_ITEM_ADDON_START(10);
       sprintf_P(tmp, PSTR("T%i->T%i"), mixer.gradient.start_vtool, mixer.gradient.end_vtool);
diff --git a/Marlin/src/lcd/menu/menu_ubl.cpp b/Marlin/src/lcd/menu/menu_ubl.cpp
index 8b182b89b9..2bb9409794 100644
--- a/Marlin/src/lcd/menu/menu_ubl.cpp
+++ b/Marlin/src/lcd/menu/menu_ubl.cpp
@@ -228,7 +228,7 @@ void _lcd_ubl_validate_mesh() {
  * UBL Grid Leveling Command
  */
 void _lcd_ubl_grid_level_cmd() {
-  char UBL_LCD_GCODE[10];
+  char UBL_LCD_GCODE[12];
   sprintf_P(UBL_LCD_GCODE, PSTR("G29 J%i"), side_points);
   lcd_enqueue_command(UBL_LCD_GCODE);
 }
@@ -269,7 +269,7 @@ void _lcd_ubl_mesh_leveling() {
  * UBL Fill-in Amount Mesh Command
  */
 void _lcd_ubl_fillin_amount_cmd() {
-  char UBL_LCD_GCODE[16];
+  char UBL_LCD_GCODE[18];
   sprintf_P(UBL_LCD_GCODE, PSTR("G29 P3 R C.%i"), ubl_fillin_amount);
   lcd_enqueue_command(UBL_LCD_GCODE);
 }
diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp
index 30f63ebed5..7f1f9172c9 100644
--- a/Marlin/src/module/motion.cpp
+++ b/Marlin/src/module/motion.cpp
@@ -982,9 +982,21 @@ void prepare_move_to_destination() {
           }
         #endif // PREVENT_COLD_EXTRUSION
         #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
-          if (ABS(destination[E_AXIS] - current_position[E_AXIS]) * planner.e_factor[active_extruder] > (EXTRUDE_MAXLENGTH)) {
-            current_position[E_AXIS] = destination[E_AXIS]; // Behave as if the move really took place, but ignore E part
-            SERIAL_ECHO_MSG(MSG_ERR_LONG_EXTRUDE_STOP);
+          const float e_delta = ABS(destination[E_AXIS] - current_position[E_AXIS]) * planner.e_factor[active_extruder];
+          if (e_delta > (EXTRUDE_MAXLENGTH)) {
+            #if ENABLED(MIXING_EXTRUDER)
+              bool ignore_e = false;
+              float collector[MIXING_STEPPERS];
+              mixer.refresh_collector(1.0, mixer.get_current_vtool(), collector);
+              MIXER_STEPPER_LOOP(e)
+                if (e_delta * collector[e] > (EXTRUDE_MAXLENGTH)) { ignore_e = true; break; }
+            #else
+              constexpr bool ignore_e = true;
+            #endif
+            if (ignore_e) {
+              current_position[E_AXIS] = destination[E_AXIS]; // Behave as if the move really took place, but ignore E part
+              SERIAL_ECHO_MSG(MSG_ERR_LONG_EXTRUDE_STOP);
+            }
           }
         #endif // PREVENT_LENGTHY_EXTRUDE
       }
diff --git a/Marlin/src/module/planner.cpp b/Marlin/src/module/planner.cpp
index ff4f13e1d7..5073d903da 100644
--- a/Marlin/src/module/planner.cpp
+++ b/Marlin/src/module/planner.cpp
@@ -1767,13 +1767,26 @@ bool Planner::_populate_block(block_t * const block, bool split_move,
         }
       #endif // PREVENT_COLD_EXTRUSION
       #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
-        if (ABS(de * e_factor[extruder]) > (int32_t)settings.axis_steps_per_mm[E_AXIS_N(extruder)] * (EXTRUDE_MAXLENGTH)) { // It's not important to get max. extrusion length in a precision < 1mm, so save some cycles and cast to int
-          position[E_AXIS] = target[E_AXIS]; // Behave as if the move really took place, but ignore E part
-          #if HAS_POSITION_FLOAT
-            position_float[E_AXIS] = target_float[E_AXIS];
+        const float e_steps = ABS(de * e_factor[extruder]);
+        const float max_e_steps = settings.axis_steps_per_mm[E_AXIS_N(extruder)] * (EXTRUDE_MAXLENGTH);
+        if (e_steps > max_e_steps) {
+          #if ENABLED(MIXING_EXTRUDER)
+            bool ignore_e = false;
+            float collector[MIXING_STEPPERS];
+            mixer.refresh_collector(1.0, mixer.get_current_vtool(), collector);
+            MIXER_STEPPER_LOOP(e)
+              if (e_steps * collector[e] > max_e_steps) { ignore_e = true; break; }
+          #else
+            constexpr bool ignore_e = true;
           #endif
-          de = 0; // no difference
-          SERIAL_ECHO_MSG(MSG_ERR_LONG_EXTRUDE_STOP);
+          if (ignore_e) {
+            position[E_AXIS] = target[E_AXIS]; // Behave as if the move really took place, but ignore E part
+            #if HAS_POSITION_FLOAT
+              position_float[E_AXIS] = target_float[E_AXIS];
+            #endif
+            de = 0; // no difference
+            SERIAL_ECHO_MSG(MSG_ERR_LONG_EXTRUDE_STOP);
+          }
         }
       #endif // PREVENT_LENGTHY_EXTRUDE
     }
diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp
index 25a45661aa..957b2db2ab 100644
--- a/Marlin/src/module/temperature.cpp
+++ b/Marlin/src/module/temperature.cpp
@@ -2825,6 +2825,7 @@ void Temperature::isr() {
     ) {
       #if TEMP_BED_RESIDENCY_TIME > 0
         millis_t residency_start_ms = 0;
+        bool first_loop = true;
         // Loop until the temperature has stabilized
         #define TEMP_BED_CONDITIONS (!residency_start_ms || PENDING(now, residency_start_ms + (TEMP_BED_RESIDENCY_TIME) * 1000UL))
       #else
@@ -2833,7 +2834,7 @@ void Temperature::isr() {
       #endif
 
       float target_temp = -1, old_temp = 9999;
-      bool wants_to_cool = false, first_loop = true;
+      bool wants_to_cool = false;
       wait_for_heatup = true;
       millis_t now, next_temp_ms = 0, next_cool_check_ms = 0;
 
@@ -2917,7 +2918,9 @@ void Temperature::isr() {
           }
         #endif
 
-        first_loop = false;
+        #if TEMP_BED_RESIDENCY_TIME > 0
+          first_loop = false;
+        #endif
 
       } while (wait_for_heatup && TEMP_BED_CONDITIONS);
 
-- 
GitLab