klippy: Improve error reporting during connect
Catch exceptions during the connect phase and report them via the gcode interface to the user. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
dbdf1e137e
commit
524e0290bc
|
@ -109,7 +109,7 @@ class GCodeParser:
|
||||||
except:
|
except:
|
||||||
logging.exception("Exception in command handler")
|
logging.exception("Exception in command handler")
|
||||||
self.toolhead.force_shutdown()
|
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
|
# Check if machine can process next command or must stall input
|
||||||
if self.busy_state is not None:
|
if self.busy_state is not None:
|
||||||
break
|
break
|
||||||
|
@ -146,6 +146,11 @@ class GCodeParser:
|
||||||
if self.is_fileinput:
|
if self.is_fileinput:
|
||||||
return
|
return
|
||||||
os.write(self.fd, msg+"\n")
|
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
|
# Busy handling
|
||||||
def set_busy(self, busy_handler):
|
def set_busy(self, busy_handler):
|
||||||
self.busy_state = busy_handler
|
self.busy_state = busy_handler
|
||||||
|
@ -154,12 +159,12 @@ class GCodeParser:
|
||||||
try:
|
try:
|
||||||
busy = self.busy_state.check_busy(eventtime)
|
busy = self.busy_state.check_busy(eventtime)
|
||||||
except homing.EndstopError, e:
|
except homing.EndstopError, e:
|
||||||
self.respond("Error: %s" % (e,))
|
self.respond_error(str(e))
|
||||||
busy = False
|
busy = False
|
||||||
except:
|
except:
|
||||||
logging.exception("Exception in busy handler")
|
logging.exception("Exception in busy handler")
|
||||||
self.toolhead.force_shutdown()
|
self.toolhead.force_shutdown()
|
||||||
self.respond('Error: Internal error in busy handler')
|
self.respond_error('Internal error in busy handler')
|
||||||
busy = False
|
busy = False
|
||||||
if busy:
|
if busy:
|
||||||
self.toolhead.reset_motor_off_time(eventtime)
|
self.toolhead.reset_motor_off_time(eventtime)
|
||||||
|
@ -208,7 +213,7 @@ class GCodeParser:
|
||||||
# Individual command handlers
|
# Individual command handlers
|
||||||
def cmd_default(self, params):
|
def cmd_default(self, params):
|
||||||
if not self.is_printer_ready:
|
if not self.is_printer_ready:
|
||||||
self.respond('Error: Printer is not ready')
|
self.respond_error(self.printer.get_state_message())
|
||||||
return
|
return
|
||||||
cmd = params.get('#command')
|
cmd = params.get('#command')
|
||||||
if not cmd:
|
if not cmd:
|
||||||
|
@ -233,7 +238,7 @@ class GCodeParser:
|
||||||
try:
|
try:
|
||||||
self.toolhead.move(self.last_position, self.speed, sloppy)
|
self.toolhead.move(self.last_position, self.speed, sloppy)
|
||||||
except homing.EndstopError, e:
|
except homing.EndstopError, e:
|
||||||
self.respond("Error: %s" % (e,))
|
self.respond_error(str(e))
|
||||||
self.last_position = self.toolhead.get_position()
|
self.last_position = self.toolhead.get_position()
|
||||||
def cmd_G4(self, params):
|
def cmd_G4(self, params):
|
||||||
# Dwell
|
# Dwell
|
||||||
|
@ -244,7 +249,7 @@ class GCodeParser:
|
||||||
self.toolhead.dwell(delay)
|
self.toolhead.dwell(delay)
|
||||||
def cmd_G20(self, params):
|
def cmd_G20(self, params):
|
||||||
# Set units to inches
|
# 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):
|
def cmd_G21(self, params):
|
||||||
# Set units to millimeters
|
# Set units to millimeters
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -7,6 +7,32 @@
|
||||||
import sys, optparse, ConfigParser, logging, time, threading
|
import sys, optparse, ConfigParser, logging, time, threading
|
||||||
import gcode, toolhead, util, mcu, fan, heater, extruder, reactor, queuelogger
|
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:
|
class ConfigWrapper:
|
||||||
def __init__(self, printer, section):
|
def __init__(self, printer, section):
|
||||||
self.printer = printer
|
self.printer = printer
|
||||||
|
@ -38,6 +64,7 @@ class Printer:
|
||||||
self.stats_timer = self.reactor.register_timer(self.stats)
|
self.stats_timer = self.reactor.register_timer(self.stats)
|
||||||
self.connect_timer = self.reactor.register_timer(
|
self.connect_timer = self.reactor.register_timer(
|
||||||
self.connect, self.reactor.NOW)
|
self.connect, self.reactor.NOW)
|
||||||
|
self.state_message = message_startup
|
||||||
self.debugoutput = self.dictionary = None
|
self.debugoutput = self.dictionary = None
|
||||||
self.fileconfig = None
|
self.fileconfig = None
|
||||||
self.mcu = None
|
self.mcu = None
|
||||||
|
@ -74,6 +101,7 @@ class Printer:
|
||||||
self.gcode.build_config()
|
self.gcode.build_config()
|
||||||
self.mcu.build_config()
|
self.mcu.build_config()
|
||||||
def connect(self, eventtime):
|
def connect(self, eventtime):
|
||||||
|
try:
|
||||||
self.load_config()
|
self.load_config()
|
||||||
if self.debugoutput is None:
|
if self.debugoutput is None:
|
||||||
self.reactor.update_timer(self.stats_timer, self.reactor.NOW)
|
self.reactor.update_timer(self.stats_timer, self.reactor.NOW)
|
||||||
|
@ -82,15 +110,33 @@ class Printer:
|
||||||
self.mcu.connect()
|
self.mcu.connect()
|
||||||
self.build_config()
|
self.build_config()
|
||||||
self.gcode.set_printer_ready(True)
|
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)
|
self.reactor.unregister_timer(self.connect_timer)
|
||||||
return self.reactor.NEVER
|
return self.reactor.NEVER
|
||||||
def run(self):
|
def run(self):
|
||||||
|
try:
|
||||||
self.reactor.run()
|
self.reactor.run()
|
||||||
|
except:
|
||||||
|
logging.exception("Unhandled exception during run")
|
||||||
|
return
|
||||||
# If gcode exits, then exit the MCU
|
# If gcode exits, then exit the MCU
|
||||||
self.stats(time.time())
|
self.stats(time.time())
|
||||||
self.mcu.disconnect()
|
self.mcu.disconnect()
|
||||||
self.stats(time.time())
|
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)
|
self.gcode.set_printer_ready(False)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -336,7 +336,7 @@ class MCU:
|
||||||
self.is_shutdown = True
|
self.is_shutdown = True
|
||||||
logging.info("%s: %s" % (params['#name'], params['#msg']))
|
logging.info("%s: %s" % (params['#name'], params['#msg']))
|
||||||
self.serial.dump_debug()
|
self.serial.dump_debug()
|
||||||
self._printer.note_shutdown()
|
self._printer.note_shutdown(params['#msg'])
|
||||||
# Connection phase
|
# Connection phase
|
||||||
def connect(self):
|
def connect(self):
|
||||||
if not self._is_fileoutput:
|
if not self._is_fileoutput:
|
||||||
|
@ -421,8 +421,7 @@ class MCU:
|
||||||
if not self._is_fileoutput:
|
if not self._is_fileoutput:
|
||||||
config_params = self.serial.send_with_response(msg, 'config')
|
config_params = self.serial.send_with_response(msg, 'config')
|
||||||
if self._config_crc != config_params['crc']:
|
if self._config_crc != config_params['crc']:
|
||||||
logging.error("Printer CRC does not match config")
|
raise error("Printer CRC does not match config")
|
||||||
sys.exit(1)
|
|
||||||
logging.info("Configured")
|
logging.info("Configured")
|
||||||
stepqueues = tuple(s._stepqueue for s in self._steppers)
|
stepqueues = tuple(s._stepqueue for s in self._steppers)
|
||||||
self._steppersync = self.ffi_lib.steppersync_alloc(
|
self._steppersync = self.ffi_lib.steppersync_alloc(
|
||||||
|
|
Loading…
Reference in New Issue