Source code for pylablib.devices.Thorlabs.serial

from ...core.devio import SCPI, interface
from ...core.utils import py3
from .base import ThorlabsError, ThorlabsBackendError



[docs] class ThorlabsSerialInterface(SCPI.SCPIDevice): """ Generic Thorlabs device interface using Serial communication. Args: conn: serial connection parameters (usually port or a tuple containing port and baudrate) """ _allow_concatenate_write=False Error=ThorlabsError ReraiseError=ThorlabsBackendError _validate_echo=False # if true; check if the echo matches the written command and raise an error (and re-run the command) if it does not _default_failsafe=True _default_retry_delay=0.5 def __init__(self, conn): super().__init__(conn,backend="serial",term_read=["\r","\n"],term_write="\r",timeout=5.,backend_defaults={"serial":("COM1",115200)}) self.open()
[docs] def open(self): super().open() self.instr.flush_read()
def _check_reply(self, reply, msg=None): return reply.find(b"CMD_")<0 and reply.find(b"Error")<0 def _instr_write(self, msg): self.instr.flush_read() if self._validate_echo: self.instr.write(msg) res=self._instr_read() if res.strip()==py3.as_bytes(msg.strip()): return raise self.Error("request {} returned unexpected echo: {}".format(py3.as_bytes(msg.strip()),res)) self.instr.write(msg,read_echo=True) def _instr_read(self, raw=False, size=None): if size: data=self.instr.read(size=size) elif raw: data=self.instr.readline(remove_term=False) else: data="" while not data: data=self.instr.readline(remove_term=True).strip() while data[:1]==b">": data=data[1:].strip() return data
[docs] class FW(ThorlabsSerialInterface): """ Thorlabs FW102/212 motorized filter wheels. Args: conn: serial connection parameters (usually port or a tuple containing port and baudrate) respect_bound(bool): if ``True``, avoid crossing the boundary between the first and the last position in the wheel """ _validate_echo=True def __init__(self, conn, respect_bound=True): super().__init__(conn) self._add_settings_variable("pos",self.get_position,self.set_position) self._add_settings_variable("pcount",self.get_pcount,self.set_pcount) self._add_settings_variable("speed_mode",self.get_speed_mode,self.set_speed_mode) self._add_settings_variable("trigger_mode",self.get_trigger_mode,self.set_trigger_mode) self._add_settings_variable("sensors_mode",self.get_sensor_mode,self.set_sensor_mode) with self._close_on_error(): self.pcount=self.get_pcount() self.respect_bound=respect_bound _id_comm="*idn?"
[docs] def ask(self, msg, data_type="string", delay=0., timeout=None, read_echo=False): self.flush() return super().ask(msg,data_type=data_type,delay=delay,timeout=timeout,read_echo=read_echo)
[docs] def get_position(self): """Get the wheel position (starting from 1)""" return self.ask("pos?","int")
[docs] def set_position(self, pos): """Set the wheel position (starting from 1)""" if self.respect_bound: # check if the wheel could go through zero; if so, manually go around instead cur_pos=self.get_position() if abs(pos-cur_pos)>=self.pcount//2: # could switch by going through zero medp1=(2*cur_pos+pos)//3 medp2=(cur_pos+2*pos)//3 self.write("pos={}".format(medp1)) self.write("pos={}".format(medp2)) self.write("pos={}".format(pos)) else: self.write("pos={}".format(pos)) else: self.write("pos={}".format(pos)) return self.get_position()
[docs] def get_pcount(self): """Get the number of wheel positions (6 or 12)""" return self.ask("pcount?","int")
[docs] def set_pcount(self, pcount): """Set the number of wheel positions (6 or 12)""" self.write("pcount={}".format(pcount)) self.pcount=self.get_pcount() return self.pcount
_p_speed_mode=interface.EnumParameterClass("speed_mode",{"low":0,"high":1})
[docs] @interface.use_parameters(_returns="speed_mode") def get_speed_mode(self): """Get the motion speed mode (``"low"`` or ``"high"``)""" return self.ask("speed?","int")
[docs] @interface.use_parameters def set_speed_mode(self, speed_mode): """Set the motion speed mode (``"low"`` or ``"high"``)""" self.write("speed={}".format(speed_mode)) return self.get_speed_mode()
_p_trigger_mode=interface.EnumParameterClass("trigger_mode",{"in":0,"out":1})
[docs] @interface.use_parameters(_returns="trigger_mode") def get_trigger_mode(self): """Get the trigger mode (``"in"`` to input external trigger, ``"out"`` to output trigger)""" return self.ask("trig?","int")
[docs] @interface.use_parameters def set_trigger_mode(self, trigger_mode): """Set the trigger mode (``"in"`` to input external trigger, ``"out"`` to output trigger)""" self.write("trig={}".format(trigger_mode)) return self.get_trigger_mode()
_p_sensor_mode=interface.EnumParameterClass("sensor_mode",{"off":0,"on":1})
[docs] @interface.use_parameters(_returns="sensor_mode") def get_sensor_mode(self): """Get the sensor mode (``"off"`` to turn off when idle to eliminate stray light, ``"on"`` to remain on)""" return self.ask("sensors?","int")
[docs] @interface.use_parameters def set_sensor_mode(self, sensor_mode): """Set the sensor mode (``"off"`` to turn off when idle to eliminate stray light, ``"on"`` to remain on)""" self.write("sensors={}".format(sensor_mode)) return self.get_sensor_mode()
[docs] def store_settings(self): """Store current settings as default""" self.write("save")
[docs] class FWv1(ThorlabsSerialInterface): """ Thorlabs FW102/212 v1.0 (older version) motorized filter wheels. Args: conn: serial connection parameters (usually port or a tuple containing port and baudrate) pcount: number of positions in the wheel respect_bound(bool): if ``True``, avoid crossing the boundary between the first and the last position in the wheel """ _validate_echo=True def __init__(self, conn, pcount=6, respect_bound=True): super().__init__(conn) self.pcount=pcount self._add_settings_variable("pos",self.get_position,self.set_position) self._add_info_variable("pcount",self.get_pcount) self._add_settings_variable("trigger_mode",self.get_trigger_mode,self.set_trigger_mode) self.respect_bound=respect_bound def _instr_write(self, msg): self.instr.flush_read() self.instr.write(">") try: self._instr_read() except self.Error: pass super()._instr_write(msg) _id_comm="*idn?"
[docs] def ask(self, msg, data_type="string", delay=0., timeout=None, read_echo=False): self.flush() return super().ask(msg,data_type=data_type,delay=delay,timeout=timeout,read_echo=read_echo)
[docs] def get_position(self): """Get the wheel position (starting from 1)""" return self.ask("pos?","int")
[docs] def set_position(self, pos): """Set the wheel position (starting from 1)""" if self.respect_bound: # check if the wheel could go through zero; if so, manually go around instead cur_pos=self.get_position() if abs(pos-cur_pos)>=self.pcount//2: # could switch by going through zero medp1=(2*cur_pos+pos)//3 medp2=(cur_pos+2*pos)//3 self.write("pos={}".format(medp1)) self.write("pos={}".format(medp2)) self.write("pos={}".format(pos)) else: self.write("pos={}".format(pos)) else: self.write("pos={}".format(pos)) return self.get_position()
[docs] def get_pcount(self): """Get the number of wheel positions (6 or 12)""" return self.pcount
_p_trigger_mode=interface.EnumParameterClass("trigger_mode",{"in":0,"out":1})
[docs] @interface.use_parameters(_returns="trigger_mode") def get_trigger_mode(self): """Get the trigger mode (``"in"`` to input external trigger, ``"out"`` to output trigger)""" return self.ask("trig?","int")
[docs] @interface.use_parameters def set_trigger_mode(self, trigger_mode): """Set the trigger mode (``"in"`` to input external trigger, ``"out"`` to output trigger)""" self.write("trig={}".format(trigger_mode)) return self.get_trigger_mode()
[docs] class MDT69xA(ThorlabsSerialInterface): """ Thorlabs MDT693A/4A high-voltage source. Uses MDT693A program interface, so should be compatible with both A and B versions (though it doesn't support all functions of MDT693B/4B) Args: conn: serial connection parameters (usually port or a tuple containing port and baudrate) """ def __init__(self, conn): super().__init__(conn) self._add_settings_variable("voltage",self.get_voltage,self.set_voltage,mux=("xyz",1)) self._add_status_variable("voltage_range",self.get_voltage_range) with self._close_on_error(): self.get_id(timeout=2.) _id_comm="I" _p_channel=interface.EnumParameterClass("channel",["x","y","z"])
[docs] @interface.use_parameters def get_voltage(self, channel="x"): """Get the output voltage in Volts at a given channel""" resp=self.ask(channel.upper()+"R?") resp=resp.strip()[2:-1].strip() return float(resp)
[docs] @interface.use_parameters def set_voltage(self, voltage, channel="x"): """Set the output voltage in Volts at a given channel""" self.write(channel.upper()+"V{:.3f}".format(voltage)) return self._wip.get_voltage(channel=channel)
[docs] def get_voltage_range(self): """Get the selected voltage range in Volts (75, 100 or 150)""" resp=self.ask("%") resp=resp.strip()[2:-1].strip() return float(resp)