From d97c1f1c6245e2b1f3152e5a210ed840b4bdbefb Mon Sep 17 00:00:00 2001
From: Jamie <vector76@users.noreply.github.com>
Date: Fri, 14 May 2021 00:14:13 -0500
Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Instant=20Freeze/Resume=20Function?=
 =?UTF-8?q?=20(#17462)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Scott Lahteine <thinkyhead@users.noreply.github.com>
---
 Marlin/Configuration_adv.h         | 10 ++++++++++
 Marlin/src/MarlinCore.cpp          |  8 ++++++++
 Marlin/src/inc/Conditionals_post.h | 16 +++++++++++++---
 Marlin/src/inc/SanityCheck.h       |  4 ++++
 Marlin/src/module/stepper.cpp      |  7 +++++++
 Marlin/src/module/stepper.h        |  4 ++++
 Marlin/src/pins/pinsDebug_list.h   |  5 ++++-
 buildroot/tests/mega2560           |  2 +-
 8 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index 47a844101f7..1a1e11e234f 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -3781,6 +3781,16 @@
   #define GANTRY_CALIBRATION_COMMANDS_POST  "G28"     // G28 highly recommended to ensure an accurate position
 #endif
 
+/**
+ * Instant freeze / unfreeze functionality
+ * Specified pin has pullup and connecting to ground will instantly pause motion.
+ * Potentially useful for emergency stop that allows being resumed.
+ */
+//#define FREEZE_FEATURE
+#if ENABLED(FREEZE_FEATURE)
+  //#define FREEZE_PIN 41   // Override the default (KILL) pin here
+#endif
+
 /**
  * MAX7219 Debug Matrix
  *
diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp
index 85ee920e72c..08d79685399 100644
--- a/Marlin/src/MarlinCore.cpp
+++ b/Marlin/src/MarlinCore.cpp
@@ -483,6 +483,10 @@ inline void manage_inactivity(const bool ignore_stepper_queue=false) {
     }
   #endif
 
+  #if HAS_FREEZE_PIN
+    Stepper::frozen = !READ(FREEZE_PIN);
+  #endif
+
   #if HAS_HOME
     // Handle a standalone HOME button
     constexpr millis_t HOME_DEBOUNCE_DELAY = 1000UL;
@@ -1089,6 +1093,10 @@ void setup() {
     #endif
   #endif
 
+  #if HAS_FREEZE_PIN
+    SET_INPUT_PULLUP(FREEZE_PIN);
+  #endif
+
   #if HAS_SUICIDE
     SETUP_LOG("SUICIDE_PIN");
     OUT_WRITE(SUICIDE_PIN, !SUICIDE_PIN_INVERTING);
diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h
index ec6e66d35a8..8c115fbab6f 100644
--- a/Marlin/src/inc/Conditionals_post.h
+++ b/Marlin/src/inc/Conditionals_post.h
@@ -2318,12 +2318,22 @@
 #endif
 
 // User Interface
+#if ENABLED(FREEZE_FEATURE)
+  #if !PIN_EXISTS(FREEZE) && PIN_EXISTS(KILL)
+    #define FREEZE_PIN KILL_PIN
+  #endif
+  #if PIN_EXISTS(FREEZE)
+    #define HAS_FREEZE_PIN 1
+  #endif
+#else
+  #undef FREEZE_PIN
+#endif
+#if PIN_EXISTS(KILL) && TERN1(FREEZE_FEATURE, KILL_PIN != FREEZE_PIN)
+  #define HAS_KILL 1
+#endif
 #if PIN_EXISTS(HOME)
   #define HAS_HOME 1
 #endif
-#if PIN_EXISTS(KILL)
-  #define HAS_KILL 1
-#endif
 #if PIN_EXISTS(SUICIDE)
   #define HAS_SUICIDE 1
 #endif
diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h
index 0034c74c090..2131fcd678c 100644
--- a/Marlin/src/inc/SanityCheck.h
+++ b/Marlin/src/inc/SanityCheck.h
@@ -3307,3 +3307,7 @@ static_assert(   _ARR_TEST(3,0) && _ARR_TEST(3,1) && _ARR_TEST(3,2)
 
 // Misc. Cleanup
 #undef _TEST_PWM
+
+#if ENABLED(FREEZE_FEATURE) && !PIN_EXISTS(FREEZE)
+  #error "FREEZE_FEATURE requires a FREEZE_PIN to be defined."
+#endif
diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp
index 5a5fa3afe66..ff2be0c3565 100644
--- a/Marlin/src/module/stepper.cpp
+++ b/Marlin/src/module/stepper.cpp
@@ -179,6 +179,10 @@ bool Stepper::abort_current_block;
 uint32_t Stepper::acceleration_time, Stepper::deceleration_time;
 uint8_t Stepper::steps_per_isr;
 
+#if HAS_FREEZE_PIN
+  bool Stepper::frozen; // = false
+#endif
+
 IF_DISABLED(ADAPTIVE_STEP_SMOOTHING, constexpr) uint8_t Stepper::oversampling_factor;
 
 xyze_long_t Stepper::delta_error{0};
@@ -1531,6 +1535,9 @@ void Stepper::pulse_phase_isr() {
   // If there is no current block, do nothing
   if (!current_block) return;
 
+  // Skipping step processing causes motion to freeze
+  if (TERN0(HAS_FREEZE_PIN, frozen)) return;
+
   // Count of pending loops and events for this iteration
   const uint32_t pending_events = step_event_count - step_events_completed;
   uint8_t events_to_do = _MIN(pending_events, steps_per_isr);
diff --git a/Marlin/src/module/stepper.h b/Marlin/src/module/stepper.h
index bbe8df146f7..5ddd762aa9e 100644
--- a/Marlin/src/module/stepper.h
+++ b/Marlin/src/module/stepper.h
@@ -266,6 +266,10 @@ class Stepper {
       static constexpr uint8_t last_moved_extruder = 0;
     #endif
 
+    #if HAS_FREEZE_PIN
+      static bool frozen;                   // Set this flag to instantly freeze motion
+    #endif
+
   private:
 
     static block_t* current_block;          // A pointer to the block currently being traced
diff --git a/Marlin/src/pins/pinsDebug_list.h b/Marlin/src/pins/pinsDebug_list.h
index 51a00630a4c..8eee4f18fb1 100644
--- a/Marlin/src/pins/pinsDebug_list.h
+++ b/Marlin/src/pins/pinsDebug_list.h
@@ -721,9 +721,12 @@
 #if PIN_EXISTS(I2C_SDA)
   REPORT_NAME_DIGITAL(__LINE__, I2C_SDA_PIN)
 #endif
-#if PIN_EXISTS(KILL)
+#if HAS_KILL
   REPORT_NAME_DIGITAL(__LINE__, KILL_PIN)
 #endif
+#if HAS_FREEZE_PIN
+  REPORT_NAME_DIGITAL(__LINE__, FREEZE_PIN)
+#endif
 #if PIN_EXISTS(LCD_BACKLIGHT)
   REPORT_NAME_DIGITAL(__LINE__, LCD_BACKLIGHT_PIN)
 #endif
diff --git a/buildroot/tests/mega2560 b/buildroot/tests/mega2560
index b4a3d2b9acc..98c4b761e00 100755
--- a/buildroot/tests/mega2560
+++ b/buildroot/tests/mega2560
@@ -21,7 +21,7 @@ opt_set MOTHERBOARD BOARD_AZTEEG_X3_PRO LCD_LANGUAGE fr \
 opt_enable AUTO_BED_LEVELING_UBL RESTORE_LEVELING_AFTER_G28 DEBUG_LEVELING_FEATURE G26_MESH_VALIDATION ENABLE_LEVELING_FADE_HEIGHT SKEW_CORRECTION \
            REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER LIGHTWEIGHT_UI STATUS_MESSAGE_SCROLLING SHOW_CUSTOM_BOOTSCREEN BOOT_MARLIN_LOGO_SMALL \
            SDSUPPORT SDCARD_SORT_ALPHA USB_FLASH_DRIVE_SUPPORT AUTO_REPORT_SD_STATUS SCROLL_LONG_FILENAMES CANCEL_OBJECTS SOUND_MENU_ITEM \
-           EEPROM_SETTINGS EEPROM_CHITCHAT GCODE_MACROS CUSTOM_MENU_MAIN \
+           EEPROM_SETTINGS EEPROM_CHITCHAT GCODE_MACROS CUSTOM_MENU_MAIN FREEZE_FEATURE \
            MULTI_NOZZLE_DUPLICATION CLASSIC_JERK LIN_ADVANCE EXTRA_LIN_ADVANCE_K QUICK_HOME \
            LCD_SET_PROGRESS_MANUALLY PRINT_PROGRESS_SHOW_DECIMALS SHOW_REMAINING_TIME \
            BABYSTEPPING BABYSTEP_XY NANODLP_Z_SYNC I2C_POSITION_ENCODERS M114_DETAIL