frappy.client.interactive: improve updates while driving

- instead to show first current 'value' and 'status', and then
  the changes, show changes only - this way updates appear
  in the expected order
- for this SecopClient.register_callback needs a 'callimmediately'
  argument

Change-Id: I3e91c2c15bca7fee2eba3b1bf1dd27313da3ae29
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/36291
Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
This commit is contained in:
zolliker 2025-05-07 14:15:53 +02:00
parent 8f2973c39d
commit b1c920819e
2 changed files with 21 additions and 18 deletions

View File

@ -209,16 +209,20 @@ class ProxyClient:
# caches (module, parameter) = value, timestamp, readerror (internal names!)
self.cache = Cache() # dict returning Cache.undefined for missing keys
def register_callback(self, key, *args, callimmediately=None, **kwds):
def register_callback(self, key, *args, callimmediately=True, **kwds):
"""register callback functions
- key might be either:
several callbacks might be registered within one call.
ProxyClient.CALLBACK_NAMES contains all names of valid callbacks
:param key: might be either:
1) None: general callback (all callbacks)
2) <module name>: callbacks related to a module (not called for 'unhandledMessage')
3) (<module name>, <parameter name>): callback for specified parameter (only called for 'updateEvent')
- all the following arguments are callback functions. The callback name may be
given by the keyword, or, for non-keyworded arguments it is taken from the
__name__ attribute of the function
3) (<module name>, <parameter name>): callback for specified parameter
(only called for 'updateEvent' and 'updateItem')
:param args: callback functions. the callback name is taken from the the __name__ attribute of the function
:param callimmediately: True (default): call immediately for updateItem and updateEvent callbacks
:param kwds: callback functions. the callback name is taken from the key
"""
for cbfunc in args:
kwds[cbfunc.__name__] = cbfunc
@ -226,8 +230,8 @@ class ProxyClient:
if cbname not in self.CALLBACK_NAMES:
raise TypeError(f"unknown callback: {', '.join(kwds)}")
# immediately call for some callback types
if cbname in ('updateItem', 'updateEvent') and callimmediately is not False:
# call immediately for some callback types
if cbname in ('updateItem', 'updateEvent') and callimmediately:
if key is None: # case generic callback
cbargs = [(m, p, d) for (m, p), d in self.cache.items()]
else:

View File

@ -143,7 +143,7 @@ class Module:
def _isBusy(self):
return self.status[0] // 100 == StatusType.BUSY // 100
def _status_value_update(self, m, p, status, t, e):
def _status_update(self, m, p, status, t, e):
if self._is_driving and not self._isBusy():
self._is_driving = False
self._driving_event.set()
@ -216,10 +216,11 @@ class Module:
def __call__(self, target=None):
if target is None:
return self.read()
for pname in 'value', 'status':
watch_params = ['value', 'status']
for pname in watch_params:
self._secnode.register_callback((self._name, pname),
callimmediately=False,
updateEvent=self._watch_parameter)
updateEvent=self._watch_parameter,
callimmediately=False)
self.target = target # this sets self._is_driving
@ -239,11 +240,10 @@ class Module:
pass
clientenv.raise_with_short_traceback(e)
finally:
# self._watch_parameter(self._name, 'status')
self._secnode.readParameter(self._name, 'value')
# self._watch_parameter(self._name, 'value', forced=True)
self._secnode.unregister_callback((self._name, 'value'), updateEvent=self._watch_parameter)
self._secnode.unregister_callback((self._name, 'status'), updateEvent=self._watch_parameter)
for pname in watch_params:
self._secnode.unregister_callback((self._name, pname),
updateEvent=self._watch_parameter)
return self.value
def __repr__(self):
@ -418,8 +418,7 @@ class Client(SecopClient):
attrs[cname] = Command(cname, modname, self)
mobj = type(f'M_{modname}', (Module,), attrs)(modname, self)
if 'status' in mobj._parameters:
self.register_callback((modname, 'status'), updateEvent=mobj._status_value_update)
self.register_callback((modname, 'value'), updateEvent=mobj._status_value_update)
self.register_callback((modname, 'status'), updateEvent=mobj._status_update)
clientenv.namespace[modname] = mobj
if removed_modules:
self.log.info('removed modules: %s', ' '.join(removed_modules))