diff --git a/config/example.cfg b/config/example.cfg index 8abaf9f7..65b6ddee 100644 --- a/config/example.cfg +++ b/config/example.cfg @@ -243,6 +243,13 @@ serial: /dev/ttyACM0 pin_map: arduino # This option may be used to enable Arduino pin name aliases. The # default is to not enable the aliases. +#restart_method: arduino +# This controls the mechanism the host will use to reset the +# micro-controller. The choices are 'arduino' and 'command'. The +# 'arduino' method (toggle DTR; set baud to 1200) is common on +# Arduino boards and clones. The 'command' method involves sending a +# Klipper command to the micro-controller so that it can reset +# itself. The default is 'arduino'. custom: # This option may be used to specify a set of custom # micro-controller commands to be sent at the start of the diff --git a/klippy/klippy.py b/klippy/klippy.py index e63bb096..c73c18c2 100644 --- a/klippy/klippy.py +++ b/klippy/klippy.py @@ -246,8 +246,8 @@ class Printer: try: if self.mcu is not None: self.stats(self.reactor.monotonic()) - self.mcu.disconnect() self.mcu.microcontroller_restart() + self.mcu.disconnect() except: logging.exception("Unhandled exception during firmware_restart") def get_startup_state(self): diff --git a/klippy/mcu.py b/klippy/mcu.py index 50a0eab4..4601e769 100644 --- a/klippy/mcu.py +++ b/klippy/mcu.py @@ -371,7 +371,6 @@ class MCU: COMM_TIMEOUT = 3.5 def __init__(self, printer, config): self._printer = printer - self._config = config # Serial port baud = config.getint('baud', 250000) self._serialport = config.get('serial', '/dev/ttyS0') @@ -382,8 +381,13 @@ class MCU: self._is_fileoutput = False self._timeout_timer = printer.reactor.register_timer( self.timeout_handler) + rmethods = {m: m for m in ['arduino', 'command']} + self._restart_method = config.getchoice( + 'restart_method', rmethods, 'arduino') # Config building - self._emergency_stop_cmd = self._clear_shutdown_cmd = None + self._config_error = config.error + self._emergency_stop_cmd = self._reset_cmd = None + self._clear_shutdown_cmd = None self._oids = [] self._config_cmds = [] self._config_crc = None @@ -430,6 +434,10 @@ class MCU: 'STATS_SUMSQ_BASE') self._emergency_stop_cmd = self.lookup_command("emergency_stop") self._clear_shutdown_cmd = self.lookup_command("clear_shutdown") + try: + self._reset_cmd = self.lookup_command("reset") + except self.serial.msgparser.error, e: + pass self.register_msg(self.handle_shutdown, 'shutdown') self.register_msg(self.handle_shutdown, 'is_shutdown') self.register_msg(self.handle_mcu_stats, 'stats') @@ -469,9 +477,24 @@ class MCU: logging.info("Sending clear_shutdown command") self.send(self._clear_shutdown_cmd.encode()) def microcontroller_restart(self): + reactor = self._printer.reactor + if self._restart_method == 'command': + last_clock, last_clock_time = self.serial.get_last_clock() + eventtime = reactor.monotonic() + if (self._reset_cmd is None + or eventtime > last_clock_time + self.COMM_TIMEOUT): + logging.info("Unable to issue reset command") + return + # Attempt reset via command + logging.info("Attempting a microcontroller reset command") + self.send(self._reset_cmd.encode()) + reactor.pause(reactor.monotonic() + 0.015) + self.disconnect() + return + # Attempt reset via arduino mechanism logging.info("Attempting a microcontroller reset") self.disconnect() - serialhdl.arduino_reset(self._serialport, self._printer.reactor) + serialhdl.arduino_reset(self._serialport, reactor) def is_fileoutput(self): return self._is_fileoutput # Configuration phase @@ -501,7 +524,7 @@ class MCU: updated_cmds.append(pins.update_command( cmd, self._mcu_freq, pnames)) except: - raise self._config.error("Unable to translate pin name: %s" % ( + raise self._config_error("Unable to translate pin name: %s" % ( cmd,)) self._config_cmds = updated_cmds diff --git a/klippy/msgproto.py b/klippy/msgproto.py index c9d14138..b0bce35b 100644 --- a/klippy/msgproto.py +++ b/klippy/msgproto.py @@ -184,6 +184,7 @@ class UnknownFormat: return {'#msgid': msgid, '#msg': msg}, len(s)-MESSAGE_TRAILER_SIZE class MessageParser: + error = error def __init__(self): self.unknown = UnknownFormat() self.messages_by_id = {}