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:
parent
1b1d2adb31
commit
ff9543eee2
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue