- before some chamges in the gerrit pipline Change-Id: I33eb2d75f83345a7039d0fb709e66defefb1c3e0
149 lines
5.0 KiB
Python
149 lines
5.0 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
# *****************************************************************************
|
|
# This program is free software; you can redistribute it and/or modify it under
|
|
# the terms of the GNU General Public License as published by the Free Software
|
|
# Foundation; either version 2 of the License, or (at your option) any later
|
|
# version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License along with
|
|
# this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
#
|
|
# Module authors:
|
|
# Oksana Shliakhtun <oksana.shliakhtun@psi.ch>
|
|
# *****************************************************************************
|
|
|
|
|
|
from frappy.core import Readable, Parameter, FloatRange, IDLE, ERROR, BoolType,\
|
|
StringIO, HasIO, Property, WARN, Drivable, BUSY, StringType, Done
|
|
from frappy.errors import InternalError
|
|
|
|
|
|
class QnwIO(StringIO):
|
|
"""communication with TC1"""
|
|
end_of_line = ']' # no line feed!
|
|
identification = [('[F1 VN ?', r'.F1 VN .*')] # Controller Firmware Version, holder number
|
|
|
|
|
|
class SensorTC1(HasIO, Readable):
|
|
ioClass = QnwIO
|
|
value = Parameter(unit='degC', min=-15, max=120)
|
|
channel = Property('channel name', StringType())
|
|
|
|
def set_param(self, adr, value=None):
|
|
short = adr.split()[0]
|
|
# try 3 times in case we got an asynchronous message
|
|
for _ in range(3):
|
|
if value is None:
|
|
reply = self.communicate(f'[F1 {adr} ?').split()
|
|
else:
|
|
reply = self.communicate(f'[F1 {adr} {value}][F1 {short} ?').split()
|
|
if reply[1] == short:
|
|
break
|
|
else:
|
|
raise InternalError(f'bad reply {reply}')
|
|
try:
|
|
return float(reply[2])
|
|
except ValueError:
|
|
return reply[2]
|
|
|
|
def get_param(self, adr):
|
|
return self.set_param(adr)
|
|
|
|
def read_value(self):
|
|
return self.get_param(self.channel)
|
|
|
|
def read_status(self):
|
|
dt = self.parameters['value'].datatype
|
|
if dt.min <= self.value <= dt.max:
|
|
return IDLE, ''
|
|
return ERROR, 'value out of range (cable unplugged?)'
|
|
|
|
|
|
class TemperatureLoopTC1(SensorTC1, Drivable):
|
|
value = Parameter('temperature', unit='degC')
|
|
target = Parameter('setpoint', unit='degC', min=-5, max=110)
|
|
control = Parameter('temperature control flag', BoolType(), readonly=False)
|
|
ramp = Parameter('ramping value', FloatRange, unit='degC/min', readonly=False)
|
|
ramp_used = Parameter('ramping status', BoolType(), default=False, readonly=False)
|
|
target_min = Parameter('lowest target temperature', FloatRange, unit='degC')
|
|
target_max = Parameter('maximum target temperature', FloatRange, unit='degC')
|
|
|
|
def read_target_min(self):
|
|
return self.get_param('LT')
|
|
|
|
def read_target_max(self):
|
|
return self.get_param('MT')
|
|
|
|
def read_status(self):
|
|
status = super().read_status()
|
|
if status[0] == ERROR:
|
|
return status
|
|
reply = self.get_param('IS') # instrument status
|
|
if len(reply) < 5:
|
|
self.set_param('IS', 'E+')
|
|
reply = self.get_param('IS') # instrument status
|
|
self.control = reply[2] == '+'
|
|
if reply[4] == '+':
|
|
return BUSY, 'ramping'
|
|
if reply[3] == 'C':
|
|
if self.control:
|
|
if self.ramp_used:
|
|
return BUSY, 'stabilizing'
|
|
return BUSY, 'changing'
|
|
if self.control:
|
|
return IDLE, ''
|
|
return WARN, 'control off'
|
|
|
|
def write_target(self, target):
|
|
if self.ramp_used:
|
|
self.set_param('RR S', self.ramp)
|
|
else:
|
|
self.set_param('RR S', 0)
|
|
target = self.set_param('TT S', target)
|
|
self.set_param('TC', '+')
|
|
self.read_status()
|
|
return target
|
|
|
|
def read_target(self):
|
|
return self.get_param('TT')
|
|
|
|
def write_control(self, control):
|
|
if control:
|
|
if not self.read_control():
|
|
self.write_target(self.value)
|
|
return True
|
|
self.set_param('TC', '-')
|
|
return False
|
|
###########
|
|
|
|
def read_ramp(self):
|
|
return float(self.get_param('RR'))
|
|
|
|
def write_ramp(self, ramp):
|
|
ramp = max(0.01, abs(ramp))
|
|
self.ramp_used = True
|
|
ramp = self.set_param('RR S', ramp)
|
|
if self.control:
|
|
self.ramp = ramp
|
|
self.write_target(self.target)
|
|
return Done
|
|
return ramp
|
|
|
|
def write_ramp_used(self, value):
|
|
if self.control:
|
|
self.ramp_used = value
|
|
self.write_target(self.target)
|
|
return Done
|
|
return value
|
|
|
|
def stop(self):
|
|
if self.control and self.ramp_used:
|
|
self.write_target(self.value)
|