fixes in mercury an triton
- Valve is now a drivable, as it will check success, and retry, which might take around 1 second + some more
This commit is contained in:
@ -20,15 +20,16 @@
|
||||
# *****************************************************************************
|
||||
"""oxford instruments triton (kelvinoxjt dil)"""
|
||||
|
||||
from secop.core import Drivable, HasIO, Writable, \
|
||||
Parameter, Property, Readable, StringIO, Attached, Done, IDLE, WARN, nopoll
|
||||
from secop.datatypes import EnumType, FloatRange, StringType, StructOf, BoolType
|
||||
from math import sqrt
|
||||
from secop.core import Writable, Parameter, Readable, Drivable, IDLE, WARN, BUSY, Done
|
||||
from secop.errors import HardwareError
|
||||
from secop.datatypes import EnumType, FloatRange
|
||||
from secop.lib.enum import Enum
|
||||
from secop_psi.mercury import MercuryChannel, Mapped, off_on
|
||||
from secop_psi.mercury import MercuryChannel, Mapped, off_on, HasInput, SELF
|
||||
import secop_psi.mercury as mercury
|
||||
|
||||
actions = Enum(none=0, condense=1, circulate=2, collect=3)
|
||||
open_close = Mapped(CLOSE=False, OPEN=True)
|
||||
open_close = Mapped(CLOSE=0, OPEN=1)
|
||||
actions_map = Mapped(STOP=actions.none, COND=actions.condense, COLL=actions.collect)
|
||||
actions_map.mapping['NONE'] = actions.none # when writing, STOP is used instead of NONE
|
||||
|
||||
@ -36,7 +37,7 @@ actions_map.mapping['NONE'] = actions.none # when writing, STOP is used instead
|
||||
class Action(MercuryChannel, Writable):
|
||||
channel_type = 'ACTN'
|
||||
value = Parameter('running action', EnumType(actions))
|
||||
target = Parameter('valve target', EnumType(none=0, condense=1, collect=3), readonly=False)
|
||||
target = Parameter('action to do', EnumType(none=0, condense=1, collect=3), readonly=False)
|
||||
_target = 0
|
||||
|
||||
def read_value(self):
|
||||
@ -64,16 +65,50 @@ class Action(MercuryChannel, Writable):
|
||||
# EPCL (empty pre-coll automation)
|
||||
|
||||
|
||||
class Valve(MercuryChannel, Writable):
|
||||
class Valve(MercuryChannel, Drivable):
|
||||
channel_type = 'VALV'
|
||||
value = Parameter('valve state', EnumType(closed=0, opened=1))
|
||||
target = Parameter('valve target', EnumType(close=0, open=1))
|
||||
|
||||
_try_count = None
|
||||
|
||||
def doPoll(self):
|
||||
self.read_status()
|
||||
|
||||
def read_value(self):
|
||||
return self.query('VALV:SIG:STATE', open_close)
|
||||
|
||||
def read_status(self):
|
||||
pos = self.read_value()
|
||||
if self._try_count is None:
|
||||
return IDLE, ''
|
||||
if pos == self.target:
|
||||
if self._try_count:
|
||||
# make sure last sent command was not opposite
|
||||
self.change('VALV:SIG:STATE', self.target, open_close)
|
||||
self._try_count = None
|
||||
self.setFastPoll(False)
|
||||
return IDLE, ''
|
||||
self._try_count += 1
|
||||
if self._try_count % 4 == 0:
|
||||
# send opposite position in order to unblock
|
||||
self.change('VALV:SIG:STATE', pos, open_close)
|
||||
return BUSY, 'unblock'
|
||||
if self._try_count > 9:
|
||||
# make sure system does not toggle later
|
||||
self.change('VALV:SIG:STATE', pos, open_close)
|
||||
return ERROR, 'can not %s valve' % self.target.name
|
||||
self.change('VALV:SIG:STATE', self.target, open_close)
|
||||
self._try_count += 1
|
||||
return BUSY, 'waiting'
|
||||
|
||||
def write_target(self, value):
|
||||
return self.change('VALV:SIG:STATE', value, open_close)
|
||||
if value != self.read_value():
|
||||
self._try_count = 0
|
||||
self.setFastPoll(True, 0.25)
|
||||
self.change('VALV:SIG:STATE', value, open_close)
|
||||
self.status = BUSY, self.target.name
|
||||
return value
|
||||
|
||||
|
||||
class Pump(MercuryChannel, Writable):
|
||||
@ -208,8 +243,52 @@ class TemperatureSensor(ScannerChannel, mercury.TemperatureSensor):
|
||||
|
||||
|
||||
class TemperatureLoop(ScannerChannel, mercury.TemperatureLoop):
|
||||
pass
|
||||
ENABLE = 'TEMP:LOOP:MODE'
|
||||
ENABLE_RAMP = 'TEMP:LOOP:RAMP:ENAB'
|
||||
RAMP_RATE = 'TEMP:LOOP:RAMP:RATE'
|
||||
enable_pid_table = None # remove, does not work on triton
|
||||
|
||||
def write_control_active(self, value):
|
||||
self.change('SYS:DR:CHAN:MC', 'T5', str)
|
||||
if value:
|
||||
self.change('TEMP:LOOP:FILT:ENAB', 'ON', str)
|
||||
if self.output_module:
|
||||
limit = self.output_module.read_limit() or None # None: max. limit
|
||||
self.output_module.write_limit(limit)
|
||||
return super().write_control_active(value)
|
||||
|
||||
|
||||
class HeaterOutput(mercury.HeaterOutput):
|
||||
pass # not sure if we need special handling of triton heater output: to be checked!
|
||||
class HeaterOutput(HasInput, MercuryChannel, Readable):
|
||||
"""heater output"""
|
||||
channel_type = 'HTR,TEMP'
|
||||
value = Parameter('heater output', FloatRange(unit='W'))
|
||||
target = Parameter('heater output', FloatRange(0, unit='$'), readonly=False)
|
||||
limit = Parameter('max. heater power', FloatRange(unit='W'), readonly=False)
|
||||
resistivity = Parameter('heater resistivity', FloatRange(unit='Ohm'))
|
||||
|
||||
def read_resistivity(self):
|
||||
return self.query('HTR:RES')
|
||||
|
||||
def read_limit(self):
|
||||
maxcur = self.query('TEMP:LOOP:RANGE') * 0.001 # mA -> A
|
||||
return self.read_resistivity() * maxcur ** 2
|
||||
|
||||
def write_limit(self, value):
|
||||
if value is None:
|
||||
maxcur = 0.1 # max. allowed current 100mA
|
||||
else:
|
||||
maxcur = sqrt(value / self.read_resistivity())
|
||||
self.change('TEMP:LOOP:RANGE', maxcur * 1000)
|
||||
return self.read_limit()
|
||||
|
||||
def read_value(self):
|
||||
return self.query('HTR:SIG:POWR') * 1e-6
|
||||
|
||||
def read_target(self):
|
||||
if self.controlled_by != 0:
|
||||
return Done
|
||||
return self.value
|
||||
|
||||
def write_target(self, value):
|
||||
self.write_controlled_by(SELF)
|
||||
return self.change('HTR:SIG:POWR', value * 1e6)
|
||||
|
Reference in New Issue
Block a user