adjust mechanism of write function with iohandler
if a write_<parameter> function is defined and <parameter> has an iohandler, the handlers write function is not called automatically. It has to be called explicitly in the write_<param> function, if needed. reasons: - the previous logic when a wrapped write function is already present, and a handler is defined on the specialized class, did not work, and is not easy to solve properly - it is probably anyway better to call the handlers write function explicitly instead of automatically depending on the return value Change-Id: I04f0849b6cc3fb9979c0f5ac8245a6ab4bf23072 Reviewed-on: https://forge.frm2.tum.de/review/c/sine2020/secop/playground/+/22565 Tested-by: JenkinsCodeReview <bjoern_pedersen@frm2.tum.de> Reviewed-by: Markus Zolliker <markus.zolliker@psi.ch>
This commit is contained in:
parent
4ed8cf5901
commit
ed12e2ed93
@ -49,9 +49,8 @@ def change_<group>(self, change):
|
|||||||
# which will be formatted by the handler, or None. The latter is used only in some
|
# which will be formatted by the handler, or None. The latter is used only in some
|
||||||
# special cases, when nothing has to be written.
|
# special cases, when nothing has to be written.
|
||||||
|
|
||||||
A write_<parameter> method may be implemented in addition. In that case, it is executed
|
A write_<parameter> method may be implemented in addition. In that case, the handlers write
|
||||||
before change_<group>. write_<parameters> may return None or Done, in these cases
|
method has to be called explicitly int the write_<parameter> method, if needed.
|
||||||
change_<group> is not called.
|
|
||||||
"""
|
"""
|
||||||
import re
|
import re
|
||||||
|
|
||||||
@ -263,6 +262,8 @@ class IOHandler(IOHandlerBase):
|
|||||||
if self._module_class != modclass:
|
if self._module_class != modclass:
|
||||||
raise ProgrammingError("the handler '%s' for '%s.%s' is already used in module '%s'"
|
raise ProgrammingError("the handler '%s' for '%s.%s' is already used in module '%s'"
|
||||||
% (self.group, modclass.__name__, pname, self._module_class.__name__))
|
% (self.group, modclass.__name__, pname, self._module_class.__name__))
|
||||||
|
# self.change might be needed even when get_write_func was not called
|
||||||
|
self.change = getattr(self._module_class, 'change_' + self.group, None)
|
||||||
self.parameters.add(pname)
|
self.parameters.add(pname)
|
||||||
self.analyze = getattr(modclass, 'analyze_' + self.group)
|
self.analyze = getattr(modclass, 'analyze_' + self.group)
|
||||||
return self.read
|
return self.read
|
||||||
@ -295,7 +296,6 @@ class IOHandler(IOHandlerBase):
|
|||||||
If pre_wfunc is given, it is to be called before change_<group>.
|
If pre_wfunc is given, it is to be called before change_<group>.
|
||||||
May be overriden to return None, if not used
|
May be overriden to return None, if not used
|
||||||
"""
|
"""
|
||||||
self.change = getattr(self._module_class, 'change_' + self.group)
|
|
||||||
|
|
||||||
def wfunc(module, value, hdl=self, pname=pname):
|
def wfunc(module, value, hdl=self, pname=pname):
|
||||||
hdl.write(module, pname, value)
|
hdl.write(module, pname, value)
|
||||||
|
@ -165,6 +165,8 @@ class ModuleMeta(PropertyMeta):
|
|||||||
|
|
||||||
if not pobj.readonly:
|
if not pobj.readonly:
|
||||||
wfunc = attrs.get('write_' + pname, None)
|
wfunc = attrs.get('write_' + pname, None)
|
||||||
|
if wfunc is None: # ignore the handler, if a write function is present
|
||||||
|
wfunc = pobj.handler.get_write_func(pname) if pobj.handler else None
|
||||||
for base in bases:
|
for base in bases:
|
||||||
if wfunc is not None:
|
if wfunc is not None:
|
||||||
break
|
break
|
||||||
@ -173,20 +175,16 @@ class ModuleMeta(PropertyMeta):
|
|||||||
# create wrapper except when write function is already wrapped
|
# create wrapper except when write function is already wrapped
|
||||||
if wfunc is None or getattr(wfunc, '__wrapped__', False) is False:
|
if wfunc is None or getattr(wfunc, '__wrapped__', False) is False:
|
||||||
|
|
||||||
# append write function from handler, to be called after wfunc
|
def wrapped_wfunc(self, value, pname=pname, wfunc=wfunc):
|
||||||
wfuncs = (wfunc, pobj.handler.get_write_func(pname) if pobj.handler else None)
|
|
||||||
|
|
||||||
def wrapped_wfunc(self, value, pname=pname, wfuncs=wfuncs):
|
|
||||||
self.log.debug("check validity of %s = %r" % (pname, value))
|
self.log.debug("check validity of %s = %r" % (pname, value))
|
||||||
pobj = self.accessibles[pname]
|
pobj = self.accessibles[pname]
|
||||||
value = pobj.datatype(value)
|
value = pobj.datatype(value)
|
||||||
for wfunc in filter(None, wfuncs):
|
if wfunc:
|
||||||
self.log.debug('calling %s %r(%r)' % (wfunc.__name__, wfunc, value))
|
self.log.debug('calling %s %r(%r)' % (wfunc.__name__, wfunc, value))
|
||||||
returned_value = wfunc(self, value)
|
returned_value = wfunc(self, value)
|
||||||
if returned_value is Done: # the setter is already triggered
|
if returned_value is Done: # the setter is already triggered
|
||||||
return getattr(self, pname)
|
return getattr(self, pname)
|
||||||
if returned_value is None: # goodie: accept missing return value
|
if returned_value is not None: # goodie: accept missing return value
|
||||||
break # handler is not called in this case
|
|
||||||
value = returned_value
|
value = returned_value
|
||||||
setattr(self, pname, value)
|
setattr(self, pname, value)
|
||||||
return value
|
return value
|
||||||
|
@ -49,6 +49,7 @@ from secop.metaclass import Done
|
|||||||
try:
|
try:
|
||||||
import secop_psi.ppmswindows as ppmshw
|
import secop_psi.ppmswindows as ppmshw
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
print('use simulation instead')
|
||||||
import secop_psi.ppmssim as ppmshw
|
import secop_psi.ppmssim as ppmshw
|
||||||
|
|
||||||
|
|
||||||
@ -231,7 +232,7 @@ class DriverChannel(Channel):
|
|||||||
return dict(current=current, powerlimit=powerlimit)
|
return dict(current=current, powerlimit=powerlimit)
|
||||||
|
|
||||||
def change_drvout(self, change):
|
def change_drvout(self, change):
|
||||||
self.readValues()
|
change.readValues()
|
||||||
return change.current, change.powerlimit
|
return change.current, change.powerlimit
|
||||||
|
|
||||||
|
|
||||||
@ -274,7 +275,7 @@ class BridgeChannel(Channel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def change_bridge(self, change):
|
def change_bridge(self, change):
|
||||||
self.readValues()
|
change.readValues()
|
||||||
if change.enabled:
|
if change.enabled:
|
||||||
return self.no, change.excitation, change.powerlimit, change.dcflag, change.readingmode, change.voltagelimit
|
return self.no, change.excitation, change.powerlimit, change.dcflag, change.readingmode, change.voltagelimit
|
||||||
return self.no, 0, 0, change.dcflag, change.readingmode, 0
|
return self.no, 0, 0, change.dcflag, change.readingmode, 0
|
||||||
@ -504,17 +505,20 @@ class Temp(PpmsMixin, Drivable):
|
|||||||
self._status_before_change = self.status
|
self._status_before_change = self.status
|
||||||
self.status = [self.Status.BUSY, 'changed target']
|
self.status = [self.Status.BUSY, 'changed target']
|
||||||
self._last_change = time.time()
|
self._last_change = time.time()
|
||||||
return target
|
self.temp.write(self, 'target', target)
|
||||||
|
return Done
|
||||||
|
|
||||||
def write_approachmode(self, value):
|
def write_approachmode(self, value):
|
||||||
if self.isDriving():
|
if self.isDriving():
|
||||||
return value
|
self.temp.write(self, 'approachmode', value)
|
||||||
return None # change_temp will not be called, as this would trigger an unnecessary T change
|
return Done
|
||||||
|
return None # do not execute TEMP command, as this would trigger an unnecessary T change
|
||||||
|
|
||||||
def write_ramp(self, value):
|
def write_ramp(self, value):
|
||||||
if self.isDriving():
|
if self.isDriving():
|
||||||
return value
|
self.temp.write(self, 'ramp', value)
|
||||||
return None # change_temp will not be called, as this would trigger an unnecessary T change
|
return Done
|
||||||
|
return None # do not execute TEMP command, as this would trigger an unnecessary T change
|
||||||
|
|
||||||
def calc_expected(self, target, ramp):
|
def calc_expected(self, target, ramp):
|
||||||
self._expected_target_time = time.time() + abs(target - self.value) * 60.0 / max(0.1, ramp)
|
self._expected_target_time = time.time() + abs(target - self.value) * 60.0 / max(0.1, ramp)
|
||||||
@ -638,7 +642,8 @@ class Field(PpmsMixin, Drivable):
|
|||||||
self._stopped = False
|
self._stopped = False
|
||||||
self._last_change = time.time()
|
self._last_change = time.time()
|
||||||
self.status = [self.Status.BUSY, 'changed target']
|
self.status = [self.Status.BUSY, 'changed target']
|
||||||
return target
|
self.field.write(self, 'target', target)
|
||||||
|
return Done
|
||||||
|
|
||||||
def write_persistentmode(self, mode):
|
def write_persistentmode(self, mode):
|
||||||
if abs(self.target - self.value) <= 2e-5 and mode == self.persistentmode:
|
if abs(self.target - self.value) <= 2e-5 and mode == self.persistentmode:
|
||||||
@ -647,17 +652,20 @@ class Field(PpmsMixin, Drivable):
|
|||||||
self._status_before_change = list(self.status)
|
self._status_before_change = list(self.status)
|
||||||
self._stopped = False
|
self._stopped = False
|
||||||
self.status = [self.Status.BUSY, 'changed persistent mode']
|
self.status = [self.Status.BUSY, 'changed persistent mode']
|
||||||
return mode
|
self.field.write(self, 'persistentmode', mode)
|
||||||
|
return Done
|
||||||
|
|
||||||
def write_ramp(self, value):
|
def write_ramp(self, value):
|
||||||
if self.isDriving():
|
if self.isDriving():
|
||||||
return value
|
self.field.write(self, 'ramp', value)
|
||||||
return None # change_field will not be called, as this would trigger a ramp up of leads current
|
return Done
|
||||||
|
return None # do not execute FIELD command, as this would trigger a ramp up of leads current
|
||||||
|
|
||||||
def write_approachmode(self, value):
|
def write_approachmode(self, value):
|
||||||
if self.isDriving():
|
if self.isDriving():
|
||||||
return value
|
self.field.write(self, 'approachmode', value)
|
||||||
return None # change_temp will not be called, as this would trigger a ramp up of leads current
|
return Done
|
||||||
|
return None # do not execute FIELD command, as this would trigger a ramp up of leads current
|
||||||
|
|
||||||
def do_stop(self):
|
def do_stop(self):
|
||||||
if not self.isDriving():
|
if not self.isDriving():
|
||||||
@ -750,12 +758,14 @@ class Position(PpmsMixin, Drivable):
|
|||||||
self._stopped = False
|
self._stopped = False
|
||||||
self._last_change = 0
|
self._last_change = 0
|
||||||
self._status_before_change = self.status
|
self._status_before_change = self.status
|
||||||
return target
|
self.move.write(self, 'target', target)
|
||||||
|
return Done
|
||||||
|
|
||||||
def write_speed(self, value):
|
def write_speed(self, value):
|
||||||
if self.isDriving():
|
if self.isDriving():
|
||||||
return value
|
self.move.write(self, 'speed', value)
|
||||||
return None # change_move not called as this would trigger an unnecessary move
|
return Done
|
||||||
|
return None # do not execute MOVE command, as this would trigger an unnecessary move
|
||||||
|
|
||||||
def do_stop(self):
|
def do_stop(self):
|
||||||
if not self.isDriving():
|
if not self.isDriving():
|
||||||
|
Loading…
x
Reference in New Issue
Block a user