Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wait for eiger to disarm before stopping it #936

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 21 additions & 12 deletions src/dodal/devices/eiger.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps this fixes the issue, but I'm unclear on what exactly we should do in stop(), looking at bluesky run_engine.py it seems stop() is invoked in a variety of scenarios, including at the end of a plan, during a suspend and when pause() is invoked. The impression I get is that being stopped is at least somewhat resumable.

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)
Expand Down
12 changes: 12 additions & 0 deletions tests/devices/unit_tests/test_eiger.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Loading