fix statemachine

- fix: calling state.start(<new state>) on restart must ensure
  that the function <new state> is called before state.start()
  returns.
- modify slighly behaviour of cleanup function

Change-Id: I483a3aefa6af4712b3cf13f62c86d4c06edd1d8d
Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/28020
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
This commit is contained in:
2022-03-28 15:14:31 +02:00
committed by l_samenv
parent 9152ea1d26
commit d5924567da
3 changed files with 123 additions and 83 deletions

View File

@ -20,8 +20,8 @@
#
# *****************************************************************************
from secop.core import Parameter, FloatRange, BUSY, IDLE, WARN, ERROR
from secop.lib.statemachine import StateMachine, Retry
from secop.core import Parameter, FloatRange, BUSY, IDLE, WARN
from secop.lib.statemachine import StateMachine, Retry, Stop
class HasConvergence:
@ -51,17 +51,25 @@ class HasConvergence:
then the timeout event happens after this time + <settling_time> + <timeout>.
''', FloatRange(0, unit='sec'), readonly=False, default=3600)
status = Parameter('status determined from convergence checks', default=(IDLE, ''))
convergence_state = None
def earlyInit(self):
super().earlyInit()
self.convergence_state = StateMachine(threaded=False, logger=self.log, spent_inside=0)
self.convergence_state = StateMachine(threaded=False, logger=self.log,
cleanup=self.cleanup, spent_inside=0)
def cleanup(self, state):
state.default_cleanup(state)
if self.stopped:
if self.stopped is Stop: # and not Restart
self.status = WARN, 'stopped'
else:
self.status = WARN, repr(state.last_error)
def doPoll(self):
super().doPoll()
state = self.convergence_state
state.cycle()
if not state.is_active and state.last_error is not None:
self.status = ERROR, repr(state.last_error)
def get_min_slope(self, dif):
slope = getattr(self, 'workingramp', 0) or getattr(self, 'ramp', 0)
@ -80,7 +88,6 @@ class HasConvergence:
def start_state(self):
"""to be called from write_target"""
self.convergence_state.start(self.state_approach)
self.convergence_state.cycle()
def state_approach(self, state):
"""approaching, checking progress (busy)"""
@ -105,8 +112,6 @@ class HasConvergence:
def state_inside(self, state):
"""inside tolerance, still busy"""
if state.init:
self.status = BUSY, 'inside tolerance'
dif, tol = self.get_dif_tol()
if dif > tol:
return self.state_outside
@ -114,18 +119,20 @@ class HasConvergence:
if state.spent_inside > self.settling_time:
self.status = IDLE, 'reached target'
return self.state_stable
if state.init:
self.status = BUSY, 'inside tolerance'
return Retry()
def state_outside(self, state):
"""temporarely outside tolerance, busy"""
if state.init:
self.status = BUSY, 'outside tolerance'
dif, tol = self.get_dif_tol()
if dif < tol:
return self.state_inside
if state.now > state.timeout_base + self.settling_time + self.timeout:
self.status = WARN, 'settling timeout'
return self.state_instable
if state.init:
self.status = BUSY, 'outside tolerance'
# do not reset the settling time on occasional outliers, count backwards instead
state.spent_inside = max(0.0, state.spent_inside - state.delta())
return Retry()