diff --git a/klippy/gcode.py b/klippy/gcode.py index 50743bc8..ff7e2443 100644 --- a/klippy/gcode.py +++ b/klippy/gcode.py @@ -109,7 +109,7 @@ class GCodeParser: except: logging.exception("Exception in command handler") self.toolhead.force_shutdown() - self.respond('Error: Internal error on command:"%s"' % (cmd,)) + self.respond_error('Internal error on command:"%s"' % (cmd,)) # Check if machine can process next command or must stall input if self.busy_state is not None: break @@ -146,6 +146,11 @@ class GCodeParser: if self.is_fileinput: return os.write(self.fd, msg+"\n") + def respond_error(self, msg): + lines = msg.strip().split('\n') + for line in lines[:-1]: + self.respond('// %s' % (line.strip(),)) + self.respond('!! %s' % (lines[-1].strip(),)) # Busy handling def set_busy(self, busy_handler): self.busy_state = busy_handler @@ -154,12 +159,12 @@ class GCodeParser: try: busy = self.busy_state.check_busy(eventtime) except homing.EndstopError, e: - self.respond("Error: %s" % (e,)) + self.respond_error(str(e)) busy = False except: logging.exception("Exception in busy handler") self.toolhead.force_shutdown() - self.respond('Error: Internal error in busy handler') + self.respond_error('Internal error in busy handler') busy = False if busy: self.toolhead.reset_motor_off_time(eventtime) @@ -208,7 +213,7 @@ class GCodeParser: # Individual command handlers def cmd_default(self, params): if not self.is_printer_ready: - self.respond('Error: Printer is not ready') + self.respond_error(self.printer.get_state_message()) return cmd = params.get('#command') if not cmd: @@ -233,7 +238,7 @@ class GCodeParser: try: self.toolhead.move(self.last_position, self.speed, sloppy) except homing.EndstopError, e: - self.respond("Error: %s" % (e,)) + self.respond_error(str(e)) self.last_position = self.toolhead.get_position() def cmd_G4(self, params): # Dwell @@ -244,7 +249,7 @@ class GCodeParser: self.toolhead.dwell(delay) def cmd_G20(self, params): # Set units to inches - self.respond('Error: Machine does not support G20 (inches) command') + self.respond_error('Machine does not support G20 (inches) command') def cmd_G21(self, params): # Set units to millimeters pass diff --git a/klippy/klippy.py b/klippy/klippy.py index 8850361d..088d81bb 100644 --- a/klippy/klippy.py +++ b/klippy/klippy.py @@ -7,6 +7,32 @@ import sys, optparse, ConfigParser, logging, time, threading import gcode, toolhead, util, mcu, fan, heater, extruder, reactor, queuelogger +message_startup = """ +The klippy host software is attempting to connect. Please +retry in a few moments. +Printer is not ready +""" + +message_restart = """ +This is an unrecoverable error. Please correct the +underlying issue and then manually restart the klippy host +software. +Printer is halted +""" + +message_mcu_connect_error = """ +This is an unrecoverable error. Please manually restart +both the firmware and the host software. +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. +Printer is shutdown +""" + class ConfigWrapper: def __init__(self, printer, section): self.printer = printer @@ -38,6 +64,7 @@ class Printer: self.stats_timer = self.reactor.register_timer(self.stats) self.connect_timer = self.reactor.register_timer( self.connect, self.reactor.NOW) + self.state_message = message_startup self.debugoutput = self.dictionary = None self.fileconfig = None self.mcu = None @@ -74,23 +101,42 @@ class Printer: self.gcode.build_config() self.mcu.build_config() def connect(self, eventtime): - self.load_config() - if self.debugoutput is None: - self.reactor.update_timer(self.stats_timer, self.reactor.NOW) - else: - self.mcu.connect_file(self.debugoutput, self.dictionary) - self.mcu.connect() - self.build_config() - self.gcode.set_printer_ready(True) + try: + self.load_config() + if self.debugoutput is None: + self.reactor.update_timer(self.stats_timer, self.reactor.NOW) + else: + self.mcu.connect_file(self.debugoutput, self.dictionary) + self.mcu.connect() + self.build_config() + self.gcode.set_printer_ready(True) + self.state_message = "Running" + except mcu.error, e: + logging.exception("MCU error during connect") + self.state_message = "%s%s" % (str(e), message_mcu_connect_error) + self.reactor.update_timer(self.stats_timer, self.reactor.NEVER) + except: + logging.exception("Unhandled exception during connect") + self.state_message = "Internal error during connect.%s" % ( + message_restart) + self.reactor.update_timer(self.stats_timer, self.reactor.NEVER) self.reactor.unregister_timer(self.connect_timer) return self.reactor.NEVER def run(self): - self.reactor.run() + try: + self.reactor.run() + except: + logging.exception("Unhandled exception during run") + return # If gcode exits, then exit the MCU self.stats(time.time()) self.mcu.disconnect() self.stats(time.time()) - def note_shutdown(self): + def get_state_message(self): + return self.state_message + def note_shutdown(self, msg): + self.state_message = "Firmware shutdown: %s%s" % ( + msg, message_shutdown) self.gcode.set_printer_ready(False) diff --git a/klippy/mcu.py b/klippy/mcu.py index 2e15287f..e039f2d5 100644 --- a/klippy/mcu.py +++ b/klippy/mcu.py @@ -336,7 +336,7 @@ class MCU: self.is_shutdown = True logging.info("%s: %s" % (params['#name'], params['#msg'])) self.serial.dump_debug() - self._printer.note_shutdown() + self._printer.note_shutdown(params['#msg']) # Connection phase def connect(self): if not self._is_fileoutput: @@ -421,8 +421,7 @@ class MCU: if not self._is_fileoutput: config_params = self.serial.send_with_response(msg, 'config') if self._config_crc != config_params['crc']: - logging.error("Printer CRC does not match config") - sys.exit(1) + raise error("Printer CRC does not match config") logging.info("Configured") stepqueues = tuple(s._stepqueue for s in self._steppers) self._steppersync = self.ffi_lib.steppersync_alloc(