add a hook for reads to be done initially

inital reads from HW should be done in the thread started by
startModule, not in startModule itself.

- add a hook method 'initialReads' for this
+ add doc for init methods
+ fix some errors in doc

Change-Id: I914e3b7ee05050eea1ee8aff3461030adf08a461
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/31374
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:
2023-06-19 08:59:31 +02:00
parent 2feff36077
commit f7129f6a00
7 changed files with 96 additions and 31 deletions

View File

@@ -1163,9 +1163,9 @@ class ValueType(DataType):
The optional (callable) validator can be used to restrict values to a
certain type.
For example using `ValueType(dict)` would ensure only values that can be
For example using ``ValueType(dict)`` would ensure only values that can be
turned into a dictionary can be used in this instance, as the conversion
`dict(value)` is called for validation.
``dict(value)`` is called for validation.
Notes:
The validator must either accept a value by returning it or the converted value,

View File

@@ -63,12 +63,15 @@ class SECoPError(RuntimeError):
"""format with info about raising methods
:param stripped: strip last method.
Use stripped=True (or str()) for the following cases, as the last method can be derived from the context:
- stored in pobj.readerror: read_<pobj.name>
- error message from a change command: write_<pname>
- error message from a read command: read_<pname>
Use stripped=False for the log file, as the related parameter is not known
:return: the formatted error message
Use stripped=True (or str()) for the following cases, as the last method can be derived from the context:
- stored in pobj.readerror: read_<pobj.name>
- error message from a change command: write_<pname>
- error message from a read command: read_<pname>
Use stripped=False for the log file, as the related parameter is not known
"""
mlist = self.raising_methods
if mlist and stripped:

View File

@@ -629,6 +629,16 @@ class Module(HasAccessibles):
mkthread(self.__pollThread, self.polledModules, start_events.get_trigger())
self.startModuleDone = True
def initialReads(self):
"""initial reads to be done
override to read initial values from HW, when it is not desired
to poll them afterwards
called from the poll thread, after writeInitParams but before
all parameters are polled once
"""
def doPoll(self):
"""polls important parameters like value and status
@@ -678,15 +688,10 @@ class Module(HasAccessibles):
before polling, parameters which need hardware initialisation are written
"""
for mobj in modules:
mobj.writeInitParams()
modules = [m for m in modules if m.enablePoll]
if not modules: # no polls needed - exit thread
started_callback()
return
polled_modules = [m for m in modules if m.enablePoll]
if hasattr(self, 'registerReconnectCallback'):
# self is a communicator supporting reconnections
def trigger_all(trg=self.triggerPoll, polled_modules=modules):
def trigger_all(trg=self.triggerPoll, polled_modules=polled_modules):
for m in polled_modules:
m.pollInfo.last_main = 0
m.pollInfo.last_slow = 0
@@ -694,7 +699,7 @@ class Module(HasAccessibles):
self.registerReconnectCallback('trigger_polls', trigger_all)
# collect all read functions
for mobj in modules:
for mobj in polled_modules:
pinfo = mobj.pollInfo = PollInfo(mobj.pollinterval, self.triggerPoll)
# trigger a poll interval change when self.pollinterval changes.
if 'pollinterval' in mobj.valueCallbacks:
@@ -704,17 +709,32 @@ class Module(HasAccessibles):
rfunc = getattr(mobj, 'read_' + pname)
if rfunc.poll:
pinfo.polled_parameters.append((mobj, rfunc, pobj))
# call all read functions a first time
try:
for m in modules:
for mobj, rfunc, _ in m.pollInfo.polled_parameters:
mobj.callPollFunc(rfunc, raise_com_failed=True)
except CommunicationFailedError as e:
# when communication failed, probably all parameters and may be more modules are affected.
# as this would take a lot of time (summed up timeouts), we do not continue
# trying and let the server accept connections, further polls might success later
self.log.error('communication failure on startup: %s', e)
started_callback()
while True:
try:
for mobj in modules:
# TODO when needed: here we might add a call to a method :meth:`beforeWriteInit`
mobj.writeInitParams()
mobj.initialReads()
# call all read functions a first time
for m in polled_modules:
for mobj, rfunc, _ in m.pollInfo.polled_parameters:
mobj.callPollFunc(rfunc, raise_com_failed=True)
# TODO when needed: here we might add calls to a method :meth:`afterInitPolls`
break
except CommunicationFailedError as e:
# when communication failed, probably all parameters and may be more modules are affected.
# as this would take a lot of time (summed up timeouts), we do not continue
# trying and let the server accept connections, further polls might success later
if started_callback:
self.log.error('communication failure on startup: %s', e)
started_callback()
started_callback = None
self.triggerPoll.wait(0.1) # wait for reconnection or max 10 sec.
break
if started_callback:
started_callback()
if not polled_modules: # no polls needed - exit thread
return
to_poll = ()
while True:
now = time.time()