#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Provides the support for the Ondax LM Laser.
Class originally contributed by Catherine Holloway.
"""
# IMPORTS #####################################################################
from __future__ import absolute_import
from __future__ import division
from enum import IntEnum
import quantities as pq
from instruments.abstract_instruments import Instrument
from instruments.util_fns import convert_temperature, assume_units
# CLASSES #####################################################################
[docs]class LM(Instrument):
"""
The LM is the Ondax SureLock VHG-stabilized laser diode.
The user manual can be found on the `Ondax website`_.
.. _Ondax website: http://www.ondax.com/Downloads/SureLock/Compact%20laser%20module%20manual.pdf
"""
def __init__(self, filelike):
super(LM, self).__init__(filelike)
self.terminator = "\r"
self.apc = self._AutomaticPowerControl(self)
self.acc = self._AutomaticCurrentControl(self)
self.tec = self._ThermoElectricCooler(self)
self.modulation = self._Modulation(self)
self._enabled = None
# ENUMS #
[docs] class Status(IntEnum):
"""
Enum containing the valid states of the laser
"""
normal = 1
inner_modulation = 2
power_scan = 3
calibrate = 4
shutdown_current = 5
shutdown_overheat = 6
waiting_stable_temperature = 7
waiting = 8
# INNER CLASSES #
class _AutomaticCurrentControl(object):
"""
Options and functions related to the laser diode's automatic current
control driver.
.. warning:: This class is not designed to be accessed directly. It
should be interfaced via `LM.acc`
"""
def __init__(self, parent):
self._parent = parent
self._enabled = False
@property
def target(self):
"""
Gets the automatic current control target setting.
This property is accessed via the `LM.acc` namespace.
Example usage:
>>> import instruments as ik
>>> laser = ik.ondax.LM.open_serial('/dev/ttyUSB0', baud=1234)
>>> print(laser.acc.target)
:return: Current ACC of the Laser
:units: mA
:type: `~quantities.Quantity`
"""
response = float(self._parent.query("rstli?"))
return response*pq.mA
@property
def enabled(self):
"""
Get/Set the enabled state of the ACC driver.
This property is accessed via the `LM.acc` namespace.
Example usage:
>>> import instruments as ik
>>> laser = ik.ondax.LM.open_serial('/dev/ttyUSB0', baud=1234)
>>> print(laser.acc.enabled)
>>> laser.acc.enabled = True
:type: `bool`
"""
return self._enabled
@enabled.setter
def enabled(self, newval):
if not isinstance(newval, bool):
raise TypeError("ACC driver enabled property must be specified"
"with a boolean, got {}.".format(type(newval)))
if newval:
self._parent.sendcmd("lcen")
else:
self._parent.sendcmd("lcdis")
self._enabled = newval
def on(self):
"""
Turns on the automatic current control driver.
This function is accessed via the `LM.acc` namespace.
Example usage:
>>> import instruments as ik
>>> laser = ik.ondax.LM.open_serial('/dev/ttyUSB0', baud=1234)
>>> laser.acc.on()
"""
self._parent.sendcmd("lcon")
def off(self):
"""
Turn off the automatic current control driver.
This function is accessed via the `LM.acc` namespace.
Example usage:
>>> import instruments as ik
>>> laser = ik.ondax.LM.open_serial('/dev/ttyUSB0', baud=1234)
>>> laser.acc.off()
"""
self._parent.sendcmd("lcoff")
class _AutomaticPowerControl(object):
"""
Options and functions related to the laser diode's automatic power
control driver.
.. warning:: This class is not designed to be accessed directly. It
should be interfaced via `LM.apc`
"""
def __init__(self, parent):
self._parent = parent
self._enabled = False
@property
def target(self):
"""
Gets the target laser power of the automatic power control in mW.
This property is accessed via the `LM.apc` namespace.
Example usage:
>>> import instruments as ik
>>> laser = ik.ondax.LM.open_serial('/dev/ttyUSB0', baud=1234)
>>> print(laser.apc.target)
:return: the target laser power
:units: mW
:type: `~quantities.Quantities`
"""
response = self._parent.query("rslp?")
return float(response)*pq.mW
@property
def enabled(self):
"""
Get/Set the enabled state of the automatic power control driver.
This property is accessed via the `LM.apc` namespace.
Example usage:
>>> import instruments as ik
>>> laser = ik.ondax.LM.open_serial('/dev/ttyUSB0', baud=1234)
>>> print(laser.apc.enabled)
>>> laser.apc.enabled = True
:type: `bool`
"""
return self._enabled
@enabled.setter
def enabled(self, newval):
if not isinstance(newval, bool):
raise TypeError("APC driver enabled property must be specified "
"with a boolean, got {}.".format(type(newval)))
if newval:
self._parent.sendcmd("len")
else:
self._parent.sendcmd("ldis")
self._enabled = newval
def start(self):
"""
Start the automatic power control scan.
This function is accessed via the `LM.apc` namespace.
Example usage:
>>> import instruments as ik
>>> laser = ik.ondax.LM.open_serial('/dev/ttyUSB0', baud=1234)
>>> laser.apc.start()
"""
self._parent.sendcmd("sps")
def stop(self):
"""
Stop the automatic power control scan.
This function is accessed via the `LM.apc` namespace.
Example usage:
>>> import instruments as ik
>>> laser = ik.ondax.LM.open_serial('/dev/ttyUSB0', baud=1234)
>>> laser.apc.stop()
"""
self._parent.sendcmd("cps")
class _Modulation(object):
"""
Options and functions related to the laser's optical output modulation.
.. warning:: This class is not designed to be accessed directly. It
should be interfaced via `LM.modulation`
"""
def __init__(self, parent):
self._parent = parent
self._enabled = False
@property
def on_time(self):
"""
Gets/sets the TTL modulation on time, in milliseconds.
This property is accessed via the `LM.modulation` namespace.
Example usage:
>>> import instruments as ik
>>> import quantities as pq
>>> laser = ik.ondax.LM.open_serial('/dev/ttyUSB0', baud=1234)
>>> print(laser.modulation.on_time)
>>> laser.modulation.on_time = 1 * pq.ms
:return: The TTL modulation on time
:units: As specified (if a `~quantities.Quantity`) or assumed
to be of units milliseconds.
:type: `~quantities.Quantity`
"""
response = self._parent.query("stsont?")
return float(response)*pq.ms
@on_time.setter
def on_time(self, newval):
newval = assume_units(newval, pq.ms).rescale(pq.ms).magnitude
self._parent.sendcmd("stsont:"+str(newval))
@property
def off_time(self):
"""
Gets/sets the TTL modulation off time, in milliseconds.
This property is accessed via the `LM.modulation` namespace.
Example usage:
>>> import instruments as ik
>>> import quantities as pq
>>> laser = ik.ondax.LM.open_serial('/dev/ttyUSB0', baud=1234)
>>> print(laser.modulation.on_time)
>>> laser.modulation.on_time = 1 * pq.ms
:return: The TTL modulation off time.
:units: As specified (if a `~quantities.Quantity`) or assumed
to be of units milliseconds.
:type: `~quantities.Quantity`
"""
response = self._parent.query("stsofft?")
return float(response)*pq.ms
@off_time.setter
def off_time(self, newval):
newval = assume_units(newval, pq.ms).rescale(pq.ms).magnitude
self._parent.sendcmd("stsofft:"+str(newval))
@property
def enabled(self):
"""
Get/Set the TTL modulation output state.
This property is accessed via the `LM.modulation` namespace.
Example usage:
>>> import instruments as ik
>>> laser = ik.ondax.LM.open_serial('/dev/ttyUSB0', baud=1234)
>>> print(laser.modulation.enabled)
>>> laser.modulation.enabled = True
:type: `bool`
"""
return self._enabled
@enabled.setter
def enabled(self, newval):
if not isinstance(newval, bool):
raise TypeError("Modulation enabled property must be specified "
"with a boolean, got {}.".format(type(newval)))
if newval:
self._parent.sendcmd("stm")
else:
self._parent.sendcmd("ctm")
self._enabled = newval
class _ThermoElectricCooler(object):
"""
Options and functions relating to the laser diode's thermo electric
cooler.
.. warning:: This class is not designed to be accessed directly. It
should be interfaced via `LM.tec`
"""
def __init__(self, parent):
self._parent = parent
self._enabled = False
@property
def current(self):
"""
Gets the thermoelectric cooler current setting.
This property is accessed via the `LM.tec` namespace.
Example usage:
>>> import instruments as ik
>>> laser = ik.ondax.LM.open_serial('/dev/ttyUSB0', baud=1234)
>>> print(laser.tec.current)
:units: mA
:type: `~quantities.Quantity`
"""
response = self._parent.query("rti?")
return float(response)*pq.mA
@property
def target(self):
"""
Gets the thermoelectric cooler target temperature.
This property is acccessed via the `LM.tec` namespace.
Example usage:
>>> import instruments as ik
>>> laser = ik.ondax.LM.open_serial('/dev/ttyUSB0', baud=1234)
>>> print(laser.tec.target)
:units: Degrees Celcius
:type: `~quantities.Quantity`
"""
response = self._parent.query("rstt?")
return float(response)*pq.degC
@property
def enabled(self):
"""
Gets/sets the enable state for the thermoelectric cooler.
This property is accessed via the `LM.tec` namespace.
Example usage:
>>> import instruments as ik
>>> laser = ik.ondax.LM.open_serial('/dev/ttyUSB0', baud=1234)
>>> print(laser.tec.enabled)
>>> laser.tec.enabled = True
:type: `bool`
"""
return self._enabled
@enabled.setter
def enabled(self, newval):
if not isinstance(newval, bool):
raise TypeError("TEC enabled property must be specified with "
"a boolean, got {}.".format(type(newval)))
if newval:
self._parent.sendcmd("tecon")
else:
self._parent.sendcmd("tecoff")
self._enabled = newval
def _ack_expected(self, msg=""):
if msg.find("?") > 0:
return None
return "OK"
@property
def firmware(self):
"""
Gets the laser system firmware version.
:type: `str`
"""
response = self.query("rsv?")
return response
@property
def current(self):
"""
Gets/sets the laser diode current, in mA.
:units: As specified (if a `~quantities.Quantity`) or assumed
to be of units mA.
:type: `~quantities.Quantity`
"""
response = self.query("rli?")
return float(response)*pq.mA
@current.setter
def current(self, newval):
newval = assume_units(newval, pq.mA).rescale(pq.mA).magnitude
self.sendcmd("slc:"+str(newval))
@property
def maximum_current(self):
"""
Get/Set the maximum laser diode current in mA. If the current is set
over the limit, the laser will shut down.
:units: As specified (if a `~quantities.Quantity`) or assumed
to be of units mA.
:type: `~quantities.Quantity`
"""
response = self.query("rlcm?")
return float(response)*pq.mA
@maximum_current.setter
def maximum_current(self, newval):
newval = assume_units(newval, pq.mA).rescale('mA').magnitude
self.sendcmd("smlc:" + str(newval))
@property
def power(self):
"""
Get/Set the laser's optical power in mW.
:units: As specified (if a `~quantities.Quantity`) or assumed
to be of units mW.
:rtype: `~quantities.Quantity`
"""
response = self.query("rlp?")
return float(response)*pq.mW
@power.setter
def power(self, newval):
newval = assume_units(newval, pq.mW).rescale(pq.mW).magnitude
self.sendcmd("slp:"+str(newval))
@property
def serial_number(self):
"""
Gets the laser controller serial number
:type: `str`
"""
response = self.query("rsn?")
return response
@property
def status(self):
"""
Read laser controller run status.
:type: `LM.Status`
"""
response = self.query("rlrs?")
return self.Status(int(response))
@property
def temperature(self):
"""
Gets/sets laser diode temperature.
:units: As specified (if a `~quantities.Quantity`) or assumed
to be of units degrees celcius.
:type: `~quantities.Quantity`
"""
response = self.query("rtt?")
return float(response)*pq.degC
@temperature.setter
def temperature(self, newval):
newval = convert_temperature(newval, pq.degC).magnitude
self.sendcmd("stt:"+str(newval))
@property
def enabled(self):
"""
Gets/sets the laser emission enabled status.
:type: `bool`
"""
return self._enabled
@enabled.setter
def enabled(self, newval):
if not isinstance(newval, bool):
raise TypeError("Laser module enabled property must be specified "
"with a boolean, got {}.".format(type(newval)))
if newval:
self.sendcmd("lon")
else:
self.sendcmd("loff")
self._enabled = newval
[docs] def save(self):
"""
Save current settings in flash memory.
"""
self.sendcmd("ssc")
[docs] def reset(self):
"""
Reset the laser controller.
"""
self.sendcmd("reset")