diff --git a/csaxs_bec/devices/jungfraujoch/eiger.py b/csaxs_bec/devices/jungfraujoch/eiger.py index e32f482..196600b 100644 --- a/csaxs_bec/devices/jungfraujoch/eiger.py +++ b/csaxs_bec/devices/jungfraujoch/eiger.py @@ -59,7 +59,9 @@ from jfjoch_client.models.dataset_settings import DatasetSettings from jfjoch_client.models.detector_selection import DetectorSelection from jfjoch_client.models.detector_settings import DetectorSettings from jfjoch_client.models.detector_timing import DetectorTiming +from ophyd import Component as Cpt from ophyd import DeviceStatus +from ophyd_devices import FileEventSignal, PreviewSignal from ophyd_devices.interfaces.base_classes.psi_device_base import PSIDeviceBase from csaxs_bec.devices.jungfraujoch.jungfrau_joch_client import ( @@ -88,6 +90,8 @@ class Eiger(PSIDeviceBase): USER_ACCESS = ["detector_distance", "beam_center"] + file_event = Cpt(FileEventSignal, name="file_event") + def __init__( self, name: str, @@ -218,11 +222,15 @@ class Eiger(PSIDeviceBase): # Set acquisition parameter ntrigger = int(scan_msg.num_points * scan_msg.scan_parameters["frames_per_trigger"]) # Fetch file path - self._full_path = get_full_path( - scan_msg, name=self.name - ) # We can discuss if this should be used with name.. - # Get Path from Broker - # Fetch basepath from JFJ broker config + self._full_path = get_full_path(scan_msg, name=f"{self.name}_master") + # JFJ adds _master.h5 automatically + path = os.path.relpath(self._full_path, start="/sls/x12sa/data").rstrip("_master.h5") + self.file_event.put( + file_path=self._full_path, + done=False, + successful=False, + hinted_h5_entries={"data": "entry/data/data"}, + ) path = os.path.relpath(self._full_path, start="/sls/x12sa/data") data_settings = DatasetSettings( image_time_us=int(frame_time_us * 1e6), # This is currently ignored @@ -239,6 +247,11 @@ class Eiger(PSIDeviceBase): self.jfj_client.start(settings=data_settings) start_call_returns = time.time() - start_time - prep_time logger.info(f"Start Rest call from JFJ took {start_call_returns:.2f}s") + sleep_time = 0.5 + time.sleep(sleep_time) + logger.info( + f"Eiger {self.name} staged and ready for acquisition; with additional sleep of {sleep_time:.2f}s" + ) def on_unstage(self) -> DeviceStatus: """Called while unstaging the device.""" @@ -249,6 +262,15 @@ class Eiger(PSIDeviceBase): def on_trigger(self) -> DeviceStatus: """Called when the device is triggered.""" + def _file_event_callback(self, status: DeviceStatus) -> None: + """Callback to update the file_event signal when the acquisition is done.""" + self.file_event.put( + file_path=self._full_path, + done=True, + successful=status.success, + hinted_h5_entries={"data": "entry/data/data"}, + ) + def on_complete(self) -> DeviceStatus: """Called to inquire if a device has completed a scans.""" @@ -257,6 +279,7 @@ class Eiger(PSIDeviceBase): for _ in range(timeout): try: self.jfj_client.wait_till_done(timeout=1, _request_timeout=5) + except ( JungfrauJochClientError ): # Means that timeout was triggered, and not _request_timeout @@ -267,9 +290,13 @@ class Eiger(PSIDeviceBase): except Exception as e: # This should actually never occur.. raise ValueError(f"Error in complete for {self.name}, exception: {e}") from e else: + # How can I check if the aquisition was successful? + # If not successfull, we have to raise an error here! + # For instance if packages were lost.. break status = self.task_handler.submit_task(wait_for_complete, run=True) + status.add_callback(self._file_event_callback) self.cancel_on_stop(status) return status