diff --git a/tomcat_bec/devices/gigafrost/stddaq_client.py b/tomcat_bec/devices/gigafrost/stddaq_client.py index 8bb8209..5a1820b 100644 --- a/tomcat_bec/devices/gigafrost/stddaq_client.py +++ b/tomcat_bec/devices/gigafrost/stddaq_client.py @@ -13,7 +13,7 @@ import requests import os from ophyd import Signal, Component, Kind -from ophyd.status import SubscriptionStatus +from ophyd.status import SubscriptionStatus, Status from websockets.sync.client import connect, ClientConnection from websockets.exceptions import ConnectionClosedOK, ConnectionClosedError @@ -41,6 +41,9 @@ class StdDaqMixin(CustomDeviceMixin): # Fish out our configuration from scaninfo (via explicit or generic addressing) # NOTE: Scans don't have to fully configure the device d = {} + scan_parameters = self.parent.scaninfo.scan_msg.scan_parameters + std_daq_params = scan_parameters.get("std_daq_params") + if "kwargs" in self.parent.scaninfo.scan_msg.info: scanargs = self.parent.scaninfo.scan_msg.info["kwargs"] if "image_width" in scanargs and scanargs["image_width"] is not None: @@ -88,6 +91,7 @@ class StdDaqMixin(CustomDeviceMixin): if points_valid: d["num_points_total"] = num_points + # Perform bluesky-style configuration if len(d) > 0: # Configure new run (will restart the stdDAQ) @@ -97,7 +101,9 @@ class StdDaqMixin(CustomDeviceMixin): sleep(0.5) # Try to start a new run (reconnects) - self.parent.bluestage() + if std_daq_params.get("reconnect",True): + self.parent.bluestage() + # And start status monitoring self._mon = Thread(target=self.monitor, daemon=True) self._mon.start() @@ -159,6 +165,7 @@ class StdDaqClient(PSIDeviceBase): "state", "bluestage", "blueunstage", + "complete", ] _wsclient = None @@ -277,6 +284,8 @@ class StdDaqClient(PSIDeviceBase): images (limited by the ringbuffer size and backend speed). file_path: str, optional File path to save the data, usually GPFS. + file_prefix: str, optional + File prefix to save the data [default = file]. image_width : int, optional ROI size in the x-direction [pixels]. image_height : int, optional @@ -299,6 +308,10 @@ class StdDaqClient(PSIDeviceBase): # Run parameters if "num_points_total" in d: self.num_images.set(d["num_points_total"]).wait() + if "file_path" in d: + self.file_path.set(d["file_path"]).wait() + if "file_prefix" in d: + self.file_prefix.set(d["file_prefix"]).wait() # Restart the DAQ if resolution changed cfg = self.get_daq_config() @@ -322,6 +335,15 @@ class StdDaqClient(PSIDeviceBase): sleep(1) self.get_daq_config(update=True) + # def configure(self, d:dict): + # if "num_points_total" in d: + # num_points = d.pop("num_points_total") + # self.num_images.set(num_points).wait() + # super().configure(d) + # self.set_daq_config() + # sleep(1) + # self.get_daq_config(update=True) + def bluestage(self): """Stages the stdDAQ @@ -351,6 +373,7 @@ class StdDaqClient(PSIDeviceBase): file_path = self.file_path.get() num_images = self.num_images.get() + file_prefix = self.name file_prefix = self.file_prefix.get() print(file_prefix) @@ -427,12 +450,18 @@ class StdDaqClient(PSIDeviceBase): def complete(self) -> SubscriptionStatus: """Wait for current run. Must end in status 'file_saved'.""" + # Return immediately if we're detached + # TODO: Maybe check for connection (not sure if it's better) + if self.state() in ["idle", "file_saved", "error"]: + status = Status(self) + status.set_finished() + return status + def is_running(*args, value, timestamp, **kwargs): result = value in ["idle", "file_saved", "error"] return result status = SubscriptionStatus(self.runstatus, is_running, settle_time=0.5) - # status.set_finished() return status def get_daq_config(self, update=False) -> dict: diff --git a/tomcat_bec/scans/tutorial_fly_scan.py b/tomcat_bec/scans/tutorial_fly_scan.py index 8ce46a0..138026c 100644 --- a/tomcat_bec/scans/tutorial_fly_scan.py +++ b/tomcat_bec/scans/tutorial_fly_scan.py @@ -4,6 +4,11 @@ import numpy as np from bec_lib.device import DeviceBase from bec_server.scan_server.scans import Acquire, AsyncFlyScanBase +from bec_lib import bec_logger + +logger = bec_logger.logger + + class AcquireDark(Acquire): scan_name = "acquire_dark" required_kwargs = ["exp_burst"] @@ -295,6 +300,7 @@ class AcquireRefs(Acquire): self.num_flats = num_flats self.file_prefix_dark = file_prefix_dark self.file_prefix_white = file_prefix_white + self.scan_parameters["std_daq_params"] = {"reconnect": False} def scan_core(self): @@ -308,11 +314,16 @@ class AcquireRefs(Acquire): ) # to set signals on a device - yield from self.stubs.send_rpc_and_wait("gfdaq", "file_prefix.set", self.file_prefix_dark) -# yield from self.stubs.send_rpc_and_wait("gfdaq", "num_images.set", self.num_darks) + cameras = [cam.name for cam in self.device_manager.devices.get_devices_with_tags("camera") if cam.enabled] + for cam in cameras: + yield from self.stubs.send_rpc_and_wait(cam, "file_prefix.set", f"{self.file_prefix}_{cam}_dark") + yield from self.stubs.send_rpc_and_wait(cam, "num_images.set", self.num_darks) + yield from self.stubs.send_rpc_and_wait(cam, "bluestage") # rename to arm + darks = AcquireDark( exp_burst=self.num_darks, +# file_prefix=self.file_prefix_dark, device_manager=self.device_manager, metadata=self.metadata, instruction_handler=self.stubs._instruction_handler, @@ -320,33 +331,52 @@ class AcquireRefs(Acquire): ) yield from darks.scan_core() + yield from self.stubs.send_rpc_and_wait("gfdaq", "complete") + yield from self.stubs.send_rpc_and_wait("gfdaq", "unstage") self.point_id = darks.point_id status_sample_out_angle.wait() - # if self.num_flats: - # self.connector.send_client_info( - # f"Acquiring {self.num_flats} flat field images", - # show_asap=True, - # rid=self.metadata.get("RID"), - # ) - # yield from self.stubs.send_rpc_and_wait("gfdaq", "file_prefix.set", self.file_prefix_white) - # yield from self.stubs.send_rpc_and_wait("gfdaq", "num_images.set", self.num_flats) + if self.num_flats: + self.connector.send_client_info( + f"Acquiring {self.num_flats} flat field images", + show_asap=True, + rid=self.metadata.get("RID"), + ) + yield from self.stubs.send_rpc_and_wait("gfdaq", "file_prefix.set", self.file_prefix_white) + yield from self.stubs.send_rpc_and_wait("gfdaq", "num_images.set", self.num_flats) + yield from self.stubs.send_rpc_and_wait("gfdaq", "bluestage") - # flats = AcquireWhite( - # exp_burst=self.num_flats, - # #sample_position_out=self.sample_position_out, - # #sample_angle_out=self.sample_angle_out, - # #motor=self.motor, - # device_manager=self.device_manager, - # metadata=self.metadata, - # instruction_handler=self.stubs._instruction_handler, - # **self.caller_kwargs, - # ) - # flats.point_id = self.point_id - # yield from flats.scan_core() - # self.point_id = flats.point_id - # ## TODO move sample in beam and do not wait - # ## TODO move rotation to angle and do not wait + logger.warning("Calling AcquireWhite") + + flats = AcquireWhite( + exp_burst=self.num_flats, + #sample_position_out=self.sample_position_out, + #sample_angle_out=self.sample_angle_out, + #motor=self.motor, + device_manager=self.device_manager, + metadata=self.metadata, + instruction_handler=self.stubs._instruction_handler, + **self.caller_kwargs, + ) + + + + flats.point_id = self.point_id + yield from flats.scan_core() + + logger.warning("Unstaging the DAQ") + + yield from self.stubs.send_rpc_and_wait("gfdaq", "complete") + yield from self.stubs.send_rpc_and_wait("gfdaq", "unstage") + logger.warning("Completing the DAQ") + + + logger.warning("Finished the DAQ") + + self.point_id = flats.point_id + ## TODO move sample in beam and do not wait + ## TODO move rotation to angle and do not wait + logger.warning("Done with scan_core") class TutorialFlyScanContLine(AsyncFlyScanBase): diff --git a/tomcat_bec/scripts/scans_fede.py b/tomcat_bec/scripts/scans_fede.py index d1682e6..2a44f7e 100644 --- a/tomcat_bec/scripts/scans_fede.py +++ b/tomcat_bec/scripts/scans_fede.py @@ -546,4 +546,20 @@ class Measurement: exp_time=self.exposure_time, exp_period=self.exposure_period, image_width=self.roix, image_height=self.roiy, acq_mode='default', file_path=self.file_path, nr_writers=2, base_path=self.base_path, file_prefix_dark=file_prefix_dark, file_prefix_white=file_prefix_white, - ddc_trigger=4, ddc_source0=1, **kwargs) \ No newline at end of file + ddc_trigger=4, ddc_source0=1, **kwargs) + + + def start_preview(self, exposure_time=None, exposure_period=None, + preview_strategy='', preview_paramters=200, **kwargs): + """ + Start the camera in preview mode, no data will be written. + + Parameters + ---------- + exposure_time : float, optional + """ + + if exposure_time is None: + exposure_time = self.exposure_time + if exposure_period is None: + exposure_period = 50 # no need to go faster for a preview \ No newline at end of file