klippy: Add ability to restart the host software

Add a "restart" gcode command that will cause the host "klippy"
software to reload its config and restart.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2016-11-30 23:47:40 -05:00
parent a6055ce069
commit fbd7cc243b
2 changed files with 39 additions and 20 deletions

View File

@ -47,7 +47,7 @@ class GCodeParser:
def build_handlers(self): def build_handlers(self):
handlers = ['G1', 'G4', 'G20', 'G21', 'G28', 'G90', 'G91', 'G92', handlers = ['G1', 'G4', 'G20', 'G21', 'G28', 'G90', 'G91', 'G92',
'M18', 'M82', 'M83', 'M105', 'M110', 'M114', 'M206', 'M18', 'M82', 'M83', 'M105', 'M110', 'M114', 'M206',
'HELP', 'QUERY_ENDSTOPS'] 'HELP', 'QUERY_ENDSTOPS', 'RESTART']
if self.heater_nozzle is not None: if self.heater_nozzle is not None:
handlers.extend(['M104', 'M109', 'PID_TUNE']) handlers.extend(['M104', 'M109', 'PID_TUNE'])
if self.heater_bed is not None: if self.heater_bed is not None:
@ -62,10 +62,6 @@ class GCodeParser:
for h, f in self.gcode_handlers.items(): for h, f in self.gcode_handlers.items():
aliases = getattr(self, 'cmd_'+h+'_aliases', []) aliases = getattr(self, 'cmd_'+h+'_aliases', [])
self.gcode_handlers.update(dict([(a, f) for a in aliases])) self.gcode_handlers.update(dict([(a, f) for a in aliases]))
def finish(self):
self.reactor.end()
self.toolhead.motor_off()
logging.debug('Completed translation by klippy')
def stats(self, eventtime): def stats(self, eventtime):
return "gcodein=%d" % (self.bytes_read,) return "gcodein=%d" % (self.bytes_read,)
def set_printer_ready(self, is_ready): def set_printer_ready(self, is_ready):
@ -75,7 +71,7 @@ class GCodeParser:
self.build_handlers() self.build_handlers()
if is_ready and self.is_fileinput and self.fd_handle is None: if is_ready and self.is_fileinput and self.fd_handle is None:
self.fd_handle = self.reactor.register_fd(self.fd, self.process_data) self.fd_handle = self.reactor.register_fd(self.fd, self.process_data)
def note_mcu_error(self): def motor_heater_off(self):
if self.toolhead is not None: if self.toolhead is not None:
self.toolhead.motor_off() self.toolhead.motor_off()
if self.heater_nozzle is not None: if self.heater_nozzle is not None:
@ -140,7 +136,8 @@ class GCodeParser:
self.input_commands = lines self.input_commands = lines
self.process_commands(eventtime) self.process_commands(eventtime)
if not data and self.is_fileinput: if not data and self.is_fileinput:
self.finish() self.motor_heater_off()
self.printer.request_exit_eof()
# Response handling # Response handling
def ack(self, msg=None): def ack(self, msg=None):
if not self.need_ack or self.is_fileinput: if not self.need_ack or self.is_fileinput:
@ -370,6 +367,11 @@ class GCodeParser:
temp = float(params.get('S', '60')) temp = float(params.get('S', '60'))
heater.start_auto_tune(temp) heater.start_auto_tune(temp)
self.bg_temp(heater) self.bg_temp(heater)
cmd_RESTART_when_not_ready = True
cmd_RESTART_help = "Reload config file and restart host software"
def cmd_RESTART(self, params):
self.printer.request_restart()
cmd_HELP_when_not_ready = True
def cmd_HELP(self, params): def cmd_HELP(self, params):
cmdhelp = ["// Available extended commands:"] cmdhelp = ["// Available extended commands:"]
for cmd in self.gcode_handlers: for cmd in self.gcode_handlers:

View File

@ -14,9 +14,8 @@ Printer is not ready
""" """
message_restart = """ message_restart = """
This is an unrecoverable error. Please correct the Once the underlying issue is corrected, use the "RESTART"
underlying issue and then manually restart the klippy host command to reload the config and restart the host software.
software.
Printer is halted Printer is halted
""" """
@ -85,6 +84,7 @@ class Printer:
self.need_dump_debug = False self.need_dump_debug = False
self.state_message = message_startup self.state_message = message_startup
self.debugoutput = self.dictionary = None self.debugoutput = self.dictionary = None
self.run_result = None
self.fileconfig = None self.fileconfig = None
self.mcu = None self.mcu = None
self.objects = {} self.objects = {}
@ -172,10 +172,7 @@ class Printer:
except: except:
logging.exception("Unhandled exception during run") logging.exception("Unhandled exception during run")
return return
# If gcode exits, then exit the MCU return self.run_result
self.stats(time.time())
self.mcu.disconnect()
self.stats(time.time())
def get_state_message(self): def get_state_message(self):
return self.state_message return self.state_message
def note_shutdown(self, msg): def note_shutdown(self, msg):
@ -187,7 +184,17 @@ class Printer:
def note_mcu_error(self, msg): def note_mcu_error(self, msg):
self.state_message = "%s%s" % (msg, message_restart) self.state_message = "%s%s" % (msg, message_restart)
self.gcode.set_printer_ready(False) self.gcode.set_printer_ready(False)
self.gcode.note_mcu_error() self.gcode.motor_heater_off()
def disconnect(self):
if self.mcu is not None:
self.stats(time.time())
self.mcu.disconnect()
def request_restart(self):
self.run_result = "restart"
self.reactor.end()
def request_exit_eof(self):
self.run_result = "exit_eof"
self.reactor.end()
###################################################################### ######################################################################
@ -239,11 +246,21 @@ def main():
logging.info("Starting Klippy...") logging.info("Starting Klippy...")
# Start firmware # Start firmware
printer = Printer(conffile, input_fd, is_fileinput=debuginput is not None) while 1:
is_fileinput = debuginput is not None
printer = Printer(conffile, input_fd, is_fileinput)
if debugoutput: if debugoutput:
proto_dict = read_dictionary(options.read_dictionary) proto_dict = read_dictionary(options.read_dictionary)
printer.set_fileoutput(debugoutput, proto_dict) printer.set_fileoutput(debugoutput, proto_dict)
printer.run() res = printer.run()
if res == 'restart':
printer.disconnect()
time.sleep(1.)
logging.info("Restarting printer")
continue
elif res == 'eof_stats':
printer.disconnect()
break
if bglogger is not None: if bglogger is not None:
bglogger.stop() bglogger.stop()