From fbcad2801b6f84ed78bc920e92a64bd610def8eb Mon Sep 17 00:00:00 2001 From: Dominic Oram Date: Fri, 29 Nov 2024 11:14:24 +0000 Subject: [PATCH] Make sure to only stop the detector if it hasn't already started disarming --- src/dodal/devices/eiger.py | 33 ++++++++++++++++---------- tests/devices/unit_tests/test_eiger.py | 12 ++++++++++ 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/dodal/devices/eiger.py b/src/dodal/devices/eiger.py index 81e1f7a922..28189dafc0 100644 --- a/src/dodal/devices/eiger.py +++ b/src/dodal/devices/eiger.py @@ -62,6 +62,9 @@ def set(self, value, *, timeout=None, settle_time=None, **kwargs): arming_status = Status() arming_status.set_finished() + disarming_status = Status() + disarming_status.set_finished() + def __init__(self, beamline: str = "i03", *args, **kwargs): super().__init__(*args, **kwargs) self.beamline = beamline @@ -140,6 +143,7 @@ def stop_odin_when_all_frames_collected(self): def unstage(self) -> bool: assert self.detector_params is not None try: + self.disarming_status = Status() self.wait_on_arming_if_started() if self.detector_params.trigger_mode == TriggerMode.FREE_RUN: # In free run mode we have to manually stop odin @@ -158,23 +162,28 @@ def unstage(self) -> bool: self.timeouts.general_status_timeout ) self.disable_roi_mode() + self.disarming_status.set_finished() return status_ok def stop(self, *args): """Emergency stop the device, mainly used to clean up after error.""" LOGGER.info("Eiger stop() called - cleaning up...") - self.wait_on_arming_if_started() - stop_status = self.odin.stop() - self.odin.file_writer.start_timeout.set(1).wait( - self.timeouts.general_status_timeout - ) - self.disarm_detector() - stop_status &= self.disable_roi_mode() - stop_status.wait(self.timeouts.general_status_timeout) - # See https://github.com/DiamondLightSource/hyperion/issues/1395 - LOGGER.info("Turning off Eiger dev/shm streaming") - self.odin.fan.dev_shm_enable.set(0).wait() - LOGGER.info("Eiger has successfully been stopped") + if not self.disarming_status.done: + LOGGER.info("Eiger still disarming, waiting on disarm") + self.disarming_status.wait(self.timeouts.arming_timeout) + else: + self.wait_on_arming_if_started() + stop_status = self.odin.stop() + self.odin.file_writer.start_timeout.set(1).wait( + self.timeouts.general_status_timeout + ) + self.disarm_detector() + stop_status &= self.disable_roi_mode() + stop_status.wait(self.timeouts.general_status_timeout) + # See https://github.com/DiamondLightSource/hyperion/issues/1395 + LOGGER.info("Turning off Eiger dev/shm streaming") + self.odin.fan.dev_shm_enable.set(0).wait() + LOGGER.info("Eiger has successfully been stopped") def disable_roi_mode(self): return self.change_roi_mode(False) diff --git a/tests/devices/unit_tests/test_eiger.py b/tests/devices/unit_tests/test_eiger.py index 1409a5c494..d2080b7486 100644 --- a/tests/devices/unit_tests/test_eiger.py +++ b/tests/devices/unit_tests/test_eiger.py @@ -740,3 +740,15 @@ def test_for_other_beamlines_i03_used_as_default(params: DetectorParams): ) assert fake_eiger.beamline == "ixx" assert fake_eiger.timeouts == AVAILABLE_TIMEOUTS["i03"] + + +def test_given_eiger_is_disarming_when_eiger_is_stopped_then_wait_for_disarming_to_finish( + fake_eiger: EigerDetector, +): + fake_eiger.disarm_detector = MagicMock() + fake_eiger.disarming_status = (disarming_status := MagicMock()) + disarming_status.done = False + fake_eiger.stop() + + disarming_status.wait.assert_called_once() + fake_eiger.disarm_detector.assert_not_called()