wasatch 2.3.2__tar.gz → 2.3.6__tar.gz
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.
- {wasatch-2.3.2 → wasatch-2.3.6}/CHANGELOG.md +10 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/Makefile +4 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/PKG-INFO +3 -2
- {wasatch-2.3.2 → wasatch-2.3.6}/pyproject.toml +1 -1
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/AndorDevice.py +1 -1
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/EEPROM.py +3 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/FeatureIdentificationDevice.py +94 -22
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/SpectrometerSettings.py +2 -2
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/SpectrometerState.py +3 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/WasatchDeviceWrapper.py +1 -1
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/__init__.py +1 -1
- {wasatch-2.3.2 → wasatch-2.3.6}/.example_pypirc +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/.flake8 +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/.gitignore +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/.pylintrc +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/Doxyfile +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/LICENSE +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/MANIFEST.in +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/README.md +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/README_PYPI.md +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/README_RPI.md +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/README_SETTINGS.md +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/README_VIRTUAL.md +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/WasatchShell/README.md +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/WasatchShell/laser-test.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/WasatchShell/load-test.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/WasatchShell/one-shot.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/WasatchShell/wasatch-shell.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/demo-auto-raman.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/demo-simple.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/demo-virtual.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/demo-workflow.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/demo.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/environments/conda-linux.yml +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/environments/conda-macos.yml +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/environments/conda-rpi.yml +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/environments/conda-win10.yml +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/screenshots/multiplatform.png +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/scripts/dark-vs-integ.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/scripts/deploy +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/testSpectrometers/SiG_785/eeprom/EEPROM-EM-9c65d19f4c.json +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/testSpectrometers/SiG_785/readings/enlighten-20210329-094722-799520-WP-00686.csv +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/testSpectrometers/SiG_785/readings/enlighten-20210329-094755-288958-WP-00686.csv +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/testSpectrometers/WP-00887/eeprom/WP-00887-mock.json +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/testSpectrometers/WP-00904/eeprom/WP-00904-mock.json +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/testSpectrometers/WP-00913/eeprom/WP-00913-mock.json +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/tests/existing_implementations.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/tests/noise-by-setpoint.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/tests/queues.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/tests/unit.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/udev/10-wasatch.rules +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/AbstractUSBDevice.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/AreaScanImage.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/AutoRaman.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/AutoRamanRequest.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/BLEDevice.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/BalanceAcquisition.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/CSVLoader.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/CommandSettings.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/ControlObject.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/DetectorROI.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/DetectorRegions.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/DeviceFinderBLE.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/DeviceFinderTCP.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/DeviceFinderUSB.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/DeviceID.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/EEPROM_multical.sav +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/FPGAOptions.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/FirmwareRequirements.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/HardwareInfo.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/IDSCamera.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/IDSDevice.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/IMX385.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/InterfaceDevice.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/MockUSBDevice.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/OceanDevice.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/PollStatus.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/ProcessedReading.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/ROI.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/Reading.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/RealUSBDevice.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/SPIDevice.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/SpectrometerRequest.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/SpectrometerResponse.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/StatusMessage.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/TCPDevice.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/TakeOneRequest.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/WasatchBus.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/WasatchDevice.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/WrapperWorker.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/applog.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/simulation_protocol.py +0 -0
- {wasatch-2.3.2 → wasatch-2.3.6}/wasatch/utils.py +0 -0
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
- 2025-11-06 2.3.6
|
|
4
|
+
- resolve hotplug race condition when laser power set in percent
|
|
5
|
+
- cache certain device getters to avoid I2C overruns
|
|
6
|
+
- stop trying to read laser temperature on FX2, it's never worked right
|
|
7
|
+
- 2025-10-22 2.3.5
|
|
8
|
+
- don't loop on spectral read errors on XS
|
|
9
|
+
- 2025-10-22 2.3.4
|
|
10
|
+
- ignore heartbeat on Andor
|
|
11
|
+
- 2025-06-30 2.3.3
|
|
12
|
+
- Hamamatsu 2048px area scan
|
|
3
13
|
- 2025-06-18 2.3.2
|
|
4
14
|
- XS area scan
|
|
5
15
|
- fixed off-by-one stop line
|
|
@@ -28,7 +28,11 @@ pip-install-local:
|
|
|
28
28
|
pip install $$PWD
|
|
29
29
|
|
|
30
30
|
publish-test:
|
|
31
|
+
@echo REMINDER to keep .toml in sync with __init__.py!
|
|
32
|
+
@echo
|
|
31
33
|
flit publish --repository testpypi
|
|
32
34
|
|
|
33
35
|
publish:
|
|
36
|
+
@echo REMINDER to keep .toml in sync with __init__.py!
|
|
37
|
+
@echo
|
|
34
38
|
flit publish
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: wasatch
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.6
|
|
4
4
|
Summary: Application-level driver for Wasatch Photonics spectrometers
|
|
5
5
|
Requires-Python: >=3.9
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
7
|
+
License-File: LICENSE
|
|
7
8
|
Requires-Dist: numpy
|
|
8
9
|
Requires-Dist: six
|
|
9
10
|
Requires-Dist: psutil
|
|
@@ -188,7 +188,7 @@ class AndorDevice(InterfaceDevice):
|
|
|
188
188
|
process_f["take_one_request"] = self.set_take_one_request
|
|
189
189
|
|
|
190
190
|
process_f["reset_scan_averaging"] = self.not_implemented
|
|
191
|
-
process_f["heartbeat"] =
|
|
191
|
+
process_f["heartbeat"] = lambda x: None
|
|
192
192
|
|
|
193
193
|
##################################################################
|
|
194
194
|
# What follows is the old init-lambdas that are squashed into process_f
|
|
@@ -308,11 +308,23 @@ class FeatureIdentificationDevice(InterfaceDevice):
|
|
|
308
308
|
return result
|
|
309
309
|
|
|
310
310
|
# ######################################################################
|
|
311
|
-
#
|
|
311
|
+
# Laser defaults
|
|
312
312
|
# ######################################################################
|
|
313
313
|
|
|
314
|
-
|
|
315
|
-
|
|
314
|
+
if self.settings.eeprom.has_laser:
|
|
315
|
+
log.debug("post_connect: setting laser defaults")
|
|
316
|
+
# MZ: why did we stop doing this?
|
|
317
|
+
# self.set_laser_enable(False)
|
|
318
|
+
|
|
319
|
+
self.settings.state.laser_power_mW = self.settings.eeprom.max_laser_power_mW
|
|
320
|
+
self.settings.state.laser_power_perc = 100
|
|
321
|
+
self.settings.state.use_mW = self.settings.eeprom.has_laser_power_calibration() and self.settings.is_mml()
|
|
322
|
+
|
|
323
|
+
log.debug(f" laser_power_mW {self.settings.state.laser_power_mW}")
|
|
324
|
+
log.debug(f" laser_power_perc {self.settings.state.laser_power_perc}")
|
|
325
|
+
log.debug(f" use_mW {self.settings.state.use_mW}")
|
|
326
|
+
|
|
327
|
+
log.debug("post_connect: done setting laser defaults")
|
|
316
328
|
|
|
317
329
|
# ######################################################################
|
|
318
330
|
# TEC Setpoint
|
|
@@ -816,20 +828,21 @@ class FeatureIdentificationDevice(InterfaceDevice):
|
|
|
816
828
|
|
|
817
829
|
try:
|
|
818
830
|
self._wait_for_usb_available()
|
|
831
|
+
log.debug("%s_get_code: request 0x%02x value 0x%04x index 0x%04x length %d", prefix, bRequest, wValue, wIndex, wLength)
|
|
819
832
|
result = self.device_type.ctrl_transfer(self.device,
|
|
820
833
|
0xc0, # DEVICE_TO_HOST
|
|
821
834
|
bRequest,
|
|
822
835
|
wValue,
|
|
823
836
|
wIndex,
|
|
824
|
-
wLength)
|
|
837
|
+
wLength) # add TIMEOUT_MS?
|
|
825
838
|
except Exception as exc:
|
|
826
839
|
log.critical(f"Hardware Failure FID Get Code Problem with ctrl transfer (bRequest 0x{bRequest:02x}, wValue 0x{wValue:04x}, wIndex 0x{wIndex:04x}, label {label})", exc_info=1)
|
|
827
840
|
self._schedule_disconnect(exc)
|
|
828
841
|
return SpectrometerResponse(poison_pill=True)
|
|
829
842
|
|
|
830
843
|
result_hex = " ".join([f"{v:02x}" for v in result])
|
|
831
|
-
log.debug("%s_get_code: request 0x%02x value 0x%04x index 0x%04x = [%s]",
|
|
832
|
-
prefix, bRequest, wValue, wIndex, result_hex)
|
|
844
|
+
log.debug("%s_get_code: request 0x%02x value 0x%04x index 0x%04x length %d = [%s]",
|
|
845
|
+
prefix, bRequest, wValue, wIndex, wLength, result_hex)
|
|
833
846
|
|
|
834
847
|
if result is None:
|
|
835
848
|
log.critical("_get_code[%s, %s]: received null", label, self.device_id)
|
|
@@ -1135,10 +1148,10 @@ class FeatureIdentificationDevice(InterfaceDevice):
|
|
|
1135
1148
|
self.settings.state.area_scan_line_step = n
|
|
1136
1149
|
return self.i2c_write(0x17, [n], label="SET_AREA_SCAN_LINE_STEP")
|
|
1137
1150
|
|
|
1138
|
-
# MZ: I don't remember what boards / firmware supports this?
|
|
1151
|
+
# MZ: I don't remember what boards / firmware supports this? How does this differ from interval?
|
|
1139
1152
|
def set_area_scan_line_count(self, n):
|
|
1140
1153
|
self.debug(f"setting line count to {n}")
|
|
1141
|
-
self.dev.ctrl_transfer(H2D, 0xa6, n, 0, Z
|
|
1154
|
+
self.dev.ctrl_transfer(H2D, 0xa6, n, 0, Z)
|
|
1142
1155
|
return self._send_code(0xa6, n, label="SET_AREA_SCAN_LINE_COUNT")
|
|
1143
1156
|
|
|
1144
1157
|
# MZ: I don't remember what boards / firmware supports this?
|
|
@@ -1401,7 +1414,12 @@ class FeatureIdentificationDevice(InterfaceDevice):
|
|
|
1401
1414
|
else:
|
|
1402
1415
|
errors += 1
|
|
1403
1416
|
log.error(f"Encountered error on read of {exc}", exc_info=1)
|
|
1404
|
-
|
|
1417
|
+
|
|
1418
|
+
# Don't loop on errors on XS, so we can experimentally
|
|
1419
|
+
# use an XS board as a detector-less laser/TEC driver
|
|
1420
|
+
# board. (A better solution would be to add FeatureMask.
|
|
1421
|
+
# has_detector or similar, this works for now.)
|
|
1422
|
+
if errors < 3 and not self.settings.is_xs():
|
|
1405
1423
|
log.error(f"ignoring error number {errors}")
|
|
1406
1424
|
else:
|
|
1407
1425
|
response.error_msg = "Encountered error on read"
|
|
@@ -1608,12 +1626,17 @@ class FeatureIdentificationDevice(InterfaceDevice):
|
|
|
1608
1626
|
self.remaining_throwaways += 1
|
|
1609
1627
|
|
|
1610
1628
|
def set_onboard_scans_to_average(self, n):
|
|
1629
|
+
"""
|
|
1630
|
+
This is provided to let ENLIGHTEN *turn off* onboard averaging settings
|
|
1631
|
+
which might have been generated, and (deliberately) left in place after
|
|
1632
|
+
an Auto-Raman measurement.
|
|
1633
|
+
"""
|
|
1611
1634
|
if not self.settings.is_xs():
|
|
1612
1635
|
return SpectrometerResponse(False)
|
|
1613
1636
|
|
|
1614
1637
|
retval = self._send_code(0xff, 0x62, n, label="SET_ONBOARD_SCANS_TO_AVERAGE")
|
|
1615
1638
|
self.settings.state.scans_to_average = n
|
|
1616
|
-
self.settings.state.onboard_averaging =
|
|
1639
|
+
self.settings.state.onboard_averaging = n > 1
|
|
1617
1640
|
return retval
|
|
1618
1641
|
|
|
1619
1642
|
def get_scans_to_average(self):
|
|
@@ -1673,6 +1696,7 @@ class FeatureIdentificationDevice(InterfaceDevice):
|
|
|
1673
1696
|
return result
|
|
1674
1697
|
|
|
1675
1698
|
def i2c_write(self, address, buf, label=""):
|
|
1699
|
+
# return log.debug(f"i2c_write: declining to send cmd 0x90, wValue {address}, wIndex {len(buf)}, data_or_wLength {buf}, label {label}")
|
|
1676
1700
|
return self._send_code(0x90, wValue=address, wIndex=len(buf), data_or_wLength=buf, label=label)
|
|
1677
1701
|
|
|
1678
1702
|
# ##########################################################################
|
|
@@ -1849,8 +1873,16 @@ class FeatureIdentificationDevice(InterfaceDevice):
|
|
|
1849
1873
|
marker = 0xffff
|
|
1850
1874
|
clamp = 0xfffe
|
|
1851
1875
|
lines = 69
|
|
1852
|
-
|
|
1853
|
-
|
|
1876
|
+
line_index = -1
|
|
1877
|
+
pixels = self.settings.pixels()
|
|
1878
|
+
line_len = pixels * 2
|
|
1879
|
+
timeout_ms = self.generate_timeout_ms() + 10
|
|
1880
|
+
|
|
1881
|
+
endpoints = [0x82]
|
|
1882
|
+
block_len_bytes = line_len
|
|
1883
|
+
if pixels == 2048 and not self.settings.is_arm():
|
|
1884
|
+
endpoints = [0x82, 0x86]
|
|
1885
|
+
block_len_bytes = 2048 # 1024 pixels apiece from two endpoints
|
|
1854
1886
|
|
|
1855
1887
|
# request a frame
|
|
1856
1888
|
self._send_code(0xad, label="ACQUIRE_SPECTRUM")
|
|
@@ -1866,10 +1898,14 @@ class FeatureIdentificationDevice(InterfaceDevice):
|
|
|
1866
1898
|
try:
|
|
1867
1899
|
while len(data) < line_len:
|
|
1868
1900
|
bytes_remaining = line_len - len(data)
|
|
1869
|
-
|
|
1870
|
-
|
|
1901
|
+
bytes_to_read = min(bytes_remaining, block_len_bytes)
|
|
1902
|
+
ep_index = 1 if len(endpoints) > 1 and len(data) >= 1024 else 0
|
|
1903
|
+
|
|
1904
|
+
# log.debug(f"get_area_scan_hamamatsu: attempting to read {bytes_to_read} from 0x{endpoints[ep_index]:02x}")
|
|
1905
|
+
latest_data = self.device_type.read(self.device, endpoints[ep_index], bytes_to_read, timeout=timeout_ms)
|
|
1871
1906
|
data.extend(latest_data)
|
|
1872
1907
|
except:
|
|
1908
|
+
# this still happens periodically
|
|
1873
1909
|
log.error(f"get_area_scan_hamamatsu {prefix}: error reading line {line}", exc_info=1)
|
|
1874
1910
|
break
|
|
1875
1911
|
|
|
@@ -1903,8 +1939,11 @@ class FeatureIdentificationDevice(InterfaceDevice):
|
|
|
1903
1939
|
spectrum[1] = spectrum[2] # stomp
|
|
1904
1940
|
|
|
1905
1941
|
# store line in image
|
|
1906
|
-
self.area_scan_frame
|
|
1907
|
-
|
|
1942
|
+
if 0 <= line_index < len(self.area_scan_frame):
|
|
1943
|
+
log.debug(f"get_area_scan_hamamatsu {prefix}: storing line {line_index}: {spectrum[:5]}")
|
|
1944
|
+
self.area_scan_frame[line_index] = spectrum
|
|
1945
|
+
else:
|
|
1946
|
+
log.warn(f"get_area_scan_hamamatsu {prefix}: dropping line {line_index}: {spectrum[:5]}")
|
|
1908
1947
|
|
|
1909
1948
|
line_count += 1
|
|
1910
1949
|
|
|
@@ -1915,7 +1954,9 @@ class FeatureIdentificationDevice(InterfaceDevice):
|
|
|
1915
1954
|
# store full-frame image data for Area Scan
|
|
1916
1955
|
data = np.array(self.area_scan_frame, dtype=np.float32, copy=True)
|
|
1917
1956
|
data -= data.min() # remove baseline
|
|
1918
|
-
|
|
1957
|
+
if self.settings.eeprom.invert_x_axis:
|
|
1958
|
+
data = np.rot90(data, k=2)
|
|
1959
|
+
asi = AreaScanImage(data=data, width=len(data[0]), height=len(data), line_index=line_index)
|
|
1919
1960
|
|
|
1920
1961
|
# vertically bin within vertical ROI for live graph
|
|
1921
1962
|
start = self.settings.eeprom.roi_vertical_region_1_start
|
|
@@ -1983,7 +2024,7 @@ class FeatureIdentificationDevice(InterfaceDevice):
|
|
|
1983
2024
|
if self.settings.state.selected_adc is None or self.settings.state.selected_adc != 1:
|
|
1984
2025
|
self.select_adc(1)
|
|
1985
2026
|
|
|
1986
|
-
result = self._get_code(0xd5, wLength=2, label="GET_ADC", lsb_len=2)
|
|
2027
|
+
result = self._get_code(0xd5, wLength=2, label="GET_ADC (secondary)", lsb_len=2)
|
|
1987
2028
|
log.debug("secondary_adc_raw: 0x%04x", result)
|
|
1988
2029
|
return result
|
|
1989
2030
|
|
|
@@ -2178,7 +2219,18 @@ class FeatureIdentificationDevice(InterfaceDevice):
|
|
|
2178
2219
|
|
|
2179
2220
|
## @note big-endian, reverse of get_laser_temperature_raw
|
|
2180
2221
|
def get_detector_temperature_raw(self):
|
|
2181
|
-
|
|
2222
|
+
# - don't poll detector temperature faster than 10Hz...analyzing performance on FX2
|
|
2223
|
+
last = self.settings.state.detector_temperature_raw_last_refreshed
|
|
2224
|
+
now = datetime.datetime.now()
|
|
2225
|
+
if last is not None and (now - last).total_seconds() < 0.1:
|
|
2226
|
+
raw = self.settings.state.detector_temperature_raw
|
|
2227
|
+
log.debug("get_detector_temperature_raw: using cached {raw}")
|
|
2228
|
+
return raw
|
|
2229
|
+
raw = self._get_code(0xd7, wLength=2, label="GET_CCD_TEMP", msb_len=2)
|
|
2230
|
+
self.settings.state.detector_temperature_raw = raw
|
|
2231
|
+
self.settings.state.detector_temperature_raw_last_refreshed = now
|
|
2232
|
+
log.debug("get_detector_temperature_raw: storing {raw}")
|
|
2233
|
+
return raw
|
|
2182
2234
|
|
|
2183
2235
|
def get_detector_temperature_degC(self, raw: float = None):
|
|
2184
2236
|
if raw is None:
|
|
@@ -2339,12 +2391,16 @@ class FeatureIdentificationDevice(InterfaceDevice):
|
|
|
2339
2391
|
|
|
2340
2392
|
def get_laser_temperature_raw(self):
|
|
2341
2393
|
""" @note little-endian, reverse of get_detector_temperature_raw """
|
|
2394
|
+
# this is currently unreliable on most (all?) Hamamatsu units, so why bother
|
|
2395
|
+
if not self.settings.is_xs():
|
|
2396
|
+
return SpectrometerResponse(0)
|
|
2397
|
+
|
|
2342
2398
|
# flip to primary ADC if needed
|
|
2343
2399
|
if self.settings.state.selected_adc is None or self.settings.state.selected_adc != 0:
|
|
2344
2400
|
# MZ: unclear if this is needed on SiG
|
|
2345
2401
|
self.select_adc(0)
|
|
2346
2402
|
|
|
2347
|
-
result = self._get_code(0xd5, wLength=2, label="GET_ADC", lsb_len=2)
|
|
2403
|
+
result = self._get_code(0xd5, wLength=2, label="GET_ADC (laser)", lsb_len=2)
|
|
2348
2404
|
if not result.data:
|
|
2349
2405
|
log.debug("Unable to read laser temperature")
|
|
2350
2406
|
return SpectrometerResponse(0)
|
|
@@ -2381,11 +2437,21 @@ class FeatureIdentificationDevice(InterfaceDevice):
|
|
|
2381
2437
|
# MZ: get_laser_enabled not currently robust on SiG :-(
|
|
2382
2438
|
return SpectrometerResponse(data=self.settings.state.laser_enabled)
|
|
2383
2439
|
|
|
2384
|
-
|
|
2440
|
+
# - don't poll laser faster than 100Hz...analyzing performance on FX2
|
|
2441
|
+
# - seems to be double-polled due to is_laser_firing()
|
|
2442
|
+
last = self.settings.state.laser_enabled_last_refreshed
|
|
2443
|
+
now = datetime.datetime.now()
|
|
2444
|
+
if last is not None and (now - last).total_seconds() < 0.01:
|
|
2445
|
+
flag = self.settings.state.laser_enabled
|
|
2446
|
+
log.debug(f"get_laser_enabled: using cached {flag}")
|
|
2447
|
+
return SpectrometerResponse(data=flag)
|
|
2448
|
+
|
|
2449
|
+
res = self._get_code(0xe2, wLength=1, label="GET_LASER_ENABLED", msb_len=1)
|
|
2385
2450
|
flag = 0 != res.data
|
|
2386
2451
|
|
|
2387
|
-
log.debug(f"get_laser_enabled: {flag} (storing to
|
|
2452
|
+
log.debug(f"get_laser_enabled: {flag} (storing to self.settings.state)")
|
|
2388
2453
|
self.settings.state.laser_enabled = flag
|
|
2454
|
+
self.settings.state.laser_enabled_last_refreshed = now
|
|
2389
2455
|
return SpectrometerResponse(data=flag)
|
|
2390
2456
|
|
|
2391
2457
|
def set_laser_enable(self, flag: bool):
|
|
@@ -2912,6 +2978,8 @@ class FeatureIdentificationDevice(InterfaceDevice):
|
|
|
2912
2978
|
self.set_vertical_roi(roi)
|
|
2913
2979
|
|
|
2914
2980
|
def set_vertical_roi(self, roi):
|
|
2981
|
+
log.debug(f"set_vertical_roi: {roi}")
|
|
2982
|
+
|
|
2915
2983
|
# check for legacy SiG-VIS since it didn't like vertical binning
|
|
2916
2984
|
if self.settings.fpga_firmware_version == "000-008" and self.settings.microcontroller_firmware_version == "0.1.0.7":
|
|
2917
2985
|
return SpectrometerResponse(data=False)
|
|
@@ -2928,6 +2996,7 @@ class FeatureIdentificationDevice(InterfaceDevice):
|
|
|
2928
2996
|
else:
|
|
2929
2997
|
log.error("set_vertical_roi: requires an ROI object or tuple of (start, stop) lines")
|
|
2930
2998
|
return SpectrometerResponse(data=False, error_msg="invalid start and stop lines")
|
|
2999
|
+
log.debug(f"set_vertical_roi: start {start}, end {end}")
|
|
2931
3000
|
|
|
2932
3001
|
if start < 0 or end < 0:
|
|
2933
3002
|
log.error("set_vertical_roi: requires POSITIVE (start, stop) lines")
|
|
@@ -2947,6 +3016,9 @@ class FeatureIdentificationDevice(InterfaceDevice):
|
|
|
2947
3016
|
# FX2 lacks USB opcodes for start/stop line, so use I2C Poke (clamp to 1 byte)
|
|
2948
3017
|
start = int(max(0, min(255, start)))
|
|
2949
3018
|
end = int(max(0, min(255, end )))
|
|
3019
|
+
|
|
3020
|
+
# start = max(1, start) # kludge
|
|
3021
|
+
|
|
2950
3022
|
self.i2c_write(0x29, [start], label="I2C_POKE(SET_CCD_START_LINE)")
|
|
2951
3023
|
self.i2c_write(0x2A, [end], label="I2C_POKE(SET_CCD_STOP_LINE)")
|
|
2952
3024
|
|
|
@@ -237,7 +237,7 @@ class SpectrometerSettings:
|
|
|
237
237
|
# order in the current codebase."
|
|
238
238
|
|
|
239
239
|
coeffs = self.eeprom.multi_wavelength_calibration.get("raman_intensity_coeffs")
|
|
240
|
-
log.debug("update_raman_intensity_factors: coeffs {coeffs}")
|
|
240
|
+
log.debug(f"update_raman_intensity_factors: coeffs {coeffs}")
|
|
241
241
|
if coeffs is None or coeffs == []:
|
|
242
242
|
return
|
|
243
243
|
|
|
@@ -256,7 +256,7 @@ class SpectrometerSettings:
|
|
|
256
256
|
except:
|
|
257
257
|
log.error(f"exception generating Raman intensity factors (coeffs {coeffs})", exc_info=1)
|
|
258
258
|
self.raman_intensity_factors = None
|
|
259
|
-
log.debug("generated {len(self.raman_intensity_factors)} Raman intensity factors")
|
|
259
|
+
log.debug(f"generated {len(self.raman_intensity_factors)} Raman intensity factors")
|
|
260
260
|
|
|
261
261
|
def set_linear_pixel_calibration(self, data):
|
|
262
262
|
self.linear_pixel_calibration = None
|
|
@@ -29,12 +29,15 @@ class SpectrometerState:
|
|
|
29
29
|
# TEC @todo rename detector_tec...
|
|
30
30
|
self.tec_setpoint_degC = 15 # that's a very strange default...
|
|
31
31
|
self.tec_enabled = False
|
|
32
|
+
self.detector_temperature_raw = None
|
|
33
|
+
self.detector_temperature_raw_last_refreshed = None
|
|
32
34
|
|
|
33
35
|
# high gain mode (InGaAs only)
|
|
34
36
|
self.high_gain_mode_enabled = False
|
|
35
37
|
|
|
36
38
|
# laser
|
|
37
39
|
self.laser_enabled = False
|
|
40
|
+
self.laser_enabled_last_refreshed = None
|
|
38
41
|
self.laser_power_mW = None # if last set in mW, will contain setpoint in mW; else will be None
|
|
39
42
|
self.laser_power_perc = 0 # should always contain a number [0, 100]
|
|
40
43
|
self.use_mW = False # bool
|
|
@@ -233,7 +233,7 @@ class WasatchDeviceWrapper:
|
|
|
233
233
|
|
|
234
234
|
self.wrapper_worker.daemon = True
|
|
235
235
|
|
|
236
|
-
log.debug("
|
|
236
|
+
log.debug("device wrapper: starting WrapperWorker thread")
|
|
237
237
|
self.wrapper_worker.start()
|
|
238
238
|
|
|
239
239
|
# expect to read a single post-initialization SpectrometerSettings object off the queue
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|