microeye 2.3.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- microEye/__init__.py +47 -0
- microEye/_version.py +2 -0
- microEye/analysis/__init__.py +1 -0
- microEye/analysis/checklist_dialog.py +143 -0
- microEye/analysis/cmosMaps.py +228 -0
- microEye/analysis/filters/__init__.py +9 -0
- microEye/analysis/filters/base.py +21 -0
- microEye/analysis/filters/spatial.py +338 -0
- microEye/analysis/filters/temporal.py +76 -0
- microEye/analysis/fitting/__init__.py +0 -0
- microEye/analysis/fitting/fit.py +680 -0
- microEye/analysis/fitting/nena.py +375 -0
- microEye/analysis/fitting/phasor_fit.py +90 -0
- microEye/analysis/fitting/processing.py +317 -0
- microEye/analysis/fitting/psf/__init__.py +6 -0
- microEye/analysis/fitting/psf/extract.py +1129 -0
- microEye/analysis/fitting/psf/rubost_mean.py +150 -0
- microEye/analysis/fitting/psf/spline.py +167 -0
- microEye/analysis/fitting/psf/stats/__init__.py +12 -0
- microEye/analysis/fitting/psf/stats/core.py +295 -0
- microEye/analysis/fitting/psf/stats/curve_fit.py +708 -0
- microEye/analysis/fitting/psf/stats/io.py +104 -0
- microEye/analysis/fitting/psf/stats/slope_fit.py +171 -0
- microEye/analysis/fitting/psf/temp.py +147 -0
- microEye/analysis/fitting/psf/test.py +47 -0
- microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUfunctions.py +657 -0
- microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUmleFit_LM.py +1336 -0
- microEye/analysis/fitting/pyfit3Dcspline/CPU/CPUsplineLib.py +270 -0
- microEye/analysis/fitting/pyfit3Dcspline/CPU/__init__.py +1 -0
- microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUfunctions.py +609 -0
- microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUmleFit_LM_EMCCD.py +1396 -0
- microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUmleFit_LM_sCMOS.py +1426 -0
- microEye/analysis/fitting/pyfit3Dcspline/GPU/GPUsplineLib.py +231 -0
- microEye/analysis/fitting/pyfit3Dcspline/GPU/__init__.py +2 -0
- microEye/analysis/fitting/pyfit3Dcspline/__init__.py +10 -0
- microEye/analysis/fitting/pyfit3Dcspline/constants.py +27 -0
- microEye/analysis/fitting/pyfit3Dcspline/mainfunctions.py +903 -0
- microEye/analysis/fitting/results.py +917 -0
- microEye/analysis/fitting/results_stats.py +251 -0
- microEye/analysis/fitting/tardis.py +209 -0
- microEye/analysis/multi_viewer.py +568 -0
- microEye/analysis/processing/__init__.py +1 -0
- microEye/analysis/processing/frc.py +120 -0
- microEye/analysis/rendering/__init__.py +3 -0
- microEye/analysis/rendering/base.py +452 -0
- microEye/analysis/rendering/cloud.py +215 -0
- microEye/analysis/rendering/core.py +47 -0
- microEye/analysis/rendering/volumetric.py +198 -0
- microEye/analysis/tools/__init__.py +0 -0
- microEye/analysis/tools/kymograms.py +1079 -0
- microEye/analysis/tools/roi_selectors.py +556 -0
- microEye/analysis/utils/__init__.py +3 -0
- microEye/analysis/utils/coordinates.py +18 -0
- microEye/analysis/utils/images.py +68 -0
- microEye/analysis/utils/windows.py +19 -0
- microEye/analysis/viewer/__init__.py +3 -0
- microEye/analysis/viewer/image_options_widget.py +615 -0
- microEye/analysis/viewer/images.py +1225 -0
- microEye/analysis/viewer/layers_widget.py +415 -0
- microEye/analysis/viewer/localizations.py +1304 -0
- microEye/analysis/viewer/psf.py +1003 -0
- microEye/analysis/viewer/volume.py +456 -0
- microEye/hardware/__init__.py +3 -0
- microEye/hardware/cams/__init__.py +29 -0
- microEye/hardware/cams/camera_calibration.py +99 -0
- microEye/hardware/cams/camera_list.py +528 -0
- microEye/hardware/cams/camera_options.py +694 -0
- microEye/hardware/cams/camera_panel.py +941 -0
- microEye/hardware/cams/dummy/__init__.py +1 -0
- microEye/hardware/cams/dummy/dummy_panel.py +759 -0
- microEye/hardware/cams/jobs.py +497 -0
- microEye/hardware/cams/line_profiler.py +99 -0
- microEye/hardware/cams/linescan/IR_Cam.py +474 -0
- microEye/hardware/cams/linescan/__init__.py +1 -0
- microEye/hardware/cams/micam.py +524 -0
- microEye/hardware/cams/pco/__init__.py +58 -0
- microEye/hardware/cams/pco/enums.py +382 -0
- microEye/hardware/cams/pco/pco_cam.py +761 -0
- microEye/hardware/cams/pco/pco_panel.py +477 -0
- microEye/hardware/cams/shortcuts.py +312 -0
- microEye/hardware/cams/thorlabs/__init__.py +1 -0
- microEye/hardware/cams/thorlabs/thorlabs.py +1508 -0
- microEye/hardware/cams/thorlabs/thorlabs_panel.py +850 -0
- microEye/hardware/cams/ueye/__init__.py +1 -0
- microEye/hardware/cams/ueye/ueye_camera.py +1023 -0
- microEye/hardware/cams/ueye/ueye_panel.py +861 -0
- microEye/hardware/cams/vimba/__init__.py +1 -0
- microEye/hardware/cams/vimba/vimba_cam.py +1000 -0
- microEye/hardware/cams/vimba/vimba_panel.py +813 -0
- microEye/hardware/device.py +60 -0
- microEye/hardware/lasers/__init__.py +13 -0
- microEye/hardware/lasers/io_matchbox.py +791 -0
- microEye/hardware/lasers/io_params.py +85 -0
- microEye/hardware/lasers/io_single_laser.py +742 -0
- microEye/hardware/lasers/laser_relay.py +594 -0
- microEye/hardware/mieye/__init__.py +1 -0
- microEye/hardware/mieye/acquisition_manager.py +467 -0
- microEye/hardware/mieye/devices_manager.py +533 -0
- microEye/hardware/mieye/miEye.py +659 -0
- microEye/hardware/misc/__init__.py +0 -0
- microEye/hardware/misc/acquisition_view.py +71 -0
- microEye/hardware/misc/reglo.py +761 -0
- microEye/hardware/misc/temp.py +188 -0
- microEye/hardware/port_config.py +59 -0
- microEye/hardware/protocols/__init__.py +2 -0
- microEye/hardware/protocols/actions.py +402 -0
- microEye/hardware/protocols/actions_items.py +703 -0
- microEye/hardware/protocols/designer.py +244 -0
- microEye/hardware/protocols/scene_manager.py +191 -0
- microEye/hardware/protocols/serialization.py +97 -0
- microEye/hardware/pycromanager/__init__.py +16 -0
- microEye/hardware/pycromanager/core.py +1433 -0
- microEye/hardware/pycromanager/devices.py +461 -0
- microEye/hardware/pycromanager/enums.py +107 -0
- microEye/hardware/pycromanager/headless.py +153 -0
- microEye/hardware/pycromanager/utils.py +34 -0
- microEye/hardware/pycromanager/widgets/__init__.py +5 -0
- microEye/hardware/pycromanager/widgets/bridges.py +407 -0
- microEye/hardware/pycromanager/widgets/headless_manager.py +258 -0
- microEye/hardware/pycromanager/widgets/headless_options.py +224 -0
- microEye/hardware/pycromanager/widgets/pycro_panel.py +455 -0
- microEye/hardware/stages/__init__.py +18 -0
- microEye/hardware/stages/elliptec/__init__.py +5 -0
- microEye/hardware/stages/elliptec/baseDevice.py +314 -0
- microEye/hardware/stages/elliptec/device.py +384 -0
- microEye/hardware/stages/elliptec/deviceID.py +212 -0
- microEye/hardware/stages/elliptec/devicePort.py +379 -0
- microEye/hardware/stages/elliptec/deviceStatus.py +65 -0
- microEye/hardware/stages/elliptec/devicesView.py +706 -0
- microEye/hardware/stages/elliptec/ellDevices.py +134 -0
- microEye/hardware/stages/elliptec/messageUpdater.py +34 -0
- microEye/hardware/stages/elliptec/motorInfo.py +153 -0
- microEye/hardware/stages/elliptec/stage.py +62 -0
- microEye/hardware/stages/elliptec/test.py +139 -0
- microEye/hardware/stages/kinesis/__init__.py +1 -0
- microEye/hardware/stages/kinesis/kdc101/__init__.py +1 -0
- microEye/hardware/stages/kinesis/kdc101/enums.py +1002 -0
- microEye/hardware/stages/kinesis/kdc101/factory.py +171 -0
- microEye/hardware/stages/kinesis/kdc101/kdc101.py +718 -0
- microEye/hardware/stages/kinesis/kinesis.py +776 -0
- microEye/hardware/stages/piezo_concept.py +607 -0
- microEye/hardware/stages/stabilizer.py +785 -0
- microEye/hardware/stages/stage.py +89 -0
- microEye/hardware/widgets/__init__.py +10 -0
- microEye/hardware/widgets/controller.py +246 -0
- microEye/hardware/widgets/devices.py +133 -0
- microEye/hardware/widgets/focusWidget.py +264 -0
- microEye/hardware/widgets/qlist_slider.py +113 -0
- microEye/hardware/widgets/scan_acquisition.py +424 -0
- microEye/icons/1024.png +0 -0
- microEye/icons/128.png +0 -0
- microEye/icons/16.png +0 -0
- microEye/icons/24.png +0 -0
- microEye/icons/256.png +0 -0
- microEye/icons/32.png +0 -0
- microEye/icons/48.png +0 -0
- microEye/icons/512.png +0 -0
- microEye/icons/64.png +0 -0
- microEye/icons/__init__.py +0 -0
- microEye/icons/close.svg +88 -0
- microEye/icons/mieye.png +0 -0
- microEye/icons/min.svg +83 -0
- microEye/icons/viewer.png +0 -0
- microEye/launcher.py +42 -0
- microEye/qt.py +181 -0
- microEye/utils/__init__.py +2 -0
- microEye/utils/enum_encoder.py +10 -0
- microEye/utils/expandable_groupbox.py +93 -0
- microEye/utils/gui_helper.py +457 -0
- microEye/utils/hid/__init__.py +8 -0
- microEye/utils/hid/controller.py +153 -0
- microEye/utils/hid/device.py +63 -0
- microEye/utils/hid/enums.py +140 -0
- microEye/utils/hid/utils.py +58 -0
- microEye/utils/labelled_slider.py +134 -0
- microEye/utils/metadata.py +599 -0
- microEye/utils/metadata_tree.py +718 -0
- microEye/utils/micro_launcher.py +245 -0
- microEye/utils/parameter_tree.py +325 -0
- microEye/utils/pyscripting.py +444 -0
- microEye/utils/retry_exec.py +35 -0
- microEye/utils/start_gui.py +112 -0
- microEye/utils/thread_worker.py +115 -0
- microEye/utils/uImage.py +1512 -0
- microeye-2.3.2.dist-info/METADATA +401 -0
- microeye-2.3.2.dist-info/RECORD +190 -0
- microeye-2.3.2.dist-info/WHEEL +5 -0
- microeye-2.3.2.dist-info/entry_points.txt +2 -0
- microeye-2.3.2.dist-info/licenses/LICENSE +674 -0
- microeye-2.3.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,742 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from pyqtgraph.parametertree import Parameter
|
|
4
|
+
|
|
5
|
+
from microEye.hardware.lasers.io_params import LaserState, MB_Params
|
|
6
|
+
from microEye.qt import QtCore, QtSerialPort, QtWidgets, Signal
|
|
7
|
+
from microEye.utils import StartGUI, Tree
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class io_single_laser(QtSerialPort.QSerialPort):
|
|
11
|
+
'''
|
|
12
|
+
Class representing a single laser MatchBox device | Inherits QSerialPort
|
|
13
|
+
'''
|
|
14
|
+
|
|
15
|
+
INFO = b'r i'
|
|
16
|
+
'''Get MatchBox Info
|
|
17
|
+
'''
|
|
18
|
+
ON_DIS = b'e 2'
|
|
19
|
+
'''Enable the combiner
|
|
20
|
+
'''
|
|
21
|
+
OFF = b'e 0'
|
|
22
|
+
'''Disable the combiner
|
|
23
|
+
'''
|
|
24
|
+
READ = b'r r'
|
|
25
|
+
SETTINGS = b'r s'
|
|
26
|
+
ON_EN = b'e 1'
|
|
27
|
+
'''Enable 1st Laser Diode
|
|
28
|
+
'''
|
|
29
|
+
|
|
30
|
+
MAX_CUR = b'Lm?'
|
|
31
|
+
'''Get maximum current
|
|
32
|
+
'''
|
|
33
|
+
P_SET = b'c 4 '
|
|
34
|
+
'''Set the power value in mW
|
|
35
|
+
'''
|
|
36
|
+
P_MAX = b'r 4'
|
|
37
|
+
'''Get the max power value
|
|
38
|
+
'''
|
|
39
|
+
STATUS = b'Le'
|
|
40
|
+
'''Get the laser diodes enabled(1)/disabled(0) states
|
|
41
|
+
'''
|
|
42
|
+
# START = b'c u 2 35488'
|
|
43
|
+
START = b'c u 1 1234'
|
|
44
|
+
'''TBA
|
|
45
|
+
'''
|
|
46
|
+
|
|
47
|
+
DataReady = Signal(str, bytes)
|
|
48
|
+
|
|
49
|
+
Max_Power = 0.0
|
|
50
|
+
|
|
51
|
+
R_Diode_Temp = 0.0
|
|
52
|
+
R_Crystal_Temp = 0.0
|
|
53
|
+
R_Body_Temp = 0.0
|
|
54
|
+
|
|
55
|
+
R_LD_Current = '0.0mA'
|
|
56
|
+
|
|
57
|
+
R_Crystal_TEC_Load = '0%'
|
|
58
|
+
R_LD_TEC_Load = '0%'
|
|
59
|
+
|
|
60
|
+
R_Status = 'OFF'
|
|
61
|
+
|
|
62
|
+
R_Fan_Load = '0%'
|
|
63
|
+
|
|
64
|
+
R_Input_Voltage = '5V'
|
|
65
|
+
|
|
66
|
+
S_Crystal_Temp = 0.0
|
|
67
|
+
S_Diode_Temp = 0.0
|
|
68
|
+
|
|
69
|
+
S_LD_Current = '0.0mA'
|
|
70
|
+
S_Feedback_DAC = 0
|
|
71
|
+
|
|
72
|
+
S_Power = 0.0
|
|
73
|
+
|
|
74
|
+
S_LD_MaxCurrent = 0.0
|
|
75
|
+
|
|
76
|
+
S_Autostart_Mode = 'OFF'
|
|
77
|
+
|
|
78
|
+
S_Access_Level = 1
|
|
79
|
+
|
|
80
|
+
S_Fan_Temp = 0.0
|
|
81
|
+
|
|
82
|
+
Firmware = ''
|
|
83
|
+
Serial = ''
|
|
84
|
+
Model = ''
|
|
85
|
+
Operation_Time = ''
|
|
86
|
+
ON_Times = ''
|
|
87
|
+
|
|
88
|
+
def SendCommand(self, command, log_print: bool = True, delay: int = 1):
|
|
89
|
+
'''
|
|
90
|
+
Sends a specific command to the device and waits for the response.
|
|
91
|
+
Then emits the DataReady signal with the response and command as arguments.
|
|
92
|
+
|
|
93
|
+
Parameters
|
|
94
|
+
----------
|
|
95
|
+
command : bytes
|
|
96
|
+
Command to be sent to the device.
|
|
97
|
+
log_print : bool, optional
|
|
98
|
+
If True, prints the response and command to the console.
|
|
99
|
+
delay : int, optional
|
|
100
|
+
Delay in milliseconds before reading the response.
|
|
101
|
+
'''
|
|
102
|
+
if self.isOpen():
|
|
103
|
+
self.write(command)
|
|
104
|
+
self.waitForBytesWritten(500)
|
|
105
|
+
QtCore.QThread.msleep(delay)
|
|
106
|
+
while self.bytesAvailable() < 5:
|
|
107
|
+
self.waitForReadyRead(500)
|
|
108
|
+
|
|
109
|
+
response = str(self.readAll(), encoding='utf8').strip('\r\n').strip()
|
|
110
|
+
if log_print:
|
|
111
|
+
print(response, command)
|
|
112
|
+
|
|
113
|
+
self.DataReady.emit(response, command)
|
|
114
|
+
|
|
115
|
+
return response
|
|
116
|
+
|
|
117
|
+
def OpenCOM(self):
|
|
118
|
+
'''Opens the serial port and initializes the combiner.'''
|
|
119
|
+
if not self.isOpen():
|
|
120
|
+
self.open(QtCore.QIODevice.OpenModeFlag.ReadWrite)
|
|
121
|
+
self.flush()
|
|
122
|
+
|
|
123
|
+
if self.isOpen():
|
|
124
|
+
self.SendCommand(io_single_laser.ON_DIS)
|
|
125
|
+
self.SendCommand(io_single_laser.START)
|
|
126
|
+
# self.SendCommand(io_single_laser.STATUS)
|
|
127
|
+
self.GetInfo()
|
|
128
|
+
self.GetMaxPower()
|
|
129
|
+
# self.SetPower(1)
|
|
130
|
+
|
|
131
|
+
def CloseCOM(self):
|
|
132
|
+
'''Closes the serial port.'''
|
|
133
|
+
if self.isOpen():
|
|
134
|
+
self.SendCommand(io_single_laser.OFF)
|
|
135
|
+
self.waitForBytesWritten(500)
|
|
136
|
+
|
|
137
|
+
self.close()
|
|
138
|
+
|
|
139
|
+
def GetMaxPower(self):
|
|
140
|
+
'''
|
|
141
|
+
Gets the maximum power that can be set for the laser diode.
|
|
142
|
+
|
|
143
|
+
This method sends the `P_MAX` command to the device and waits for the response.
|
|
144
|
+
If the response does not contain an error message,
|
|
145
|
+
the method sets the `Max_Power` attribute of the `io_single_laser`
|
|
146
|
+
instance to the value contained in the response.
|
|
147
|
+
'''
|
|
148
|
+
if self.isOpen():
|
|
149
|
+
res = self.SendCommand(io_single_laser.P_MAX)
|
|
150
|
+
|
|
151
|
+
if not ('<ERR>' in res or '<ACK>' in res):
|
|
152
|
+
self.Max_Power = float(res)
|
|
153
|
+
|
|
154
|
+
def GetReadings(self, log_print: bool = True):
|
|
155
|
+
'''
|
|
156
|
+
Gets the current readings from the device.
|
|
157
|
+
|
|
158
|
+
This method first checks if the serial port is open. If it is, it sends the
|
|
159
|
+
`READ` command to the device and waits for the response. If the response
|
|
160
|
+
does not contain an error message, the method sets the various attributes
|
|
161
|
+
of the `io_single_laser` instance with the values contained in the
|
|
162
|
+
response.
|
|
163
|
+
'''
|
|
164
|
+
if self.isOpen():
|
|
165
|
+
res = self.SendCommand(io_single_laser.READ, log_print)
|
|
166
|
+
|
|
167
|
+
if not ('<ERR>' in res or '<ACK>' in res):
|
|
168
|
+
readings = res.split(' ')
|
|
169
|
+
if len(readings) >= 10:
|
|
170
|
+
self.R_Diode_Temp = float(readings[1])
|
|
171
|
+
self.R_Crystal_Temp = float(readings[2])
|
|
172
|
+
self.R_Body_Temp = float(readings[3])
|
|
173
|
+
self.R_LD_Current = readings[4]
|
|
174
|
+
self.R_Crystal_TEC_Load = readings[5]
|
|
175
|
+
self.R_LD_TEC_Load = readings[6]
|
|
176
|
+
self.R_Status = readings[7]
|
|
177
|
+
self.R_Fan_Load = readings[8]
|
|
178
|
+
self.R_Input_Voltage = readings[9]
|
|
179
|
+
|
|
180
|
+
return {
|
|
181
|
+
MB_Params.LD_TEMP: self.R_Diode_Temp,
|
|
182
|
+
MB_Params.CRYSTAL_TEMP: self.R_Crystal_Temp,
|
|
183
|
+
MB_Params.BODY_TEMP: self.R_Body_Temp,
|
|
184
|
+
MB_Params.LD_CURRENT: self.R_LD_Current,
|
|
185
|
+
MB_Params.CRYSTAL_TEC_LOAD: self.R_Crystal_TEC_Load,
|
|
186
|
+
MB_Params.LD_TEC_LOAD: self.R_LD_TEC_Load,
|
|
187
|
+
MB_Params.STATUS: self.R_Status,
|
|
188
|
+
MB_Params.FAN_LOAD: self.R_Fan_Load,
|
|
189
|
+
MB_Params.IN_VOLTAGE: self.R_Input_Voltage,
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return {}
|
|
193
|
+
|
|
194
|
+
def GetSettings(self, log_print: bool = True):
|
|
195
|
+
'''Gets the current settings from the device.
|
|
196
|
+
|
|
197
|
+
This method first checks if the serial port is open. If it is, it sends the
|
|
198
|
+
`SETTINGS` command to the device and waits for the response. If the response
|
|
199
|
+
does not contain an error message, the method sets the various attributes
|
|
200
|
+
of the `io_single_laser` instance with the values contained in the
|
|
201
|
+
response.
|
|
202
|
+
'''
|
|
203
|
+
if self.isOpen():
|
|
204
|
+
res = self.SendCommand(io_single_laser.SETTINGS, log_print)
|
|
205
|
+
|
|
206
|
+
if not ('<ERR>' in res or '<ACK>' in res):
|
|
207
|
+
readings = res.split(' ')
|
|
208
|
+
if len(readings) >= 10:
|
|
209
|
+
self.S_Crystal_Temp = float(readings[1]) / 100
|
|
210
|
+
self.S_Diode_Temp = float(readings[2]) / 100
|
|
211
|
+
self.S_LD_Current = float(readings[3])
|
|
212
|
+
self.S_Feedback_DAC = float(readings[4])
|
|
213
|
+
self.S_Power = float(readings[5])
|
|
214
|
+
self.S_LD_MaxCurrent = float(readings[6])
|
|
215
|
+
self.S_Autostart_Mode = readings[7]
|
|
216
|
+
self.S_Access_Level = int(readings[8])
|
|
217
|
+
self.S_Fan_Temp = float(readings[9]) / 100
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
MB_Params.CRYSTAL_TEMP_SET: self.S_Crystal_Temp,
|
|
221
|
+
MB_Params.LD_TEMP_SET: self.S_Diode_Temp,
|
|
222
|
+
MB_Params.LD_CURRENT_SET: self.S_LD_Current,
|
|
223
|
+
MB_Params.FEEDBACK_DAC: self.S_Feedback_DAC,
|
|
224
|
+
MB_Params.POWER_READ: self.S_Power,
|
|
225
|
+
MB_Params.LD_CURRENT_MAX: self.S_LD_MaxCurrent,
|
|
226
|
+
MB_Params.AUTO_MODE: self.S_Autostart_Mode,
|
|
227
|
+
MB_Params.ACCESS_LEVEL: self.S_Access_Level,
|
|
228
|
+
MB_Params.FAN_TEMP_SET: self.S_Fan_Temp,
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return {}
|
|
232
|
+
|
|
233
|
+
def SetPower(self, value: float) -> bool:
|
|
234
|
+
'''Sets the power level of the laser diode.
|
|
235
|
+
|
|
236
|
+
This method sends the `P_SET` command to the device followed by the desired
|
|
237
|
+
power level (in milliwatts) as a floating point number. It then waits for
|
|
238
|
+
the response and returns a boolean indicating whether the command was
|
|
239
|
+
successful (`True`) or not (`False`).
|
|
240
|
+
|
|
241
|
+
Parameters
|
|
242
|
+
----------
|
|
243
|
+
value : float
|
|
244
|
+
The desired power level in milliwatts.
|
|
245
|
+
|
|
246
|
+
Returns
|
|
247
|
+
-------
|
|
248
|
+
bool
|
|
249
|
+
`True` if the command was successful, `False` otherwise.
|
|
250
|
+
'''
|
|
251
|
+
if self.isOpen():
|
|
252
|
+
if not isinstance(value, (int, float)):
|
|
253
|
+
raise TypeError('Power must be a number!')
|
|
254
|
+
if value < 0 or value > self.Max_Power:
|
|
255
|
+
raise ValueError(f'Power must be between 0 and {self.Max_Power}')
|
|
256
|
+
|
|
257
|
+
res = self.SendCommand(io_single_laser.P_SET + f'{value:.2f}'.encode())
|
|
258
|
+
|
|
259
|
+
return '<ACK>' in res
|
|
260
|
+
|
|
261
|
+
def GetInfo(self):
|
|
262
|
+
'''Gets the information about the device.
|
|
263
|
+
|
|
264
|
+
This method sends the `INFO` command to the device and waits for the response.
|
|
265
|
+
If the response does not contain an error message, the method sets the
|
|
266
|
+
`Firmware`, `Serial`, `Model`, `Operation_Time`, and `ON_Times`
|
|
267
|
+
attributes of the `io_single_laser` instance with the values contained in
|
|
268
|
+
the response.
|
|
269
|
+
'''
|
|
270
|
+
if self.isOpen():
|
|
271
|
+
res = self.SendCommand(io_single_laser.INFO, delay=50)
|
|
272
|
+
|
|
273
|
+
if not ('<ERR>' in res or '<ACK>' in res):
|
|
274
|
+
info = res.split('\r\n')
|
|
275
|
+
|
|
276
|
+
self.Firmware = info[0]
|
|
277
|
+
self.Serial = info[1].split(':')[1]
|
|
278
|
+
self.Model = info[2].split(':')[1]
|
|
279
|
+
self.Operation_Time = info[3]
|
|
280
|
+
self.ON_Times = info[4]
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class SingleMatchBox(Tree):
|
|
284
|
+
'''A class representing a single MatchBox device.
|
|
285
|
+
|
|
286
|
+
This class provides a high-level interface for controlling a single MatchBox
|
|
287
|
+
device. It uses the `io_single_laser` class to communicate with the device
|
|
288
|
+
over a serial port.
|
|
289
|
+
|
|
290
|
+
Attributes
|
|
291
|
+
----------
|
|
292
|
+
Laser : io_single_laser
|
|
293
|
+
The `io_single_laser` instance used to communicate with the device.
|
|
294
|
+
|
|
295
|
+
Methods
|
|
296
|
+
-------
|
|
297
|
+
create_parameters()
|
|
298
|
+
Creates the parameter tree for the MatchBox GUI.
|
|
299
|
+
|
|
300
|
+
update_stats()
|
|
301
|
+
Updates the statistics displayed in the MatchBox GUI.
|
|
302
|
+
|
|
303
|
+
set_config()
|
|
304
|
+
Sets the serial port configuration.
|
|
305
|
+
|
|
306
|
+
laser_connect()
|
|
307
|
+
Connects to the MatchBox device.
|
|
308
|
+
|
|
309
|
+
laser_disconnect()
|
|
310
|
+
Disconnects from the MatchBox device.
|
|
311
|
+
|
|
312
|
+
set_power(value)
|
|
313
|
+
Sets the power level of the laser diode.
|
|
314
|
+
|
|
315
|
+
get_relay_state()
|
|
316
|
+
Gets the state of the relay.
|
|
317
|
+
'''
|
|
318
|
+
|
|
319
|
+
PARAMS = MB_Params
|
|
320
|
+
removed = Signal(object)
|
|
321
|
+
|
|
322
|
+
def __init__(self, parent: Optional['QtWidgets.QWidget'] = None):
|
|
323
|
+
'''Initializes a new SingleMatchBox instance.
|
|
324
|
+
|
|
325
|
+
Parameters
|
|
326
|
+
----------
|
|
327
|
+
parent : Optional[QWidget]
|
|
328
|
+
The parent widget for this SingleMatchBox instance.
|
|
329
|
+
|
|
330
|
+
Attributes
|
|
331
|
+
----------
|
|
332
|
+
Laser : io_single_laser
|
|
333
|
+
The `io_single_laser` instance used to communicate with the device.
|
|
334
|
+
'''
|
|
335
|
+
super().__init__(parent=parent)
|
|
336
|
+
|
|
337
|
+
self.Laser = io_single_laser()
|
|
338
|
+
|
|
339
|
+
self.wavelength = '000'
|
|
340
|
+
|
|
341
|
+
# Statues Bar Timer
|
|
342
|
+
self.timer = QtCore.QTimer()
|
|
343
|
+
self.timer.setInterval(500)
|
|
344
|
+
self.timer.timeout.connect(self.update_stats)
|
|
345
|
+
self.timer.start()
|
|
346
|
+
|
|
347
|
+
def create_parameters(self):
|
|
348
|
+
'''
|
|
349
|
+
Create the parameter tree structure.
|
|
350
|
+
'''
|
|
351
|
+
params = [
|
|
352
|
+
{
|
|
353
|
+
'name': str(MB_Params.MODEL),
|
|
354
|
+
'type': 'str',
|
|
355
|
+
'value': 'N/A',
|
|
356
|
+
'readonly': True,
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
'name': str(MB_Params.WAVELENGTH),
|
|
360
|
+
'type': 'int',
|
|
361
|
+
'value': 0,
|
|
362
|
+
'suffix': 'nm',
|
|
363
|
+
'readonly': True,
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
'name': str(MB_Params.SERIAL_PORT),
|
|
367
|
+
'type': 'group',
|
|
368
|
+
'expanded': False,
|
|
369
|
+
'children': [
|
|
370
|
+
{
|
|
371
|
+
'name': str(MB_Params.PORT),
|
|
372
|
+
'type': 'list',
|
|
373
|
+
'limits': [
|
|
374
|
+
info.portName()
|
|
375
|
+
for info in QtSerialPort.QSerialPortInfo.availablePorts()
|
|
376
|
+
],
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
'name': str(MB_Params.BAUDRATE),
|
|
380
|
+
'type': 'list',
|
|
381
|
+
'value': 115200,
|
|
382
|
+
'limits': [
|
|
383
|
+
baudrate
|
|
384
|
+
for baudrate in QtSerialPort.QSerialPortInfo.standardBaudRates()
|
|
385
|
+
],
|
|
386
|
+
},
|
|
387
|
+
{'name': str(MB_Params.SET_PORT), 'type': 'action'},
|
|
388
|
+
{'name': str(MB_Params.OPEN), 'type': 'action'},
|
|
389
|
+
{'name': str(MB_Params.CLOSE), 'type': 'action'},
|
|
390
|
+
{
|
|
391
|
+
'name': str(MB_Params.PORT_STATE),
|
|
392
|
+
'type': 'str',
|
|
393
|
+
'value': 'closed',
|
|
394
|
+
'readonly': True,
|
|
395
|
+
},
|
|
396
|
+
],
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
'name': str(MB_Params.OPTIONS),
|
|
400
|
+
'type': 'group',
|
|
401
|
+
'children': [
|
|
402
|
+
{
|
|
403
|
+
'name': str(MB_Params.STATE),
|
|
404
|
+
'type': 'list',
|
|
405
|
+
'value': LaserState.OFF,
|
|
406
|
+
'limits': LaserState.get_list(),
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
'name': str(MB_Params.POWER),
|
|
410
|
+
'type': 'float',
|
|
411
|
+
'value': 0,
|
|
412
|
+
'limits': [0, 100],
|
|
413
|
+
'step': 0.1,
|
|
414
|
+
'dec': False,
|
|
415
|
+
},
|
|
416
|
+
{'name': str(MB_Params.SET_POWER), 'type': 'action'},
|
|
417
|
+
],
|
|
418
|
+
},
|
|
419
|
+
{
|
|
420
|
+
'name': str(MB_Params.READINGS),
|
|
421
|
+
'type': 'group',
|
|
422
|
+
'children': [
|
|
423
|
+
{
|
|
424
|
+
'name': str(MB_Params.POWER_READ),
|
|
425
|
+
'type': 'str',
|
|
426
|
+
'value': '0',
|
|
427
|
+
'readonly': True,
|
|
428
|
+
},
|
|
429
|
+
{
|
|
430
|
+
'name': str(MB_Params.LD_CURRENT),
|
|
431
|
+
'type': 'str',
|
|
432
|
+
'value': '0',
|
|
433
|
+
'readonly': True,
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
'name': str(MB_Params.LD_CURRENT_SET),
|
|
437
|
+
'type': 'str',
|
|
438
|
+
'value': '0',
|
|
439
|
+
'readonly': True,
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
'name': str(MB_Params.LD_CURRENT_MAX),
|
|
443
|
+
'type': 'str',
|
|
444
|
+
'value': '0',
|
|
445
|
+
'readonly': True,
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
'name': str(MB_Params.LD_TEMP),
|
|
449
|
+
'type': 'str',
|
|
450
|
+
'value': '0',
|
|
451
|
+
'readonly': True,
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
'name': str(MB_Params.LD_TEMP_SET),
|
|
455
|
+
'type': 'str',
|
|
456
|
+
'value': '0',
|
|
457
|
+
'readonly': True,
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
'name': str(MB_Params.LD_TEC_LOAD),
|
|
461
|
+
'type': 'str',
|
|
462
|
+
'value': '0',
|
|
463
|
+
'readonly': True,
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
'name': str(MB_Params.CRYSTAL_TEMP),
|
|
467
|
+
'type': 'str',
|
|
468
|
+
'value': '0',
|
|
469
|
+
'readonly': True,
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
'name': str(MB_Params.CRYSTAL_TEMP_SET),
|
|
473
|
+
'type': 'str',
|
|
474
|
+
'value': '0',
|
|
475
|
+
'readonly': True,
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
'name': str(MB_Params.CRYSTAL_TEC_LOAD),
|
|
479
|
+
'type': 'str',
|
|
480
|
+
'value': '0',
|
|
481
|
+
'readonly': True,
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
'name': str(MB_Params.BODY_TEMP),
|
|
485
|
+
'type': 'str',
|
|
486
|
+
'value': '0',
|
|
487
|
+
'readonly': True,
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
'name': str(MB_Params.FAN_TEMP_SET),
|
|
491
|
+
'type': 'str',
|
|
492
|
+
'value': '0',
|
|
493
|
+
'readonly': True,
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
'name': str(MB_Params.FAN_LOAD),
|
|
497
|
+
'type': 'str',
|
|
498
|
+
'value': '0',
|
|
499
|
+
'readonly': True,
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
'name': str(MB_Params.FEEDBACK_DAC),
|
|
503
|
+
'type': 'str',
|
|
504
|
+
'value': '0',
|
|
505
|
+
'readonly': True,
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
'name': str(MB_Params.AUTO_MODE),
|
|
509
|
+
'type': 'str',
|
|
510
|
+
'value': '0',
|
|
511
|
+
'readonly': True,
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
'name': str(MB_Params.ACCESS_LEVEL),
|
|
515
|
+
'type': 'str',
|
|
516
|
+
'value': '0',
|
|
517
|
+
'readonly': True,
|
|
518
|
+
},
|
|
519
|
+
{
|
|
520
|
+
'name': str(MB_Params.STATUS),
|
|
521
|
+
'type': 'str',
|
|
522
|
+
'value': '0',
|
|
523
|
+
'readonly': True,
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
'name': str(MB_Params.IN_VOLTAGE),
|
|
527
|
+
'type': 'str',
|
|
528
|
+
'value': '0',
|
|
529
|
+
'readonly': True,
|
|
530
|
+
},
|
|
531
|
+
],
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
'name': str(MB_Params.INFO),
|
|
535
|
+
'type': 'group',
|
|
536
|
+
'children': [
|
|
537
|
+
{
|
|
538
|
+
'name': str(MB_Params.FIRMWARE),
|
|
539
|
+
'type': 'str',
|
|
540
|
+
'value': 'N/A',
|
|
541
|
+
'readonly': True,
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
'name': str(MB_Params.SERIAL),
|
|
545
|
+
'type': 'str',
|
|
546
|
+
'value': 'N/A',
|
|
547
|
+
'readonly': True,
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
'name': str(MB_Params.OPERATION_TIME),
|
|
551
|
+
'type': 'str',
|
|
552
|
+
'value': 'N/A',
|
|
553
|
+
'readonly': True,
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
'name': str(MB_Params.ON_TIMES),
|
|
557
|
+
'type': 'str',
|
|
558
|
+
'value': 'N/A',
|
|
559
|
+
'readonly': True,
|
|
560
|
+
},
|
|
561
|
+
],
|
|
562
|
+
},
|
|
563
|
+
{'name': str(MB_Params.REMOVE), 'type': 'action'},
|
|
564
|
+
]
|
|
565
|
+
|
|
566
|
+
self.param_tree = Parameter.create(name='', type='group', children=params)
|
|
567
|
+
self.param_tree.sigTreeStateChanged.connect(self.change)
|
|
568
|
+
self.header().setSectionResizeMode(
|
|
569
|
+
QtWidgets.QHeaderView.ResizeMode.ResizeToContents
|
|
570
|
+
)
|
|
571
|
+
|
|
572
|
+
self.get_param(MB_Params.STATE).sigValueChanged.connect(
|
|
573
|
+
lambda: self.laser_state_changed()
|
|
574
|
+
)
|
|
575
|
+
|
|
576
|
+
self.get_param(MB_Params.SET_PORT).sigActivated.connect(self.set_config)
|
|
577
|
+
self.get_param(MB_Params.OPEN).sigActivated.connect(self.laser_connect)
|
|
578
|
+
self.get_param(MB_Params.CLOSE).sigActivated.connect(
|
|
579
|
+
lambda: self.Laser.CloseCOM()
|
|
580
|
+
)
|
|
581
|
+
self.get_param(MB_Params.SET_POWER).sigActivated.connect(self.set_power)
|
|
582
|
+
|
|
583
|
+
self.get_param(MB_Params.REMOVE).sigActivated.connect(self.remove_widget)
|
|
584
|
+
|
|
585
|
+
def set_config(self):
|
|
586
|
+
'''Sets the serial port configuration.
|
|
587
|
+
|
|
588
|
+
This method sets the serial port configuration based on the current
|
|
589
|
+
settings in the parameter tree.
|
|
590
|
+
'''
|
|
591
|
+
if not self.Laser.isOpen():
|
|
592
|
+
self.Laser.setPortName(self.get_param_value(MB_Params.PORT))
|
|
593
|
+
self.Laser.setBaudRate(self.get_param_value(MB_Params.BAUDRATE))
|
|
594
|
+
|
|
595
|
+
def laser_connect(self):
|
|
596
|
+
'''Connects to the MatchBox device.
|
|
597
|
+
|
|
598
|
+
This method opens the serial port and initializes the laser.
|
|
599
|
+
'''
|
|
600
|
+
self.Laser.OpenCOM()
|
|
601
|
+
|
|
602
|
+
self.wavelength = self.Laser.Model.split('L')[0]
|
|
603
|
+
self.get_param(MB_Params.POWER).setLimits([0, self.Laser.Max_Power])
|
|
604
|
+
|
|
605
|
+
self.set_param_value(MB_Params.MODEL, self.Laser.Model)
|
|
606
|
+
self.set_param_value(MB_Params.WAVELENGTH, int(self.wavelength))
|
|
607
|
+
self.set_param_value(MB_Params.FIRMWARE, self.Laser.Firmware)
|
|
608
|
+
self.set_param_value(MB_Params.SERIAL, self.Laser.Serial)
|
|
609
|
+
|
|
610
|
+
def update_stats(self):
|
|
611
|
+
"""
|
|
612
|
+
Updates the statistics displayed in the MatchBox GUI.
|
|
613
|
+
|
|
614
|
+
This method retrieves the current readings and settings from the device, and
|
|
615
|
+
updates the corresponding parameter tree items with the new values. It also
|
|
616
|
+
sets the limits of the power parameter based on the maximum power that can be
|
|
617
|
+
set for the laser diode.
|
|
618
|
+
|
|
619
|
+
If the laser is not connected, the method sets the 'Port State' parameter to
|
|
620
|
+
'closed'.
|
|
621
|
+
"""
|
|
622
|
+
if self.Laser.isOpen():
|
|
623
|
+
readings = self.Laser.GetReadings(False)
|
|
624
|
+
settings = self.Laser.GetSettings(False)
|
|
625
|
+
|
|
626
|
+
for key, value in readings.items():
|
|
627
|
+
if isinstance(value, (int, float)):
|
|
628
|
+
self.set_param_value(key, f'{value:.2f}')
|
|
629
|
+
elif isinstance(value, str):
|
|
630
|
+
self.set_param_value(key, value)
|
|
631
|
+
|
|
632
|
+
for key, value in settings.items():
|
|
633
|
+
if isinstance(value, (int, float)):
|
|
634
|
+
self.set_param_value(key, f'{value:.2f}')
|
|
635
|
+
elif isinstance(value, str):
|
|
636
|
+
self.set_param_value(key, value)
|
|
637
|
+
|
|
638
|
+
self.set_param_value(MB_Params.OPERATION_TIME, self.Laser.Operation_Time)
|
|
639
|
+
self.set_param_value(MB_Params.ON_TIMES, self.Laser.ON_Times)
|
|
640
|
+
|
|
641
|
+
self.set_param_value(MB_Params.PORT_STATE, 'open')
|
|
642
|
+
else:
|
|
643
|
+
self.set_param_value(MB_Params.PORT_STATE, 'closed')
|
|
644
|
+
|
|
645
|
+
self.RefreshPorts()
|
|
646
|
+
|
|
647
|
+
def RefreshPorts(self):
|
|
648
|
+
"""
|
|
649
|
+
Refreshes the available serial ports list in the GUI.
|
|
650
|
+
|
|
651
|
+
This method updates the list of available serial ports in the GUI by fetching
|
|
652
|
+
the current list of available ports and setting it as the options for the
|
|
653
|
+
'Serial Port' parameter in the parameter tree.
|
|
654
|
+
"""
|
|
655
|
+
if not self.Laser.isOpen():
|
|
656
|
+
self.get_param(MB_Params.PORT).setLimits(
|
|
657
|
+
[
|
|
658
|
+
info.portName()
|
|
659
|
+
for info in QtSerialPort.QSerialPortInfo.availablePorts()
|
|
660
|
+
]
|
|
661
|
+
)
|
|
662
|
+
|
|
663
|
+
def laser_state_changed(self):
|
|
664
|
+
'''Sends enable/disable signals to the
|
|
665
|
+
laser combiner according to selected state setting
|
|
666
|
+
'''
|
|
667
|
+
if self.get_param_value(MB_Params.STATE) == LaserState.OFF:
|
|
668
|
+
self.Laser.SendCommand(io_single_laser.ON_DIS)
|
|
669
|
+
else:
|
|
670
|
+
self.Laser.SendCommand(io_single_laser.ON_EN)
|
|
671
|
+
|
|
672
|
+
def set_power(self):
|
|
673
|
+
'''
|
|
674
|
+
Sets the power level of the laser diode
|
|
675
|
+
based on the current value in the GUI
|
|
676
|
+
'''
|
|
677
|
+
self.Laser.SetPower(self.get_param_value(MB_Params.POWER))
|
|
678
|
+
|
|
679
|
+
def GetRelayState(self):
|
|
680
|
+
'''
|
|
681
|
+
Returns the current state as a string to send to the laser relay box.
|
|
682
|
+
'''
|
|
683
|
+
try:
|
|
684
|
+
return f'L{self.wavelength}{self.get_param_value(MB_Params.STATE)}'
|
|
685
|
+
except Exception:
|
|
686
|
+
return ''
|
|
687
|
+
|
|
688
|
+
def get_config(self) -> dict:
|
|
689
|
+
'''
|
|
690
|
+
Returns the current configuration of the laser device as a dictionary.
|
|
691
|
+
'''
|
|
692
|
+
return {
|
|
693
|
+
'port': self.Laser.portName(),
|
|
694
|
+
'baudrate': self.Laser.baudRate(),
|
|
695
|
+
'class': self.__class__.__name__,
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
def load_config(self, config: dict) -> bool:
|
|
699
|
+
'''
|
|
700
|
+
Loads the configuration from the given dictionary.
|
|
701
|
+
'''
|
|
702
|
+
port = config.get('port')
|
|
703
|
+
baudrate = config.get('baudrate')
|
|
704
|
+
if port:
|
|
705
|
+
self.Laser.setPortName(port)
|
|
706
|
+
self.set_param_value(MB_Params.PORT, port)
|
|
707
|
+
if baudrate:
|
|
708
|
+
self.Laser.setBaudRate(baudrate)
|
|
709
|
+
self.set_param_value(MB_Params.BAUDRATE, baudrate)
|
|
710
|
+
|
|
711
|
+
def remove_widget(self):
|
|
712
|
+
if self.parent() and not self.Laser.isOpen():
|
|
713
|
+
self.parent().removeWidget(self)
|
|
714
|
+
self.removed.emit(self)
|
|
715
|
+
self.deleteLater()
|
|
716
|
+
else:
|
|
717
|
+
print(f'Disconnect device {self.Laser.Model} before removing!')
|
|
718
|
+
|
|
719
|
+
def __str__(self):
|
|
720
|
+
return self.Laser.Model.strip() or self.__class__.__name__
|
|
721
|
+
|
|
722
|
+
def StartGUI():
|
|
723
|
+
'''Initializes a new QApplication and SingleMatchBox.
|
|
724
|
+
|
|
725
|
+
Use
|
|
726
|
+
-------
|
|
727
|
+
app, window = SingleMatchBox.StartGUI()
|
|
728
|
+
|
|
729
|
+
app.exec()
|
|
730
|
+
|
|
731
|
+
Returns
|
|
732
|
+
-------
|
|
733
|
+
tuple (QApplication, SingleMatchBox)
|
|
734
|
+
Returns a tuple with QApp and SingleMatchBox main window.
|
|
735
|
+
'''
|
|
736
|
+
return StartGUI(SingleMatchBox)
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
if __name__ == '__main__':
|
|
740
|
+
app, widget = SingleMatchBox.StartGUI()
|
|
741
|
+
|
|
742
|
+
app.exec()
|