diff --git a/debye_bec/devices/mo1_bragg/mo1_bragg.py b/debye_bec/devices/mo1_bragg/mo1_bragg.py index dca0b14..984e5a1 100644 --- a/debye_bec/devices/mo1_bragg/mo1_bragg.py +++ b/debye_bec/devices/mo1_bragg/mo1_bragg.py @@ -123,10 +123,11 @@ class Mo1Bragg(PSIDeviceBase, Mo1BraggPositioner): Information about the upcoming scan can be accessed from the scan_info (self.scan_info.msg) object. """ - # self._check_scan_msg(ScanControlLoadMessage.PENDING) - status = CompareStatus(self.scan_control.scan_msg, ScanControlLoadMessage.PENDING) - self.cancel_on_stop(status) - status.wait(timeout=self.timeout_for_pvwait) + if self.scan_control.scan_msg.get() != ScanControlLoadMessage.PENDING: + status = CompareStatus(self.scan_control.scan_msg, ScanControlLoadMessage.PENDING) + self.cancel_on_stop(status) + self.scan_control.scan_val_reset.put(1) + status.wait(timeout=self.timeout_for_pvwait) scan_name = self.scan_info.msg.scan_name self._update_scan_parameter() @@ -204,11 +205,15 @@ class Mo1Bragg(PSIDeviceBase, Mo1BraggPositioner): ) else: return + # Setting scan duration seems to lag behind slightly in the backend, include small sleep + logger.info(f"Sleeping for one second") + time.sleep(1) + logger.info(f"Device {self.name}, done sleeping") # Load the scan parameters to the controller - self.scan_control.scan_load.put(1) - # Wait for params to be checked from controller status = CompareStatus(self.scan_control.scan_msg, ScanControlLoadMessage.SUCCESS) self.cancel_on_stop(status) + self.scan_control.scan_load.put(1) + # Wait for params to be checked from controller status.wait(self.timeout_for_pvwait) return None @@ -230,6 +235,10 @@ class Mo1Bragg(PSIDeviceBase, Mo1BraggPositioner): logger.warning( f"Timeout in on_unstage of {self.name} after {self.timeout_for_pvwait}s, current scan_control_message : {self.scan_control.scan_msg.get()}" ) + status = CompareStatus(self.scan_control.scan_msg, ScanControlLoadMessage.PENDING) + self.cancel_on_stop(status) + self.scan_control.scan_val_reset.put(1) + status.wait(timeout=self.timeout_for_pvwait) else: status = CompareStatus(self.scan_control.scan_msg, ScanControlLoadMessage.PENDING) self.cancel_on_stop(status) @@ -251,7 +260,7 @@ class Mo1Bragg(PSIDeviceBase, Mo1BraggPositioner): def on_kickoff(self) -> DeviceStatus | StatusBase | None: """Called to kickoff a device for a fly scan. Has to be called explicitly.""" - scan_duration = self.scan_control.scan_duration.get() + scan_duration = self.scan_parameter.scan_duration # TODO implement better logic for infinite scans, at least bring it up with Debye start_func = ( self.scan_control.scan_start_infinite.put @@ -291,25 +300,20 @@ class Mo1Bragg(PSIDeviceBase, Mo1BraggPositioner): high (float): High energy/angle value of the scan scan_time (float): Time for a half oscillation """ - self.scan_settings.s_scan_energy_lo.put(low) - self.scan_settings.s_scan_energy_hi.put(high) - self.scan_settings.s_scan_scantime.put(scan_time) - def wait_for_signal(self, signal: Cpt, value: Any, timeout: float | None = None) -> None: - """Wait for a signal to reach a certain value.""" - if timeout is None: - timeout = self.timeout_for_pvwait - start_time = time.time() - while time.time() - start_time < timeout: - if signal.get() == value: - return None - if self.stopped is True: # Should this check be optional or configurable?! - raise DeviceStopError(f"Device {self.name} was stopped while waiting for signal") - 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 for signal {signal.name} with value {signal.get()}, expected {value}" - ) + status_list = [] + + status_list.append(self.scan_settings.s_scan_energy_lo.set(low)) + self.cancel_on_stop(status_list[-1]) + + status_list.append(self.scan_settings.s_scan_energy_hi.set(high)) + self.cancel_on_stop(status_list[-1]) + + status_list.append(self.scan_settings.s_scan_scantime.set(scan_time)) + self.cancel_on_stop(status_list[-1]) + + for s in status_list: + s.wait(timeout=self.timeout_for_pvwait) @typechecked def convert_angle_energy( @@ -326,15 +330,19 @@ class Mo1Bragg(PSIDeviceBase, Mo1BraggPositioner): """ self.calculator.calc_reset.put(0) self.calculator.calc_reset.put(1) - self.wait_for_signal(self.calculator.calc_done, 0) + status = CompareStatus(self.calculator.calc_done, 0) + self.cancel_on_stop(status) + status.wait(self.timeout_for_pvwait) if mode == "AngleToEnergy": self.calculator.calc_angle.put(inp) elif mode == "EnergyToAngle": self.calculator.calc_energy.put(inp) - self.wait_for_signal(self.calculator.calc_done, 1) - time.sleep(0.25) # Needed due to update frequency of softIOC + status = CompareStatus(self.calculator.calc_done, 1) + self.cancel_on_stop(status) + status.wait(self.timeout_for_pvwait) + time.sleep(0.25) #TODO needed still? Needed due to update frequency of softIOC if mode == "AngleToEnergy": return self.calculator.calc_energy.get() elif mode == "EnergyToAngle": @@ -365,9 +373,19 @@ class Mo1Bragg(PSIDeviceBase, Mo1BraggPositioner): scan_time=scan_time, ) - self.scan_settings.a_scan_pos.set(pos) - self.scan_settings.a_scan_vel.set(vel) - self.scan_settings.a_scan_time.set(dt) + status_list = [] + + status_list.append(self.scan_settings.a_scan_pos.set(pos)) + self.cancel_on_stop(status_list[-1]) + + status_list.append(self.scan_settings.a_scan_vel.set(vel)) + self.cancel_on_stop(status_list[-1]) + + status_list.append(self.scan_settings.a_scan_time.set(dt)) + self.cancel_on_stop(status_list[-1]) + + for s in status_list: + s.wait(timeout=self.timeout_for_pvwait) def set_trig_settings( self, @@ -390,12 +408,30 @@ class Mo1Bragg(PSIDeviceBase, Mo1BraggPositioner): cycle_low (int): Cycle for low energy/angle cycle_high (int): Cycle for high energy/angle """ - self.scan_settings.trig_ena_hi_enum.put(int(enable_high)) - self.scan_settings.trig_ena_lo_enum.put(int(enable_low)) - self.scan_settings.trig_time_hi.put(exp_time_high) - self.scan_settings.trig_time_lo.put(exp_time_low) - self.scan_settings.trig_every_n_hi.put(cycle_high) - self.scan_settings.trig_every_n_lo.put(cycle_low) + + status_list = [] + + status_list.append(self.scan_settings.trig_ena_hi_enum.set(int(enable_high))) + self.cancel_on_stop(status_list[-1]) + + status_list.append(self.scan_settings.trig_ena_lo_enum.set(int(enable_low))) + self.cancel_on_stop(status_list[-1]) + + status_list.append(self.scan_settings.trig_time_hi.set(exp_time_high)) + self.cancel_on_stop(status_list[-1]) + + status_list.append(self.scan_settings.trig_time_lo.set(exp_time_low)) + self.cancel_on_stop(status_list[-1]) + + status_list.append(self.scan_settings.trig_every_n_hi.set(cycle_high)) + self.cancel_on_stop(status_list[-1]) + + status_list.append(self.scan_settings.trig_every_n_lo.set(cycle_low)) + self.cancel_on_stop(status_list[-1]) + + for s in status_list: + s.wait(timeout=self.timeout_for_pvwait) + def set_scan_control_settings(self, mode: ScanControlMode, scan_duration: float) -> None: """Set the scan control settings for the upcoming scan. @@ -405,8 +441,18 @@ class Mo1Bragg(PSIDeviceBase, Mo1BraggPositioner): scan_duration (float): Duration of the scan """ val = ScanControlMode(mode).value - self.scan_control.scan_mode_enum.put(val) - self.scan_control.scan_duration.put(scan_duration) + + status_list = [] + + status_list.append(self.scan_control.scan_mode_enum.set(val)) + self.cancel_on_stop(status_list[-1]) + + status_list.append(self.scan_control.scan_duration.set(scan_duration)) + self.cancel_on_stop(status_list[-1]) + + for s in status_list: + s.wait(timeout=self.timeout_for_pvwait) + def _update_scan_parameter(self): """Get the scan_info parameters for the scan.""" @@ -416,39 +462,3 @@ class Mo1Bragg(PSIDeviceBase, Mo1BraggPositioner): for key, value in self.scan_info.msg.request_inputs["kwargs"].items(): if hasattr(self.scan_parameter, key): setattr(self.scan_parameter, key, value) - - def _check_scan_msg(self, target_state: ScanControlLoadMessage) -> None: - """Check if the scan message is gettting available - - Args: - target_state (ScanControlLoadMessage): Target state to check for - - Raises: - TimeoutError: If the scan message is not available after the timeout - """ - try: - self.wait_for_signal(self.scan_control.scan_msg, target_state, timeout=1) - except TimeoutError as exc: - logger.warning( - 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" - ) - 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