From 6569b9ba56731fcc5d12a53a65235299794b62c3 Mon Sep 17 00:00:00 2001
From: Scott Lahteine <github@thinkyhead.com>
Date: Thu, 26 Oct 2017 21:47:42 -0500
Subject: [PATCH] Fix FWRETRACT logic, apply common sense

---
 Marlin/Marlin_main.cpp | 69 ++++++++++++++++++++----------------------
 Marlin/language_en.h   |  5 ++-
 Marlin/language_fr.h   |  1 +
 Marlin/planner.h       |  2 +-
 Marlin/ultralcd.cpp    |  3 ++
 5 files changed, 41 insertions(+), 39 deletions(-)

diff --git a/Marlin/Marlin_main.cpp b/Marlin/Marlin_main.cpp
index 48bf292248..4c9006d321 100644
--- a/Marlin/Marlin_main.cpp
+++ b/Marlin/Marlin_main.cpp
@@ -3162,16 +3162,20 @@ static void homeaxis(const AxisEnum axis) {
     #endif
   ) {
 
-    static float hop_height,        // Remember where the Z height started
-                 hop_amount = 0.0;  // Total amount lifted, for use in recover
+    static float hop_amount = 0.0;  // Total amount lifted, for use in recover
 
-    // Simply never allow two retracts or recovers in a row
+    // Prevent two retracts or recovers in a row
     if (retracted[active_extruder] == retracting) return;
 
-    #if EXTRUDERS < 2
-      bool swapping = false;
+    // Prevent two swap-retract or recovers in a row
+    #if EXTRUDERS > 1
+      // Allow G10 S1 only after G10
+      if (swapping && retracted_swap[active_extruder] == retracting) return;
+      // G11 priority to recover the long retract if activated
+      if (!retracting) swapping = retracted_swap[active_extruder];
+    #else
+      const bool swapping = false;
     #endif
-    if (!retracting) swapping = retracted_swap[active_extruder];
 
     /* // debugging
       SERIAL_ECHOLNPAIR("retracting ", retracting);
@@ -3188,64 +3192,55 @@ static void homeaxis(const AxisEnum axis) {
     //*/
 
     const bool has_zhop = retract_zlift > 0.01;     // Is there a hop set?
-
     const float old_feedrate_mm_s = feedrate_mm_s;
-    const int16_t old_flow = flow_percentage[active_extruder];
-
-    // Don't apply flow multiplication to retract/recover
-    flow_percentage[active_extruder] = 100;
 
     // The current position will be the destination for E and Z moves
     set_destination_from_current();
+    stepper.synchronize();  // Wait for buffered moves to complete
 
-    stepper.synchronize(); // Wait for all moves to finish
+    const float renormalize = 100.0 / flow_percentage[active_extruder] / volumetric_multiplier[active_extruder];
 
     if (retracting) {
-      // Remember the Z height since G-code may include its own Z-hop
-      // For best results turn off Z hop if G-code already includes it
-      hop_height = destination[Z_AXIS];
-
       // Retract by moving from a faux E position back to the current E position
       feedrate_mm_s = retract_feedrate_mm_s;
-      current_position[E_AXIS] += (swapping ? swap_retract_length : retract_length) / volumetric_multiplier[active_extruder];
+      current_position[E_AXIS] += (swapping ? swap_retract_length : retract_length) * renormalize;
       sync_plan_position_e();
       prepare_move_to_destination();
 
       // Is a Z hop set, and has the hop not yet been done?
-      if (has_zhop) {
-        hop_amount += retract_zlift;                // Carriage is raised for retraction hop
-        current_position[Z_AXIS] -= retract_zlift;  // Pretend current pos is lower. Next move raises Z.
-        SYNC_PLAN_POSITION_KINEMATIC();             // Set the planner to the new position
-        prepare_move_to_destination();              // Raise up to the old current pos
+      if (has_zhop && !hop_amount) {
+        hop_amount += retract_zlift;                        // Carriage is raised for retraction hop
+        feedrate_mm_s = planner.max_feedrate_mm_s[Z_AXIS];  // Z feedrate to max
+        current_position[Z_AXIS] -= retract_zlift;          // Pretend current pos is lower. Next move raises Z.
+        SYNC_PLAN_POSITION_KINEMATIC();                     // Set the planner to the new position
+        prepare_move_to_destination();                      // Raise up to the old current pos
+        feedrate_mm_s = retract_feedrate_mm_s;              // Restore feedrate
       }
     }
     else {
       // If a hop was done and Z hasn't changed, undo the Z hop
-      if (hop_amount && NEAR(hop_height, destination[Z_AXIS])) {
-        current_position[Z_AXIS] += hop_amount;     // Pretend current pos is higher. Next move lowers Z.
-        SYNC_PLAN_POSITION_KINEMATIC();             // Set the planner to the new position
-        prepare_move_to_destination();              // Lower to the old current pos
-        hop_amount = 0.0;
+      if (hop_amount) {
+        current_position[Z_AXIS] -= retract_zlift;          // Pretend current pos is lower. Next move raises Z.
+        SYNC_PLAN_POSITION_KINEMATIC();                     // Set the planner to the new position
+        feedrate_mm_s = planner.max_feedrate_mm_s[Z_AXIS];  // Z feedrate to max
+        prepare_move_to_destination();                      // Raise up to the old current pos
+        hop_amount = 0.0;                                   // Clear hop
       }
 
       // A retract multiplier has been added here to get faster swap recovery
       feedrate_mm_s = swapping ? swap_retract_recover_feedrate_mm_s : retract_recover_feedrate_mm_s;
 
       const float move_e = swapping ? swap_retract_length + swap_retract_recover_length : retract_length + retract_recover_length;
-      current_position[E_AXIS] -= move_e / volumetric_multiplier[active_extruder];
+      current_position[E_AXIS] -= move_e * renormalize;
       sync_plan_position_e();
-
-      prepare_move_to_destination();  // Recover E
+      prepare_move_to_destination();                        // Recover E
     }
 
-    // Restore flow and feedrate
-    flow_percentage[active_extruder] = old_flow;
-    feedrate_mm_s = old_feedrate_mm_s;
+    feedrate_mm_s = old_feedrate_mm_s;                      // Restore original feedrate
 
-    // The active extruder is now retracted or recovered
-    retracted[active_extruder] = retracting;
+    retracted[active_extruder] = retracting;                // Active extruder now retracted / recovered
 
-    // If swap retract/recover then update the retracted_swap flag too
+    // If swap retract/recover update the retracted_swap flag too
     #if EXTRUDERS > 1
       if (swapping) retracted_swap[active_extruder] = retracting;
     #endif
@@ -3264,7 +3259,7 @@ static void homeaxis(const AxisEnum axis) {
       SERIAL_ECHOLNPAIR("hop_amount ", hop_amount);
     //*/
 
-  } // retract()
+  }
 
 #endif // FWRETRACT
 
diff --git a/Marlin/language_en.h b/Marlin/language_en.h
index 3713433530..9c3b0b7711 100644
--- a/Marlin/language_en.h
+++ b/Marlin/language_en.h
@@ -615,7 +615,10 @@
   #define MSG_CONTROL_RETRACT_RECOVER_SWAP    _UxGT("S UnRet mm")
 #endif
 #ifndef MSG_CONTROL_RETRACT_RECOVERF
-  #define MSG_CONTROL_RETRACT_RECOVERF        _UxGT("UnRet  V")
+  #define MSG_CONTROL_RETRACT_RECOVERF        _UxGT("UnRet V")
+#endif
+#ifndef MSG_CONTROL_RETRACT_RECOVER_SWAPF
+  #define MSG_CONTROL_RETRACT_RECOVER_SWAPF   _UxGT("S UnRet V")
 #endif
 #ifndef MSG_AUTORETRACT
   #define MSG_AUTORETRACT                     _UxGT("AutoRetr.")
diff --git a/Marlin/language_fr.h b/Marlin/language_fr.h
index b98fc38643..f96426bd29 100644
--- a/Marlin/language_fr.h
+++ b/Marlin/language_fr.h
@@ -222,6 +222,7 @@
 #define MSG_CONTROL_RETRACT_RECOVER         _UxGT("UnRet mm")
 #define MSG_CONTROL_RETRACT_RECOVER_SWAP    _UxGT("Ech. UnRet mm")
 #define MSG_CONTROL_RETRACT_RECOVERF        _UxGT("UnRet V")
+#define MSG_CONTROL_RETRACT_RECOVER_SWAPF   _UxGT("Ech. UnRet V")
 #define MSG_AUTORETRACT                     _UxGT("Retract. Auto.")
 #define MSG_FILAMENTCHANGE                  _UxGT("Changer filament")
 #define MSG_INIT_SDCARD                     _UxGT("Init. la carte SD")
diff --git a/Marlin/planner.h b/Marlin/planner.h
index 3351697eac..619a3de67a 100644
--- a/Marlin/planner.h
+++ b/Marlin/planner.h
@@ -288,7 +288,7 @@ class Planner {
         return 1.0;
       }
 
-      FORCE_INLINE static bool leveling_active_at_z(const float &lz) { return true; }
+      FORCE_INLINE static bool leveling_active_at_z(const float &lz) { UNUSED(lz); return true; }
 
     #endif
 
diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp
index eebd522b98..633db5fe3d 100644
--- a/Marlin/ultralcd.cpp
+++ b/Marlin/ultralcd.cpp
@@ -3726,6 +3726,9 @@ void kill_screen(const char* lcd_msg) {
         MENU_ITEM_EDIT(float52, MSG_CONTROL_RETRACT_RECOVER_SWAP, &swap_retract_recover_length, -100, 100);
       #endif
       MENU_ITEM_EDIT(float3, MSG_CONTROL_RETRACT_RECOVERF, &retract_recover_feedrate_mm_s, 1, 999);
+      #if EXTRUDERS > 1
+        MENU_ITEM_EDIT(float3, MSG_CONTROL_RETRACT_RECOVER_SWAPF, &swap_retract_recover_feedrate_mm_s, 1, 999);
+      #endif
       END_MENU();
     }