diff --git a/debye_bec/devices/mo1_bragg/mo1_bragg.py b/debye_bec/devices/mo1_bragg/mo1_bragg.py index 4bfa0cb..31c23b9 100644 --- a/debye_bec/devices/mo1_bragg/mo1_bragg.py +++ b/debye_bec/devices/mo1_bragg/mo1_bragg.py @@ -14,7 +14,8 @@ from typing import Any, Literal from bec_lib.devicemanager import ScanInfo from bec_lib.logger import bec_logger from ophyd import Component as Cpt -from ophyd import DeviceStatus, StatusBase +from ophyd import DeviceStatus, StatusBase, Signal +from ophyd.status import SubscriptionStatus from ophyd_devices.interfaces.base_classes.psi_device_base import PSIDeviceBase from ophyd_devices.utils.errors import DeviceStopError from pydantic import BaseModel, Field @@ -200,39 +201,39 @@ class Mo1Bragg(PSIDeviceBase, Mo1BraggPositioner): # Load the scan parameters to the controller self.scan_control.scan_load.put(1) # Wait for params to be checked from controller - status = self.task_handler.submit_task( - task=self.wait_for_signal, - task_args=(self.scan_control.scan_msg, ScanControlLoadMessage.SUCCESS), - ) - return status + self.wait_for_signal(self.scan_control.scan_msg, ScanControlLoadMessage.SUCCESS, timeout=self.timeout_for_pvwait) + return None def on_unstage(self) -> DeviceStatus | StatusBase | None: """Called while unstaging the device.""" - - def unstage_procedure(): + if self.stopped is True: + logger.warning(f"Resetting stopped in unstage for device {self.name}.") + self._stopped = False + current_state = self.scan_control.scan_msg.get() + # Case 1, message is already ScanControlLoadMessage.PENDING + if current_state == ScanControlLoadMessage.PENDING: + return None + # Case 2, probably called after scan, backend should resolve on its own. Timeout to wait + if current_state in [ScanControlLoadMessage.STARTED, ScanControlLoadMessage.SUCCESS]: try: self.wait_for_signal( self.scan_control.scan_msg, ScanControlLoadMessage.PENDING, - timeout=self.timeout_for_pvwait / 2, + timeout=self.timeout_for_pvwait, ) return except TimeoutError: logger.warning( - f"Timeout after {self.timeout_for_pvwait} while waiting for scan validation" + f"Timeout in on_unstage of {self.name} after {self.timeout_for_pvwait}s, current scan_control_message : {self.scan_control.scan_msg.get()}" ) - time.sleep(0.25) - start_time = time.time() - while time.time() - start_time < self.timeout_for_pvwait / 2: - if not self.scan_control.scan_msg.get() == ScanControlLoadMessage.PENDING: - break - time.sleep(0.1) - raise TimeoutError( - f"Device {self.name} run into timeout after {self.timeout_for_pvwait} while waiting for scan validation" - ) - status = self.task_handler.submit_task(unstage_procedure) - status.wait() + def callback(*, old_value, value, **kwargs): + if value == ScanControlLoadMessage.PENDING: + return True + return False + status = SubscriptionStatus(self.scan_control.scan_msg, callback=callback) + self.scan_control.scan_val_reset.put(1) + status.wait(timeout=self.timeout_for_pvwait) return None def on_pre_scan(self) -> DeviceStatus | StatusBase | None: @@ -268,11 +269,13 @@ class Mo1Bragg(PSIDeviceBase, Mo1BraggPositioner): if scan_duration < 0.1 else self.scan_control.scan_start_timer.put ) + def callback(*, old_value, value, **kwargs): + if old_value == ScanControlScanStatus.READY and value == ScanControlScanStatus.RUNNING: + return True + return False + + status = SubscriptionStatus(self.scan_control.scan_status, callback=callback) start_func(1) - status = self.task_handler.submit_task( - task=self.wait_for_signal, - task_args=(self.scan_control.scan_status, ScanControlScanStatus.RUNNING), - ) return status def on_stop(self) -> None: @@ -328,7 +331,7 @@ class Mo1Bragg(PSIDeviceBase, Mo1BraggPositioner): time.sleep(0.1) # If we end up here, the status did not resolve raise TimeoutError( - f"Device {self.name} run into timeout after {timeout}s while waiting for scan to start" + f"Device {self.name} run into timeout after {timeout}s for signal {signal.name} with value {signal.get()}, expected {value}" ) @typechecked @@ -462,12 +465,23 @@ class Mo1Bragg(PSIDeviceBase, Mo1BraggPositioner): f"Resetting scan validation in stage for state: {ScanControlLoadMessage(self.scan_control.scan_msg.get())}, " f"retry .get() on scan_control: {ScanControlLoadMessage(self.scan_control.scan_msg.get())} and sleeping 1s" ) - self.scan_control.scan_val_reset.put(1) + current_scan_msg = self.scan_control.scan_msg.get() + + def callback(*, old_value, value, **kwargs): + if old_value == current_scan_msg and value == target_state: + return True + return False + + status = SubscriptionStatus(self.scan_control.scan_msg, callback=callback) + self.scan_control.scan_val_reset.put(1) + + status.wait(timeout=self.timeout_for_pvwait) + + # try: + # self.wait_for_signal(self.scan_control.scan_msg, target_state, timeout=4) + # except TimeoutError as exc: + # raise TimeoutError( + # f"Timeout after {self.timeout_for_pvwait} while waiting for scan status," + # f" current state: {ScanControlScanStatus(self.scan_control.scan_msg.get())}" + # ) from exc - try: - self.wait_for_signal(self.scan_control.scan_msg, target_state, timeout=4) - except TimeoutError as exc: - raise TimeoutError( - f"Timeout after {self.timeout_for_pvwait} while waiting for scan status," - f" current state: {ScanControlScanStatus(self.scan_control.scan_msg.get())}" - ) from exc diff --git a/debye_bec/devices/nidaq/nidaq.py b/debye_bec/devices/nidaq/nidaq.py index f6b31e9..ef70788 100644 --- a/debye_bec/devices/nidaq/nidaq.py +++ b/debye_bec/devices/nidaq/nidaq.py @@ -135,6 +135,7 @@ class Nidaq(PSIDeviceBase, NidaqControl): def __init__(self, prefix: str = "", *, name: str, scan_info: ScanInfo = None, **kwargs): super().__init__(name=name, prefix=prefix, scan_info=scan_info, **kwargs) self.timeout_wait_for_signal = 5 # put 5s firsts + self._timeout_wait_for_pv = 3 # 3s timeout for pv calls self.valid_scan_names = [ "xas_simple_scan", "xas_simple_scan_with_xrd", @@ -278,7 +279,7 @@ class Nidaq(PSIDeviceBase, NidaqControl): timeout = self.timeout_wait_for_signal, check_stopped=True): raise NidaqError(f"Device {self.name} has not been reached in state STANDBY, current state {NidaqState(self.state.get())}") - self.scan_duration.set(0).wait() + self.scan_duration.set(0).wait(timeout=self._timeout_wait_for_pv) def on_stage(self) -> DeviceStatus | StatusBase | None: """ @@ -296,9 +297,9 @@ class Nidaq(PSIDeviceBase, NidaqControl): raise NidaqError( f"Device {self.name} has not been reached in state STANDBY, current state {NidaqState(self.state.get())}" ) - self.scan_type.set(ScanType.TRIGGERED).wait() - self.scan_duration.set(0).wait() - self.stage_call.set(1).wait() + self.scan_type.set(ScanType.TRIGGERED).wait(timeout = self._timeout_wait_for_pv) + self.scan_duration.set(0).wait(timeout=self._timeout_wait_for_pv) + self.stage_call.set(1).wait(timeout = self._timeout_wait_for_pv) if not self.wait_for_condition( condition=lambda: self.state.get() == NidaqState.STAGE, timeout=self.timeout_wait_for_signal, check_stopped=True @@ -306,7 +307,7 @@ class Nidaq(PSIDeviceBase, NidaqControl): raise NidaqError( f"Device {self.name} has not been reached in state STAGE, current state {NidaqState(self.state.get())}" ) - self.kickoff_call.set(1).wait() + self.kickoff_call.set(1).wait(timeout = self._timeout_wait_for_pv) logger.info(f"Device {self.name} was staged: {NidaqState(self.state.get())}") def on_unstage(self) -> DeviceStatus | StatusBase | None: @@ -374,4 +375,4 @@ class Nidaq(PSIDeviceBase, NidaqControl): def on_stop(self) -> None: """Called when the device is stopped.""" - self.stop_call.set(1).wait() + self.stop_call.put(1)