diff --git a/ophyd_devices/__init__.py b/ophyd_devices/__init__.py index 3402f8a..05c9b20 100644 --- a/ophyd_devices/__init__.py +++ b/ophyd_devices/__init__.py @@ -1,3 +1,4 @@ +from .eiger1p5m_csaxs.eiger1p5m import Eiger1p5MDetector from .galil.galil_ophyd import GalilMotor from .npoint.npoint import NPointAxis from .rt_lamni import RtLamniMotor diff --git a/ophyd_devices/eiger1p5m_csaxs/eiger1p5m.py b/ophyd_devices/eiger1p5m_csaxs/eiger1p5m.py new file mode 100644 index 0000000..92038a4 --- /dev/null +++ b/ophyd_devices/eiger1p5m_csaxs/eiger1p5m.py @@ -0,0 +1,169 @@ +import os +import time +from typing import List + +from bec_utils import BECMessage, MessageEndpoints, bec_logger +from ophyd import Component as Cpt +from ophyd import Device, DeviceStatus, EpicsSignal, Signal + +logger = bec_logger.logger + + +class _SLSDetectorConfigSignal(Signal): + def put(self, value, *, timestamp=None, force=False): + self._readback = value + self.parent.sim_state[self.name] = value + + def get(self): + self._readback = self.parent.sim_state[self.name] + return self.parent.sim_state[self.name] + + +# if (_eigerinvac_is_on == 1) { +# tic("setup eiger in vac") +# epics_put("X12SA-ES1-DOUBLE-02",0) +# unix(sprintf("mkdir -p /sls/X12SA/data/%s/Data10/eiger_4/S%05d-%05d/S%05d",_username,int((SCAN_N+1)/1000)*1000,int((SCAN_N+1)/1000)*1000+999,SCAN_N+1)) + +# epics_put("XOMNYI-DET-OUTDIR:0.DESC",sprintf("/sls/X12SA/data/%s/Data10/eiger_4/",_username)) +# epics_put("XOMNYI-DET-OUTDIR:1.DESC",sprintf("S%05d-%05d/S%05d",int((SCAN_N+1)/1000)*1000,int((SCAN_N+1)/1000)*1000+999,SCAN_N+1)) +# epics_put("XOMNYI-DET-CYCLES:0", _lamni_scan_numberofpts) +# epics_put("XOMNYI-DET-EXPTIME:0", $2) +# epics_put("XOMNYI-DET-INDEX:0", SCAN_N+1) + +# epics_put("XOMNYI-DET-CONTROL:0.DESC", "begin") +# if(_eigerinvac_burst==0) +# { +# epics_put("XOMNYI-DET-CYCLES:0", _lamni_scan_numberofpts) +# epics_put("XOMNYI-DET-EXPTIME:0", $2) +# metadata_set("eiger_burst", "int", 1, 1) +# } +# else +# { +# metadata_set("eiger_burst", "int", 1, (int($2/0.0085))) +# epics_put("XOMNYI-DET-CYCLES:0", _lamni_scan_numberofpts*(int($2/0.0085))) +# epics_put("XOMNYI-DET-EXPTIME:0", 0.005) +# } +# global _DC_acquisition_ID +# _DC_acquisition_ID = SCAN_N+1 + + +class Eiger1p5MDetector(Device): + USER_ACCESS = [] + file_path = Cpt( + EpicsSignal, name="file_path", read_pv="XOMNYI-DET-OUTDIR:0.DESC", kind="config" + ) + detector_out_scan_dir = Cpt( + EpicsSignal, name="detector_out_scan_dir", read_pv="XOMNYI-DET-OUTDIR:1.DESC", kind="config" + ) + frames = Cpt(EpicsSignal, name="frames", read_pv="XOMNYI-DET-CYCLES:0", kind="config") + exp_time = Cpt(EpicsSignal, name="exp_time", read_pv="XOMNYI-DET-EXPTIME:0", kind="config") + index = Cpt(EpicsSignal, name="index", read_pv="XOMNYI-DET-INDEX:0", kind="config") + detector_control = Cpt( + EpicsSignal, name="detector_control", read_pv="XOMNYI-DET-CONTROL:0.DESC", kind="config" + ) + + file_pattern = Cpt(_SLSDetectorConfigSignal, name="file_pattern", value="", kind="config") + burst = Cpt(_SLSDetectorConfigSignal, name="burst", value=1, kind="config") + save_file = Cpt(_SLSDetectorConfigSignal, name="save_file", value=False, kind="config") + + def __init__(self, *, name, kind=None, parent=None, device_manager=None, **kwargs): + self.device_manager = device_manager + super().__init__(name=name, parent=parent, kind=kind, **kwargs) + self.sim_state = { + f"{self.name}_file_path": "~/Data10/data/", + f"{self.name}_file_pattern": f"{self.name}_{{:05d}}.h5", + f"{self.name}_frames": 1, + f"{self.name}_burst": 1, + f"{self.name}_save_file": False, + f"{self.name}_exp_time": 0, + } + self._stopped = False + self.file_name = "" + self.metadata = {} + self.username = "e20588" # TODO get from config + + def trigger(self): + status = DeviceStatus(self) + + self.subscribe(status._finished, event_type=self.SUB_ACQ_DONE, run=False) + + # def acquire(): + # try: + # for _ in range(self.burst.get()): + # ttime.sleep(self.exp_time.get()) + # if self._stopped: + # raise DeviceStop + # except DeviceStop: + # pass + # finally: + # self._stopped = False + # self._done_acquiring() + + # threading.Thread(target=acquire, daemon=True).start() + return status + + def _get_current_scan_msg(self) -> BECMessage.ScanStatusMessage: + msg = self.device_manager.producer.get(MessageEndpoints.scan_status()) + return BECMessage.ScanStatusMessage.loads(msg) + + def _get_scan_dir(self, scan_bundle, scan_number, leading_zeros=None): + if leading_zeros is None: + leading_zeros = len(str(scan_bundle)) + floor_dir = scan_number // scan_bundle * scan_bundle + return f"S{floor_dir:0{leading_zeros}d}-{floor_dir+scan_bundle-1:0{leading_zeros}d}/S{scan_number:0{leading_zeros}d}" + + def stage(self) -> List[object]: + scan_msg = self._get_current_scan_msg() + self.metadata = { + "scanID": scan_msg.content["scanID"], + "RID": scan_msg.content["info"]["RID"], + "queueID": scan_msg.content["info"]["queueID"], + } + scan_number = scan_msg.content["info"]["scan_number"] + exp_time = scan_msg.content["info"]["exp_time"] + + # set base path for detector output + self.file_path.set(f"/sls/X12SA/data/{self.username}/Data10/eiger_4/") + + # set scan directory (e.g. S00000-00999/S00020) + scan_dir = self._get_scan_dir(scan_bundle=1000, scan_number=scan_number, leading_zeros=5) + self.detector_out_scan_dir.set(scan_dir) + + self.file_name = os.path.join(f"/sls/X12SA/data/{self.username}/Data10/eiger_4/", scan_dir) + + # set the scan number + self.index.set(scan_number) + + # set the number of frames + self.frames.set(scan_msg.content["info"]["num_points"]) + + # set the exposure time + self.exp_time.set(exp_time) + + # send the "begin" flag to start processing the above commands + self.detector_control.set("begin") + + # wait for detector to be "armed" + logger.info("Waiting for detector setup") + while True: + det_ctrl = self.detector_control.get()["detector_control"]["value"] + if det_ctrl == "armed": + break + time.sleep(0.005) + + self.detector_control.put("acquiring") + + return super().stage() + + def unstage(self) -> List[object]: + signals = {"config": self.read_configuration(), "data": self.file_name} + msg = BECMessage.DeviceMessage(signals=signals, metadata=self.metadata) + self.device_manager.producer.set_and_publish( + MessageEndpoints.device_read(self.name), msg.dumps() + ) + return super().unstage() + + def stop(self, *, success=False): + self.detector_control.put("stop") + super().stop(success=success) + self._stopped = True diff --git a/ophyd_devices/sim/sim.py b/ophyd_devices/sim/sim.py index 57ec57f..b734a1a 100644 --- a/ophyd_devices/sim/sim.py +++ b/ophyd_devices/sim/sim.py @@ -271,7 +271,6 @@ class SynSLSDetector(Device): self.metadata = { "scanID": scan_msg.content["scanID"], "RID": scan_msg.content["info"]["RID"], - "RID": scan_msg.content["info"]["RID"], "queueID": scan_msg.content["info"]["queueID"], } scan_number = scan_msg.content["info"]["scan_number"] diff --git a/ophyd_devices/sls_devices/cSAXS/xeye.py b/ophyd_devices/sls_devices/cSAXS/xeye.py new file mode 100644 index 0000000..f62cc60 --- /dev/null +++ b/ophyd_devices/sls_devices/cSAXS/xeye.py @@ -0,0 +1,9 @@ +from ophyd import Component as Cpt +from ophyd import Device, EpicsSignal + + +class Xeye(Device): + save_frame = Cpt(EpicsSignal, "XOMNY-XEYE-SAVEFRAME:0") + acquisition_done = Cpt(EpicsSignal, "XOMNY-XEYE-ACQDONE:0") + acquisition = Cpt(EpicsSignal, "XOMNY-XEYE-ACQ:0") + x_width = Cpt(EpicsSignal, "XOMNY-XEYE-XWIDTH_X:0")