mcu: Detect if the communication channel to the firmware is lost

Detect a comms loss and report it to the user.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2016-11-30 19:31:46 -05:00
parent 5ebe8ce025
commit bc80ed4e88
4 changed files with 30 additions and 5 deletions

View File

@ -72,6 +72,13 @@ 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):
if self.toolhead is not None:
self.toolhead.motor_off()
if self.heater_nozzle is not None:
self.heater_nozzle.set_temp(0., 0.)
if self.heater_bed is not None:
self.heater_bed.set_temp(0., 0.)
def dump_debug(self): def dump_debug(self):
logging.info("Dumping gcode input %d blocks" % ( logging.info("Dumping gcode input %d blocks" % (
len(self.input_log),)) len(self.input_log),))

View File

@ -184,6 +184,10 @@ class Printer:
self.state_message = "Firmware shutdown: %s%s" % ( self.state_message = "Firmware shutdown: %s%s" % (
msg, message_shutdown) msg, message_shutdown)
self.gcode.set_printer_ready(False) self.gcode.set_printer_ready(False)
def note_mcu_error(self, msg):
self.state_message = "%s%s" % (msg, message_restart)
self.gcode.set_printer_ready(False)
self.gcode.note_mcu_error()
###################################################################### ######################################################################

View File

@ -168,7 +168,7 @@ class MCU_endstop:
raise error("Timeout during endstop homing") raise error("Timeout during endstop homing")
if self._mcu.is_shutdown: if self._mcu.is_shutdown:
raise error("MCU is shutdown") raise error("MCU is shutdown")
last_clock = self._mcu.get_last_clock() last_clock, last_clock_time = self._mcu.get_last_clock()
if last_clock >= self._next_query_clock: if last_clock >= self._next_query_clock:
self._next_query_clock = last_clock + self._retry_query_ticks self._next_query_clock = last_clock + self._retry_query_ticks
msg = self._query_cmd.encode(self._oid) msg = self._query_cmd.encode(self._oid)
@ -278,8 +278,8 @@ class MCU_adc:
self._max_sample = min(0xffff, int(math.ceil(maxval * max_adc))) self._max_sample = min(0xffff, int(math.ceil(maxval * max_adc)))
self._inv_max_adc = 1.0 / max_adc self._inv_max_adc = 1.0 / max_adc
def _init_callback(self): def _init_callback(self):
cur_clock = self._mcu.get_last_clock() last_clock, last_clock_time = self._mcu.get_last_clock()
clock = cur_clock + int(self._mcu_freq * (1.0 + self._oid * 0.01)) # XXX clock = last_clock + int(self._mcu_freq * (1.0 + self._oid * 0.01)) # XXX
msg = self._query_cmd.encode( msg = self._query_cmd.encode(
self._oid, clock, self._sample_ticks, self._sample_count self._oid, clock, self._sample_ticks, self._sample_count
, self._report_clock, self._min_sample, self._max_sample) , self._report_clock, self._min_sample, self._max_sample)
@ -295,6 +295,7 @@ class MCU_adc:
self._callback = callback self._callback = callback
class MCU: class MCU:
COMM_TIMEOUT = 3.5
def __init__(self, printer, config): def __init__(self, printer, config):
self._printer = printer self._printer = printer
self._config = config self._config = config
@ -304,6 +305,8 @@ class MCU:
self.serial = serialhdl.SerialReader(printer.reactor, serialport, baud) self.serial = serialhdl.SerialReader(printer.reactor, serialport, baud)
self.is_shutdown = False self.is_shutdown = False
self._is_fileoutput = False self._is_fileoutput = False
self._timeout_timer = printer.reactor.register_timer(
self.timeout_handler)
# Config building # Config building
self._emergency_stop_cmd = None self._emergency_stop_cmd = None
self._num_oids = 0 self._num_oids = 0
@ -341,7 +344,10 @@ class MCU:
def connect(self): def connect(self):
if not self._is_fileoutput: if not self._is_fileoutput:
self.serial.connect() self.serial.connect()
self._printer.reactor.update_timer(
self._timeout_timer, time.time() + self.COMM_TIMEOUT)
self._mcu_freq = float(self.serial.msgparser.config['CLOCK_FREQ']) self._mcu_freq = float(self.serial.msgparser.config['CLOCK_FREQ'])
self._emergency_stop_cmd = self.lookup_command("emergency_stop")
self.register_msg(self.handle_shutdown, 'shutdown') self.register_msg(self.handle_shutdown, 'shutdown')
self.register_msg(self.handle_shutdown, 'is_shutdown') self.register_msg(self.handle_shutdown, 'is_shutdown')
self.register_msg(self.handle_mcu_stats, 'stats') self.register_msg(self.handle_mcu_stats, 'stats')
@ -355,6 +361,15 @@ class MCU:
return 0.250 return 0.250
self.set_print_start_time = dummy_set_print_start_time self.set_print_start_time = dummy_set_print_start_time
self.get_print_buffer_time = dummy_get_print_buffer_time self.get_print_buffer_time = dummy_get_print_buffer_time
def timeout_handler(self, eventtime):
last_clock, last_clock_time = self.serial.get_last_clock()
timeout = last_clock_time + self.COMM_TIMEOUT
if eventtime < timeout:
return timeout
logging.info("Timeout with firmware (eventtime=%f last_status=%f)" % (
eventtime, last_clock_time))
self._printer.note_mcu_error("Lost communication with firmware")
return self._printer.reactor.NEVER
def disconnect(self): def disconnect(self):
self.serial.disconnect() self.serial.disconnect()
if self._steppersync is not None: if self._steppersync is not None:
@ -386,7 +401,6 @@ class MCU:
continue continue
self.add_config_cmd(line) self.add_config_cmd(line)
def build_config(self): def build_config(self):
self._emergency_stop_cmd = self.lookup_command("emergency_stop")
# Build config commands # Build config commands
self._add_custom() self._add_custom()
self._config_cmds.insert(0, "allocate_oids count=%d" % ( self._config_cmds.insert(0, "allocate_oids count=%d" % (

View File

@ -152,7 +152,7 @@ class SerialReader:
return last_ack_clock - clock_diff return last_ack_clock - clock_diff
def get_last_clock(self): def get_last_clock(self):
with self.lock: with self.lock:
return self.last_ack_clock return self.last_ack_clock, self.last_ack_time
# Command sending # Command sending
def send(self, cmd, minclock=0, reqclock=0, cq=None): def send(self, cmd, minclock=0, reqclock=0, cq=None):
if cq is None: if cq is None: