Source code for msl.equipment.resources.thorlabs.kinesis.filter_flipper

"""
This module provides all the functionality required to control a
Filter Flipper (MFF101, MFF102).
"""
from __future__ import annotations

from ctypes import byref
from ctypes import c_int64

from msl.equipment.resources import register
from .api_functions import FilterFlipper_FCNS
from .enums import FF_IOModes
from .enums import FF_SignalModes
from .motion_control import MotionControl
from .structs import FF_IOSettings
from ...utils import DWORD
from ...utils import WORD


[docs] @register(manufacturer=r'Thorlabs', model=r'MFF10[1|2]') class FilterFlipper(MotionControl): MIN_TRANSIT_TIME = 300 MAX_TRANSIT_TIME = 2800 MIN_PULSE_WIDTH = 10 MAX_PULSE_WIDTH = 200 def __init__(self, record): """A wrapper around ``Thorlabs.MotionControl.FilterFlipper.dll``. The :attr:`~msl.equipment.record_types.ConnectionRecord.properties` for a FilterFlipper connection supports the following key-value pairs in the :ref:`connections-database`:: 'device_name': str, the device name found in ThorlabsDefaultSettings.xml [default: None] Do not instantiate this class directly. Use the :meth:`~.EquipmentRecord.connect` method to connect to the equipment. Parameters ---------- record : :class:`~msl.equipment.record_types.EquipmentRecord` A record from an :ref:`equipment-database`. """ name = record.connection.properties.get('device_name') if name is None: record.connection.properties['device_name'] = 'MFF Filter Flipper' super(FilterFlipper, self).__init__(record, FilterFlipper_FCNS)
[docs] def open(self): """Open the device for communication. Raises ------ ~msl.equipment.exceptions.ThorlabsError If not successful. """ self.sdk.FF_Open(self._serial)
[docs] def close(self): """Disconnect and close the device.""" self.sdk.FF_Close(self._serial)
[docs] def check_connection(self): """Check connection. Returns ------- :class:`bool` Whether the USB is listed by the FTDI controller. """ return self.sdk.FF_CheckConnection(self._serial)
[docs] def identify(self): """Sends a command to the device to make it identify itself.""" self.sdk.FF_Identify(self._serial)
[docs] def get_hardware_info(self): """Gets the hardware information from the device. Returns ------- :class:`.structs.TLI_HardwareInformation` The hardware information. Raises ------ ~msl.equipment.exceptions.ThorlabsError If not successful. """ return self._get_hardware_info(self.sdk.FF_GetHardwareInfo)
[docs] def get_firmware_version(self): """Gets version number of the device firmware. Returns ------- :class:`str` The firmware version. """ return self.to_version(self.sdk.FF_GetFirmwareVersion(self._serial))
[docs] def get_software_version(self): """Gets version number of the device software. Returns ------- :class:`str` The device software version. """ return self.to_version(self.sdk.FF_GetSoftwareVersion(self._serial))
[docs] def load_settings(self): """Update device with stored settings. The settings are read from ``ThorlabsDefaultSettings.xml``, which gets created when the Kinesis software is installed. Raises ------ ~msl.equipment.exceptions.ThorlabsError If not successful. """ self.sdk.FF_LoadSettings(self._serial)
[docs] def load_named_settings(self, settings_name): """Update device with named settings. Parameters ---------- settings_name : :class:`str` The name of the device to load the settings for. Examples for the value of `setting_name` can be found in `ThorlabsDefaultSettings.xml``, which gets created when the Kinesis software is installed. Raises ------ ~msl.equipment.exceptions.ThorlabsError If not successful. """ self.sdk.FF_LoadNamedSettings(self._serial, settings_name.encode())
[docs] def persist_settings(self): """Persist the devices current settings. Raises ------ ~msl.equipment.exceptions.ThorlabsError If not successful. """ self.sdk.FF_PersistSettings(self._serial)
[docs] def get_number_positions(self): """Get number of positions available from the device. Returns ------- :class:`int` The number of positions. """ return self.sdk.FF_GetNumberPositions(self._serial)
[docs] def home(self): """Home the device. Homing the device will set the device to a known state and determine the home position. Raises ------ ~msl.equipment.exceptions.ThorlabsError If not successful. """ self.sdk.FF_Home(self._serial)
[docs] def move_to_position(self, position): """Move the device to the specified position (index). Parameters ---------- position : :class:`int` The required position. Must be 1 or 2. Raises ------ ~msl.equipment.exceptions.ThorlabsError If not successful. """ self.sdk.FF_MoveToPosition(self._serial, position)
[docs] def get_position(self): """Get the current position. Returns ------- :class:`int` The position, 1 or 2 (can be 0 during a move). """ return self.sdk.FF_GetPosition(self._serial)
[docs] def get_io_settings(self): """Gets the I/O settings from filter flipper. Returns ------- :class:`~.structs.FF_IOSettings` The Filter Flipper I/O settings. Raises ------ ~msl.equipment.exceptions.ThorlabsError If not successful. """ settings = FF_IOSettings() self.sdk.FF_GetIOSettings(self._serial, byref(settings)) return settings
[docs] def request_io_settings(self): """Requests the I/O settings from the filter flipper. Raises ------ ~msl.equipment.exceptions.ThorlabsError If not successful. """ self.sdk.FF_RequestIOSettings(self._serial)
[docs] def set_io_settings(self, transit_time=500, oper1=FF_IOModes.FF_ToggleOnPositiveEdge, sig1=FF_SignalModes.FF_InputButton, pw1=200, oper2=FF_IOModes.FF_ToggleOnPositiveEdge, sig2=FF_SignalModes.FF_OutputLevel, pw2=200): """ Sets the settings on filter flipper. Parameters ---------- transit_time : :class:`int`, optional Time taken to get from one position to other in milliseconds. oper1 : :class:`~.enums.FF_IOModes`, optional I/O 1 Operating Mode. sig1 : :class:`~.enums.FF_SignalModes`, optional I/O 1 Signal Mode. pw1 : :class:`int`, optional Digital I/O 1 pulse width in milliseconds. oper2 : :class:`~.enums.FF_IOModes`, optional I/O 2 Operating Mode. sig2 : :class:`~.enums.FF_SignalModes`, optional I/O 2 Signal Mode. pw2 : :class:`int`, optional Digital I/O 2 pulse width in milliseconds. Raises ------ ~msl.equipment.exceptions.ThorlabsError If not successful. """ if transit_time > self.MAX_TRANSIT_TIME or transit_time < self.MIN_TRANSIT_TIME: msg = 'Invalid transit time value of {} ms; {} <= transit_time <= {}'.format( transit_time, self.MIN_TRANSIT_TIME, self.MAX_TRANSIT_TIME) self.raise_exception(msg) if pw1 > self.MAX_PULSE_WIDTH or pw1 < self.MIN_PULSE_WIDTH: msg = 'Invalid digital I/O 1 pulse width of {} ms; {} <= pw <= {}'.format( pw1, self.MIN_PULSE_WIDTH, self.MAX_PULSE_WIDTH) self.raise_exception(msg) if pw2 > self.MAX_PULSE_WIDTH or pw2 < self.MIN_PULSE_WIDTH: msg = 'Invalid digital I/O 2 pulse width of {} ms; {} <= pw <= {}'.format( pw2, self.MIN_PULSE_WIDTH, self.MAX_PULSE_WIDTH) self.raise_exception(msg) settings = FF_IOSettings() settings.transitTime = int(transit_time) settings.digIO1OperMode = self.convert_to_enum(oper1, FF_IOModes, prefix='FF_') settings.digIO1SignalMode = self.convert_to_enum(sig1, FF_SignalModes, prefix='FF_') settings.digIO1PulseWidth = int(pw1) settings.digIO2OperMode = self.convert_to_enum(oper2, FF_IOModes, prefix='FF_') settings.digIO2SignalMode = self.convert_to_enum(sig2, FF_SignalModes, prefix='FF_') settings.digIO2PulseWidth = int(pw2) self.sdk.FF_SetIOSettings(self._serial, byref(settings))
[docs] def get_transit_time(self): """Gets the transit time. Returns ------- :class:`int` The transit time in milliseconds. """ return self.sdk.FF_GetTransitTime(self._serial)
[docs] def set_transit_time(self, transit_time): """Sets the transit time. Parameters ---------- transit_time : :class:`int` The transit time in milliseconds. Raises ------ ~msl.equipment.exceptions.ThorlabsError If not successful. """ if transit_time > self.MAX_TRANSIT_TIME or transit_time < self.MIN_TRANSIT_TIME: msg = 'Invalid transit time value of {} ms; {} <= transit_time <= {}'.format( transit_time, self.MIN_TRANSIT_TIME, self.MAX_TRANSIT_TIME) self.raise_exception(msg) self.sdk.FF_SetTransitTime(self._serial, int(transit_time))
[docs] def request_status(self): """Request status bits. This needs to be called to get the device to send it's current status. This is called automatically if Polling is enabled for the device using :meth:`.start_polling`. Raises ------ ~msl.equipment.exceptions.ThorlabsError If not successful. """ self.sdk.FF_RequestStatus(self._serial)
[docs] def get_status_bits(self): """Get the current status bits. This returns the latest status bits received from the device. To get new status bits, use :meth:`.request_status` or use the polling function, :meth:`.start_polling` Returns ------- :class:`int` The status bits from the device. """ return self.sdk.FF_GetStatusBits(self._serial)
[docs] def start_polling(self, milliseconds): """Starts the internal polling loop. This function continuously requests position and status messages. Parameters ---------- milliseconds : :class:`int` The polling rate, in milliseconds. Raises ------ ~msl.equipment.exceptions.ThorlabsError If not successful. """ self.sdk.FF_StartPolling(self._serial, int(milliseconds))
[docs] def polling_duration(self): """Gets the polling loop duration. Returns ------- :class:`int` The time between polls in milliseconds or 0 if polling is not active. """ return self.sdk.FF_PollingDuration(self._serial)
[docs] def stop_polling(self): """Stops the internal polling loop.""" self.sdk.FF_StopPolling(self._serial)
[docs] def time_since_last_msg_received(self): """Gets the time, in milliseconds, since tha last message was received. This can be used to determine whether communications with the device is still good. Returns ------- :class:`int` The time, in milliseconds, since the last message was received. """ ms = c_int64() self.sdk.FF_TimeSinceLastMsgReceived(self._serial, byref(ms)) return ms.value
[docs] def enable_last_msg_timer(self, enable, msg_timeout=0): """Enables the last message monitoring timer. This can be used to determine whether communications with the device is still good. Parameters ---------- enable : :class:`bool` :data:`True` to enable monitoring otherwise :data:`False` to disable. msg_timeout : :class:`int`, optional The last message error timeout in ms. Set to 0 to disable. """ self.sdk.FF_EnableLastMsgTimer(self._serial, enable, msg_timeout)
[docs] def has_last_msg_timer_overrun(self): """Queries if the time since the last message has exceeded the ``lastMsgTimeout`` set by :meth:`.enable_last_msg_timer`. This can be used to determine whether communications with the device is still good. Returns ------- :class:`bool` :data:`True` if last message timer has elapsed or :data:`False` if monitoring is not enabled or if time of last message received is less than ``msg_timeout``. """ return self.sdk.FF_HasLastMsgTimerOverrun(self._serial)
[docs] def request_settings(self): """Requests that all settings are downloaded from the device. This function requests that the device upload all it's settings to the DLL. Raises ------ ~msl.equipment.exceptions.ThorlabsError If not successful. """ self.sdk.FF_RequestSettings(self._serial)
[docs] def clear_message_queue(self): """Clears the device message queue.""" self.sdk.FF_ClearMessageQueue(self._serial)
[docs] def register_message_callback(self, callback): """Registers a callback on the message queue. Parameters ---------- callback : :class:`~msl.equipment.resources.thorlabs.kinesis.callbacks.MotionControlCallback` A function to be called whenever messages are received. """ self.sdk.FF_RegisterMessageCallback(self._serial, callback)
[docs] def message_queue_size(self): """Gets the size of the message queue. Returns ------- :class:`int` The number of messages in the queue. """ return self.sdk.FF_MessageQueueSize(self._serial)
[docs] def get_next_message(self): """Get the next Message Queue item. See :mod:`.messages`. Returns ------- :class:`int` The message type. :class:`int` The message ID. :class:`int` The message data. Raises ------ ~msl.equipment.exceptions.ThorlabsError If not successful. """ message_type = WORD() message_id = WORD() message_data = DWORD() self.sdk.FF_GetNextMessage(self._serial, byref(message_type), byref(message_id), byref(message_data)) return message_type.value, message_id.value, message_data.value
[docs] def wait_for_message(self): """Wait for next Message Queue item. See :mod:`.messages`. Returns ------- :class:`int` The message type. :class:`int` The message ID. :class:`int` The message data. Raises ------ ~msl.equipment.exceptions.ThorlabsError If not successful. """ message_type = WORD() message_id = WORD() message_data = DWORD() self.sdk.FF_WaitForMessage(self._serial, byref(message_type), byref(message_id), byref(message_data)) return message_type.value, message_id.value, message_data.value
if __name__ == '__main__': from msl.equipment.resources.thorlabs.kinesis import _print _print(FilterFlipper, FilterFlipper_FCNS, 'Thorlabs.MotionControl.FilterFlipper.h')