Refactor Trigger Card and Falcon device to use Compare and TransitionStatus #24
@@ -8,6 +8,7 @@ from bec_lib.logger import bec_logger
|
||||
from ophyd import Component as Cpt
|
||||
from ophyd import DeviceStatus, Kind, Signal, StatusBase
|
||||
from ophyd.status import SubscriptionStatus
|
||||
from ophyd_devices import CompareStatus, StatusBase, TransitionStatus
|
||||
from ophyd_devices.devices.dxp import EpicsDXPFalcon, EpicsMCARecord, Falcon
|
||||
from ophyd_devices.interfaces.base_classes.psi_device_base import PSIDeviceBase
|
||||
|
||||
@@ -141,7 +142,7 @@ class FalconSuperXAS(PSIDeviceBase, FalconControl):
|
||||
Default values for signals should be set here.
|
||||
"""
|
||||
|
||||
def on_stage(self) -> DeviceStatus | StatusBase | None:
|
||||
def on_stage(self) -> CompareStatus:
|
||||
"""
|
||||
Called while staging the device.
|
||||
|
||||
@@ -149,26 +150,16 @@ class FalconSuperXAS(PSIDeviceBase, FalconControl):
|
||||
"""
|
||||
self.collect_mode.set(0).wait()
|
||||
self.preset_real_time.set(0).wait()
|
||||
status = CompareStatus(self.acquiring, FalconAcquiringStatus.DONE, timeout=self._pv_timeout)
|
||||
self.stop_all.put(1)
|
||||
if (
|
||||
self.wait_for_condition(
|
||||
lambda: self.acquiring.get() == FalconAcquiringStatus.DONE, timeout=self._pv_timeout
|
||||
)
|
||||
is False
|
||||
):
|
||||
raise TimeoutError("Timeout on Falcon stage")
|
||||
return status
|
||||
|
||||
def on_unstage(self) -> DeviceStatus | StatusBase | None:
|
||||
def on_unstage(self) -> CompareStatus:
|
||||
"""Called while unstaging the device."""
|
||||
self.stop_all.put(1)
|
||||
self.erase_all.put(1)
|
||||
if (
|
||||
self.wait_for_condition(
|
||||
lambda: self.acquiring.get() == FalconAcquiringStatus.DONE, timeout=self._pv_timeout
|
||||
)
|
||||
is False
|
||||
):
|
||||
raise TimeoutError("Timeout on Falcon unstage")
|
||||
status = CompareStatus(self.acquiring, FalconAcquiringStatus.DONE, timeout=self._pv_timeout)
|
||||
return status
|
||||
|
||||
def on_pre_scan(self) -> DeviceStatus | StatusBase | None:
|
||||
"""Called right before the scan starts on all devices automatically."""
|
||||
@@ -186,19 +177,18 @@ class FalconSuperXAS(PSIDeviceBase, FalconControl):
|
||||
"""Called when the device is stopped."""
|
||||
self.stop_all.put(1)
|
||||
|
||||
def _stop_erase_and_wait_for_acquiring(self) -> DeviceStatus:
|
||||
def _stop_erase_and_wait_for_acquiring(self) -> TransitionStatus:
|
||||
"""Method called from the Trigger card to reset counts on the Falcon"""
|
||||
|
||||
if self.acquiring.get() != FalconAcquiringStatus.DONE:
|
||||
self.stop_all.put(1)
|
||||
|
||||
def _check_acquiriting(*, old_value, value, **kwargs):
|
||||
if old_value == FalconAcquiringStatus.DONE and value == FalconAcquiringStatus.ACQUIRING:
|
||||
return True
|
||||
return False
|
||||
|
||||
status = SubscriptionStatus(self.acquiring, _check_acquiriting)
|
||||
|
||||
logger.info("Triggering Falcon")
|
||||
# TODO in case this fails, it could be that DONE is not emitted as it is only visible
|
||||
# for a short time, below the update frequency of the EPICS acquiring PV (100ms). In this case,
|
||||
# add here a CompareStatus, waiting for Done to appear before sending the erase command.
|
||||
status = TransitionStatus(
|
||||
self.acquiring,
|
||||
transitions=[FalconAcquiringStatus.DONE, FalconAcquiringStatus.ACQUIRING],
|
||||
)
|
||||
self.erase_start.put(1)
|
||||
return status
|
||||
|
||||
@@ -260,7 +260,7 @@ class TimepixFlyClient:
|
||||
or exception, respectively and removed from the list of callbacks.
|
||||
"""
|
||||
status = self._status
|
||||
logger.warning(f"Running status callbacks for status: {status.value}")
|
||||
logger.debug(f"Running status callbacks for status: {status.value}")
|
||||
callback_ids = list(self._status_callbacks.keys())
|
||||
for cb_id in callback_ids:
|
||||
dev_status, success, error = self._status_callbacks[cb_id]
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
"""SuperXAS Trigger Device"""
|
||||
|
||||
from bec_lib.logger import bec_logger
|
||||
from ophyd import Component as Cpt
|
||||
from ophyd import Device, DeviceStatus, EpicsSignal, EpicsSignalRO, Kind, StatusBase
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
import enum
|
||||
|
||||
from bec_lib.devicemanager import ScanInfo
|
||||
from bec_lib.logger import bec_logger
|
||||
from ophyd import Component as Cpt
|
||||
from ophyd import Device, DeviceStatus, EpicsSignal, EpicsSignalRO, Kind, StatusBase
|
||||
from ophyd_devices import TransitionStatus
|
||||
from ophyd_devices.interfaces.base_classes.psi_device_base import PSIDeviceBase
|
||||
|
||||
logger = bec_logger.logger
|
||||
|
||||
|
||||
class ContinuousSamplingMode(int, enum.Enum):
|
||||
"""Options for start_csmpl signal"""
|
||||
@@ -107,20 +107,10 @@ class Trigger(PSIDeviceBase, TriggerControl):
|
||||
status = falcon._stop_erase_and_wait_for_acquiring()
|
||||
status.wait()
|
||||
|
||||
started = False
|
||||
|
||||
def _sampling_done():
|
||||
nonlocal started
|
||||
if not started and self.smpl_done.get() == SamplingDone.RUNNING:
|
||||
started = True
|
||||
return False
|
||||
if started and self.smpl_done.get() == SamplingDone.DONE:
|
||||
return True
|
||||
|
||||
return self.smpl_done.get() == SamplingDone.DONE
|
||||
|
||||
status = TransitionStatus(
|
||||
self.smpl_done, transitions=[SamplingDone.DONE, SamplingDone.RUNNING, SamplingDone.DONE]
|
||||
)
|
||||
self.smpl.put(1)
|
||||
status = self.task_handler.submit_task(_sampling_done, run=True)
|
||||
return status
|
||||
|
||||
def on_complete(self) -> DeviceStatus | StatusBase | None:
|
||||
|
||||
@@ -5,6 +5,7 @@ from unittest import mock
|
||||
|
||||
import ophyd
|
||||
import pytest
|
||||
from ophyd.utils.errors import StatusTimeoutError
|
||||
from ophyd_devices.tests.utils import MockPV, patch_dual_pvs
|
||||
|
||||
from superxas_bec.devices.falcon import FalconAcquiringStatus, FalconSuperXAS
|
||||
@@ -50,8 +51,9 @@ def test_devices_falcon_stage(falcon):
|
||||
# Should timeout
|
||||
falcon.acquiring.put(FalconAcquiringStatus.ACQUIRING)
|
||||
falcon._pv_timeout = 0.1
|
||||
with pytest.raises(TimeoutError):
|
||||
falcon.on_stage()
|
||||
with pytest.raises(StatusTimeoutError):
|
||||
status = falcon.on_stage()
|
||||
status.wait(timeout=2)
|
||||
|
||||
|
||||
def test_devices_falcon_unstage(falcon):
|
||||
@@ -67,8 +69,9 @@ def test_devices_falcon_unstage(falcon):
|
||||
# Should timeout
|
||||
falcon.acquiring.put(FalconAcquiringStatus.ACQUIRING)
|
||||
falcon._pv_timeout = 0.1
|
||||
with pytest.raises(TimeoutError):
|
||||
falcon.on_unstage()
|
||||
with pytest.raises(StatusTimeoutError):
|
||||
status = falcon.on_unstage()
|
||||
status.wait(timeout=2)
|
||||
|
||||
|
||||
def test_devices_falcon_stop(falcon):
|
||||
|
||||
@@ -9,7 +9,7 @@ from bec_server.device_server.tests.utils import DMMock
|
||||
from ophyd import DeviceStatus
|
||||
from ophyd_devices.tests.utils import MockPV, patch_dual_pvs
|
||||
|
||||
from superxas_bec.devices.trigger import ContinuousSamplingMode, Trigger
|
||||
from superxas_bec.devices.trigger import ContinuousSamplingMode, SamplingDone, Trigger
|
||||
|
||||
# pylint: disable=protected-access
|
||||
# pylint: disable=redefined-outer-name
|
||||
@@ -94,13 +94,19 @@ def test_devices_trigger_trigger(trigger):
|
||||
|
||||
trigger_status = DeviceStatus(device=trigger)
|
||||
trigger_status.set_finished()
|
||||
with mock.patch.object(
|
||||
trigger.task_handler, "submit_task", return_value=trigger_status
|
||||
) as mock_submit:
|
||||
status = trigger.trigger()
|
||||
assert falcon._stop_erase_and_wait_for_acquiring.call_count == 1
|
||||
assert trigger.smpl.get() == 1 # smpl called with 1
|
||||
# TODO check that the task_handler is called with the correct function
|
||||
# This is currently not easily testable
|
||||
assert mock_submit.call_count == 1
|
||||
assert trigger_status == status
|
||||
trigger.smpl_done._read_pv.mock_data = SamplingDone.DONE
|
||||
status = trigger.trigger()
|
||||
assert falcon._stop_erase_and_wait_for_acquiring.call_count == 1
|
||||
assert trigger.smpl.get() == 1 # smpl called with 1
|
||||
assert status.done is False
|
||||
trigger.smpl_done._read_pv.mock_data = SamplingDone.RUNNING
|
||||
assert status.done is False
|
||||
trigger.smpl_done._read_pv.mock_data = SamplingDone.DONE
|
||||
status.wait(timeout=2)
|
||||
assert status.done is True
|
||||
assert status.success is True
|
||||
|
||||
# # TODO check that the task_handler is called with the correct function
|
||||
# # This is currently not easily testable
|
||||
# assert mock_submit.call_count == 1
|
||||
# assert trigger_status == status
|
||||
|
||||
Reference in New Issue
Block a user