[WIP] frappy_psi:ccu4: add HeLevel, N2
Change-Id: Ib31ec440ecc51b01035d783065cb805b942b61b1
This commit is contained in:
parent
4da6aa95d7
commit
c6056ad1de
@ -20,9 +20,12 @@
|
||||
# *****************************************************************************
|
||||
|
||||
"""drivers for CCU4, the cryostat control unit at SINQ"""
|
||||
import time
|
||||
# the most common Frappy classes can be imported from frappy.core
|
||||
from frappy.core import EnumType, FloatRange, \
|
||||
HasIO, Parameter, Readable, StringIO, StatusType
|
||||
from frappy.core import EnumType, FloatRange, TupleOf, \
|
||||
HasIO, Parameter, Command, Readable, StringIO, StatusType, \
|
||||
BUSY, IDLE, ERROR, DISABLED
|
||||
from frappy.states import HasStates, status_code, Retry
|
||||
|
||||
|
||||
class CCU4IO(StringIO):
|
||||
@ -54,12 +57,12 @@ class HeLevel(HasIO, Readable):
|
||||
|
||||
# conversion of the code from the CCU4 parameter 'hsf'
|
||||
STATUS_MAP = {
|
||||
0: (StatusType.IDLE, 'sensor ok'),
|
||||
1: (StatusType.ERROR, 'sensor warm'),
|
||||
2: (StatusType.ERROR, 'no sensor'),
|
||||
3: (StatusType.ERROR, 'timeout'),
|
||||
4: (StatusType.ERROR, 'not yet read'),
|
||||
5: (StatusType.DISABLED, 'disabled'),
|
||||
0: (IDLE, 'sensor ok'),
|
||||
1: (ERROR, 'sensor warm'),
|
||||
2: (ERROR, 'no sensor'),
|
||||
3: (ERROR, 'timeout'),
|
||||
4: (ERROR, 'not yet read'),
|
||||
5: (DISABLED, 'disabled'),
|
||||
}
|
||||
|
||||
def query(self, cmd):
|
||||
@ -96,3 +99,116 @@ class HeLevel(HasIO, Readable):
|
||||
|
||||
def write_sample_rate(self, value):
|
||||
return self.query(f'hf={int(value)}')
|
||||
|
||||
|
||||
|
||||
class HeLevelAuto(HasStates, HeLevel):
|
||||
fill_level = Parameter('low threshold triggering start filling',
|
||||
FloatRange(unit='%'), readonly=False)
|
||||
full_level = Parameter('high threshold triggering stop filling',
|
||||
FloatRange(unit='%'), readonly=False)
|
||||
raw = Parameter('unsmoothed level', FloatRange(unit='%'))
|
||||
fill_minutes_range = Parameter('range of possible fill rate',
|
||||
TupleOf(FloatRange(unit='min'), FloatRange(unit='min')),
|
||||
readonly=False)
|
||||
hold_hours_range = Parameter('range of possible consumption rate',
|
||||
TupleOf(FloatRange(unit='h'), FloatRange(unit='h')),
|
||||
readonly=False)
|
||||
fill_delay = Parameter('delay for cooling the transfer line',
|
||||
FloatRange(unit='min'), readonly=False)
|
||||
status = Parameter(datatype=StatusType(HeLevel, 'BUSY'))
|
||||
|
||||
_filling = False
|
||||
_fillstart = 0
|
||||
_last_read = 0
|
||||
|
||||
def doPoll(self):
|
||||
super().doPoll()
|
||||
if self._filling:
|
||||
if self._filling == 1 and
|
||||
if self.value
|
||||
self.query('hcd=1')
|
||||
|
||||
def read_value(self):
|
||||
self.raw = super().read_value()
|
||||
if not self._state_machine.is_active:
|
||||
return self.raw
|
||||
return self.value
|
||||
|
||||
def read_status(self):
|
||||
status = HeLevel.read_status(self)
|
||||
if status[0] == IDLE:
|
||||
return HasStates.read_status(self)
|
||||
self.stop_machine(status)
|
||||
return status
|
||||
|
||||
@status_code(BUSY)
|
||||
def watching(self, state):
|
||||
delta = state.delta(10)
|
||||
if self.raw > self.value:
|
||||
self.value -= delta / (3600 * self.fill_hours_range[1])
|
||||
elif self.raw < self.value:
|
||||
self.value -= delta / (3600 * self.fill_hours_range[0])
|
||||
else:
|
||||
self.value = self.raw
|
||||
if self.value < self.fill_level:
|
||||
self.query('hcd=1 hf=1')
|
||||
state.fillstart = state.now
|
||||
return self.precooling
|
||||
self.query('hcd=1 hf=1')
|
||||
return Retry
|
||||
|
||||
@status_code(BUSY)
|
||||
def precooling(self, state):
|
||||
delta = state.delta(1)
|
||||
if self.raw > self.value:
|
||||
self.value += delta / (60 * self.fill_minutes_range[0])
|
||||
elif self.raw < self.value:
|
||||
self.value -= delta / (60 * self.fill_minutes_range[0])
|
||||
else:
|
||||
self.value = self.raw
|
||||
if self.value > self.full_level:
|
||||
self.query('hcd=0 hf=0')
|
||||
return self.watching
|
||||
self.query('hcd=1 hf=1')
|
||||
if state.now > state.fillstart + self.fill_delay * 60:
|
||||
return self.filling
|
||||
return Retry
|
||||
|
||||
@status_code(BUSY)
|
||||
def filling(self, state):
|
||||
delta = state.delta(1)
|
||||
if self.raw > self.value:
|
||||
self.value += delta / (60 * self.fill_minutes_range[0])
|
||||
elif self.raw < self.value:
|
||||
self.value += delta / (60 * self.fill_minutes_range[1])
|
||||
else:
|
||||
self.value = self.raw
|
||||
if self.value > self.full_level:
|
||||
self.query('hcd=0 hf=0')
|
||||
return self.watching
|
||||
self.query('hcd=1 hf=1')
|
||||
return Retry
|
||||
|
||||
@Command()
|
||||
def fill(self):
|
||||
self.start_machine(self.precooling, fillstart=time.time())
|
||||
self.query('hcd=1 hf=1')
|
||||
|
||||
@Command()
|
||||
def stop(self):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class N2Sensor(HasIO, Readable):
|
||||
# conversion of the code from the CCU4 parameter 'ns'
|
||||
STATUS_MAP = {
|
||||
0: (IDLE, 'sensor ok'),
|
||||
1: (ERROR, 'no sensor'),
|
||||
2: (ERROR, 'short circuit'),
|
||||
3: (ERROR, 'upside down'),
|
||||
4: (ERROR, 'sensor warm'),
|
||||
5: (ERROR, 'empty'),
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user