refactor(timepix): leave detector setup to the IOC and only check it at stage
CI for superxas_bec / test (push) Successful in 1m59s
CI for superxas_bec / test (push) Successful in 1m59s
This commit is contained in:
1 parent
531f8657c4
commit
bda6e5f709
2 files changed
+66
-15
No files matched your search
@@ -213,6 +213,14 @@ TIMEPIX_FLY_BACKEND_DEFAULT_REDIS_TOPIC = "public/timepix_fly_backend/raw_data"
|
||||
|
||||
TIMEPIX_SCAN_NAME = "timepix_scan"
|
||||
|
||||
# detector setup lives in the IOC (autosave); BEC only checks it at stage
|
||||
EXPECTED_DETECTOR_SETUP = {
|
||||
"trigger_mode": TRIGGERMODE.INTERNAL,
|
||||
"trigger_source": TRIGGERSOURCE.HDMI1_1,
|
||||
"exposure_mode": EXPOSUREMODE.TIMED,
|
||||
}
|
||||
EXPECTED_XES_SETUP = {"tdc1_edge": TDCEdge.RISING, "tdc1_output": TDCOuput.ALL_CHANNELS}
|
||||
|
||||
# max wait for the images of a lost acquisition before repeating it
|
||||
LOST_ACQUISITION_IMAGE_TIMEOUT = 2.0
|
||||
|
||||
@@ -721,13 +729,25 @@ class Timepix(PSIDeviceBase, TimePixControl):
|
||||
"""Enable XES specific settings for the TimePix detector."""
|
||||
enabled_value = 1 if enabled else 0
|
||||
self.cam.tdc1_enable.set(enabled_value).wait(timeout=self._pv_timeout)
|
||||
self.cam.tdc2_enable.set(enabled_value).wait(timeout=self._pv_timeout)
|
||||
# TDC2 is not cabled; TimePixFly would count its edges as periods too
|
||||
self.cam.tdc2_enable.set(0).wait(timeout=self._pv_timeout)
|
||||
self.cam.raw_enable.set(enabled_value).wait(timeout=self._pv_timeout)
|
||||
if enabled:
|
||||
self.cam.tdc1_edge.set(TDCEdge.RISING).wait(timeout=self._pv_timeout)
|
||||
self.cam.tdc1_output.set(TDCOuput.ALL_CHANNELS).wait(timeout=self._pv_timeout)
|
||||
self.cam.tdc2_edge.set(TDCEdge.RISING).wait(timeout=self._pv_timeout)
|
||||
self.cam.tdc2_output.set(TDCOuput.ALL_CHANNELS).wait(timeout=self._pv_timeout)
|
||||
|
||||
def _check_detector_setup(self) -> None:
|
||||
"""Warn about detector setup PVs, kept in the IOC, that differ from what BEC expects."""
|
||||
expected = dict(EXPECTED_DETECTOR_SETUP)
|
||||
if self.enable_xes:
|
||||
expected.update(EXPECTED_XES_SETUP)
|
||||
wrong = []
|
||||
for attr, value in expected.items():
|
||||
current = getattr(self.cam, attr).get()
|
||||
if current != value:
|
||||
wrong.append(f"{attr}={current} (expected {value.name})")
|
||||
if wrong:
|
||||
logger.warning(
|
||||
f"{self.name}: detector setup differs from what BEC expects: {', '.join(wrong)}. "
|
||||
"These are set in the IOC, not by BEC."
|
||||
)
|
||||
|
||||
def wait_for_connection(
|
||||
self, all_signals: bool = False, timeout: float | None = None, **kwargs
|
||||
@@ -745,9 +765,6 @@ class Timepix(PSIDeviceBase, TimePixControl):
|
||||
logger.info(f"On Connected of TimePix detector {self.name}...")
|
||||
# Prepare TimePix Detector
|
||||
self._enable_xes_settings(self.enable_xes)
|
||||
self.cam.trigger_mode.set(TRIGGERMODE.INTERNAL).wait(timeout=self._pv_timeout)
|
||||
self.cam.trigger_source.set(TRIGGERSOURCE.HDMI1_1).wait(timeout=self._pv_timeout)
|
||||
self.cam.exposure_mode.set(EXPOSUREMODE.TIMED).wait(timeout=self._pv_timeout)
|
||||
# Reset array counter on connect
|
||||
self.cam.array_counter.set(0).wait(timeout=self._pv_timeout)
|
||||
# Set image mode to multiple
|
||||
@@ -830,6 +847,7 @@ class Timepix(PSIDeviceBase, TimePixControl):
|
||||
self.cam.acquire_period.set(exp_time).wait(timeout=self._pv_timeout)
|
||||
self.cam.num_images.set(burst_images).wait(timeout=self._pv_timeout)
|
||||
self.cam.data_source.set(DATASOURCE.IMAGE).wait(timeout=self._pv_timeout)
|
||||
self._check_detector_setup()
|
||||
|
||||
# Setup file writing
|
||||
self._full_path = get_full_path(scan_msg, name="timepix")
|
||||
|
||||
@@ -264,16 +264,12 @@ def pixel_map():
|
||||
|
||||
def test_timepix_on_connected_configures_signals_and_registers_callback(timepix):
|
||||
"""Connected hook should configure camera, file writer, and backend callback."""
|
||||
timepix.cam.tdc2_enable.put(1)
|
||||
timepix.on_connected()
|
||||
|
||||
assert timepix.cam.tdc1_enable.get() == 1
|
||||
assert timepix.cam.tdc2_enable.get() == 1
|
||||
assert timepix.cam.tdc2_enable.get() == 0
|
||||
assert timepix.cam.raw_enable.get() == 1
|
||||
assert timepix.cam.tdc1_edge.get() == TDCEdge.RISING
|
||||
assert timepix.cam.tdc1_output.get() == TDCOuput.ALL_CHANNELS
|
||||
assert timepix.cam.trigger_mode.get() == TRIGGERMODE.INTERNAL
|
||||
assert timepix.cam.trigger_source.get() == TRIGGERSOURCE.HDMI1_1
|
||||
assert timepix.cam.exposure_mode.get() == EXPOSUREMODE.TIMED
|
||||
assert timepix.cam.array_counter.get() == 0
|
||||
assert timepix.hdf.enable.get() == "1"
|
||||
assert timepix.hdf.file_write_mode.get() == FILEWRITEMODE.STREAM.value
|
||||
@@ -909,3 +905,40 @@ def test_timepix_stop_cancels_repetition_of_lost_acquisition(xes_timepix):
|
||||
assert timepix.backend.on_trigger_finished.call_count == 1
|
||||
assert not timepix._xes_acquisitions
|
||||
assert timepix._images_to_skip == 0
|
||||
|
||||
|
||||
def test_timepix_on_connected_leaves_detector_setup_to_the_ioc(timepix):
|
||||
"""Trigger and TDC edge/output PVs belong to the IOC setup; connecting must not write them."""
|
||||
timepix.cam.trigger_mode.put(TRIGGERMODE.EXTERNAL)
|
||||
timepix.cam.exposure_mode.put(EXPOSUREMODE.TRIGGER_WIDTH)
|
||||
timepix.cam.tdc1_edge.put(TDCEdge.FALLING)
|
||||
timepix.cam.tdc1_output.put(TDCOuput.CHANNEL_0)
|
||||
|
||||
timepix.on_connected()
|
||||
|
||||
assert timepix.cam.trigger_mode.get() == TRIGGERMODE.EXTERNAL
|
||||
assert timepix.cam.exposure_mode.get() == EXPOSUREMODE.TRIGGER_WIDTH
|
||||
assert timepix.cam.tdc1_edge.get() == TDCEdge.FALLING
|
||||
assert timepix.cam.tdc1_output.get() == TDCOuput.CHANNEL_0
|
||||
|
||||
|
||||
def test_timepix_check_detector_setup_warns_about_unexpected_values(timepix):
|
||||
"""A setup PV that differs from what BEC expects is reported, not overwritten."""
|
||||
timepix._enable_xes = True
|
||||
timepix.cam.trigger_mode.put(TRIGGERMODE.EXTERNAL)
|
||||
timepix.cam.tdc1_edge.put(TDCEdge.FALLING)
|
||||
|
||||
with mock.patch("superxas_bec.devices.timepix.timepix.logger") as logger:
|
||||
timepix._check_detector_setup()
|
||||
|
||||
message = logger.warning.call_args.args[0]
|
||||
assert "trigger_mode" in message and "tdc1_edge" in message
|
||||
assert timepix.cam.trigger_mode.get() == TRIGGERMODE.EXTERNAL
|
||||
|
||||
|
||||
def test_timepix_check_detector_setup_is_quiet_when_setup_matches(timepix):
|
||||
"""No warning when the IOC setup matches."""
|
||||
timepix._enable_xes = True
|
||||
with mock.patch("superxas_bec.devices.timepix.timepix.logger") as logger:
|
||||
timepix._check_detector_setup()
|
||||
logger.warning.assert_not_called()
|
||||
Reference in new issue
Block a user