from ...core.devio import SCPI, interface, comm_backend
[docs]
class CryoconError(comm_backend.DeviceError):
"""Generic Cryocon devices error"""
[docs]
class CryoconBackendError(CryoconError,comm_backend.DeviceBackendError):
"""Generic Lakeshore backend communication error"""
[docs]
class Cryocon1x(SCPI.SCPIDevice):
"""
Cryocon 1x series (12C, 14C, 18C) temperature controller.
Args:
conn: serial connection parameters (usually port or a tuple containing port and baudrate)
"""
_default_write_sync=True
Error=CryoconError
ReraiseError=CryoconBackendError
def __init__(self, conn, nchannels="auto"):
SCPI.SCPIDevice.__init__(self,conn,backend="serial",term_write="\n",term_read="\r\n",backend_defaults={"serial":("COM1",9600,8,'N',1)})
channels={n:n for n in range(8)}
channels.update({"ABCDEFGH"[n]:n for n in range(8)})
channels.update({"CH"+"ABCDEFGH"[n]:n for n in range(8)})
self._add_parameter_class(interface.EnumParameterClass("channel",channels))
with self._close_on_error():
self.get_id(timeout=2)
if nchannels=="auto":
nchannels=max(n for n in range(8) if self._is_channel_connected(n))+1
self._nchannels=nchannels
channels=range(self._nchannels)
self._add_status_variable("temperature",self.get_all_temperatures)
self._add_status_variable("sensor_reading",self.get_all_sensor_readings)
self._add_status_variable("sensor_kind",self.get_all_sensor_kinds)
@interface.use_parameters
def _is_channel_connected(self, channel):
return self.ask("INP {}:ALARM?".format(channel))!="NAK"
[docs]
def get_number_of_channels(self):
"""Return total number of channels in the device (2, 4, or 8)"""
return self._nchannels
_p_display_units=interface.EnumParameterClass("units",{"K":"K","C":"C","F":"F","S":"S"})
[docs]
@interface.use_parameters
def get_display_units(self, channel):
return self.ask("INP {}:UNIT?".format(channel))
[docs]
@interface.use_parameters
def set_display_units(self, channel, units):
self.write("INP {}:UNIT".format(channel),units)
return self.get_display_units(channel)
def _read_raw_temperature(self, channel):
value=self.ask("INP? {}".format(channel))
return None if all(c in ".-" for c in value) else float(value)
[docs]
@interface.use_parameters
def get_temperature(self, channel, display_units=False):
"""
Get a reading on a given channel.
If ``display_units==True``, return reading in the display units; otherwise, return reading in Kelvin.
If in this case the display units are ``"S"`` (sensor), set them to Kelvin to get the reading.
If sensor is disconnected, return ``None``.
"""
if display_units:
return self._read_raw_temperature(channel)
units=self.get_display_units(channel)
if units=="S":
self.set_display_units(channel,"K")
units="K"
value=self._read_raw_temperature(channel)
if value is None:
return None
if units=="K":
return value
if units=="C":
return value+273.15
if units=="F":
return (value-32)*(5/9)+273.15
[docs]
def get_all_temperatures(self, display_units=False):
"""
Get readings on all channels.
If ``display_units==True``, return reading in the display units; otherwise, return reading in Kelvin.
If in this case the display units are ``"S"`` (sensor), set them to Kelvin to get the reading.
If sensor is disconnected, return ``None``.
"""
return [self.get_temperature(ch,display_units=display_units) for ch in range(self._nchannels)]
[docs]
@interface.use_parameters
def get_sensor_reading(self, channel):
"""Get readings (in sensor units) on a given channel (1 to 8)"""
value=self.ask("INP {}:SENP?".format(channel))
return None if all(c in ".-" for c in value) else float(value)
[docs]
def get_all_sensor_readings(self):
"""Get readings (in sensor units) on all channels"""
return [self.get_sensor_reading(ch) for ch in range(self._nchannels)]
_p_sensor_kind=interface.EnumParameterClass("sensor_kind",
{"none":0,"S900":1,"DT670":2,"DT470":3,"S950":4,"SI410":5,"Pt100":20,"Pt1k":21,"Pt10k":22,"ThFe":23,"RO105":31,"RO600":32},
allowed_alias="all",allowed_value="all")
[docs]
@interface.use_parameters(channel="channel",_returns="sensor_kind")
def get_sensor_kind(self, channel):
"""Get sensor kind of a given channel (1 to 8)"""
return self.ask("INP {}:SENS?".format(channel),"int")
[docs]
def get_all_sensor_kinds(self):
"""Get readings (in sensor units) on all channels"""
return [self.get_sensor_kind(ch) for ch in range(self._nchannels)]
[docs]
@interface.use_parameters(channel="channel",kind="sensor_kind")
def set_sensor_kind(self, channel, kind):
"""
Set sensor kind of a given channel (1 to 8).
Can be an integer using internal classification (see manual),
or one of ``"none"``, ``"S900"``, ``"DT670"``, ``"DT470"``, ``"S950"``, ``"SI410"``, ``"Pt100"``, ``"Pt1k"``, ``"Pt10k"``, ``"ThFe"``, ``"RO105"``, ``"RO600"``.
Setting kind to ``"none"`` disables the sensor.
"""
if not isinstance(kind,int):
raise ValueError("unrecognized sensor kind: {}; allowed kinds are {}".format(kind,list(self._p_sensor_kind._alias_map)))
self.write("INP {}:SENS".format(channel),kind)
return self.get_sensor_kind(channel)