support for fast poll when busy
Module.setFastPoll may be called depending on status in order to change the poll interval dependent whether the module is busy or not. It is assured that the new interval is applied immediately. Change-Id: I2bd8f68440dc4a93b39e5083a579fc1c123fe578 Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/27896 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:
parent
b423235c5d
commit
e0fe7e46d1
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import threading
|
from queue import Queue, Empty
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
@ -293,7 +293,7 @@ class Module(HasAccessibles):
|
|||||||
self.initModuleDone = False
|
self.initModuleDone = False
|
||||||
self.startModuleDone = False
|
self.startModuleDone = False
|
||||||
self.remoteLogHandler = None
|
self.remoteLogHandler = None
|
||||||
self.nextPollEvent = threading.Event()
|
self.changePollinterval = Queue() # used for waiting between polls and transmit info to the thread
|
||||||
errors = []
|
errors = []
|
||||||
|
|
||||||
# handle module properties
|
# handle module properties
|
||||||
@ -587,9 +587,17 @@ class Module(HasAccessibles):
|
|||||||
all other parameters are polled automatically
|
all other parameters are polled automatically
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def triggerPollEvent(self, *args): # args needed for valueCallback
|
def setFastPoll(self, pollinterval):
|
||||||
"""interrupts waiting between polls"""
|
"""change poll interval
|
||||||
self.nextPollEvent.set() # trigger poll loop
|
|
||||||
|
:param pollinterval: a new (typically lower) pollinterval
|
||||||
|
special values: True: set to 0.25 (default fast poll interval)
|
||||||
|
False: set to self.pollinterval (value for idle)
|
||||||
|
"""
|
||||||
|
if pollinterval is False:
|
||||||
|
self.changePollinterval.put(self.pollinterval)
|
||||||
|
return
|
||||||
|
self.changePollinterval.put(0.25 if pollinterval is True else pollinterval)
|
||||||
|
|
||||||
def callPollFunc(self, rfunc):
|
def callPollFunc(self, rfunc):
|
||||||
"""call read method with proper error handling"""
|
"""call read method with proper error handling"""
|
||||||
@ -614,25 +622,27 @@ class Module(HasAccessibles):
|
|||||||
polled_parameters.append((rfunc, pobj))
|
polled_parameters.append((rfunc, pobj))
|
||||||
self.callPollFunc(rfunc)
|
self.callPollFunc(rfunc)
|
||||||
started_callback()
|
started_callback()
|
||||||
|
pollinterval = self.pollinterval
|
||||||
last_slow = last_main = 0
|
last_slow = last_main = 0
|
||||||
last_error = None
|
last_error = None
|
||||||
error_count = 0
|
error_count = 0
|
||||||
to_poll = ()
|
to_poll = ()
|
||||||
while True:
|
while True:
|
||||||
now = time.time()
|
now = time.time()
|
||||||
wait_main = last_main + self.pollinterval - now
|
wait_main = last_main + pollinterval - now
|
||||||
wait_slow = last_slow + self.slowinterval - now
|
wait_slow = last_slow + self.slowinterval - now
|
||||||
wait_time = min(wait_main, wait_slow)
|
wait_time = min(wait_main, wait_slow)
|
||||||
if wait_time > 0:
|
if wait_time > 0:
|
||||||
self.nextPollEvent.wait(wait_time)
|
try:
|
||||||
self.nextPollEvent.clear()
|
result = self.changePollinterval.get(timeout=wait_time)
|
||||||
# remark: if there would be a need to trigger polling all parameters,
|
except Empty:
|
||||||
# we might replace nextPollEvent by a Queue and act depending on the
|
result = None
|
||||||
# queued item
|
if result is not None:
|
||||||
|
pollinterval = result
|
||||||
continue
|
continue
|
||||||
# call doPoll, if due
|
# call doPoll, if due
|
||||||
if wait_main <= 0:
|
if wait_main <= 0:
|
||||||
last_main = (now // self.pollinterval) * self.pollinterval
|
last_main = (now // pollinterval) * pollinterval
|
||||||
try:
|
try:
|
||||||
self.doPoll()
|
self.doPoll()
|
||||||
if last_error and error_count > 1:
|
if last_error and error_count > 1:
|
||||||
@ -712,8 +722,9 @@ class Readable(Module):
|
|||||||
|
|
||||||
def earlyInit(self):
|
def earlyInit(self):
|
||||||
super().earlyInit()
|
super().earlyInit()
|
||||||
# in case pollinterval is reduced a lot, we do not want to wait
|
# trigger a poll interval change when self.pollinterval changes.
|
||||||
self.valueCallbacks['pollinterval'].append(self.triggerPollEvent)
|
# self.setFastPoll with a float argument does the job here
|
||||||
|
self.valueCallbacks['pollinterval'].append(self.setFastPoll)
|
||||||
|
|
||||||
def doPoll(self):
|
def doPoll(self):
|
||||||
self.read_value()
|
self.read_value()
|
||||||
|
@ -507,13 +507,14 @@ class AnalogOutput(PyTangoDevice, Drivable):
|
|||||||
if self._isAtTarget():
|
if self._isAtTarget():
|
||||||
self._timeout = None
|
self._timeout = None
|
||||||
self._moving = False
|
self._moving = False
|
||||||
return super().read_status()
|
status = super().read_status()
|
||||||
if self._timeout:
|
else:
|
||||||
if self._timeout < currenttime():
|
if self._timeout and self._timeout < currenttime():
|
||||||
return self.Status.UNSTABLE, 'timeout after waiting for stable value'
|
status = self.Status.UNSTABLE, 'timeout after waiting for stable value'
|
||||||
if self._moving:
|
else:
|
||||||
return (self.Status.BUSY, 'moving')
|
status = (self.Status.BUSY, 'moving') if self._moving else (self.Status.IDLE, 'stable')
|
||||||
return (self.Status.IDLE, 'stable')
|
self.setFastPoll(self.isBusy(status))
|
||||||
|
return status
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def absmin(self):
|
def absmin(self):
|
||||||
@ -578,7 +579,7 @@ class AnalogOutput(PyTangoDevice, Drivable):
|
|||||||
# do not clear the history here:
|
# do not clear the history here:
|
||||||
# - if the target is not changed by more than precision, there is no need to wait
|
# - if the target is not changed by more than precision, there is no need to wait
|
||||||
# self._history = []
|
# self._history = []
|
||||||
self.read_status() # poll our status to keep it updated
|
self.read_status() # poll our status to keep it updated (this will also set fast poll)
|
||||||
return self.read_target()
|
return self.read_target()
|
||||||
|
|
||||||
def _hw_wait(self):
|
def _hw_wait(self):
|
||||||
@ -850,9 +851,15 @@ class DigitalOutput(PyTangoDevice, Drivable):
|
|||||||
def read_value(self):
|
def read_value(self):
|
||||||
return self._dev.value # mapping is done by datatype upon export()
|
return self._dev.value # mapping is done by datatype upon export()
|
||||||
|
|
||||||
|
def read_status(self):
|
||||||
|
status = self.read_status()
|
||||||
|
self.setFastPoll(self.isBusy(status))
|
||||||
|
return status
|
||||||
|
|
||||||
def write_target(self, value):
|
def write_target(self, value):
|
||||||
self._dev.value = value
|
self._dev.value = value
|
||||||
self.read_value()
|
self.read_value()
|
||||||
|
self.read_status() # this will also set fast poll
|
||||||
return self.read_target()
|
return self.read_target()
|
||||||
|
|
||||||
def read_target(self):
|
def read_target(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user