diff --git a/secop/iohandler.py b/secop/iohandler.py index f6ff2c3..e88dba7 100644 --- a/secop/iohandler.py +++ b/secop/iohandler.py @@ -49,9 +49,8 @@ def change_(self, change): # which will be formatted by the handler, or None. The latter is used only in some # special cases, when nothing has to be written. -A write_ method may be implemented in addition. In that case, it is executed -before change_. write_ may return None or Done, in these cases -change_ is not called. +A write_ method may be implemented in addition. In that case, the handlers write +method has to be called explicitly int the write_ method, if needed. """ import re @@ -263,6 +262,8 @@ class IOHandler(IOHandlerBase): if self._module_class != modclass: raise ProgrammingError("the handler '%s' for '%s.%s' is already used in module '%s'" % (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.analyze = getattr(modclass, 'analyze_' + self.group) return self.read @@ -295,7 +296,6 @@ class IOHandler(IOHandlerBase): If pre_wfunc is given, it is to be called before change_. 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): hdl.write(module, pname, value) diff --git a/secop/metaclass.py b/secop/metaclass.py index b67b2fc..548c121 100644 --- a/secop/metaclass.py +++ b/secop/metaclass.py @@ -165,29 +165,27 @@ class ModuleMeta(PropertyMeta): if not pobj.readonly: wfunc = attrs.get('write_' + pname, None) - for base in bases: - if wfunc is not None: - break - wfunc = getattr(base, '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: + if wfunc is not None: + break + wfunc = getattr(base, 'write_' + pname, None) # create wrapper except when write function is already wrapped if wfunc is None or getattr(wfunc, '__wrapped__', False) is False: - # append write function from handler, to be called after wfunc - wfuncs = (wfunc, pobj.handler.get_write_func(pname) if pobj.handler else None) - - def wrapped_wfunc(self, value, pname=pname, wfuncs=wfuncs): + def wrapped_wfunc(self, value, pname=pname, wfunc=wfunc): self.log.debug("check validity of %s = %r" % (pname, value)) pobj = self.accessibles[pname] value = pobj.datatype(value) - for wfunc in filter(None, wfuncs): + if wfunc: self.log.debug('calling %s %r(%r)' % (wfunc.__name__, wfunc, value)) returned_value = wfunc(self, value) if returned_value is Done: # the setter is already triggered return getattr(self, pname) - if returned_value is None: # goodie: accept missing return value - break # handler is not called in this case - value = returned_value + if returned_value is not None: # goodie: accept missing return value + value = returned_value setattr(self, pname, value) return value diff --git a/secop_psi/ppms.py b/secop_psi/ppms.py index 05f41d0..3c596ba 100755 --- a/secop_psi/ppms.py +++ b/secop_psi/ppms.py @@ -49,6 +49,7 @@ from secop.metaclass import Done try: import secop_psi.ppmswindows as ppmshw except ImportError: + print('use simulation instead') import secop_psi.ppmssim as ppmshw @@ -231,7 +232,7 @@ class DriverChannel(Channel): return dict(current=current, powerlimit=powerlimit) def change_drvout(self, change): - self.readValues() + change.readValues() return change.current, change.powerlimit @@ -274,7 +275,7 @@ class BridgeChannel(Channel): ) def change_bridge(self, change): - self.readValues() + change.readValues() if change.enabled: return self.no, change.excitation, change.powerlimit, change.dcflag, change.readingmode, change.voltagelimit 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 = [self.Status.BUSY, 'changed target'] self._last_change = time.time() - return target + self.temp.write(self, 'target', target) + return Done def write_approachmode(self, value): if self.isDriving(): - return value - return None # change_temp will not be called, as this would trigger an unnecessary T change + self.temp.write(self, 'approachmode', value) + return Done + return None # do not execute TEMP command, as this would trigger an unnecessary T change def write_ramp(self, value): if self.isDriving(): - return value - return None # change_temp will not be called, as this would trigger an unnecessary T change + self.temp.write(self, 'ramp', value) + return Done + return None # do not execute TEMP command, as this would trigger an unnecessary T change def calc_expected(self, target, 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._last_change = time.time() self.status = [self.Status.BUSY, 'changed target'] - return target + self.field.write(self, 'target', target) + return Done def write_persistentmode(self, mode): 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._stopped = False self.status = [self.Status.BUSY, 'changed persistent mode'] - return mode + self.field.write(self, 'persistentmode', mode) + return Done def write_ramp(self, value): if self.isDriving(): - return value - return None # change_field will not be called, as this would trigger a ramp up of leads current + self.field.write(self, 'ramp', value) + return Done + return None # do not execute FIELD command, as this would trigger a ramp up of leads current def write_approachmode(self, value): if self.isDriving(): - return value - return None # change_temp will not be called, as this would trigger a ramp up of leads current + self.field.write(self, 'approachmode', value) + return Done + return None # do not execute FIELD command, as this would trigger a ramp up of leads current def do_stop(self): if not self.isDriving(): @@ -750,12 +758,14 @@ class Position(PpmsMixin, Drivable): self._stopped = False self._last_change = 0 self._status_before_change = self.status - return target + self.move.write(self, 'target', target) + return Done def write_speed(self, value): if self.isDriving(): - return value - return None # change_move not called as this would trigger an unnecessary move + self.move.write(self, 'speed', value) + return Done + return None # do not execute MOVE command, as this would trigger an unnecessary move def do_stop(self): if not self.isDriving():