clocksync: Simplify is_active() check

In some rare circumstances it was possible for the host software to
become so busy that it does not transmit a get_clock request for
several seconds.  (In particular, this could occur with some complex
calls to coordinate_descent.)  If that happened, it was possible for
the code to incorrectly report a "Timeout with MCU" error.  Rework the
is_active() check to prevent that.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2018-05-31 18:18:23 -04:00
parent 1b1d2adb31
commit ff9543eee2
2 changed files with 9 additions and 9 deletions

View File

@ -1,11 +1,10 @@
# Micro-controller clock synchronization # Micro-controller clock synchronization
# #
# Copyright (C) 2016,2017 Kevin O'Connor <kevin@koconnor.net> # Copyright (C) 2016-2018 Kevin O'Connor <kevin@koconnor.net>
# #
# This file may be distributed under the terms of the GNU GPLv3 license. # This file may be distributed under the terms of the GNU GPLv3 license.
import logging, threading, math import logging, math
COMM_TIMEOUT = 3.5
RTT_AGE = .000010 / (60. * 60.) RTT_AGE = .000010 / (60. * 60.)
DECAY = 1. / 30. DECAY = 1. / 30.
TRANSMIT_EXTRA = .001 TRANSMIT_EXTRA = .001
@ -16,6 +15,7 @@ class ClockSync:
self.serial = None self.serial = None
self.get_clock_timer = self.reactor.register_timer(self._get_clock_event) self.get_clock_timer = self.reactor.register_timer(self._get_clock_event)
self.get_clock_cmd = None self.get_clock_cmd = None
self.queries_pending = 0
self.mcu_freq = 1. self.mcu_freq = 1.
self.last_clock = 0 self.last_clock = 0
self.clock_est = (0., 0., 0.) self.clock_est = (0., 0., 0.)
@ -57,10 +57,12 @@ class ClockSync:
# MCU clock querying (_handle_clock is invoked from background thread) # MCU clock querying (_handle_clock is invoked from background thread)
def _get_clock_event(self, eventtime): def _get_clock_event(self, eventtime):
self.get_clock_cmd.send() self.get_clock_cmd.send()
self.queries_pending += 1
# Use an unusual time for the next event so clock messages # Use an unusual time for the next event so clock messages
# don't resonate with other periodic events. # don't resonate with other periodic events.
return eventtime + .9839 return eventtime + .9839
def _handle_clock(self, params): def _handle_clock(self, params):
self.queries_pending = 0
# Extend clock to 64bit # Extend clock to 64bit
last_clock = self.last_clock last_clock = self.last_clock
clock = (last_clock & ~0xffffffff) | params['clock'] clock = (last_clock & ~0xffffffff) | params['clock']
@ -138,10 +140,8 @@ class ClockSync:
if clock_diff & 0x80000000: if clock_diff & 0x80000000:
return last_clock + 0x100000000 - clock_diff return last_clock + 0x100000000 - clock_diff
return last_clock - clock_diff return last_clock - clock_diff
def is_active(self, eventtime): def is_active(self):
print_time = self.estimated_print_time(eventtime) return self.queries_pending <= 4
last_clock_print_time = self.clock_to_print_time(self.last_clock)
return print_time < last_clock_print_time + COMM_TIMEOUT
def dump_debug(self): def dump_debug(self):
sample_time, clock, freq = self.clock_est sample_time, clock, freq = self.clock_est
return ("clocksync state: mcu_freq=%d last_clock=%d" return ("clocksync state: mcu_freq=%d last_clock=%d"

View File

@ -690,7 +690,7 @@ class MCU:
serialhdl.arduino_reset(self._serialport, self._reactor) serialhdl.arduino_reset(self._serialport, self._reactor)
def _restart_via_command(self): def _restart_via_command(self):
if ((self._reset_cmd is None and self._config_reset_cmd is None) if ((self._reset_cmd is None and self._config_reset_cmd is None)
or not self._clocksync.is_active(self._reactor.monotonic())): or not self._clocksync.is_active()):
logging.info("Unable to issue reset command on MCU '%s'", self._name) logging.info("Unable to issue reset command on MCU '%s'", self._name)
return return
if self._reset_cmd is None: if self._reset_cmd is None:
@ -739,7 +739,7 @@ class MCU:
return return
offset, freq = self._clocksync.calibrate_clock(print_time, eventtime) offset, freq = self._clocksync.calibrate_clock(print_time, eventtime)
self._ffi_lib.steppersync_set_time(self._steppersync, offset, freq) self._ffi_lib.steppersync_set_time(self._steppersync, offset, freq)
if (self._clocksync.is_active(eventtime) or self.is_fileoutput() if (self._clocksync.is_active() or self.is_fileoutput()
or self._is_timeout): or self._is_timeout):
return return
self._is_timeout = True self._is_timeout = True