fix amagnet

Change-Id: I6f1dedd5dfdd10cc828e27ea22440c35a25c2b9d
Reviewed-on: https://forge.frm2.tum.de/review/16790
Tested-by: JenkinsCodeReview <bjoern_pedersen@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Tested-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
This commit is contained in:
Enrico Faulhaber
2017-11-30 10:29:43 +01:00
parent 4cf4ecb507
commit 4b02a4c82e
4 changed files with 35 additions and 50 deletions

View File

@ -134,7 +134,7 @@ variable-rgx=[a-z_][a-zA-Z0-9_]{0,30}$
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
# Good variable names which should always be accepted, separated by a comma # Good variable names which should always be accepted, separated by a comma
good-names=i,j,k,ex,Run,_,a,b,c,d,m,n,u,v,w,x,y,z,e good-names=i,j,k,ex,Run,_,a,b,c,d,m,n,u,v,w,x,y,z,e,CMDS,PARAMS,OVERRIDES,DISPATCHER,PROPERTIES
# Bad variable names which should always be refused, separated by a comma # Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,baz,toto,tutu,tata bad-names=foo,bar,baz,toto,tutu,tata

View File

@ -23,7 +23,7 @@ encoding=secop
[device enable] [device enable]
class=secop_mlz.entangle.NamedDigitalOutput class=secop_mlz.entangle.NamedDigitalOutput
tangodevice='tango://amagnet.antares.frm2:10000/box/plc/_enable' tangodevice='tango://localhost:10000/box/plc/_enable'
value.datatype=["enum", {'On':1,'Off':0}] value.datatype=["enum", {'On':1,'Off':0}]
target.datatype=["enum", {'On':1,'Off':0}] target.datatype=["enum", {'On':1,'Off':0}]
.description='Enables to Output of the Powersupply' .description='Enables to Output of the Powersupply'
@ -31,7 +31,7 @@ target.datatype=["enum", {'On':1,'Off':0}]
[device polarity] [device polarity]
class=secop_mlz.entangle.NamedDigitalOutput class=secop_mlz.entangle.NamedDigitalOutput
tangodevice=tango://amagnet.antares.frm2:10000/box/plc/_polarity tangodevice=tango://localhost:10000/box/plc/_polarity
value.datatype=["enum", {'+1':1,'0':0,'-1':-1}] value.datatype=["enum", {'+1':1,'0':0,'-1':-1}]
target.datatype=["enum", {'+1':1,'0':0,'-1':-1}] target.datatype=["enum", {'+1':1,'0':0,'-1':-1}]
.description=polarity (+/-) switch .description=polarity (+/-) switch
@ -45,7 +45,7 @@ comtries=50
[device symmetry] [device symmetry]
class=secop_mlz.entangle.NamedDigitalOutput class=secop_mlz.entangle.NamedDigitalOutput
tangodevice=tango://amagnet.antares.frm2:10000/box/plc/_symmetric tangodevice=tango://localhost:10000/box/plc/_symmetric
value.datatype=["enum",{'symmetric':1,'short':0, 'asymmetric':-1}] value.datatype=["enum",{'symmetric':1,'short':0, 'asymmetric':-1}]
target.datatype=["enum",{'symmetric':1,'short':0, 'asymmetric':-1}] target.datatype=["enum",{'symmetric':1,'short':0, 'asymmetric':-1}]
.description=par/ser switch selecting (a)symmetric mode .description=par/ser switch selecting (a)symmetric mode
@ -55,35 +55,35 @@ target.datatype=["enum",{'symmetric':1,'short':0, 'asymmetric':-1}]
[device T1] [device T1]
class=secop_mlz.entangle.AnalogInput class=secop_mlz.entangle.AnalogInput
tangodevice=tango://amagnet.antares.frm2:10000/box/plc/_t1 tangodevice=tango://localhost:10000/box/plc/_t1
.description=Temperature1 of the coils system .description=Temperature1 of the coils system
#warnlimits=(0, 50) #warnlimits=(0, 50)
value.unit='degC' value.unit='degC'
[device T2] [device T2]
class=secop_mlz.entangle.AnalogInput class=secop_mlz.entangle.AnalogInput
tangodevice=tango://amagnet.antares.frm2:10000/box/plc/_t2 tangodevice=tango://localhost:10000/box/plc/_t2
.description=Temperature2 of the coils system .description=Temperature2 of the coils system
#warnlimits=(0, 50) #warnlimits=(0, 50)
value.unit='degC' value.unit='degC'
[device T3] [device T3]
class=secop_mlz.entangle.AnalogInput class=secop_mlz.entangle.AnalogInput
tangodevice=tango://amagnet.antares.frm2:10000/box/plc/_t3 tangodevice=tango://localhost:10000/box/plc/_t3
.description=Temperature3 of the coils system .description=Temperature3 of the coils system
#warnlimits=(0, 50) #warnlimits=(0, 50)
value.unit='degC' value.unit='degC'
[device T4] [device T4]
class=secop_mlz.entangle.AnalogInput class=secop_mlz.entangle.AnalogInput
tangodevice=tango://amagnet.antares.frm2:10000/box/plc/_t4 tangodevice=tango://localhost:10000/box/plc/_t4
.description=Temperature4 of the coils system .description=Temperature4 of the coils system
#warnlimits=(0, 50) #warnlimits=(0, 50)
value.unit='degC' value.unit='degC'
[device currentsource] [device currentsource]
class=secop_mlz.entangle.PowerSupply class=secop_mlz.entangle.PowerSupply
tangodevice=tango://amagnet.antares.frm2:10000/box/lambda/curr tangodevice=tango://localhost:10000/box/lambda/curr
.description=Device for the magnet power supply (current mode) .description=Device for the magnet power supply (current mode)
abslimits=(0,200) abslimits=(0,200)
speed=1 speed=1

View File

@ -142,11 +142,11 @@ class OVERRIDE(object):
# storage for CMDs settings (description + call signature...) # storage for CMDs settings (description + call signature...)
class CMD(object): class CMD(object):
def __init__(self, description, arguments=[], result=None): def __init__(self, description, arguments=None, result=None):
# descriptive text for humans # descriptive text for humans
self.description = description self.description = description
# list of datatypes for arguments # list of datatypes for arguments
self.arguments = arguments self.arguments = arguments or []
# datatype for result # datatype for result
self.resulttype = result self.resulttype = result
@ -210,18 +210,16 @@ class ModuleMeta(type):
if rfunc: if rfunc:
self.log.debug("rfunc(%s): call %r" % (pname, rfunc)) self.log.debug("rfunc(%s): call %r" % (pname, rfunc))
value = rfunc(self, maxage) value = rfunc(self, maxage)
setattr(self, pname, value)
return value
else: else:
# return cached value # return cached value
self.log.debug("rfunc(%s): return cached value" % pname) self.log.debug("rfunc(%s): return cached value" % pname)
value = self.PARAMS[pname].value value = self.PARAMS[pname].value
setattr(self, pname, value) setattr(self, pname, value) # important! trigger the setter
return value return value
if rfunc: if rfunc:
wrapped_rfunc.__doc__ = rfunc.__doc__ wrapped_rfunc.__doc__ = rfunc.__doc__
if getattr(rfunc, '__wrapped__', False) == False: if getattr(rfunc, '__wrapped__', False) is False:
setattr(newtype, 'read_' + pname, wrapped_rfunc) setattr(newtype, 'read_' + pname, wrapped_rfunc)
wrapped_rfunc.__wrapped__ = True wrapped_rfunc.__wrapped__ = True
@ -246,7 +244,7 @@ class ModuleMeta(type):
if wfunc: if wfunc:
wrapped_wfunc.__doc__ = wfunc.__doc__ wrapped_wfunc.__doc__ = wfunc.__doc__
if getattr(wfunc, '__wrapped__', False) == False: if getattr(wfunc, '__wrapped__', False) is False:
setattr(newtype, 'write_' + pname, wrapped_wfunc) setattr(newtype, 'write_' + pname, wrapped_wfunc)
wrapped_wfunc.__wrapped__ = True wrapped_wfunc.__wrapped__ = True
@ -268,16 +266,16 @@ class ModuleMeta(type):
# also collect/update information about CMD's # also collect/update information about CMD's
setattr(newtype, 'CMDS', getattr(newtype, 'CMDS', {})) setattr(newtype, 'CMDS', getattr(newtype, 'CMDS', {}))
for name in attrs: for attrname in attrs:
if name.startswith('do_'): if attrname.startswith('do_'):
if name[3:] in newtype.CMDS: if attrname[3:] in newtype.CMDS:
continue continue
value = getattr(newtype, name) value = getattr(newtype, attrname)
if isinstance(value, types.MethodType): if isinstance(value, types.MethodType):
argspec = inspect.getargspec(value) argspec = inspect.getargspec(value)
if argspec[0] and argspec[0][0] == 'self': if argspec[0] and argspec[0][0] == 'self':
del argspec[0][0] del argspec[0][0]
newtype.CMDS[name[3:]] = CMD( newtype.CMDS[attrname[3:]] = CMD(
getattr(value, '__doc__'), argspec.args, getattr(value, '__doc__'), argspec.args,
None) # XXX: how to find resulttype? None) # XXX: how to find resulttype?
attrs['__constructed__'] = True attrs['__constructed__'] = True
@ -400,11 +398,11 @@ class Module(object):
# only check if datatype given # only check if datatype given
try: try:
v = datatype.validate(v) v = datatype.validate(v)
except (ValueError, TypeError) as e: except (ValueError, TypeError):
self.log.exception(formatExtendedStack()) self.log.exception(formatExtendedStack())
raise raise
raise ConfigError('Module %s: config parameter %r:\n%r' % # raise ConfigError('Module %s: config parameter %r:\n%r' %
(self.name, k, e)) # (self.name, k, e))
setattr(self, k, v) setattr(self, k, v)
self._requestLock = threading.RLock() self._requestLock = threading.RLock()
@ -431,7 +429,7 @@ class Readable(Module):
datatype=TupleOf( datatype=TupleOf(
EnumType(**{ EnumType(**{
'IDLE': status.OK, 'IDLE': status.OK,
# 'BUSY': status.BUSY, 'BUSY': status.BUSY,
'WARN': status.WARN, 'WARN': status.WARN,
'UNSTABLE': status.UNSTABLE, 'UNSTABLE': status.UNSTABLE,
'ERROR': status.ERROR, 'ERROR': status.ERROR,
@ -475,7 +473,7 @@ class Readable(Module):
# status was already polled above # status was already polled above
continue continue
if ((int(pobj.poll) < 0) and fastpoll) or ( if ((int(pobj.poll) < 0) and fastpoll) or (
0 == nr % abs(int(pobj.poll))): nr % abs(int(pobj.poll))) == 0:
# poll always if pobj.poll is negative and fastpoll (i.e. Module is busy) # poll always if pobj.poll is negative and fastpoll (i.e. Module is busy)
# otherwise poll every 'pobj.poll' iteration # otherwise poll every 'pobj.poll' iteration
rfunc = getattr(self, 'read_' + pname, None) rfunc = getattr(self, 'read_' + pname, None)
@ -511,18 +509,6 @@ class Drivable(Writable):
Also status gets extended with a BUSY state indicating a running action. Also status gets extended with a BUSY state indicating a running action.
""" """
OVERRIDES = {
"status" : OVERRIDE(datatype=TupleOf(
EnumType(**{
'IDLE': status.OK,
'BUSY': status.BUSY,
'WARN': status.WARN,
'UNSTABLE': status.UNSTABLE,
'ERROR': status.ERROR,
'UNKNOWN': status.UNKNOWN
}), StringType())),
}
def do_stop(self): def do_stop(self):
"""default implementation of the stop command """default implementation of the stop command
@ -536,7 +522,7 @@ class Communicator(Module):
""" """
CMDS = { CMDS = {
"communicate" : CMD("provides the simplest mean to communication", "communicate" : CMD("provides the simplest mean to communication",
arguments=[StringType()], arguments=[StringType()],
result=StringType() result=StringType()
), ),

View File

@ -28,12 +28,11 @@ Supporting classes for FRM2 magnets, currently only Garfield (amagnet).
import math import math
from secop.lib import lazy_property, mkthread
from secop.lib.sequence import SequencerMixin, Step from secop.lib.sequence import SequencerMixin, Step
from secop.protocol import status from secop.protocol import status
from secop.datatypes import * from secop.datatypes import StringType, TupleOf, FloatRange, ArrayOf, StructOf
from secop.errors import SECoPServerError, ConfigError, ProgrammingError, CommunicationError, HardwareError, DisabledError from secop.errors import DisabledError, ConfigError
from secop.modules import PARAM, CMD, OVERRIDE, Readable, Drivable from secop.modules import PARAM, Drivable
class GarfieldMagnet(SequencerMixin, Drivable): class GarfieldMagnet(SequencerMixin, Drivable):
@ -132,7 +131,7 @@ class GarfieldMagnet(SequencerMixin, Drivable):
trycurr = (maxcurr - mincurr) * ratio + mincurr trycurr = (maxcurr - mincurr) * ratio + mincurr
self.log.debug('current for %g T is %g A', field, trycurr) self.log.debug('current for %g T is %g A', field, trycurr)
return trycurr # interpolated return trycurr # interpolated
raise ConfigurationError(self, raise ConfigError(self,
'_current2field polynome not monotonic!') '_current2field polynome not monotonic!')
def init(self): def init(self):
@ -195,6 +194,7 @@ class GarfieldMagnet(SequencerMixin, Drivable):
def _set_field_polarity(self, polarity): def _set_field_polarity(self, polarity):
current_pol = self._get_field_polarity() current_pol = self._get_field_polarity()
polarity = int(polarity)
if current_pol == polarity: if current_pol == polarity:
return return
if polarity == 0: if polarity == 0:
@ -202,7 +202,7 @@ class GarfieldMagnet(SequencerMixin, Drivable):
if current_pol == 0: if current_pol == 0:
# safe to switch # safe to switch
self._polswitch.write_target( self._polswitch.write_target(
'+1' if polarity == 1 else str(polarity)) '+1' if polarity > 0 else str(polarity))
return 0 return 0
if self._currentsource.value < 0.1: if self._currentsource.value < 0.1:
self._polswitch.write_target('0') self._polswitch.write_target('0')
@ -222,8 +222,7 @@ class GarfieldMagnet(SequencerMixin, Drivable):
if self._enable.read_status(maxage)[0] != status.OK: if self._enable.read_status(maxage)[0] != status.OK:
return self._enable.status return self._enable.status
if self._polswitch.value in ['0', 0]: if self._polswitch.value in ['0', 0]:
return self._currentsource.status[ return status.OK, 'Shorted, ' + self._currentsource.status[1]
0], 'Shorted, ' + self._currentsource.status[1]
if self._symmetry.value in ['short', 0]: if self._symmetry.value in ['short', 0]:
return self._currentsource.status[ return self._currentsource.status[
0], 'Shorted, ' + self._currentsource.status[1] 0], 'Shorted, ' + self._currentsource.status[1]
@ -236,7 +235,7 @@ class GarfieldMagnet(SequencerMixin, Drivable):
wanted_current = self._field2current(abs(target)) wanted_current = self._field2current(abs(target))
wanted_polarity = -1 if target < 0 else (+1 if target else 0) wanted_polarity = -1 if target < 0 else (+1 if target else 0)
current_polarity = self._get_field_polarity() current_polarity = int(self._get_field_polarity())
# generate Step sequence and start it # generate Step sequence and start it
seq = [] seq = []
@ -320,7 +319,7 @@ class GarfieldMagnet(SequencerMixin, Drivable):
def _set_polarity(self, store, target): def _set_polarity(self, store, target):
if self._polswitch.read_status(0)[0] == status.BUSY: if self._polswitch.read_status(0)[0] == status.BUSY:
return True return True
if self._polswitch.value == target: if int(self._polswitch.value) == int(target):
return False # done with this step return False # done with this step
if self._polswitch.read_value(0) != 0: if self._polswitch.read_value(0) != 0:
self._polswitch.write_target(0) self._polswitch.write_target(0)