Skip to content
8 changes: 1 addition & 7 deletions src/ophyd_async/fastcs/eiger/_eiger.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
from ophyd_async.core import (
AsyncStatus,
PathProvider,
StandardDetector,
TriggerInfo,
)
from ophyd_async.epics.odin import Odin, OdinWriter

Expand All @@ -29,15 +27,11 @@ def __init__(
self.odin = Odin(prefix + hdf_suffix, nodes=odin_nodes)

super().__init__(
EigerController(self.drv),
EigerController(self.drv, self.odin),
OdinWriter(
path_provider,
self.odin,
self.drv.detector.bit_depth_image,
),
name=name,
)

@AsyncStatus.wrap
async def prepare(self, value: TriggerInfo) -> None:
await super().prepare(value)
10 changes: 6 additions & 4 deletions src/ophyd_async/fastcs/eiger/_eiger_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
DEFAULT_TIMEOUT,
DetectorController,
DetectorTrigger,
Reference,
TriggerInfo,
wait_for_value,
)
from ophyd_async.epics.odin import Odin

from ._eiger_io import EigerDriverIO, EigerTriggerMode

Expand All @@ -19,11 +21,9 @@


class EigerController(DetectorController):
def __init__(
self,
driver: EigerDriverIO,
) -> None:
def __init__(self, driver: EigerDriverIO, odin: Odin) -> None:
self._drv = driver
self._odin = Reference(odin)
Comment thread
shihab-dls marked this conversation as resolved.
Outdated

def get_deadtime(self, exposure: float | None) -> float:
# See https://media.dectris.com/filer_public/30/14/3014704e-5f3b-43ba-8ccf-8ef720e60d2a/240202_usermanual_eiger2.pdf
Expand Down Expand Up @@ -60,6 +60,8 @@ async def arm(self):
# but will return after the Eiger has completed arming in 0.9.0.
# https://github.com/DiamondLightSource/FastCS/pull/141
await self._drv.detector.arm.trigger(timeout=DEFAULT_TIMEOUT)
# Wait for Odin fan to be ready after arming Eiger
await wait_for_value(self._odin().fan_ready, 1, DEFAULT_TIMEOUT)
Comment thread
shihab-dls marked this conversation as resolved.
Outdated

async def wait_for_idle(self):
await wait_for_value(self._drv.detector.state, "idle", timeout=DEFAULT_TIMEOUT)
Expand Down
10 changes: 7 additions & 3 deletions tests/fastcs/eiger/test_eiger_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
TriggerInfo,
init_devices,
)
from ophyd_async.epics.odin import Odin
from ophyd_async.fastcs.eiger import EigerController, EigerDriverIO
from ophyd_async.testing import (
callback_on_mock_put,
Expand All @@ -21,13 +22,16 @@
def eiger_driver_and_controller_no_arm(RE) -> DriverAndController:
with init_devices(mock=True):
driver = EigerDriverIO("")
controller = EigerController(driver)
odin = Odin("")
controller = EigerController(driver, odin)

def become_idle_after_arm(*args, **kwargs):
def complete_arming(*args, **kwargs):
# Mocking that Odin fan is ready
set_mock_value(odin.fan_ready, True)
# Mocking that eiger has armed and finished taking frames.
set_mock_value(driver.detector.state, "idle")

callback_on_mock_put(driver.detector.arm, become_idle_after_arm)
callback_on_mock_put(driver.detector.arm, complete_arming)

return driver, controller

Expand Down
19 changes: 19 additions & 0 deletions tests/fastcs/eiger/test_eiger_detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ def set_meta_filename_and_id(value, *args, **kwargs):

callback_on_mock_put(detector.odin.file_name, set_meta_filename_and_id)

def set_odin_fan_ready(value, *args, **kwargs):
set_mock_value(detector.odin.fan_ready, 1)

callback_on_mock_put(detector.drv.detector.arm, set_odin_fan_ready)

detector._writer._path_provider.return_value.filename = "filename.h5" # type: ignore

set_mock_value(detector.odin.meta_active, "Active")
Expand All @@ -43,3 +48,17 @@ async def test_when_prepared_eiger_bit_depth_is_passed_and_set_in_odin(detector)
get_mock_put(detector.odin.data_type).assert_called_once_with(
f"UInt{expected_datatype}", wait=True
)


async def test_when_kickoff_called_odin_fan_waited_for(
detector,
):
await detector.prepare(
TriggerInfo(
exposure_timeout=None,
number_of_events=1,
trigger=DetectorTrigger.INTERNAL,
)
)
await detector.kickoff()
assert await detector.odin.fan_ready.get_value() == 1
Loading