aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--klippy/extras/error_mcu.py67
-rw-r--r--klippy/klippy.py25
-rw-r--r--klippy/mcu.py41
3 files changed, 87 insertions, 46 deletions
diff --git a/klippy/extras/error_mcu.py b/klippy/extras/error_mcu.py
new file mode 100644
index 00000000..ad737f9a
--- /dev/null
+++ b/klippy/extras/error_mcu.py
@@ -0,0 +1,67 @@
+# More verbose information on micro-controller errors
+#
+# Copyright (C) 2024 Kevin O'Connor <kevin@koconnor.net>
+#
+# This file may be distributed under the terms of the GNU GPLv3 license.
+import logging
+
+message_shutdown = """
+Once the underlying issue is corrected, use the
+"FIRMWARE_RESTART" command to reset the firmware, reload the
+config, and restart the host software.
+Printer is shutdown
+"""
+
+Common_MCU_errors = {
+ ("Timer too close",): """
+This often indicates the host computer is overloaded. Check
+for other processes consuming excessive CPU time, high swap
+usage, disk errors, overheating, unstable voltage, or
+similar system problems on the host computer.""",
+ ("Missed scheduling of next ",): """
+This is generally indicative of an intermittent
+communication failure between micro-controller and host.""",
+ ("ADC out of range",): """
+This generally occurs when a heater temperature exceeds
+its configured min_temp or max_temp.""",
+ ("Rescheduled timer in the past", "Stepper too far in past"): """
+This generally occurs when the micro-controller has been
+requested to step at a rate higher than it is capable of
+obtaining.""",
+ ("Command request",): """
+This generally occurs in response to an M112 G-Code command
+or in response to an internal error in the host software.""",
+}
+
+def error_hint(msg):
+ for prefixes, help_msg in Common_MCU_errors.items():
+ for prefix in prefixes:
+ if msg.startswith(prefix):
+ return help_msg
+ return ""
+
+class PrinterMCUError:
+ def __init__(self, config):
+ self.printer = config.get_printer()
+ self.printer.register_event_handler("klippy:notify_mcu_shutdown",
+ self._handle_notify_mcu_shutdown)
+ def _check_mcu_shutdown(self, msg, details):
+ mcu_name = details['mcu']
+ mcu_msg = details['reason']
+ event_type = details['event_type']
+ prefix = "MCU '%s' shutdown: " % (mcu_name,)
+ if event_type == 'is_shutdown':
+ prefix = "Previous MCU '%s' shutdown: " % (mcu_name,)
+ # Lookup generic hint
+ hint = error_hint(msg)
+ # Update error message
+ newmsg = "%s%s%s%s" % (prefix, mcu_msg, hint, message_shutdown)
+ self.printer.update_error_msg(msg, newmsg)
+ def _handle_notify_mcu_shutdown(self, msg, details):
+ if msg == "MCU shutdown":
+ self._check_mcu_shutdown(msg, details)
+ else:
+ self.printer.update_error_msg(msg, "%s%s" % (msg, message_shutdown))
+
+def load_config(config):
+ return PrinterMCUError(config)
diff --git a/klippy/klippy.py b/klippy/klippy.py
index 097cff99..5574063d 100644
--- a/klippy/klippy.py
+++ b/klippy/klippy.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python2
# Main code for host side printer firmware
#
-# Copyright (C) 2016-2020 Kevin O'Connor <kevin@koconnor.net>
+# Copyright (C) 2016-2024 Kevin O'Connor <kevin@koconnor.net>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
import sys, os, gc, optparse, logging, time, collections, importlib
@@ -40,13 +40,6 @@ config, and restart the host software.
Error configuring printer
"""
-message_shutdown = """
-Once the underlying issue is corrected, use the
-"FIRMWARE_RESTART" command to reset the firmware, reload the
-config, and restart the host software.
-Printer is shutdown
-"""
-
class Printer:
config_error = configfile.error
command_error = gcode.CommandError
@@ -85,6 +78,13 @@ class Printer:
if (msg != message_ready
and self.start_args.get('debuginput') is not None):
self.request_exit('error_exit')
+ def update_error_msg(self, oldmsg, newmsg):
+ if (self.state_message != oldmsg
+ or self.state_message in (message_ready, message_startup)
+ or newmsg in (message_ready, message_startup)):
+ return
+ self.state_message = newmsg
+ logging.error(newmsg)
def add_object(self, name, obj):
if name in self.objects:
raise self.config_error(
@@ -241,12 +241,12 @@ class Printer:
logging.info(info)
if self.bglogger is not None:
self.bglogger.set_rollover_info(name, info)
- def invoke_shutdown(self, msg):
+ def invoke_shutdown(self, msg, details={}):
if self.in_shutdown_state:
return
logging.error("Transition to shutdown state: %s", msg)
self.in_shutdown_state = True
- self._set_state("%s%s" % (msg, message_shutdown))
+ self._set_state(msg)
for cb in self.event_handlers.get("klippy:shutdown", []):
try:
cb()
@@ -254,9 +254,10 @@ class Printer:
logging.exception("Exception during shutdown handler")
logging.info("Reactor garbage collection: %s",
self.reactor.get_gc_stats())
- def invoke_async_shutdown(self, msg):
+ self.send_event("klippy:notify_mcu_shutdown", msg, details)
+ def invoke_async_shutdown(self, msg, details):
self.reactor.register_async_callback(
- (lambda e: self.invoke_shutdown(msg)))
+ (lambda e: self.invoke_shutdown(msg, details)))
def register_event_handler(self, event, callback):
self.event_handlers.setdefault(event, []).append(callback)
def send_event(self, event, *params):
diff --git a/klippy/mcu.py b/klippy/mcu.py
index 23ba0717..feb4856a 100644
--- a/klippy/mcu.py
+++ b/klippy/mcu.py
@@ -1,6 +1,6 @@
# Interface to Klipper micro-controller code
#
-# Copyright (C) 2016-2023 Kevin O'Connor <kevin@koconnor.net>
+# Copyright (C) 2016-2024 Kevin O'Connor <kevin@koconnor.net>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
import sys, os, zlib, logging, math
@@ -605,6 +605,7 @@ class MCU:
self._mcu_tick_stddev = 0.
self._mcu_tick_awake = 0.
# Register handlers
+ printer.load_object(config, "error_mcu")
printer.register_event_handler("klippy:firmware_restart",
self._firmware_restart)
printer.register_event_handler("klippy:mcu_identify",
@@ -631,13 +632,13 @@ class MCU:
if clock is not None:
self._shutdown_clock = self.clock32_to_clock64(clock)
self._shutdown_msg = msg = params['static_string_id']
- logging.info("MCU '%s' %s: %s\n%s\n%s", self._name, params['#name'],
+ event_type = params['#name']
+ self._printer.invoke_async_shutdown(
+ "MCU shutdown", {"reason": msg, "mcu": self._name,
+ "event_type": event_type})
+ logging.info("MCU '%s' %s: %s\n%s\n%s", self._name, event_type,
self._shutdown_msg, self._clocksync.dump_debug(),
self._serial.dump_debug())
- prefix = "MCU '%s' shutdown: " % (self._name,)
- if params['#name'] == 'is_shutdown':
- prefix = "Previous MCU '%s' shutdown: " % (self._name,)
- self._printer.invoke_async_shutdown(prefix + msg + error_help(msg))
def _handle_starting(self, params):
if not self._is_shutdown:
self._printer.invoke_async_shutdown("MCU '%s' spontaneous restart"
@@ -1008,34 +1009,6 @@ class MCU:
self._get_status_info['last_stats'] = last_stats
return False, '%s: %s' % (self._name, stats)
-Common_MCU_errors = {
- ("Timer too close",): """
-This often indicates the host computer is overloaded. Check
-for other processes consuming excessive CPU time, high swap
-usage, disk errors, overheating, unstable voltage, or
-similar system problems on the host computer.""",
- ("Missed scheduling of next ",): """
-This is generally indicative of an intermittent
-communication failure between micro-controller and host.""",
- ("ADC out of range",): """
-This generally occurs when a heater temperature exceeds
-its configured min_temp or max_temp.""",
- ("Rescheduled timer in the past", "Stepper too far in past"): """
-This generally occurs when the micro-controller has been
-requested to step at a rate higher than it is capable of
-obtaining.""",
- ("Command request",): """
-This generally occurs in response to an M112 G-Code command
-or in response to an internal error in the host software.""",
-}
-
-def error_help(msg):
- for prefixes, help_msg in Common_MCU_errors.items():
- for prefix in prefixes:
- if msg.startswith(prefix):
- return help_msg
- return ""
-
def add_printer_objects(config):
printer = config.get_printer()
reactor = printer.get_reactor()