diff --git a/cfg/ccr12.cfg b/cfg/ccr.cfg similarity index 65% rename from cfg/ccr12.cfg rename to cfg/ccr.cfg index 4f65e0e..8c56f02 100644 --- a/cfg/ccr12.cfg +++ b/cfg/ccr.cfg @@ -1,5 +1,5 @@ [node MLZ_ccr12] -description = CCR12 box of MLZ Sample environment group +description = CCR box of MLZ Sample environment group . Contains a Lakeshore 336 and an PLC controlling the compressor and some valves. @@ -14,58 +14,86 @@ bindport=10767 class=secop_mlz.entangle.NamedDigitalOutput tangodevice=tango://localhost:10000/box/plc/_automatik mapping=dict(Off=0,p1=1,p2=2) +description="controls the (simple) pressure regulation + . + selects between off, regulate on p1 or regulate on p2 sensor" [module compressor] class=secop_mlz.entangle.NamedDigitalOutput tangodevice=tango://localhost:10000/box/plc/_cooler_onoff mapping=dict(Off=0,On=1) +description=control the compressor (on/off) [module gas] class=secop_mlz.entangle.NamedDigitalOutput tangodevice=tango://localhost:10000/box/plc/_gas_onoff mapping=dict(Off=0,On=1) +description=control the gas inlet into the ccr (on/off) + . + note: this switches off automatically after 15 min. + note: activation de-activates the vacuum inlet + note: if the pressure regulation is active, it enslave this device [module vacuum] class=secop_mlz.entangle.NamedDigitalOutput tangodevice=tango://localhost:10000/box/plc/_vacuum_Onoff mapping=dict(Off=0,On=1) +description=control the vacuum inlet into the ccr (on/off) + . + note: activation de-activates the gas inlet + note: if the pressure regulation is active, it enslave this device [module p1] class=secop_mlz.entangle.AnalogInput tangodevice=tango://localhost:10000/box/plc/_p1 value.unit='mbar' +description=pressure sensor 1 (linear scale) [module p2] class=secop_mlz.entangle.AnalogInput tangodevice=tango://localhost:10000/box/plc/_p2 value.unit='mbar' +description=pressure sensor 2 (selectable curve) [module curve_p2] class=secop_mlz.entangle.NamedDigitalInput tangodevice=tango://localhost:10000/box/plc/_curve -value.default='undefined' -mapping=dict(curve1=1,curve2=2,curve3=3) +value.default=0 +description=calibration curve for pressure sensor 2 +mapping="{'0-10V':0, '0-1000mbar':1, '1-9V to 0-1 mbar':2, + 'DI200':3, 'DI2000':4, 'TTR100':7, 'PTR90':8, + 'PTR225/237':9, 'ITR90':10, 'ITR100-D':11, + 'ITR100-2':12, 'ITR100-3':13, 'ITR100-4':14, + 'ITR100-5':15, 'ITR100-6':16, 'ITR100-7':17, + 'ITR100-8':18, 'ITR100-9':19, 'ITR100-A':20, + 'CMR361':21, 'CMR362':22, 'CMR363':23, + 'CMR364':24, 'CMR365':25}" # sensors [module T_sample] class=secop_mlz.entangle.Sensor tangodevice=tango://localhost:10000/box/sample/sensora value.unit='K' +description=sample temperature [module T_stick] class=secop_mlz.entangle.Sensor tangodevice=tango://localhost:10000/box/stick/sensorb value.unit='K' +description=temperature at bottom of sample stick [module T_coldhead] class=secop_mlz.entangle.Sensor tangodevice=tango://localhost:10000/box/coldhead/sensorc value.unit='K' +description=temperature at coldhead [module T_tube] class=secop_mlz.entangle.Sensor tangodevice=tango://localhost:10000/box/tube/sensord value.unit='K' +description=temperature at thermal coupling tube <-> stick + # regulations @@ -73,6 +101,7 @@ value.unit='K' class=secop_mlz.entangle.TemperatureController tangodevice=tango://localhost:10000/box/stick/control2 heateroutput.default=0 +description=regulation of stick temperature ramp.default=6 speed.default=0.1 setpoint.default=0 @@ -89,11 +118,13 @@ class=secop_mlz.entangle.AnalogOutput tangodevice=tango://localhost:10000/box/stick/range2 precision.default=1 abslimits=(0,3) +description=heaterrange for stick regulation [module T_tube_regulation] class=secop_mlz.entangle.TemperatureController tangodevice=tango://localhost:10000/box/tube/control1 +description=regulation of tube temperature heateroutput.default=0 ramp.default=6 speed.default=0.1 @@ -116,4 +147,4 @@ value.unit='K' class=secop_mlz.entangle.NamedDigitalOutput tangodevice=tango://localhost:10000/box/tube/range1 mapping=dict(Off=0, Low=1, Medium=2, High=3) - +description=heaterrange for tube regulation diff --git a/secop/datatypes.py b/secop/datatypes.py index 727b5d3..0662325 100644 --- a/secop/datatypes.py +++ b/secop/datatypes.py @@ -26,10 +26,10 @@ import sys -import math from base64 import b64decode, b64encode from secop.errors import ProgrammingError, ProtocolError, BadValueError, ConfigError +from secop.lib import clamp from secop.lib.enum import Enum from secop.parse import Parser from secop.properties import HasProperties, Property @@ -160,8 +160,8 @@ class Stub(DataType): class FloatRange(DataType): """Restricted float type""" properties = { - 'min': Property('low limit', Stub('FloatRange'), extname='min', default=float('-inf')), - 'max': Property('high limit', Stub('FloatRange'), extname='max', default=float('+inf')), + 'min': Property('low limit', Stub('FloatRange'), extname='min', default=-sys.float_info.max), + 'max': Property('high limit', Stub('FloatRange'), extname='max', default=sys.float_info.max), 'unit': Property('physical unit', Stub('StringType'), extname='unit', default=''), 'fmtstr': Property('format string', Stub('StringType'), extname='fmtstr', default='%g'), 'absolute_resolution': Property('absolute resolution', Stub('FloatRange', 0), @@ -172,10 +172,8 @@ class FloatRange(DataType): def __init__(self, minval=None, maxval=None, **kwds): super().__init__() - if minval is not None: - kwds['min'] = minval - if maxval is not None: - kwds['max'] = maxval + kwds['min'] = minval if minval is not None else -sys.float_info.max + kwds['max'] = maxval if maxval is not None else sys.float_info.max self.set_properties(**kwds) def checkProperties(self): @@ -192,9 +190,10 @@ class FloatRange(DataType): value = float(value) except Exception: raise BadValueError('Can not __call__ %r to float' % value) - if math.isinf(value): - raise BadValueError('FloatRange does not accept infinity') + # map +/-infty to +/-max possible number + value = clamp(-sys.float_info.max, value, sys.float_info.max) + # now check the limits prec = max(abs(value * self.relative_resolution), self.absolute_resolution) if self.min - prec <= value <= self.max + prec: return min(max(value, self.min), self.max) diff --git a/secop_mlz/entangle.py b/secop_mlz/entangle.py index 8485feb..6ed1bb1 100644 --- a/secop_mlz/entangle.py +++ b/secop_mlz/entangle.py @@ -36,7 +36,7 @@ from time import sleep import PyTango from secop.datatypes import ArrayOf, EnumType, \ - FloatRange, IntRange, StringType, TupleOf + FloatRange, IntRange, StringType, TupleOf, LimitsType from secop.errors import CommunicationFailedError, \ ConfigError, HardwareError, ProgrammingError from secop.lib import lazy_property @@ -429,30 +429,26 @@ class AnalogOutput(PyTangoDevice, Drivable): parameters = { 'userlimits': Parameter('User defined limits of device value', - datatype=TupleOf(FloatRange(), FloatRange()), + datatype=LimitsType(FloatRange(unit='$')), default=(float('-Inf'), float('+Inf')), - unit='main', readonly=False, poll=10, + readonly=False, poll=10, ), 'abslimits': Parameter('Absolute limits of device value', - datatype=TupleOf(FloatRange(), FloatRange()), - unit='main', + datatype=LimitsType(FloatRange(unit='$')), ), 'precision': Parameter('Precision of the device value (allowed deviation ' 'of stable values from target)', - unit='main', datatype=FloatRange(1e-38), + datatype=FloatRange(1e-38, unit='$'), readonly=False, group='stability', ), 'window': Parameter('Time window for checking stabilization if > 0', - unit='s', default=60.0, readonly=False, - datatype=FloatRange(0, 900), group='stability', - ), + default=60.0, readonly=False, + datatype=FloatRange(0, 900, unit='s'), group='stability', + ), 'timeout': Parameter('Timeout for waiting for a stable value (if > 0)', - unit='s', default=60.0, readonly=False, - datatype=FloatRange(0, 900), group='stability', - ), - } - commands = { - 'stop': Command('Stops current movement.', argument=None, result=None), + default=60.0, readonly=False, + datatype=FloatRange(0, 900, unit='s'), group='stability', + ), } _history = () _timeout = None @@ -607,12 +603,12 @@ class Actuator(AnalogOutput): parameters = { 'speed': Parameter('The speed of changing the value', - unit='main/s', readonly=False, datatype=FloatRange(0), + readonly=False, datatype=FloatRange(0, unit='$/s'), ), 'ramp': Parameter('The speed of changing the value', - unit='main/min', readonly=False, datatype=FloatRange(0), - poll=30, - ), + readonly=False, datatype=FloatRange(0, unit='$/s'), + poll=30, + ), } commands = { @@ -647,13 +643,13 @@ class Motor(Actuator): parameters = { 'refpos': Parameter('Reference position', - datatype=FloatRange(), unit='main', + datatype=FloatRange(unit='$'), ), 'accel': Parameter('Acceleration', - datatype=FloatRange(), readonly=False, unit='main/s^2', + datatype=FloatRange(unit='$/s^2'), readonly=False, ), 'decel': Parameter('Deceleration', - datatype=FloatRange(), readonly=False, unit='main/s^2', + datatype=FloatRange(unit='$/s^2'), readonly=False, ), } @@ -699,18 +695,17 @@ class TemperatureController(Actuator): datatype=TupleOf(FloatRange(), FloatRange(), FloatRange()), readonly=False, group='pid', poll=30, ), - 'setpoint': Parameter('Current setpoint', datatype=FloatRange(), poll=1, + 'setpoint': Parameter('Current setpoint', datatype=FloatRange(unit='$'), poll=1, ), 'heateroutput': Parameter('Heater output', datatype=FloatRange(), poll=1, ), - 'ramp': Parameter('Temperature ramp', unit='main/min', - datatype=FloatRange(), readonly=False, poll=30), } overrides = { # We want this to be freely user-settable, and not produce a warning # on startup, so select a usually sensible default. 'precision': Override(default=0.1), + 'ramp': Override(description='Temperature ramp'), } def read_ramp(self): @@ -761,12 +756,13 @@ class PowerSupply(Actuator): """ parameters = { - 'ramp': Parameter('Current/voltage ramp', unit='main/min', - datatype=FloatRange(), readonly=False, poll=30,), - 'voltage': Parameter('Actual voltage', unit='V', - datatype=FloatRange(), poll=-5), - 'current': Parameter('Actual current', unit='A', - datatype=FloatRange(), poll=-5), + 'voltage': Parameter('Actual voltage', + datatype=FloatRange(unit='V'), poll=-5), + 'current': Parameter('Actual current', + datatype=FloatRange(unit='A'), poll=-5), + } + overrides = { + 'ramp': Override(description='Current/voltage ramp'), } def read_ramp(self): @@ -807,7 +803,11 @@ class NamedDigitalInput(DigitalInput): super(NamedDigitalInput, self).initModule() try: # pylint: disable=eval-used - self.accessibles['value'].datatype = EnumType('value', **eval(self.mapping)) + mapping = eval(self.mapping.replace('\n', ' ')) + if isinstance(mapping, str): + # pylint: disable=eval-used + mapping = eval(mapping) + self.accessibles['value'].setProperty('datatype', EnumType('value', **mapping)) except Exception as e: raise ValueError('Illegal Value for mapping: %r' % e) @@ -874,9 +874,12 @@ class NamedDigitalOutput(DigitalOutput): super(NamedDigitalOutput, self).initModule() try: # pylint: disable=eval-used - self.accessibles['value'].datatype = EnumType('value', **eval(self.mapping)) - # pylint: disable=eval-used - self.accessibles['target'].datatype = EnumType('target', **eval(self.mapping)) + mapping = eval(self.mapping.replace('\n', ' ')) + if isinstance(mapping, str): + # pylint: disable=eval-used + mapping = eval(mapping) + self.accessibles['value'].setProperty('datatype', EnumType('value', **mapping)) + self.accessibles['target'].setProperty('datatype', EnumType('target', **mapping)) except Exception as e: raise ValueError('Illegal Value for mapping: %r' % e) @@ -924,8 +927,8 @@ class StringIO(PyTangoDevice, Module): parameters = { 'bustimeout': Parameter('Communication timeout', - datatype=FloatRange(), readonly=False, - unit='s', group='communication'), + datatype=FloatRange(unit='s'), readonly=False, + group='communication'), 'endofline': Parameter('End of line', datatype=StringType(), readonly=False, group='communication'),