diff --git a/catkit2/services/thorlabs_fw102c_dll/FWxC_COMMAND_LIB.py b/catkit2/services/thorlabs_fw102c_dll/FWxC_COMMAND_LIB.py new file mode 100644 index 000000000..8621014c8 --- /dev/null +++ b/catkit2/services/thorlabs_fw102c_dll/FWxC_COMMAND_LIB.py @@ -0,0 +1,293 @@ +# flake8: noqa + +# This module is a modified version of the original FWxC_COMMAND_LIB.py file from the Thorlabs FW102C filter wheel SDK v5.0.0 + +# The Thorlabs FW102C filter wheel SDK is available at https://www.thorlabs.com/software_pages/ViewSoftwarePage.cfm?Code=FW102C +# The original FWxC_COMMAND_LIB.py file is located at c://Program Files (x86)//Thorlabs//FWxC//Sample//Thorlabs_FWxC_PythonSDK +# The original FWxC_COMMAND_LIB.py file loads the FilterWheel102_win32.dll file instead of the FilterWheel102_win64.dll file +# modified by: Arnaud Sevin + + +from ctypes import * + +import os +os.add_dll_directory("c://Program Files (x86)//Thorlabs//FWxC//Sample//Thorlabs_FWxC_C++SDK") + +#region import dll functions +FWxCLib = cdll.LoadLibrary("FilterWheel102_win64.dll") + +"""common command +""" +List = FWxCLib.List +List.restype = c_int +List.argtypes = [c_char_p, c_uint] + +Open = FWxCLib.Open +Open.restype = c_int +Open.argtypes = [c_char_p,c_int,c_int] + +IsOpen = FWxCLib.IsOpen +IsOpen.restype = c_int +IsOpen.argtypes = [c_char_p] + +Close = FWxCLib.Close +Close.restype = c_int +Close.argtypes = [c_int] + +"""device command +""" +SetPosition = FWxCLib.SetPosition +SetPosition.restype = c_int +SetPosition.argtypes = [c_int,c_int] + +SetPositionCount = FWxCLib.SetPositionCount +SetPositionCount.restype = c_int +SetPositionCount.argtypes = [c_int,c_int] + +SetSpeedMode = FWxCLib.SetSpeedMode +SetSpeedMode.restype = c_int +SetSpeedMode.argtypes = [c_int,c_int] + +SetTriggerMode = FWxCLib.SetTriggerMode +SetTriggerMode.restype = c_int +SetTriggerMode.argtypes = [c_int,c_int] + +SetSensorMode = FWxCLib.SetSensorMode +SetSensorMode.restype = c_int +SetSensorMode.argtypes = [c_int,c_int] + +Save = FWxCLib.Save +Save.restype = c_int +Save.argtypes = [c_int] + +GetId = FWxCLib.GetId +GetId.restype = c_int +GetId.argtypes = [c_int,c_char_p] + +GetPosition = FWxCLib.GetPosition +GetPosition.restype = c_int +GetPosition.argtypes = [c_int,POINTER(c_int)] + +GetPositionCount = FWxCLib.GetPositionCount +GetPositionCount.restype = c_int +GetPositionCount.argtypes = [c_int,POINTER(c_int)] + +GetSpeedMode = FWxCLib.GetSpeedMode +GetSpeedMode.restype = c_int +GetSpeedMode.argtypes = [c_int,POINTER(c_int)] + +GetTriggerMode = FWxCLib.GetTriggerMode +GetTriggerMode.restype = c_int +GetTriggerMode.argtypes = [c_int,POINTER(c_int)] + +GetSensorMode = FWxCLib.GetSensorMode +GetSensorMode.restype = c_int +GetSensorMode.argtypes = [c_int,POINTER(c_int)] + + +#region command for FWxC +def FWxCListDevices(): + """ List all connected FWxC devices + Returns: + The FWxC device list, each deice item is [serialNumber, FWxCType] + """ + str = create_string_buffer(1024, '\0') + result = List(str,1024) + devicesStr = str.raw.decode("utf-8").rstrip('\x00').split(',') + length = len(devicesStr) + i = 0 + devices = [] + devInfo = ["",""] + while(i < length): + str = devicesStr[i] + if (i % 2 == 0): + if str != '': + devInfo[0] = str + else: + i+=1 + else: + if(str.find("FWxC") >= 0): + isFind = True + devInfo[1] = str + devices.append(devInfo.copy()) + i+=1 + return devices + + +def FWxCOpen(serialNo, nBaud, timeout): + """ Open FWxC device + Args: + serialNo: serial number of FWxC device + nBaud: bit per second of port + timeout: set timeout value in (s) + Returns: + non-negative number: hdl number returned Successful; negative number: failed. + """ + return Open(serialNo.encode('utf-8'), nBaud, timeout) + +def FWxCIsOpen(serialNo): + """ Check opened status of FWxC device + Args: + serialNo: serial number of FWxC device + Returns: + 0: FWxC device is not opened; 1: FWxC device is opened. + """ + return IsOpen(serialNo.encode('utf-8')) + +def FWxCClose(hdl): + """ Close opened FWxC device + Args: + hdl: the handle of opened FWxC device + Returns: + 0: Success; negative number: failed. + """ + return Close(hdl) + +def FWxCSetPosition(hdl, pos): + """ set fiterwheel's position + Args: + hdl: the handle of opened FWxC device + pos: fiterwheel position + Returns: + 0: Success; 0xEA: CMD_NOT_DEFINED; 0xEB: time out; 0xED: invalid string buffer. + """ + return SetPosition(hdl,pos) + +def FWxCSetPositionCount(hdl, count): + """ set fiterwheel's position count + Args: + hdl: the handle of opened FWxC device + count: fiterwheel PositionCount + Returns: + 0: Success; 0xEA: CMD_NOT_DEFINED; 0xEB: time out; 0xED: invalid string buffer. + """ + return SetPositionCount(hdl, count) + +def FWxCSetSpeedMode(hdl, spmode): + """ set fiterwheel's trigger mode + Args: + hdl: the handle of opened FWxC device + spmode: fiterwheel speed mode + speed=0 Sets the move profile to slow speed + speed=1 Sets the move profile to high speed + Returns: + 0: Success; 0xEA: CMD_NOT_DEFINED; 0xEB: time out; 0xED: invalid string buffer. + """ + return SetSpeedMode(hdl,spmode) + +def FWxCSetTriggerMode(hdl, trimode): + """ set fiterwheel's trigger mode + Args: + hdl: the handle of opened FWxC device + trimode: fiterwheel's trigger mode + trig=0 Sets the external trigger to the input mode, Respond to an active low pulse by advancing position by 1 + trig=1 Sets the external trigger to the output mode, Generate an active high pulse when selected position arrived at + Returns: + 0: Success; 0xEA: CMD_NOT_DEFINED; 0xEB: time out; 0xED: invalid string buffer. + """ + return SetTriggerMode(hdl,trimode) + +def FWxCSetSensorMode(hdl, senmode): + """ set fiterwheel's sensor mode + Args: + hdl: the handle of opened FWxC device + senmode: fiterwheel sensor mode + sensors=0 Sensors turn off when wheel is idle to eliminate stray light + sensors=1 Sensors remain active + Returns: + 0: Success; 0xEA: CMD_NOT_DEFINED; 0xEB: time out; 0xED: invalid string buffer. + """ + return SetSensorMode(hdl, senmode) + +def FWxCSave(hdl): + """ save all the settings as default on power up + Args: + hdl: the handle of opened FWxC device + Returns: + 0: Success; 0xEA: CMD_NOT_DEFINED; 0xEB: time out; 0xED: invalid string buffer. + """ + return Save(hdl) + +def FWxCGetId(hdl, value): + """ get the FWxC id + Args: + hdl: the handle of opened FWxC device + value: the model number, hardware and firmware versions + Returns: + 0: Success; 0xEA: CMD_NOT_DEFINED; 0xEB: time out; 0xED: invalid string buffer. + """ + idStr = create_string_buffer(1024,'\0') + ret = GetId(hdl,idStr) + value.append(idStr.raw.decode("utf-8").rstrip('\x00')) + return ret + + +def FWxCGetPosition(hdl, pos): + """ get the fiterwheel current position + Args: + hdl: the handle of opened FWxC device + pos: fiterwheel actual position + Returns: + 0: Success; 0xEA: CMD_NOT_DEFINED; 0xEB: time out; 0xED: invalid string buffer. + """ + val = c_int(0) + ret = GetPosition(hdl,val) + pos[0] = val.value + return ret + +def FWxCGetPositionCount(hdl, poscount): + """ get the fiterwheel current position count + Args: + hdl: the handle of opened FWxC device + poscount: fiterwheel actual position count + Returns: + 0: Success; 0xEA: CMD_NOT_DEFINED; 0xEB: time out; 0xED: invalid string buffer. + """ + val = c_int(0) + ret = GetPositionCount(hdl,val) + poscount[0] = val.value + return ret + +def FWxCGetSpeedMode(hdl, spemode): + """ get the fiterwheel current speed mode + Args: + hdl: the handle of opened FWxC device + spemode: 0,slow speed:1,high speed + Returns: + 0: Success; 0xEA: CMD_NOT_DEFINED; 0xEB: time out; 0xED: invalid string buffer. + """ + val = c_int(0) + ret = GetSpeedMode(hdl,val) + spemode[0] = val.value + return ret + +def FWxCGetTriggerMode(hdl, triggermode): + """ get the fiterwheel current position count + Args: + hdl: the handle of opened FWxC device + triggermode: fiterwheel actual trigger mode:0, input mode;1, output mode + Returns: + 0: Success; 0xEA: CMD_NOT_DEFINED; 0xEB: time out; 0xED: invalid string buffer. + """ + val = c_int(0) + ret = GetTriggerMode(hdl,val) + triggermode[0] = val.value + return ret + +def FWxCGetSensorMode(hdl, sensormode): + """ get the fiterwheel current sensor mode + Args: + hdl: the handle of opened FWxC device + sensormode: fiterwheel actual sensor mode:0, Sensors turn off;1, Sensors remain active + Returns: + 0: Success; 0xEA: CMD_NOT_DEFINED; 0xEB: time out; 0xED: invalid string buffer. + """ + val = c_int(0) + ret = GetSensorMode(hdl,val) + sensormode[0] = val.value + return ret + + + + +#endregion diff --git a/catkit2/services/thorlabs_fw102c_dll/thorlabs_fw102c_dll.py b/catkit2/services/thorlabs_fw102c_dll/thorlabs_fw102c_dll.py new file mode 100644 index 000000000..4bb775284 --- /dev/null +++ b/catkit2/services/thorlabs_fw102c_dll/thorlabs_fw102c_dll.py @@ -0,0 +1,203 @@ +''' +Thorlabs FW102C DLL Service +--------------------------- + +This service is used to control the Thorlabs FW102C filter wheel using the Thorlabs FW102C DLL. + +The Thorlabs FW102C filter wheel SDK is available at https://www.thorlabs.com/software_pages/ViewSoftwarePage.cfm?Code=FW102C + +The original FWxC_COMMAND_LIB.py file is located at c://Program Files (x86)//Thorlabs//FWxC//Sample//Thorlabs_FWxC_PythonSDK +The original FWxC_COMMAND_LIB.py file loads the FilterWheel102_win32.dll file instead of the FilterWheel102_win64.dll file +''' + +import time +from catkit2.testbed.service import Service + +try: + from FWxC_COMMAND_LIB import ( + FWxCOpen, + FWxCClose, + FWxCGetPosition, + FWxCSetPosition, + FWxCListDevices, + FWxCSetTriggerMode, + FWxCSetSpeedMode, + FWxCSetSensorMode + ) +except OSError as ex: + print("Warning:", ex) + + +class ThorlabsFW102CDll(Service): + ''' + Thorlabs FW102C DLL Service + --------------------------- + + This class provides a service to control the Thorlabs FW102C filter wheel using the Thorlabs FW102C DLL. + It inherits from the Service class in the catkit2.testbed package. + + Attributes + ---------- + serial : str + The serial number of the device. + hdl : int + The handle of the device. + + Methods + ------- + __init__(): + Initializes the ThorlabsFW102CDll service. + open(): + Opens a connection to the device. + main(): + Main loop that keeps the service running. + close(): + Closes the connection to the device. + get_position(): + Gets the current position of the filter wheel. + set_position(position: int): + Sets the position of the filter wheel. + position: + Property that gets or sets the position of the filter wheel. + ''' + def __init__(self): + ''' + Initialize the ThorlabsFW102CDll service. + + This method initializes the ThorlabsFW102CDll service by calling the __init__ method of the superclass with 'thorlabs_fw102c_dll' as the argument. + It also initializes the serial number of the device and the handle of the device. + ''' + super().__init__('thorlabs_fw102c_dll') + + self.serial = self.config['serial'] + devs = FWxCListDevices() + if len(devs) <= 0: + raise RuntimeError("There is no devices connected") + if self.serial not in [dev[0] for dev in devs]: + raise RuntimeError("Device %s not found", self.serial) + self.hdl = None + + def make_property_helper(property_name, read_only=False, dtype=None): + if dtype is None: + dtype = '' + + def getter(): + return getattr(self, property_name) + + if read_only: + self.make_property(property_name, getter, type=dtype) + return + + def setter(value): + setattr(self, property_name, value) + + self.make_property(property_name, getter, setter, type=dtype) + + make_property_helper('position', dtype='int64') + + # self.make_command('get_position', self.get_position) + # self.make_command('set_position', self.set_position) + + def open(self): + ''' + Open a connection to the device. + + This method opens a connection to the device using the FWxCOpen function from the FWxC_COMMAND_LIB library. + It also sets the input trigger mode, high speed mode, and turn off the sensor of the device. + ''' + self.hdl = FWxCOpen(self.serial, 115200, 3) + if self.hdl < 0: + raise RuntimeError(f"Connect {self.serial} fail") + + # 0: input mode, 1: output mode + result = FWxCSetTriggerMode(self.hdl, 0) + if result < 0: + self.log.warning("Set Trigger Mode fail") + + # 0: slow speed, 1: high speed + result = FWxCSetSpeedMode(self.hdl, 1) + if result < 0: + self.log.warning("Set Speed Mode fail") + + # 0: Sensors turn off, 1: Sensors remain active + result = FWxCSetSensorMode(self.hdl, 0) + if result < 0: + self.log.warning("Set Sensor Mode fail") + + self.log.info("Connect %s successful", self.serial) + + def main(self): + ''' + Main loop that keeps the service running. + + This method keeps the service running until it should shut down. + ''' + while not self.should_shut_down: + time.sleep(0.1) + + def close(self): + ''' + Close the connection to the device. + + This method closes the connection to the device using the FWxCClose function from the FWxC_COMMAND_LIB library. + ''' + if self.hdl is None: + raise RuntimeError("Device not connected") + FWxCClose(self.hdl) + self.log.info("Close %s successful", self.serial) + + def get_position(self): + ''' + Get the current position of the filter wheel. + + This method gets the current position of the filter wheel using the FWxCGetPosition function from the FWxC_COMMAND_LIB library. + ''' + if self.hdl is None: + return -1 + pos = [-1] + + result = FWxCGetPosition(self.hdl, pos) + if result < 0 and pos[0] < 0: + self.log.error("Get Position fail") + return -1 + + # self.log.info("Get Position: %d", pos[0]) + return pos[0] + + def set_position(self, position: int): + ''' + Set the position of the filter wheel. + + This method sets the position of the filter wheel using the FWxCSetPosition function from the FWxC_COMMAND_LIB library. + + Parameters + ---------- + position : int + The position to set the filter wheel to. + ''' + if self.hdl is None: + raise RuntimeError("Device not connected") + result = FWxCSetPosition(self.hdl, position) + if result < 0: + self.log.error("Set Position fail") + return -1 + + self.log.info("Position is %d", position) + + @property + def position(self): + ''' + Get or set the position of the filter wheel. + + This property gets or sets the position of the filter wheel using the get_position and set_position methods. + ''' + return self.get_position() + + @position.setter + def position(self, position: int): + self.set_position(position) + + +if __name__ == '__main__': + service = ThorlabsFW102CDll() + service.run() diff --git a/catkit2/services/thorlabs_fw102c_dll_sim/thorlabs_fw102c_dll_sim.py b/catkit2/services/thorlabs_fw102c_dll_sim/thorlabs_fw102c_dll_sim.py new file mode 100644 index 000000000..19148fa09 --- /dev/null +++ b/catkit2/services/thorlabs_fw102c_dll_sim/thorlabs_fw102c_dll_sim.py @@ -0,0 +1,142 @@ +''' +Thorlabs FW102C DLL simulated Service +------------------------------------- + +This service is simulating the control of the Thorlabs FW102C filter wheel using the Thorlabs FW102C DLL. + +''' + +import time +from catkit2.testbed.service import Service + + +class ThorlabsFW102CDllSim(Service): + ''' + Thorlabs FW102C DLL Service + --------------------------- + + This class provides a simulated service to control the Thorlabs FW102C filter wheel using the Thorlabs FW102C DLL. + It inherits from the Service class in the catkit2.testbed package. + + Attributes + ---------- + serial : str + The serial number of the device. + + Methods + ------- + __init__(): + Initializes the ThorlabsFW102CDll service. + open(): + Opens a connection to the device. + main(): + Main loop that keeps the service running. + close(): + Closes the connection to the device. + get_position(): + Gets the current position of the filter wheel. + set_position(position: int): + Sets the position of the filter wheel. + position: + Property that gets or sets the position of the filter wheel. + ''' + def __init__(self): + ''' + Initialize the ThorlabsFW102CDll service. + + This method initializes the ThorlabsFW102CDll service by calling the __init__ method of the superclass with 'thorlabs_fw102c_dll' as the argument. + It also initializes the serial number of the device and the handle of the device. + ''' + super().__init__('thorlabs_fw102c_dll_sim') + + self.serial = self.config['serial'] + self.hdl = None + self._position = 1 + + def make_property_helper(property_name, read_only=False, dtype=None): + if dtype is None: + dtype = '' + + def getter(): + return getattr(self, property_name) + + if read_only: + self.make_property(property_name, getter, type=dtype) + return + + def setter(value): + setattr(self, property_name, value) + + self.make_property(property_name, getter, setter, type=dtype) + + make_property_helper('position', dtype='int64') + + # self.make_command('get_position', self.get_position) + # self.make_command('set_position', self.set_position) + + def open(self): + ''' + Open a connection to the device. + + This method opens a connection to the device using the FWxCOpen function from the FWxC_COMMAND_LIB library. + It also sets the input trigger mode, high speed mode, and turn off the sensor of the device. + ''' + self.log.info("Connect %s successful", self.serial) + + def main(self): + ''' + Main loop that keeps the service running. + + This method keeps the service running until it should shut down. + ''' + while not self.should_shut_down: + time.sleep(0.1) + + def close(self): + ''' + Close the connection to the device. + + This method closes the connection to the device using the FWxCClose function from the FWxC_COMMAND_LIB library. + ''' + self.log.info("Close %s successful", self._position) + + def get_position(self): + ''' + Get the current position of the filter wheel. + + This method gets the current position of the filter wheel using the FWxCGetPosition function from the FWxC_COMMAND_LIB library. + ''' + # self.log.info("Get Position: %d", pos[0]) + return self._position + + def set_position(self, position: int): + ''' + Set the position of the filter wheel. + + This method sets the position of the filter wheel using the FWxCSetPosition function from the FWxC_COMMAND_LIB library. + + Parameters + ---------- + position : int + The position to set the filter wheel to. + ''' + self._position = position + self.log.info("Position is %d", position) + + @property + def position(self): + ''' + Get or set the position of the filter wheel. + + This property gets or sets the position of the filter wheel using the get_position and set_position methods. + ''' + return self.get_position() + + @position.setter + def position(self, position: int): + return self.set_position(position) + + +if __name__ == '__main__': + service = ThorlabsFW102CDllSim() + service.run()