diff --git a/src/dodal/beamlines/b07.py b/src/dodal/beamlines/b07.py index a30c3343c5a..015602cc4cf 100644 --- a/src/dodal/beamlines/b07.py +++ b/src/dodal/beamlines/b07.py @@ -1,3 +1,5 @@ +from ophyd_async.epics.adcore import ADAcquireLogic + from dodal.beamlines.b07_shared import devices as b07_shared_devices from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline from dodal.device_manager import DeviceManager @@ -7,7 +9,11 @@ LensMode, ) from dodal.devices.beamlines.b07_shared import PsuMode -from dodal.devices.electron_analyser.specs import SpecsDetector +from dodal.devices.electron_analyser.base import ( + ElectronAnalayserTriggerLogic, + RegionLogic, +) +from dodal.devices.electron_analyser.specs import SpecsAnalyserDriverIO, SpecsDetector from dodal.devices.hutch_shutter import ( EXP_SHUTTER_2_INFIX, HutchShutter, @@ -47,15 +53,16 @@ def pgm() -> PlaneGratingMonochromator: ) -# CAM:IMAGE will fail to connect outside the beamline network, -# see https://github.com/DiamondLightSource/dodal/issues/1852 @devices.factory() def analyser(pgm: PlaneGratingMonochromator) -> SpecsDetector[LensMode, PsuMode]: + prefix = f"{B_PREFIX.beamline_prefix}-EA-DET-02:CAM:" + driver = SpecsAnalyserDriverIO(prefix, LensMode, PsuMode) return SpecsDetector[LensMode, PsuMode]( - prefix=f"{B_PREFIX.beamline_prefix}-EA-DET-01:CAM:", - lens_mode_type=LensMode, - psu_mode_type=PsuMode, - energy_source=pgm.energy.user_readback, + prefix, + driver, + acquire_logic=ADAcquireLogic(driver), + trigger_logic=ElectronAnalayserTriggerLogic(driver), + region_logic=RegionLogic(driver, pgm.energy.user_readback), ) diff --git a/src/dodal/beamlines/b07_1.py b/src/dodal/beamlines/b07_1.py index 0e21d76eccf..306965ce022 100644 --- a/src/dodal/beamlines/b07_1.py +++ b/src/dodal/beamlines/b07_1.py @@ -1,13 +1,16 @@ +from ophyd_async.epics.adcore import ADAcquireLogic + from dodal.beamlines.b07_shared import devices as b07_shared_devices from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline from dodal.device_manager import DeviceManager -from dodal.devices.beamlines.b07_1 import ( - ChannelCutMonochromator, - Grating, - LensMode, -) +from dodal.devices.beamlines.b07 import Grating, LensMode +from dodal.devices.beamlines.b07_1 import ChannelCutMonochromator, Grating, LensMode from dodal.devices.beamlines.b07_shared import PsuMode -from dodal.devices.electron_analyser.specs import SpecsDetector +from dodal.devices.electron_analyser.base import ( + ElectronAnalayserTriggerLogic, + RegionLogic, +) +from dodal.devices.electron_analyser.specs import SpecsAnalyserDriverIO, SpecsDetector from dodal.devices.hutch_shutter import HutchShutter from dodal.devices.motors import XYZAzimuthPolarStage from dodal.devices.pgm import PlaneGratingMonochromator @@ -41,15 +44,16 @@ def ccmc() -> ChannelCutMonochromator: return ChannelCutMonochromator(prefix=f"{C_PREFIX.beamline_prefix}-OP-CCM-01:") -# CAM:IMAGE will fail to connect outside the beamline network, -# see https://github.com/DiamondLightSource/dodal/issues/1852 @devices.factory() def analyser(pgm: PlaneGratingMonochromator) -> SpecsDetector[LensMode, PsuMode]: + prefix = f"{C_PREFIX.beamline_prefix}-EA-DET-01:CAM:" + driver = SpecsAnalyserDriverIO(prefix, LensMode, PsuMode) return SpecsDetector[LensMode, PsuMode]( - prefix=f"{C_PREFIX.beamline_prefix}-EA-DET-01:CAM:", - lens_mode_type=LensMode, - psu_mode_type=PsuMode, - energy_source=pgm.energy.user_readback, + prefix, + driver, + acquire_logic=ADAcquireLogic(driver), + trigger_logic=ElectronAnalayserTriggerLogic(driver), + region_logic=RegionLogic(driver, pgm.energy.user_readback), ) diff --git a/src/dodal/beamlines/i05.py b/src/dodal/beamlines/i05.py index 42e3a9292e2..be77d07833c 100644 --- a/src/dodal/beamlines/i05.py +++ b/src/dodal/beamlines/i05.py @@ -1,11 +1,18 @@ +from ophyd_async.epics.adcore import ADAcquireLogic + from dodal.beamlines.i05_shared import devices as i05_shared_devices from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline from dodal.device_manager import DeviceManager from dodal.devices.beamlines.i05 import I05Goniometer from dodal.devices.beamlines.i05_shared import LensMode, M4M5Mirror, PassEnergy from dodal.devices.common_mirror import XYZSwitchingMirror +from dodal.devices.electron_analyser.base import ( + ElectronAnalayserTriggerLogic, + RegionLogic, +) from dodal.devices.electron_analyser.mbs import ( EntranceSlitInformationDevice, + MbsAnalyserDriverIO, MbsDetector, ) from dodal.devices.hutch_shutter import HutchShutter @@ -62,11 +69,14 @@ def analyser_slits() -> EntranceSlitInformationDevice: def analyser( pgm: PlaneGratingMonochromator, analyser_slits: EntranceSlitInformationDevice ) -> MbsDetector[LensMode, PassEnergy]: + prefix = f"{PREFIX.beamline_prefix}-EA-DET-02:CAM:" + driver = MbsAnalyserDriverIO(prefix, LensMode, PassEnergy) return MbsDetector[LensMode, PassEnergy]( - prefix=f"{PREFIX.beamline_prefix}-EA-DET-02:CAM:", - lens_mode_type=LensMode, - pass_energy_type=PassEnergy, - energy_source=pgm.energy.user_readback, + prefix, + driver, + acquire_logic=ADAcquireLogic(driver), + trigger_logic=ElectronAnalayserTriggerLogic(driver), + region_logic=RegionLogic(driver, pgm.energy.user_readback), config_sigs=( analyser_slits.direction, analyser_slits.size, diff --git a/src/dodal/beamlines/i05_1.py b/src/dodal/beamlines/i05_1.py index 6d80d0ddf0d..76849e138fc 100644 --- a/src/dodal/beamlines/i05_1.py +++ b/src/dodal/beamlines/i05_1.py @@ -1,11 +1,18 @@ +from ophyd_async.epics.adcore import ADAcquireLogic + from dodal.beamlines.i05_shared import devices as i05_shared_devices from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline from dodal.device_manager import DeviceManager from dodal.devices.beamlines.i05_1 import XYZAzimuthPolarDefocusStage from dodal.devices.beamlines.i05_shared import LensMode, Mj7j8Mirror, PassEnergy from dodal.devices.common_mirror import XYZPiezoSwitchingMirror +from dodal.devices.electron_analyser.base import ( + ElectronAnalayserTriggerLogic, + RegionLogic, +) from dodal.devices.electron_analyser.mbs import ( EntranceSlitInformationDevice, + MbsAnalyserDriverIO, MbsDetector, ) from dodal.devices.hutch_shutter import HutchShutter @@ -52,11 +59,14 @@ def analyser_slits() -> EntranceSlitInformationDevice: def analyser( pgm: PlaneGratingMonochromator, analyser_slits: EntranceSlitInformationDevice ) -> MbsDetector[LensMode, PassEnergy]: + prefix = f"{PREFIX.beamline_prefix}-EA-DET-04:CAM:" + driver = MbsAnalyserDriverIO(prefix, LensMode, PassEnergy) return MbsDetector[LensMode, PassEnergy]( - prefix=f"{PREFIX.beamline_prefix}-EA-DET-04:CAM:", - lens_mode_type=LensMode, - pass_energy_type=PassEnergy, - energy_source=pgm.energy.user_readback, + prefix, + driver, + acquire_logic=ADAcquireLogic(driver), + trigger_logic=ElectronAnalayserTriggerLogic(driver), + region_logic=RegionLogic(driver, pgm.energy.user_readback), config_sigs=( analyser_slits.direction, analyser_slits.size, diff --git a/src/dodal/beamlines/i09.py b/src/dodal/beamlines/i09.py index c42df5f47ca..e142f8486f7 100644 --- a/src/dodal/beamlines/i09.py +++ b/src/dodal/beamlines/i09.py @@ -1,4 +1,4 @@ -from ophyd_async.core import InOut, SignalRW +from ophyd_async.core import InOut, SignalRW, soft_signal_rw from ophyd_async.epics.core import epics_signal_rw from dodal.beamlines.i09_1_shared import devices as i09_1_shared_devices @@ -13,8 +13,16 @@ ) from dodal.devices.beamlines.i09.scaler import ScalerController from dodal.devices.common_dcm import DoubleCrystalMonochromatorWithDSpacing -from dodal.devices.electron_analyser.base import DualEnergySource -from dodal.devices.electron_analyser.vgscienta import VGScientaDetector +from dodal.devices.electron_analyser.base import ( + DualEnergySource, + ElectronAnalayserTriggerLogic, + RegionLogic, + ShutterCoordinatorADAcquireLogic, +) +from dodal.devices.electron_analyser.vgscienta import ( + VGScientaAnalyserDriverIO, + VGScientaDetector, +) from dodal.devices.fast_shutter import DualFastShutter, FastShutter from dodal.devices.hutch_shutter import EXP_SHUTTER_2_INFIX, HutchShutter from dodal.devices.motors import XYZAzimuthPolarStage @@ -106,22 +114,28 @@ def dual_fast_shutter( return DualFastShutter[InOut](fsi1, fsj1, source_selector.selected_source) -# CAM:IMAGE will fail to connect outside the beamline network, -# see https://github.com/DiamondLightSource/dodal/issues/1852 +@devices.factory() +def ew4000_close_shutter_when_idle() -> SignalRW[bool]: + return soft_signal_rw(bool, initial_value=True) + + @devices.factory() def ew4000( dual_fast_shutter: DualFastShutter, dual_energy_source: DualEnergySource, source_selector: SourceSelector, + ew4000_close_shutter_when_idle: SignalRW[bool], ) -> VGScientaDetector[LensMode, PsuMode, PassEnergy]: + prefix = f"{I_PREFIX.beamline_prefix}-EA-DET-01:CAM:" + driver = VGScientaAnalyserDriverIO(prefix, LensMode, PsuMode, PassEnergy) return VGScientaDetector[LensMode, PsuMode, PassEnergy]( - prefix=f"{I_PREFIX.beamline_prefix}-EA-DET-01:CAM:", - lens_mode_type=LensMode, - psu_mode_type=PsuMode, - pass_energy_type=PassEnergy, - energy_source=dual_energy_source.energy, - shutter=dual_fast_shutter, - source_selector=source_selector, + prefix, + driver, + acquire_logic=ShutterCoordinatorADAcquireLogic( + driver, dual_fast_shutter, ew4000_close_shutter_when_idle + ), + trigger_logic=ElectronAnalayserTriggerLogic(driver), + region_logic=RegionLogic(driver, dual_energy_source.energy, source_selector), ) diff --git a/src/dodal/beamlines/i09_1.py b/src/dodal/beamlines/i09_1.py index 8e504ad0d97..414b065f504 100644 --- a/src/dodal/beamlines/i09_1.py +++ b/src/dodal/beamlines/i09_1.py @@ -1,9 +1,15 @@ +from ophyd_async.epics.adcore import ADAcquireLogic + from dodal.beamlines.i09_1_shared import devices as i09_1_shared_devices from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline from dodal.device_manager import DeviceManager from dodal.devices.beamlines.i09_1 import LensMode, PsuMode from dodal.devices.common_dcm import DoubleCrystalMonochromatorWithDSpacing -from dodal.devices.electron_analyser.specs import SpecsDetector +from dodal.devices.electron_analyser.base import ( + ElectronAnalayserTriggerLogic, + RegionLogic, +) +from dodal.devices.electron_analyser.specs import SpecsAnalyserDriverIO, SpecsDetector from dodal.devices.motors import XYZAzimuthTiltPolarStage from dodal.devices.synchrotron import Synchrotron from dodal.devices.temperture_controller import Lakeshore336 @@ -24,17 +30,18 @@ def synchrotron() -> Synchrotron: return Synchrotron() -# CAM:IMAGE will fail to connect outside the beamline network, -# see https://github.com/DiamondLightSource/dodal/issues/1852 @devices.factory() def analyser( dcm: DoubleCrystalMonochromatorWithDSpacing, ) -> SpecsDetector[LensMode, PsuMode]: + prefix = f"{PREFIX.beamline_prefix}-EA-DET-02:CAM:" + driver = SpecsAnalyserDriverIO(prefix, LensMode, PsuMode) return SpecsDetector[LensMode, PsuMode]( - prefix=f"{PREFIX.beamline_prefix}-EA-DET-02:CAM:", - lens_mode_type=LensMode, - psu_mode_type=PsuMode, - energy_source=dcm.energy_in_eV, + prefix, + driver, + acquire_logic=ADAcquireLogic(driver), + trigger_logic=ElectronAnalayserTriggerLogic(driver), + region_logic=RegionLogic(driver, dcm.energy_in_eV), ) diff --git a/src/dodal/beamlines/p60.py b/src/dodal/beamlines/p60.py index cfe2176488f..f94f58be98e 100644 --- a/src/dodal/beamlines/p60.py +++ b/src/dodal/beamlines/p60.py @@ -1,5 +1,8 @@ +from ophyd_async.epics.adcore import ADAcquireLogic + from dodal.common.beamlines.beamline_utils import set_beamline as set_utils_beamline from dodal.device_manager import DeviceManager +from dodal.devices.beamlines.i09 import LensMode, PassEnergy, PsuMode from dodal.devices.beamlines.p60 import ( LabXraySource, LabXraySourceReadable, @@ -7,8 +10,15 @@ PassEnergy, PsuMode, ) -from dodal.devices.electron_analyser.base import DualEnergySource -from dodal.devices.electron_analyser.vgscienta import VGScientaDetector +from dodal.devices.electron_analyser.base import ( + DualEnergySource, + ElectronAnalayserTriggerLogic, + RegionLogic, +) +from dodal.devices.electron_analyser.vgscienta import ( + VGScientaAnalyserDriverIO, + VGScientaDetector, +) from dodal.devices.selectable_source import SourceSelector from dodal.log import set_beamline as set_log_beamline from dodal.utils import BeamlinePrefix, get_beamline_name @@ -42,7 +52,7 @@ def mg_kalpha_source() -> LabXraySourceReadable: @devices.factory() -def energy_source( +def dual_energy_source( al_kalpha_source: LabXraySourceReadable, mg_kalpha_source: LabXraySourceReadable, source_selector: SourceSelector, @@ -54,16 +64,16 @@ def energy_source( ) -# Connect will work again after this work completed -# https://jira.diamond.ac.uk/browse/P60-13 @devices.factory() -def r4000( - energy_source: DualEnergySource, +def ew4000( + dual_energy_source: DualEnergySource, ) -> VGScientaDetector[LensMode, PsuMode, PassEnergy]: + prefix = f"{PREFIX.beamline_prefix}-EA-DET-01:CAM:" + driver = VGScientaAnalyserDriverIO(prefix, LensMode, PsuMode, PassEnergy) return VGScientaDetector[LensMode, PsuMode, PassEnergy]( - prefix=f"{PREFIX.beamline_prefix}-EA-DET-01:CAM:", - lens_mode_type=LensMode, - psu_mode_type=PsuMode, - pass_energy_type=PassEnergy, - energy_source=energy_source.energy, + prefix=prefix, + driver=driver, + acquire_logic=ADAcquireLogic(driver), + trigger_logic=ElectronAnalayserTriggerLogic(driver), + region_logic=RegionLogic(driver, dual_energy_source.energy), ) diff --git a/src/dodal/devices/cryostream.py b/src/dodal/devices/cryostream.py index 272791c91f5..daaf254e329 100644 --- a/src/dodal/devices/cryostream.py +++ b/src/dodal/devices/cryostream.py @@ -4,11 +4,7 @@ StandardReadableFormat, StrictEnum, ) -from ophyd_async.epics.core import ( - epics_signal_r, - epics_signal_rw, - epics_signal_x, -) +from ophyd_async.epics.core import epics_signal_r, epics_signal_rw, epics_signal_x class TurboEnum(StrictEnum): diff --git a/src/dodal/devices/electron_analyser/base/__init__.py b/src/dodal/devices/electron_analyser/base/__init__.py index a088b6fd8dd..8ccd906d370 100644 --- a/src/dodal/devices/electron_analyser/base/__init__.py +++ b/src/dodal/devices/electron_analyser/base/__init__.py @@ -16,6 +16,11 @@ TLensMode, ) from .base_util import to_binding_energy, to_kinetic_energy +from .detector_logic import ( + ElectronAnalayserTriggerLogic, + RegionLogic, + ShutterCoordinatorADAcquireLogic, +) from .energy_sources import DualEnergySource __all__ = [ @@ -35,5 +40,8 @@ "TLensMode", "to_binding_energy", "to_kinetic_energy", + "ElectronAnalayserTriggerLogic", + "RegionLogic", + "ShutterCoordinatorADAcquireLogic", "DualEnergySource", ] diff --git a/src/dodal/devices/electron_analyser/base/base_detector.py b/src/dodal/devices/electron_analyser/base/base_detector.py index 429b12b7469..7e348a69486 100644 --- a/src/dodal/devices/electron_analyser/base/base_detector.py +++ b/src/dodal/devices/electron_analyser/base/base_detector.py @@ -1,5 +1,5 @@ import asyncio -from collections.abc import Sequence +from collections.abc import Mapping, Sequence from typing import Generic import numpy as np @@ -8,11 +8,10 @@ Array1D, AsyncStatus, DetectorAcquireLogic, - DetectorTriggerLogic, SignalR, - StandardDetector, derived_signal_r, ) +from ophyd_async.epics.adcore import ADWriterFactory, AreaDetector, NDPluginBaseIO from dodal.devices.electron_analyser.base.base_driver_io import ( GenericAnalyserDriverIO, @@ -26,7 +25,10 @@ TBaseRegion, ) from dodal.devices.electron_analyser.base.base_util import to_binding_energy -from dodal.devices.electron_analyser.base.detector_logic import RegionLogic +from dodal.devices.electron_analyser.base.detector_logic import ( + ElectronAnalayserTriggerLogic, + RegionLogic, +) class SequenceHolder(Stageable, Preparable): @@ -53,7 +55,7 @@ async def unstage(self): class ElectronAnalyserDetector( - StandardDetector, + AreaDetector[TAbstractAnalyserDriverIO], Generic[TAbstractAnalyserDriverIO, TBaseRegion], ): """Detector for data acquisition of electron analyser. Can be configured with @@ -62,14 +64,18 @@ class ElectronAnalyserDetector( def __init__( self, + driver: TAbstractAnalyserDriverIO, + prefix: str, + *writer_factories: ADWriterFactory, acquire_logic: DetectorAcquireLogic, - trigger_logic: DetectorTriggerLogic, + trigger_logic: ElectronAnalayserTriggerLogic, region_logic: RegionLogic, + plugins: Mapping[str, NDPluginBaseIO] | None = None, config_sigs: Sequence[SignalR] = (), name: str = "", ): + self.sequence = SequenceHolder() self._region_logic = region_logic - self.binding_energy_axis = derived_signal_r( self._calculate_binding_energy_axis, "eV", @@ -77,12 +83,17 @@ def __init__( excitation_energy=region_logic.energy_source, energy_mode=region_logic.driver.energy_mode, ) - # ToDo - Add data logic - self.add_detector_logics(acquire_logic, trigger_logic) - self.add_config_signals(self.binding_energy_axis, *config_sigs) - - self.sequence = SequenceHolder() - super().__init__(name) + config_sigs = (self.binding_energy_axis, *config_sigs) + super().__init__( + driver, + prefix, + *writer_factories, + acquire_logic=acquire_logic, + trigger_logic=trigger_logic, + plugins=plugins, + config_sigs=config_sigs, + name=name, + ) def _calculate_binding_energy_axis( self, diff --git a/src/dodal/devices/electron_analyser/base/detector_logic.py b/src/dodal/devices/electron_analyser/base/detector_logic.py index b8c9aae43db..13c1bbed7d2 100644 --- a/src/dodal/devices/electron_analyser/base/detector_logic.py +++ b/src/dodal/devices/electron_analyser/base/detector_logic.py @@ -1,32 +1,28 @@ -from typing import Any, Generic +from dataclasses import dataclass, field +from typing import Any from ophyd_async.core import DetectorTriggerLogic, SignalDict, SignalR from ophyd_async.epics.adcore import ADAcquireLogic, ADImageMode -from dodal.devices.electron_analyser.base.base_driver_io import ( - AbstractAnalyserDriverIO, - TAbstractAnalyserDriverIO, -) +from dodal.devices.electron_analyser.base.base_driver_io import AbstractAnalyserDriverIO from dodal.devices.electron_analyser.base.base_region import BaseRegion from dodal.devices.fast_shutter import GenericFastShutter from dodal.devices.selectable_source import SourceSelector -class ShutterCoordinatorADAcquireLogic( - ADAcquireLogic, Generic[TAbstractAnalyserDriverIO] -): +class ShutterCoordinatorADAcquireLogic(ADAcquireLogic): """Extends the acquire logic to coordinate opening shutters before acquisition with optional configuration of when to close. """ def __init__( self, - driver: TAbstractAnalyserDriverIO, + driver: AbstractAnalyserDriverIO, shutter: GenericFastShutter, - _close_shutter_when_idle: SignalR[bool] | None = None, + close_shutter_when_idle: SignalR[bool] | None = None, ): self._shutter = shutter - self._close_shutter_when_idle = _close_shutter_when_idle + self._close_shutter_when_idle = close_shutter_when_idle super().__init__(driver) async def start_acquiring(self): @@ -44,41 +40,33 @@ async def wait_for_idle(self): await self._shutter.set(self._shutter.close_state) -class ElectronAnalayserTriggerLogic( - DetectorTriggerLogic, Generic[TAbstractAnalyserDriverIO] -): +@dataclass +class ElectronAnalayserTriggerLogic(DetectorTriggerLogic): """Simple trigger logic for electron analyser.""" - def __init__( - self, driver: TAbstractAnalyserDriverIO, config_sigs: set[SignalR[Any]] - ): - self.driver = driver - self._config_sigs = config_sigs + driver: AbstractAnalyserDriverIO + config_signals: set[SignalR[Any]] = field(default_factory=set) + deadtime: float = 0 def config_sigs(self) -> set[SignalR[Any]]: """Return the signals that should appear in read_configuration.""" - return self._config_sigs + return self.config_signals def get_deadtime(self, config_values: SignalDict) -> float: - return 0.0 + return self.deadtime async def prepare_internal(self, num: int, livetime: float, deadtime: float): - # Only set image mode to single, num images and exposure is done with region. + # Only set image mode to single, num images and exposure is done with region logic. await self.driver.image_mode.set(ADImageMode.SINGLE) +@dataclass class RegionLogic: """Logic for wrapping electron analyser driver to correctly set region data.""" - def __init__( - self, - driver: AbstractAnalyserDriverIO, - energy_source: SignalR[float], - source_selector: SourceSelector | None = None, - ): - self.driver = driver - self.energy_source = energy_source - self.source_selector = source_selector + driver: AbstractAnalyserDriverIO + energy_source: SignalR[float] + source_selector: SourceSelector | None = None async def setup_with_region(self, region: BaseRegion) -> None: """Logic to correctly wrap the driver with a region.""" diff --git a/src/dodal/devices/electron_analyser/mbs/mbs_detector.py b/src/dodal/devices/electron_analyser/mbs/mbs_detector.py index 55af88b4d39..f7f598cc444 100644 --- a/src/dodal/devices/electron_analyser/mbs/mbs_detector.py +++ b/src/dodal/devices/electron_analyser/mbs/mbs_detector.py @@ -1,22 +1,18 @@ -from collections.abc import Sequence +from collections.abc import Mapping, Sequence from typing import Generic -from ophyd_async.core import SignalR, soft_signal_rw -from ophyd_async.epics.adcore import ADAcquireLogic +from ophyd_async.core import SignalR +from ophyd_async.epics.adcore import ADAcquireLogic, ADWriterFactory, NDPluginBaseIO from dodal.devices.electron_analyser.base import ElectronAnalyserDetector from dodal.devices.electron_analyser.base.base_detector import ElectronAnalyserDetector from dodal.devices.electron_analyser.base.base_region import TLensMode, TPassEnergy from dodal.devices.electron_analyser.base.detector_logic import ( - ADAcquireLogic, ElectronAnalayserTriggerLogic, RegionLogic, - ShutterCoordinatorADAcquireLogic, ) from dodal.devices.electron_analyser.mbs.mbs_driver_io import MbsAnalyserDriverIO from dodal.devices.electron_analyser.mbs.mbs_region import MbsRegion -from dodal.devices.fast_shutter import GenericFastShutter -from dodal.devices.selectable_source import SourceSelector class MbsDetector( @@ -28,62 +24,53 @@ class MbsDetector( def __init__( self, prefix: str, - lens_mode_type: type[TLensMode], - pass_energy_type: type[TPassEnergy], - energy_source: SignalR[float], - shutter: GenericFastShutter | None = None, - source_selector: SourceSelector | None = None, + driver: MbsAnalyserDriverIO[TLensMode, TPassEnergy], + *writer_factories: ADWriterFactory, + acquire_logic: ADAcquireLogic, + trigger_logic: ElectronAnalayserTriggerLogic, + region_logic: RegionLogic, + plugins: Mapping[str, NDPluginBaseIO] | None = None, config_sigs: Sequence[SignalR] = (), name: str = "", ): - # Make attribute of class so connect applies to driver and populates parent. - self.driver = MbsAnalyserDriverIO[TLensMode, TPassEnergy]( - prefix, lens_mode_type, pass_energy_type - ) - region_logic = RegionLogic(self.driver, energy_source, source_selector) - self.close_shutter_when_idle = soft_signal_rw(bool, initial_value=True) - acquire_logic = ( - ShutterCoordinatorADAcquireLogic( - self.driver, shutter, self.close_shutter_when_idle - ) - if shutter is not None - else ADAcquireLogic(self.driver) - ) - trigger_logic = ElectronAnalayserTriggerLogic(self.driver, set()) config_sigs = ( *config_sigs, - self.driver.region_name, - self.driver.energy_mode, - self.driver.acquisition_mode, - self.driver.lens_mode, - self.driver.low_energy, - self.driver.centre_energy, - self.driver.high_energy, - self.driver.deflector_x, - self.driver.energy_step, - self.driver.pass_energy, - self.driver.slices, - self.driver.iterations, - self.driver.total_steps, - self.driver.acquire_time, - self.driver.acquire_period, - self.driver.total_time, - self.driver.energy_axis, - self.driver.angle_axis, - self.driver.psu_mode, - self.driver.dither_steps, - self.driver.spin_offset, - self.driver.array_size_x, - self.driver.array_size_y, - self.driver.min_x, - self.driver.min_y, - self.driver.max_x, - self.driver.max_y, + driver.region_name, + driver.energy_mode, + driver.acquisition_mode, + driver.lens_mode, + driver.low_energy, + driver.centre_energy, + driver.high_energy, + driver.deflector_x, + driver.energy_step, + driver.pass_energy, + driver.slices, + driver.iterations, + driver.total_steps, + driver.acquire_time, + driver.acquire_period, + driver.total_time, + driver.energy_axis, + driver.angle_axis, + driver.psu_mode, + driver.dither_steps, + driver.spin_offset, + driver.array_size_x, + driver.array_size_y, + driver.min_x, + driver.min_y, + driver.max_x, + driver.max_y, ) super().__init__( + driver, + prefix, + *writer_factories, region_logic=region_logic, acquire_logic=acquire_logic, trigger_logic=trigger_logic, + plugins=plugins, config_sigs=config_sigs, name=name, ) diff --git a/src/dodal/devices/electron_analyser/specs/specs_detector.py b/src/dodal/devices/electron_analyser/specs/specs_detector.py index f896ede4b15..36618393434 100644 --- a/src/dodal/devices/electron_analyser/specs/specs_detector.py +++ b/src/dodal/devices/electron_analyser/specs/specs_detector.py @@ -1,19 +1,17 @@ +from collections.abc import Mapping, Sequence from typing import Generic -from ophyd_async.core import SignalR, soft_signal_rw +from ophyd_async.core import SignalR +from ophyd_async.epics.adcore import ADAcquireLogic, ADWriterFactory, NDPluginBaseIO from dodal.devices.electron_analyser.base.base_detector import ElectronAnalyserDetector from dodal.devices.electron_analyser.base.base_region import TLensMode, TPsuMode from dodal.devices.electron_analyser.base.detector_logic import ( - ADAcquireLogic, ElectronAnalayserTriggerLogic, RegionLogic, - ShutterCoordinatorADAcquireLogic, ) from dodal.devices.electron_analyser.specs.specs_driver_io import SpecsAnalyserDriverIO from dodal.devices.electron_analyser.specs.specs_region import SpecsRegion -from dodal.devices.fast_shutter import GenericFastShutter -from dodal.devices.selectable_source import SourceSelector class SpecsDetector( @@ -26,51 +24,43 @@ class SpecsDetector( def __init__( self, prefix: str, - lens_mode_type: type[TLensMode], - psu_mode_type: type[TPsuMode], - energy_source: SignalR[float], - shutter: GenericFastShutter | None = None, - source_selector: SourceSelector | None = None, + driver: SpecsAnalyserDriverIO[TLensMode, TPsuMode], + *writer_factories: ADWriterFactory, + acquire_logic: ADAcquireLogic, + trigger_logic: ElectronAnalayserTriggerLogic, + region_logic: RegionLogic, + plugins: Mapping[str, NDPluginBaseIO] | None = None, + config_sigs: Sequence[SignalR] = (), name: str = "", ): - # Make attribute of class so connect applies to driver and populates parent. - self.driver = SpecsAnalyserDriverIO[TLensMode, TPsuMode]( - prefix, lens_mode_type, psu_mode_type - ) - region_logic = RegionLogic(self.driver, energy_source, source_selector) - self.close_shutter_when_idle = soft_signal_rw(bool, initial_value=True) - acquire_logic = ( - ShutterCoordinatorADAcquireLogic( - self.driver, shutter, self.close_shutter_when_idle - ) - if shutter is not None - else ADAcquireLogic(self.driver) - ) - trigger_logic = ElectronAnalayserTriggerLogic(self.driver, set()) config_sigs = ( - self.driver.region_name, - self.driver.energy_mode, - self.driver.acquisition_mode, - self.driver.lens_mode, - self.driver.low_energy, - self.driver.centre_energy, - self.driver.high_energy, - self.driver.energy_step, - self.driver.pass_energy, - self.driver.slices, - self.driver.acquire_time, - self.driver.iterations, - self.driver.total_steps, - self.driver.total_time, - self.driver.energy_axis, - self.driver.angle_axis, - self.driver.snapshot_values, - self.driver.psu_mode, + driver.region_name, + driver.energy_mode, + driver.acquisition_mode, + driver.lens_mode, + driver.low_energy, + driver.centre_energy, + driver.high_energy, + driver.energy_step, + driver.pass_energy, + driver.slices, + driver.acquire_time, + driver.iterations, + driver.total_steps, + driver.total_time, + driver.energy_axis, + driver.angle_axis, + driver.snapshot_values, + driver.psu_mode, ) super().__init__( + driver, + prefix, + *writer_factories, region_logic=region_logic, acquire_logic=acquire_logic, trigger_logic=trigger_logic, + plugins=plugins, config_sigs=config_sigs, name=name, ) diff --git a/src/dodal/devices/electron_analyser/vgscienta/vgscienta_detector.py b/src/dodal/devices/electron_analyser/vgscienta/vgscienta_detector.py index a4fb8c883ae..a917437adb7 100644 --- a/src/dodal/devices/electron_analyser/vgscienta/vgscienta_detector.py +++ b/src/dodal/devices/electron_analyser/vgscienta/vgscienta_detector.py @@ -1,7 +1,8 @@ +from collections.abc import Mapping, Sequence from typing import Generic -from ophyd_async.core import SignalR, soft_signal_rw -from ophyd_async.epics.adcore import ADAcquireLogic +from ophyd_async.core import SignalR +from ophyd_async.epics.adcore import ADAcquireLogic, ADWriterFactory, NDPluginBaseIO from dodal.devices.electron_analyser.base.base_detector import ElectronAnalyserDetector from dodal.devices.electron_analyser.base.base_region import ( @@ -12,14 +13,11 @@ from dodal.devices.electron_analyser.base.detector_logic import ( ElectronAnalayserTriggerLogic, RegionLogic, - ShutterCoordinatorADAcquireLogic, ) from dodal.devices.electron_analyser.vgscienta.vgscienta_driver_io import ( VGScientaAnalyserDriverIO, ) from dodal.devices.electron_analyser.vgscienta.vgscienta_region import VGScientaRegion -from dodal.devices.fast_shutter import GenericFastShutter -from dodal.devices.selectable_source import SourceSelector class VGScientaDetector( @@ -32,58 +30,49 @@ class VGScientaDetector( def __init__( self, prefix: str, - lens_mode_type: type[TLensMode], - psu_mode_type: type[TPsuMode], - pass_energy_type: type[TPassEnergy], - energy_source: SignalR[float], - shutter: GenericFastShutter | None = None, - source_selector: SourceSelector | None = None, + driver: VGScientaAnalyserDriverIO[TLensMode, TPsuMode, TPassEnergy], + *writer_factories: ADWriterFactory, + acquire_logic: ADAcquireLogic, + trigger_logic: ElectronAnalayserTriggerLogic, + region_logic: RegionLogic, + plugins: Mapping[str, NDPluginBaseIO] | None = None, + config_sigs: Sequence[SignalR] = (), name: str = "", ): - # Make attribute of class so connect applies to driver and populates parent. - self.driver = VGScientaAnalyserDriverIO[TLensMode, TPsuMode, TPassEnergy]( - prefix, lens_mode_type, psu_mode_type, pass_energy_type - ) - region_logic = RegionLogic(self.driver, energy_source, source_selector) - self.close_shutter_when_idle = soft_signal_rw(bool, initial_value=True) - acquire_logic = ( - ShutterCoordinatorADAcquireLogic( - self.driver, shutter, self.close_shutter_when_idle - ) - if shutter is not None - else ADAcquireLogic(self.driver) - ) - trigger_logic = ElectronAnalayserTriggerLogic(self.driver, set()) config_sigs = ( - self.driver.region_name, - self.driver.energy_mode, - self.driver.acquisition_mode, - self.driver.lens_mode, - self.driver.low_energy, - self.driver.centre_energy, - self.driver.high_energy, - self.driver.energy_step, - self.driver.pass_energy, - self.driver.slices, - self.driver.iterations, - self.driver.total_steps, - self.driver.acquire_time, - self.driver.total_time, - self.driver.energy_axis, - self.driver.angle_axis, - self.driver.detector_mode, - self.driver.region_min_x, - self.driver.region_size_x, - self.driver.sensor_max_size_x, - self.driver.region_min_y, - self.driver.region_size_y, - self.driver.sensor_max_size_y, - self.driver.psu_mode, + driver.region_name, + driver.energy_mode, + driver.acquisition_mode, + driver.lens_mode, + driver.low_energy, + driver.centre_energy, + driver.high_energy, + driver.energy_step, + driver.pass_energy, + driver.slices, + driver.iterations, + driver.total_steps, + driver.acquire_time, + driver.total_time, + driver.energy_axis, + driver.angle_axis, + driver.detector_mode, + driver.region_min_x, + driver.region_size_x, + driver.sensor_max_size_x, + driver.region_min_y, + driver.region_size_y, + driver.sensor_max_size_y, + driver.psu_mode, ) super().__init__( + driver, + prefix, + *writer_factories, region_logic=region_logic, acquire_logic=acquire_logic, trigger_logic=trigger_logic, + plugins=plugins, config_sigs=config_sigs, name=name, ) diff --git a/src/dodal/devices/focusing_mirror.py b/src/dodal/devices/focusing_mirror.py index e701f1e1693..4d958d36ebc 100644 --- a/src/dodal/devices/focusing_mirror.py +++ b/src/dodal/devices/focusing_mirror.py @@ -11,11 +11,7 @@ observe_value, soft_signal_r_and_setter, ) -from ophyd_async.epics.core import ( - epics_signal_r, - epics_signal_rw, - epics_signal_x, -) +from ophyd_async.epics.core import epics_signal_r, epics_signal_rw, epics_signal_x from ophyd_async.epics.motor import Motor from dodal.devices.motors import XYPitchStage diff --git a/tests/devices/beamlines/i21/test_toolpoint_motion.py b/tests/devices/beamlines/i21/test_toolpoint_motion.py index 5e92b0cfc12..be6991bf495 100644 --- a/tests/devices/beamlines/i21/test_toolpoint_motion.py +++ b/tests/devices/beamlines/i21/test_toolpoint_motion.py @@ -191,7 +191,6 @@ async def test_uvw_set(uvw: ToolPointMotion) -> None: }, full_match=False, ) - assert await uvw.smp_ref().azimuth.user_readback.get_value() == pos.azimuth_deg assert await uvw.smp_ref().tilt.user_readback.get_value() == pos.tilt_deg diff --git a/tests/devices/electron_analyser/base/conftest.py b/tests/devices/electron_analyser/base/conftest.py index e0d75ef3737..7f2e25d586d 100644 --- a/tests/devices/electron_analyser/base/conftest.py +++ b/tests/devices/electron_analyser/base/conftest.py @@ -3,6 +3,6 @@ from dodal.devices.electron_analyser.base import ElectronAnalyserDetector -@pytest.fixture(params=["ew4000", "b07b_specs150"]) +@pytest.fixture(params=["ew4000", "b07b_specs150", "i05_mbs_analyser"]) def sim_detector(request: pytest.FixtureRequest) -> ElectronAnalyserDetector: return request.getfixturevalue(request.param) diff --git a/tests/devices/electron_analyser/base/test_base_driver_io.py b/tests/devices/electron_analyser/base/test_base_driver_io.py index a6968d48b0e..31b781c9235 100644 --- a/tests/devices/electron_analyser/base/test_base_driver_io.py +++ b/tests/devices/electron_analyser/base/test_base_driver_io.py @@ -14,7 +14,7 @@ async def sim_driver( sim_detector: GenericElectronAnalyserDetector, ) -> GenericAnalyserDriverIO: - return sim_detector.driver # type: ignore + return sim_detector.driver def test_driver_throws_error_with_wrong_lens_mode( diff --git a/tests/devices/electron_analyser/base/test_detector_logic.py b/tests/devices/electron_analyser/base/test_detector_logic.py index d888316bd82..272f4ffcf24 100644 --- a/tests/devices/electron_analyser/base/test_detector_logic.py +++ b/tests/devices/electron_analyser/base/test_detector_logic.py @@ -15,8 +15,9 @@ from ophyd_async.testing import assert_configuration, partial_reading from dodal.devices.beamlines import b07, b07_shared, i05_shared, i09 -from dodal.devices.electron_analyser.base import AbstractAnalyserDriverIO, BaseRegion -from dodal.devices.electron_analyser.base.detector_logic import ( +from dodal.devices.electron_analyser.base import ( + AbstractAnalyserDriverIO, + BaseRegion, ElectronAnalayserTriggerLogic, RegionLogic, ShutterCoordinatorADAcquireLogic, @@ -178,7 +179,9 @@ async def test_region_logic_setup_with_region_moves_selected_source_if_not_none( @pytest.fixture -def trigger_logic(driver: AbstractAnalyserDriverIO) -> ElectronAnalayserTriggerLogic: +def trigger_logic( + driver: AbstractAnalyserDriverIO, +) -> ElectronAnalayserTriggerLogic: return ElectronAnalayserTriggerLogic(driver, {driver.lens_mode, driver.psu_mode}) diff --git a/tests/devices/electron_analyser/conftest.py b/tests/devices/electron_analyser/conftest.py index d8befa77ec5..d7784b332e4 100644 --- a/tests/devices/electron_analyser/conftest.py +++ b/tests/devices/electron_analyser/conftest.py @@ -2,7 +2,14 @@ import numpy as np import pytest -from ophyd_async.core import InOut, SignalR, init_devices, set_mock_value +from ophyd_async.core import ( + InOut, + SignalR, + init_devices, + set_mock_value, + soft_signal_rw, +) +from ophyd_async.epics.adcore import ADAcquireLogic from dodal.devices.beamlines import b07, b07_shared, i05_shared, i09 from dodal.devices.beamlines.i09 import Grating @@ -11,10 +18,18 @@ PitchAndRollCrystal, StationaryCrystal, ) -from dodal.devices.electron_analyser.base import DualEnergySource -from dodal.devices.electron_analyser.mbs import MbsDetector -from dodal.devices.electron_analyser.specs import SpecsDetector -from dodal.devices.electron_analyser.vgscienta import VGScientaDetector +from dodal.devices.electron_analyser.base import ( + DualEnergySource, + ElectronAnalayserTriggerLogic, + RegionLogic, + ShutterCoordinatorADAcquireLogic, +) +from dodal.devices.electron_analyser.mbs import MbsAnalyserDriverIO, MbsDetector +from dodal.devices.electron_analyser.specs import SpecsAnalyserDriverIO, SpecsDetector +from dodal.devices.electron_analyser.vgscienta import ( + VGScientaAnalyserDriverIO, + VGScientaDetector, +) from dodal.devices.fast_shutter import DualFastShutter, FastShutter from dodal.devices.pgm import PlaneGratingMonochromator from dodal.devices.selectable_source import SourceSelector @@ -100,15 +115,16 @@ def dual_fast_shutter( @pytest.fixture async def b07b_specs150( source_energy: SignalR[float], - shutter1: FastShutter, ) -> SpecsDetector[b07.LensMode, b07_shared.PsuMode]: with init_devices(mock=True): + prefix = "TEST:" + driver = SpecsAnalyserDriverIO(prefix, b07.LensMode, b07_shared.PsuMode) b07b_specs150 = SpecsDetector[b07.LensMode, b07_shared.PsuMode]( - prefix="TEST:", - lens_mode_type=b07.LensMode, - psu_mode_type=b07_shared.PsuMode, - energy_source=source_energy, - shutter=shutter1, + prefix, + driver, + acquire_logic=ADAcquireLogic(driver), + trigger_logic=ElectronAnalayserTriggerLogic(driver), + region_logic=RegionLogic(driver, source_energy), ) # Needed for specs so we don't get division by zero error. set_mock_value(b07b_specs150.driver.slices, 1) @@ -117,19 +133,26 @@ async def b07b_specs150( @pytest.fixture async def ew4000( - dual_source_energy: SignalR[float], + dual_energy_source: DualEnergySource, dual_fast_shutter: DualFastShutter, source_selector: SourceSelector, ) -> VGScientaDetector[i09.LensMode, i09.PsuMode, i09.PassEnergy]: with init_devices(mock=True): + prefix = "TEST:" + driver = VGScientaAnalyserDriverIO( + prefix, i09.LensMode, i09.PsuMode, i09.PassEnergy + ) + close_shutter_when_idle = soft_signal_rw(bool, initial_value=True) ew4000 = VGScientaDetector[i09.LensMode, i09.PsuMode, i09.PassEnergy]( - prefix="TEST:", - lens_mode_type=i09.LensMode, - psu_mode_type=i09.PsuMode, - pass_energy_type=i09.PassEnergy, - energy_source=dual_source_energy, - shutter=dual_fast_shutter, - source_selector=source_selector, + prefix, + driver, + acquire_logic=ShutterCoordinatorADAcquireLogic( + driver, dual_fast_shutter, close_shutter_when_idle + ), + trigger_logic=ElectronAnalayserTriggerLogic(driver), + region_logic=RegionLogic( + driver, dual_energy_source.energy, source_selector + ), ) energy_axis = [1, 2, 3, 4, 5] set_mock_value(ew4000.driver.energy_axis, np.array(energy_axis, dtype=float)) @@ -139,15 +162,16 @@ async def ew4000( @pytest.fixture async def i05_mbs_analyser( source_energy: SignalR[float], - shutter1: FastShutter, ) -> MbsDetector[i05_shared.LensMode, i05_shared.PassEnergy]: with init_devices(mock=True): + prefix = "TEST:" + driver = MbsAnalyserDriverIO(prefix, i05_shared.LensMode, i05_shared.PassEnergy) i05_mbs_analyser = MbsDetector[i05_shared.LensMode, i05_shared.PassEnergy]( - prefix="TEST:", - lens_mode_type=i05_shared.LensMode, - pass_energy_type=i05_shared.PassEnergy, - energy_source=source_energy, - shutter=shutter1, + prefix, + driver, + acquire_logic=ADAcquireLogic(driver), + trigger_logic=ElectronAnalayserTriggerLogic(driver), + region_logic=RegionLogic(driver, source_energy), ) energy_axis = [1, 2, 3, 4, 5] set_mock_value( diff --git a/tests/devices/electron_analyser/specs/test_specs_detector.py b/tests/devices/electron_analyser/specs/test_specs_detector.py index 8d79523205a..494d4d9df0c 100644 --- a/tests/devices/electron_analyser/specs/test_specs_detector.py +++ b/tests/devices/electron_analyser/specs/test_specs_detector.py @@ -35,5 +35,6 @@ async def test_specs_detector_read_configuration(b07b_specs150: SpecsDetector) - f"{prefix}energy_axis": partial_reading(ANY), f"{prefix}angle_axis": partial_reading(ANY), f"{prefix}psu_mode": partial_reading(ANY), + f"{prefix}acquire_period": partial_reading(ANY), }, ) diff --git a/tests/devices/electron_analyser/vgscienta/test_vgscienta_detector.py b/tests/devices/electron_analyser/vgscienta/test_vgscienta_detector.py index 2b9aa3ce44f..894bcb64ffc 100644 --- a/tests/devices/electron_analyser/vgscienta/test_vgscienta_detector.py +++ b/tests/devices/electron_analyser/vgscienta/test_vgscienta_detector.py @@ -40,5 +40,6 @@ async def test_vgscienta_detector_read_configuration(ew4000: VGScientaDetector) f"{prefix}region_size_y": partial_reading(region.size_y), f"{prefix}sensor_max_size_y": partial_reading(ANY), f"{prefix}psu_mode": partial_reading(ANY), + f"{prefix}acquire_period": partial_reading(ANY), }, ) diff --git a/tests/devices/mx_phase1/test_beamstop.py b/tests/devices/mx_phase1/test_beamstop.py index 599a763678c..146451eb541 100644 --- a/tests/devices/mx_phase1/test_beamstop.py +++ b/tests/devices/mx_phase1/test_beamstop.py @@ -7,7 +7,7 @@ from bluesky import plan_stubs as bps from bluesky.preprocessors import run_decorator from bluesky.run_engine import RunEngine -from ophyd_async.core import get_mock, get_mock_put, set_mock_value +from ophyd_async.core import get_mock, get_mock_put, init_devices, set_mock_value from dodal.devices.beamlines.i03 import Beamstop, BeamstopPositions from dodal.testing.fixtures.config_server import fake_config_server_get_file_contents @@ -19,6 +19,13 @@ def beamline_parameters() -> dict[str, Any]: return fake_config_server_get_file_contents(TEST_BEAMLINE_PARAMETERS_TXT, dict) +@pytest.fixture +def beamstop(beamline_parameters: dict[str, Any]) -> Beamstop: + with init_devices(mock=True): + beamstop = Beamstop("", beamline_parameters) + return beamstop + + @pytest.mark.parametrize( "x, y, z, expected_pos", [ @@ -32,15 +39,13 @@ def beamline_parameters() -> dict[str, Any]: ], ) async def test_beamstop_pos_read_selected_pos( - beamline_parameters: dict[str, Any], + beamstop: Beamstop, run_engine: RunEngine, x: float, y: float, z: float, expected_pos: BeamstopPositions, ): - beamstop = Beamstop("-MO-BS-01:", beamline_parameters, name="beamstop") - await beamstop.connect(mock=True) set_mock_value(beamstop.x_mm.user_readback, x) set_mock_value(beamstop.y_mm.user_readback, y) set_mock_value(beamstop.z_mm.user_readback, z) @@ -57,6 +62,8 @@ def check_in_beam(): yield from bps.save() run_engine(check_in_beam()) + current_pos = await beamstop.selected_pos.get_value() + assert current_pos == expected_pos event_call = next( dropwhile(lambda c: c.args[0] != "event", mock_callback.mock_calls) @@ -76,14 +83,11 @@ def check_in_beam(): ], ) async def test_set_beamstop_position_to_data_collection_moves_beamstop( + beamstop: Beamstop, demanded_pos: BeamstopPositions, expected_coords: tuple[float, float, float], - beamline_parameters: dict[str, Any], run_engine: RunEngine, ): - beamstop = Beamstop("-MO-BS-01:", beamline_parameters, name="beamstop") - await beamstop.connect(mock=True) - x_mock = beamstop.x_mm.user_setpoint y_mock = beamstop.y_mm.user_setpoint z_mock = beamstop.z_mm.user_setpoint @@ -103,10 +107,8 @@ async def test_set_beamstop_position_to_data_collection_moves_beamstop( async def test_set_beamstop_position_to_unknown_raises_error( - beamline_parameters: dict[str, Any], run_engine: RunEngine + beamstop: Beamstop, run_engine: RunEngine ): - beamstop = Beamstop("-MO-BS-01:", beamline_parameters, name="beamstop") - await beamstop.connect(mock=True) with pytest.raises(FailedStatus) as e: run_engine( bps.abs_set(beamstop.selected_pos, BeamstopPositions.UNKNOWN, wait=True) @@ -115,11 +117,9 @@ async def test_set_beamstop_position_to_unknown_raises_error( async def test_beamstop_select_pos_moves_z_axis_first( - run_engine: RunEngine, beamline_parameters: dict[str, Any] + run_engine: RunEngine, + beamstop: Beamstop, ): - beamstop = Beamstop("-MO-BS-01:", beamline_parameters, name="beamstop") - await beamstop.connect(mock=True) - run_engine( bps.abs_set(beamstop.selected_pos, BeamstopPositions.DATA_COLLECTION, wait=True) )