From d2ecc9d80c749454b3d14d547d8ec71c0c124fd1 Mon Sep 17 00:00:00 2001
From: Kevin O'Connor <kevin@koconnor.net>
Date: Thu, 1 Dec 2016 00:08:35 -0500
Subject: [PATCH] gcode: Add support for CLEAR_SHUTDOWN command

Add ability to clear the MCU shutdown flag from the console.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
---
 docs/Todo.md     | 10 ----------
 klippy/gcode.py  | 10 +++++++++-
 klippy/klippy.py |  6 +++---
 klippy/mcu.py    |  6 +++++-
 4 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/docs/Todo.md b/docs/Todo.md
index 77f892a18..a533fde90 100644
--- a/docs/Todo.md
+++ b/docs/Todo.md
@@ -14,16 +14,6 @@ Host user interaction
  * Provide startup scripts so that Klippy can startup at system
    bootup.
 
- * Possibly rework the startup order of Klippy communication with
-   octoprint and the mcu. Currently Klippy only starts communication
-   with Octoprint after it connects with the firmware. However, this
-   limits the ability for Klippy to communicate connection errors to
-   the user. It also makes it difficult for Klippy to reconnect to the
-   firmware and/or restart the firmware if it needs to.
-
- * Support clearing MCU shutdown events from the host without having
-   to restart the firmware.
-
  * Allow loading of a new config without having to restart the mcu.
 
 * Improve gcode interface:
diff --git a/klippy/gcode.py b/klippy/gcode.py
index 0f4bc6031..454d52fcf 100644
--- a/klippy/gcode.py
+++ b/klippy/gcode.py
@@ -47,7 +47,7 @@ class GCodeParser:
     def build_handlers(self):
         handlers = ['G1', 'G4', 'G20', 'G21', 'G28', 'G90', 'G91', 'G92',
                     'M18', 'M82', 'M83', 'M105', 'M110', 'M114', 'M206',
-                    'HELP', 'QUERY_ENDSTOPS', 'RESTART']
+                    'HELP', 'QUERY_ENDSTOPS', 'RESTART', 'CLEAR_SHUTDOWN']
         if self.heater_nozzle is not None:
             handlers.extend(['M104', 'M109', 'PID_TUNE'])
         if self.heater_bed is not None:
@@ -367,6 +367,14 @@ class GCodeParser:
         temp = float(params.get('S', '60'))
         heater.start_auto_tune(temp)
         self.bg_temp(heater)
+    cmd_CLEAR_SHUTDOWN_when_not_ready = True
+    cmd_CLEAR_SHUTDOWN_help = "Clear firmware shutdown and restart"
+    def cmd_CLEAR_SHUTDOWN(self, params):
+        if self.toolhead is None:
+            self.cmd_default(params)
+            return
+        self.printer.mcu.clear_shutdown()
+        self.printer.request_restart()
     cmd_RESTART_when_not_ready = True
     cmd_RESTART_help = "Reload config file and restart host software"
     def cmd_RESTART(self, params):
diff --git a/klippy/klippy.py b/klippy/klippy.py
index 2787a6aa1..d1bf26e8c 100644
--- a/klippy/klippy.py
+++ b/klippy/klippy.py
@@ -26,9 +26,9 @@ Error configuring printer
 """
 
 message_shutdown = """
-This is an unrecoverable error.  Please correct the
-underlying issue and then manually restart both the
-firmware and the host software.
+Once the underlying issue is corrected, the "CLEAR_SHUTDOWN"
+command can be used to clear the firmware flag and restart
+the host software.
 Printer is shutdown
 """
 
diff --git a/klippy/mcu.py b/klippy/mcu.py
index 2b0fe259e..c1abb9598 100644
--- a/klippy/mcu.py
+++ b/klippy/mcu.py
@@ -308,7 +308,7 @@ class MCU:
         self._timeout_timer = printer.reactor.register_timer(
             self.timeout_handler)
         # Config building
-        self._emergency_stop_cmd = None
+        self._emergency_stop_cmd = self._clear_shutdown_cmd = None
         self._num_oids = 0
         self._config_cmds = []
         self._config_crc = None
@@ -348,6 +348,7 @@ class MCU:
                 self._timeout_timer, time.time() + self.COMM_TIMEOUT)
         self._mcu_freq = float(self.serial.msgparser.config['CLOCK_FREQ'])
         self._emergency_stop_cmd = self.lookup_command("emergency_stop")
+        self._clear_shutdown_cmd = self.lookup_command("clear_shutdown")
         self.register_msg(self.handle_shutdown, 'shutdown')
         self.register_msg(self.handle_shutdown, 'is_shutdown')
         self.register_msg(self.handle_mcu_stats, 'stats')
@@ -387,6 +388,9 @@ class MCU:
         return stats
     def force_shutdown(self):
         self.send(self._emergency_stop_cmd.encode())
+    def clear_shutdown(self):
+        logging.info("Sending clear_shutdown command")
+        self.send(self._clear_shutdown_cmd.encode())
     def is_fileoutput(self):
         return self._is_fileoutput
     # Configuration phase