feat: add falcon and progress bar option to devices

This commit is contained in:
appel_c 2023-09-07 11:07:59 +02:00
parent 3a126976cd
commit 3bab432a2f
8 changed files with 316 additions and 212 deletions

View File

@ -134,6 +134,10 @@ class DelayGeneratorDG645(Device):
current device current device
""" """
SUB_PROGRESS = "progress"
SUB_VALUE = "value"
_default_sub = SUB_VALUE
USER_ACCESS = [ USER_ACCESS = [
"set_channels", "set_channels",
"_set_trigger", "_set_trigger",
@ -403,7 +407,7 @@ class DelayGeneratorDG645(Device):
LINE = 6 LINE = 6
""" """
value = int(trigger_source) value = int(trigger_source)
self.source.set(value) self.source.put(value)
def _ddg_is_okay(self, raise_on_error=False) -> None: def _ddg_is_okay(self, raise_on_error=False) -> None:
status = self.status.read()[self.status.name]["value"] status = self.status.read()[self.status.name]["value"]
@ -452,14 +456,14 @@ class DelayGeneratorDG645(Device):
) )
self._set_trigger(getattr(TriggerSource, self.set_trigger_source.get())) self._set_trigger(getattr(TriggerSource, self.set_trigger_source.get()))
# Set threshold level for ext. pulses # Set threshold level for ext. pulses
self.level.set(self.thres_trig_level.get()) self.level.put(self.thres_trig_level.get())
def _check_burst_cycle(self, status) -> None: def _check_burst_cycle(self, status) -> None:
"""Checks burst cycle of delay generator """Checks burst cycle of delay generator
Force readout, return value from end of burst cycle Force readout, return value from end of burst cycle
""" """
while True: while True:
self.trigger_burst_readout.set(1) self.trigger_burst_readout.put(1)
if ( if (
self.burst_cycle_finished.read()[self.burst_cycle_finished.name]["value"] == 1 self.burst_cycle_finished.read()[self.burst_cycle_finished.name]["value"] == 1
and self.delay_finished.read()[self.delay_finished.name]["value"] == 1 and self.delay_finished.read()[self.delay_finished.name]["value"] == 1
@ -571,7 +575,7 @@ class DelayGeneratorDG645(Device):
def trigger(self) -> DeviceStatus: def trigger(self) -> DeviceStatus:
# if self.scaninfo.scan_type == "step": # if self.scaninfo.scan_type == "step":
if self.source.read()[self.source.name]["value"] == int(TriggerSource.SINGLE_SHOT): if self.source.read()[self.source.name]["value"] == int(TriggerSource.SINGLE_SHOT):
self.trigger_shot.set(1).wait() self.trigger_shot.put(1)
# status = super().trigger(status=) # status = super().trigger(status=)
status = DeviceStatus(self) status = DeviceStatus(self)
burst_state = threading.Thread(target=self._check_burst_cycle, args=(status,), daemon=True) burst_state = threading.Thread(target=self._check_burst_cycle, args=(status,), daemon=True)
@ -590,19 +594,19 @@ class DelayGeneratorDG645(Device):
"first", "first",
], "Supported bust configs are 'all' and 'first'" ], "Supported bust configs are 'all' and 'first'"
self.burstMode.set(1).wait() self.burstMode.put(1)
self.burstCount.set(count).wait() self.burstCount.put(count)
self.burstDelay.set(delay).wait() self.burstDelay.put(delay)
self.burstPeriod.set(period).wait() self.burstPeriod.put(period)
if config == "all": if config == "all":
self.burstConfig.set(0).wait() self.burstConfig.put(0)
elif config == "first": elif config == "first":
self.burstConfig.set(1).wait() self.burstConfig.put(1)
def burst_disable(self): def burst_disable(self):
"""Disable the burst mode""" """Disable the burst mode"""
self.burstMode.set(0).wait() self.burstMode.put(0)
# Automatically connect to test environmenr if directly invoked # Automatically connect to test environmenr if directly invoked

View File

@ -1,6 +1,9 @@
import os import os
from bec_lib.core import DeviceManagerBase, BECMessage, MessageEndpoints from bec_lib.core import DeviceManagerBase, BECMessage, MessageEndpoints
from bec_lib.core import bec_logger
logger = bec_logger.logger
class BecScaninfoMixin: class BecScaninfoMixin:
@ -39,23 +42,28 @@ class BecScaninfoMixin:
info=self.bec_info_msg, info=self.bec_info_msg,
) )
def _get_username(self) -> str: def get_username(self) -> str:
if not self.sim_mode: if not self.sim_mode:
return self.device_manager.producer.get(MessageEndpoints.account()).decode() return self.device_manager.producer.get(MessageEndpoints.account()).decode()
return os.getlogin() return os.getlogin()
def load_scan_metadata(self) -> None: def load_scan_metadata(self) -> None:
self.scan_msg = scan_msg = self._get_current_scan_msg() self.scan_msg = scan_msg = self._get_current_scan_msg()
self.metadata = { logger.info(f"{self.scan_msg}")
"scanID": scan_msg.content["scanID"], try:
"RID": scan_msg.content["info"]["RID"], self.metadata = {
"queueID": scan_msg.content["info"]["queueID"], "scanID": scan_msg.content["scanID"],
} "RID": scan_msg.content["info"]["RID"],
self.scanID = scan_msg.content["scanID"] "queueID": scan_msg.content["info"]["queueID"],
self.scan_number = scan_msg.content["info"]["scan_number"] }
self.exp_time = scan_msg.content["info"]["exp_time"] self.scanID = scan_msg.content["scanID"]
self.frames_per_trigger = scan_msg.content["info"]["frames_per_trigger"] self.scan_number = scan_msg.content["info"]["scan_number"]
self.num_points = scan_msg.content["info"]["num_points"] self.exp_time = scan_msg.content["info"]["exp_time"]
self.scan_type = scan_msg.content["info"].get("scan_type", "step") self.frames_per_trigger = scan_msg.content["info"]["frames_per_trigger"]
self.readout_time = scan_msg.content["info"]["readout_time"] self.num_points = scan_msg.content["info"]["num_points"]
self.username = self._get_username() self.scan_type = scan_msg.content["info"].get("scan_type", "step")
self.readout_time = scan_msg.content["info"]["readout_time"]
except Exception as exc:
logger.error(f"Failed to load scan metadata: {exc}.")
self.username = self.get_username()

View File

@ -4,9 +4,8 @@ from typing import Any, List
import numpy as np import numpy as np
from ophyd import EpicsSignal, EpicsSignalRO, EpicsSignalWithRBV from ophyd import EpicsSignal, EpicsSignalRO, EpicsSignalWithRBV
from ophyd import CamBase, DetectorBase, Device from ophyd import DetectorBase, Device
from ophyd import ADComponent as ADCpt from ophyd import ADComponent as ADCpt
from ophyd.areadetector.plugins import FileBase
from bec_lib.core import BECMessage, MessageEndpoints from bec_lib.core import BECMessage, MessageEndpoints
from bec_lib.core.file_utils import FileWriterMixin from bec_lib.core.file_utils import FileWriterMixin
@ -25,7 +24,7 @@ class EigerError(Exception):
pass pass
class SlsDetectorCam(Device): # CamBase, FileBase): class SlsDetectorCam(Device):
detector_type = ADCpt(EpicsSignalRO, "DetectorType_RBV") detector_type = ADCpt(EpicsSignalRO, "DetectorType_RBV")
setting = ADCpt(EpicsSignalWithRBV, "Setting") setting = ADCpt(EpicsSignalWithRBV, "Setting")
delay_time = ADCpt(EpicsSignalWithRBV, "DelayTime") delay_time = ADCpt(EpicsSignalWithRBV, "DelayTime")
@ -125,6 +124,7 @@ class Eiger9mCsaxs(DetectorBase):
parent=parent, parent=parent,
**kwargs, **kwargs,
) )
self._stopped = False
if device_manager is None and not sim_mode: if device_manager is None and not sim_mode:
raise EigerError("Add DeviceManager to initialization or init with sim_mode=True") raise EigerError("Add DeviceManager to initialization or init with sim_mode=True")
@ -234,16 +234,22 @@ class Eiger9mCsaxs(DetectorBase):
def _prep_file_writer(self) -> None: def _prep_file_writer(self) -> None:
self.filepath = self.filewriter.compile_full_filename( self.filepath = self.filewriter.compile_full_filename(
self.scaninfo.scan_number, "eiger.h5", 1000, 5, True self.scaninfo.scan_number, f"{self.name}.h5", 1000, 5, True
) )
# self._close_file_writer() # self._close_file_writer()
logger.info(f" std_daq output filepath {self.filepath}") logger.info(f" std_daq output filepath {self.filepath}")
self.std_client.start_writer_async( try:
{ self.std_client.start_writer_async(
"output_file": self.filepath, {
"n_images": int(self.scaninfo.num_points * self.scaninfo.frames_per_trigger), "output_file": self.filepath,
} "n_images": int(self.scaninfo.num_points * self.scaninfo.frames_per_trigger),
) }
)
except Exception as exc:
time.sleep(5)
if self.std_client.get_status()["state"] == "READY":
raise EigerError(f"Timeout of start_writer_async with {exc}")
while True: while True:
det_ctrl = self.std_client.get_status()["acquisition"]["state"] det_ctrl = self.std_client.get_status()["acquisition"]["state"]
if det_ctrl == "WAITING_IMAGES": if det_ctrl == "WAITING_IMAGES":
@ -277,24 +283,29 @@ class Eiger9mCsaxs(DetectorBase):
msg.dumps(), msg.dumps(),
) )
self.arm_acquisition() self.arm_acquisition()
logger.info("Waiting for detector to be armed") logger.info("Waiting for Eiger9m to be armed")
while True: while True:
det_ctrl = self.cam.detector_state.read()[self.cam.detector_state.name]["value"] det_ctrl = self.cam.detector_state.read()[self.cam.detector_state.name]["value"]
if det_ctrl == int(DetectorState.RUNNING): if det_ctrl == int(DetectorState.RUNNING):
break break
if self._stopped == True:
break
time.sleep(0.005) time.sleep(0.005)
logger.info("Detector is armed") logger.info("Eiger9m is armed")
self._stopped = False
return super().stage() return super().stage()
def unstage(self) -> List[object]: def unstage(self) -> List[object]:
"""unstage the detector and file writer""" """unstage the detector and file writer"""
logger.info("Waiting for eiger9M to return from acquisition") logger.info("Waiting for Eiger9M to return from acquisition")
while True: while True:
det_ctrl = self.cam.acquire.read()[self.cam.acquire.name]["value"] det_ctrl = self.cam.acquire.read()[self.cam.acquire.name]["value"]
if det_ctrl == 0: if det_ctrl == 0:
break break
if self._stopped == True:
break
time.sleep(0.005) time.sleep(0.005)
logger.info("Eiger9M finished")
logger.info("Waiting for std daq to receive images") logger.info("Waiting for std daq to receive images")
while True: while True:
@ -302,7 +313,10 @@ class Eiger9mCsaxs(DetectorBase):
# TODO if no writing was performed before # TODO if no writing was performed before
if det_ctrl == "FINISHED": if det_ctrl == "FINISHED":
break break
if self._stopped == True:
break
time.sleep(0.005) time.sleep(0.005)
logger.info("Std_daq finished")
# Message to BEC # Message to BEC
state = True state = True
@ -311,7 +325,7 @@ class Eiger9mCsaxs(DetectorBase):
MessageEndpoints.public_file(self.scaninfo.scanID, self.name), MessageEndpoints.public_file(self.scaninfo.scanID, self.name),
msg.dumps(), msg.dumps(),
) )
logger.info("Eiger done") self._stopped = False
return super().unstage() return super().unstage()
def arm_acquisition(self) -> None: def arm_acquisition(self) -> None:
@ -324,12 +338,9 @@ class Eiger9mCsaxs(DetectorBase):
"""Stop the scan, with camera and file writer""" """Stop the scan, with camera and file writer"""
self.cam.acquire.set(0) self.cam.acquire.set(0)
self._close_file_writer() self._close_file_writer()
self.unstage()
super().stop(success=success) super().stop(success=success)
self._stopped = True self._stopped = True
# Automatically connect to test environmenr if directly invoked
if __name__ == "__main__": if __name__ == "__main__":
eiger = Eiger9mCsaxs(name="eiger", prefix="X12SA-ES-EIGER9M:", sim_mode=True) eiger = Eiger9mCsaxs(name="eiger", prefix="X12SA-ES-EIGER9M:", sim_mode=True)
eiger.stage()

View File

@ -40,5 +40,6 @@ class EpicsMotorEx(EpicsMotor):
# set configuration attributes # set configuration attributes
for key, value in attrs.items(): for key, value in attrs.items():
# print out attributes that are being configured
print("setting ", key, "=", value) print("setting ", key, "=", value)
getattr(self, key).put(value) getattr(self, key).put(value)

View File

@ -1,13 +1,14 @@
import enum
import os import os
import time import time
from typing import List from typing import List
from ophyd import EpicsSignal, EpicsSignalRO, EpicsSignalWithRBV, Component as Cpt, Device from ophyd import EpicsSignal, EpicsSignalRO, EpicsSignalWithRBV, Component as Cpt, Device
from ophyd.mca import EpicsMCARecord, EpicsDXPMapping, EpicsDXPLowLevel, EpicsDXPMultiElementSystem from ophyd.mca import EpicsMCARecord
from ophyd.areadetector.plugins import HDF5Plugin, HDF5Plugin_V21, FilePlugin_V22 from ophyd.areadetector.plugins import HDF5Plugin_V21, FilePlugin_V22
from bec_lib.core.file_utils import FileWriterMixin from bec_lib.core.file_utils import FileWriterMixin
from bec_lib.core import MessageEndpoints, BECMessage, RedisConnector from bec_lib.core import MessageEndpoints, BECMessage
from bec_lib.core import bec_logger from bec_lib.core import bec_logger
from ophyd_devices.epics.devices.bec_scaninfo_mixin import BecScaninfoMixin from ophyd_devices.epics.devices.bec_scaninfo_mixin import BecScaninfoMixin
@ -16,6 +17,15 @@ from ophyd_devices.utils import bec_utils
logger = bec_logger.logger logger = bec_logger.logger
class FalconError(Exception):
pass
class DetectorState(int, enum.Enum):
DONE = 0
ACQUIRING = 1
class EpicsDXPFalcon(Device): class EpicsDXPFalcon(Device):
"""All high-level DXP parameters for each channel""" """All high-level DXP parameters for each channel"""
@ -37,12 +47,21 @@ class EpicsDXPFalcon(Device):
current_pixel = Cpt(EpicsSignalRO, "CurrentPixel") current_pixel = Cpt(EpicsSignalRO, "CurrentPixel")
class FalconError(Exception): class FalconHDF5Plugins(Device): # HDF5Plugin_V21, FilePlugin_V22):
pass capture = Cpt(EpicsSignalWithRBV, "Capture")
enable = Cpt(EpicsSignalWithRBV, "EnableCallbacks", string=True, kind="config")
xml_file_name = Cpt(EpicsSignalWithRBV, "XMLFileName", string=True, kind="config")
class FalconHDF5Plugins(HDF5Plugin_V21, FilePlugin_V22): lazy_open = Cpt(EpicsSignalWithRBV, "LazyOpen", string=True, doc="0='No' 1='Yes'")
pass temp_suffix = Cpt(EpicsSignalWithRBV, "TempSuffix", string=True)
# file_path = Cpt(
# EpicsSignalWithRBV, "FilePath", string=True, kind="config", path_semantics="posix"
# )
file_path = Cpt(EpicsSignalWithRBV, "FilePath", string=True, kind="config")
file_name = Cpt(EpicsSignalWithRBV, "FileName", string=True, kind="config")
file_template = Cpt(EpicsSignalWithRBV, "FileTemplate", string=True, kind="config")
num_capture = Cpt(EpicsSignalWithRBV, "NumCapture", kind="config")
file_write_mode = Cpt(EpicsSignalWithRBV, "FileWriteMode", kind="config")
capture = Cpt(EpicsSignalWithRBV, "Capture")
class FalconCsaxs(Device): class FalconCsaxs(Device):
@ -77,6 +96,8 @@ class FalconCsaxs(Device):
pixels_per_buffer = Cpt(EpicsSignal, "PixelsPerBuffer") pixels_per_buffer = Cpt(EpicsSignal, "PixelsPerBuffer")
pixels_per_run = Cpt(EpicsSignal, "PixelsPerRun") pixels_per_run = Cpt(EpicsSignal, "PixelsPerRun")
# HDF5
def __init__( def __init__(
self, self,
prefix="", prefix="",
@ -101,153 +122,141 @@ class FalconCsaxs(Device):
) )
if device_manager is None and not sim_mode: if device_manager is None and not sim_mode:
raise FalconError("Add DeviceManager to initialization or init with sim_mode=True") raise FalconError("Add DeviceManager to initialization or init with sim_mode=True")
self._stopped = False
self.name = name self.name = name
self.wait_for_connection() # Make sure to be connected before talking to PVs self.wait_for_connection() # Make sure to be connected before talking to PVs
if not sim_mode: if not sim_mode:
from bec_lib.core.bec_service import SERVICE_CONFIG
self.device_manager = device_manager self.device_manager = device_manager
self._producer = self.device_manager.producer self._producer = self.device_manager.producer
self.service_cfg = SERVICE_CONFIG.config["service_config"]["file_writer"]
else: else:
self._producer = bec_utils.MockProducer() self._producer = bec_utils.MockProducer()
self.device_manager = bec_utils.MockDeviceManager() self.device_manager = bec_utils.MockDeviceManager()
self.scaninfo = BecScaninfoMixin(device_manager, sim_mode)
self.scaninfo.load_scan_metadata()
self.service_cfg = {"base_path": f"/sls/X12SA/data/{self.scaninfo.username}/Data10/"}
self.scaninfo = BecScaninfoMixin(device_manager, sim_mode) self.scaninfo = BecScaninfoMixin(device_manager, sim_mode)
# TODO self.scaninfo.load_scan_metadata()
self.scaninfo.username = "e21206"
self.service_cfg = {"base_path": f"/sls/X12SA/data/{self.scaninfo.username}/Data10/"}
self.filewriter = FileWriterMixin(self.service_cfg) self.filewriter = FileWriterMixin(self.service_cfg)
self.readout = 0.003 # 3 ms self.readout = 0.003 # 3 ms
self._value_pixel_per_buffer = 16 self._value_pixel_per_buffer = 1 # 16
# TODO create file template from filewriter compile filename
self._file_template = f"%s%s_{self.name}.h5"
self.num_frames = 0
self._clean_up() self._clean_up()
self._init_hdf5_saving() self._init_hdf5_saving()
self._init_mapping_mode() self._init_mapping_mode()
def _clean_up(self) -> None: def _clean_up(self) -> None:
"""Clean up""" """Clean up"""
self.hdf5.capture.set(0) self.hdf5.capture.put(0)
self.stop_all.set(1) self.stop_all.put(1)
self.erase_all.set(1) self.erase_all.put(1)
def _init_hdf5_saving(self) -> None: def _init_hdf5_saving(self) -> None:
"""Set up hdf5 save parameters""" """Set up hdf5 save parameters"""
self.hdf5.enable.set(1) # EnableCallbacks self.hdf5.enable.put(1) # EnableCallbacks
self.hdf5.xml_file_name.set("layout.xml") # Points to hardcopy of HDF5 Layout xml file self.hdf5.xml_file_name.put("layout.xml") # Points to hardcopy of HDF5 Layout xml file
self.hdf5.lazy_open.set(1) # Yes -> To be checked how to add FilePlugin_V21+ self.hdf5.lazy_open.put(1) # Yes -> To be checked how to add FilePlugin_V21+
self.hdf5.temp_suffix.set("temps") # -> To be checked how to add FilePlugin_V22+ self.hdf5.temp_suffix.put("temps") # -> To be checked how to add FilePlugin_V22+
def _init_mapping_mode(self) -> None: def _init_mapping_mode(self) -> None:
"""Set up mapping mode params""" """Set up mapping mode params"""
self.collect_mode.set(1) # 1 MCA Mapping, 0 MCA Spectrum self.collect_mode.put(1) # 1 MCA Mapping, 0 MCA Spectrum
self.preset_mode.set(1) # 1 Realtime self.preset_mode.put(1) # 1 Realtime
self.input_logic_polarity.set(0) # 0 Normal, 1 Inverted self.input_logic_polarity.put(0) # 0 Normal, 1 Inverted
self.pixel_advance_mode.set(1) # 0 User, 1 Gate, 2 Sync self.pixel_advance_mode.put(1) # 0 User, 1 Gate, 2 Sync
self.ignore_gate.set(1) # 1 Yes self.ignore_gate.put(1) # 1 Yes
self.auto_pixels_per_buffer.set(0) # 0 Manual 1 Auto self.auto_pixels_per_buffer.put(0) # 0 Manual 1 Auto
self.pixels_per_buffer.set(16) # self.pixels_per_buffer.put(16) #
def _get_current_scan_msg(self) -> BECMessage.ScanStatusMessage:
msg = self.device_manager.producer.get(MessageEndpoints.scan_status())
return BECMessage.ScanStatusMessage.loads(msg)
def _load_scan_metadata(self) -> None:
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"],
}
self.scanID = scan_msg.content["scanID"]
self.scan_number = scan_msg.content["info"]["scan_number"]
self.exp_time = scan_msg.content["info"]["exp_time"]
self.num_frames = scan_msg.content["info"]["num_points"]
self.username = self.device_manager.producer.get(MessageEndpoints.account()).decode()
self.device_manager.devices.mokev.read()["mokev"]["value"]
# self.triggermode = scan_msg.content["info"]["trigger_mode"]
self.filepath = self.filewriter.compile_full_filename(
self.scan_number, "falcon", 1000, 5, True
)
def _prep_det(self) -> None: def _prep_det(self) -> None:
"""Prepare detector for acquisition""" """Prepare detector for acquisition"""
self.collect_mode.set(1) self.collect_mode.put(1)
self.preset_real.set(self.exposure_time) self.preset_real.put(self.scaninfo.exp_time)
self.pixels_per_run.set(self.num_frames) self.pixels_per_run.put(int(self.scaninfo.num_points * self.scaninfo.frames_per_trigger))
self.auto_pixels_per_buffer.set(0) self.auto_pixels_per_buffer.put(0)
self.pixels_per_buffer.set(self._value_pixel_per_buffer) self.pixels_per_buffer.put(self._value_pixel_per_buffer)
def _prep_file_writer(self) -> None: def _prep_file_writer(self) -> None:
"""Prep HDF5 weriting""" """Prep HDF5 weriting"""
# TODO creta filename and destination path from filepath # TODO creta filename and destination path from filepath
self.destination_path = os.path.join(self.service_cfg["base_path"]) self.destination_path = self.filewriter.compile_full_filename(
self.filename = f"test_{self.scan_number}" self.scaninfo.scan_number, f"{self.name}.h5", 1000, 5, True
self.hdf5.file_path.set(self.destination_path) )
self.hdf5.file_name.set(self.filename) # self.hdf5.file_path.set(self.destination_path)
self.hdf5.file_template.set(self._file_template) file_path, file_name = os.path.split(self.destination_path)
self.hdf5.num_capture.set(self.num_frames // self._value_pixel_per_buffer + 1) self.hdf5.file_path.put(file_path)
self.hdf5.file_write_mode.set(2) self.hdf5.file_name.put(file_name)
self.hdf5.capture.set(1) self.hdf5.file_template.put(f"%s%s")
self.hdf5.num_capture.put(self.scaninfo.num_points // self._value_pixel_per_buffer + 1)
self.hdf5.file_write_mode.put(2)
self.hdf5.capture.put(1)
def stage(self) -> List[object]: def stage(self) -> List[object]:
"""stage the detector and file writer""" """stage the detector and file writer"""
# TODO remove once running from BEC # TODO clean up needed?
# self._load_scan_metadata() # self._clean_up()
self.scan_number = 10 self.scaninfo.load_scan_metadata()
self.exp_time = 0.5 self.mokev = self.device_manager.devices.mokev.obj.read()[
self.num_frames = 3 self.device_manager.devices.mokev.name
self.mokev = 12 ]["value"]
logger.info("Waiting for pilatus2 to be armed")
self._prep_det() self._prep_det()
logger.info("Pilatus2 armed")
logger.info("Waiting for pilatus2 zmq stream to be ready")
self._prep_file_writer() self._prep_file_writer()
logger.info("Pilatus2 zmq ready")
msg = BECMessage.FileMessage(file_path=self.filepath, done=False) msg = BECMessage.FileMessage(file_path=self.destination_path, done=False)
self.producer.set_and_publish( self._producer.set_and_publish(
MessageEndpoints.public_file(self.metadata["scanID"], self.name), MessageEndpoints.public_file(self.scaninfo.scanID, self.name),
msg.dumps(), msg.dumps(),
) )
self.arm_acquisition()
logger.info("Waiting for Falcon to be armed")
while True:
det_ctrl = self.state.read()[self.state.name]["value"]
if det_ctrl == int(DetectorState.ACQUIRING):
break
if self._stopped == True:
break
time.sleep(0.005)
logger.info("Falcon is armed")
self._stopped = False
return super().stage() return super().stage()
def acquire(self) -> None: def arm_acquisition(self) -> None:
self.start_all.set(1) self.start_all.put(1)
def unstage(self) -> List[object]: def unstage(self) -> List[object]:
logger.info("Waiting for Falcon to return from acquisition")
while True:
det_ctrl = self.state.read()[self.state.name]["value"]
if det_ctrl == int(DetectorState.DONE):
break
if self._stopped == True:
break
time.sleep(0.005)
logger.info("Falcon done")
# TODO needed?
self._clean_up() self._clean_up()
# TODO check if acquisition is done and successful!
state = True state = True
msg = BECMessage.FileMessage(file_path=self.filepath, done=True, successful=state) msg = BECMessage.FileMessage(file_path=self.destination_path, done=True, successful=state)
self.producer.set_and_publish( self._producer.set_and_publish(
MessageEndpoints.public_file(self.metadata["scanID"], self.name), MessageEndpoints.public_file(self.scaninfo.metadata["scanID"], self.name),
msg.dumps(), msg.dumps(),
) )
self._stopped = False
return super().unstage() return super().unstage()
def _check_falcon_done(self) -> bool:
state = self.state.read()[f"{self.name }_state"]["value"]
if state is [0, 1]:
return not bool(state)
else:
# TODO raise error
logger.warning("Returned in unknown state")
return state
def stop(self, *, success=False) -> None: def stop(self, *, success=False) -> None:
"""Stop acquisition """Stop the scan, with camera and file writer"""
Stop or Stop and Erase self._clean_up()
"""
self._clean_up.set(1)
# self.erase_all.set(1)
self.unstage()
super().stop(success=success) super().stop(success=success)
self._stopped = True self._stopped = True
# Automatically connect to test environmenr if directly invoked
if __name__ == "__main__": if __name__ == "__main__":
falcon = FalconCsaxs(name="falcon", prefix="X12SA-SITORO:", sim_mode=True) falcon = FalconCsaxs(name="falcon", prefix="X12SA-SITORO:", sim_mode=True)
falcon.stage()

View File

@ -93,6 +93,9 @@ class SIS38XX(Device):
class McsCsaxs(SIS38XX): class McsCsaxs(SIS38XX):
SUB_PROGRESS = "progress"
SUB_VALUE = "value"
_default_sub = SUB_VALUE
# scaler = Cpt(ScalerCH, "scaler1") # scaler = Cpt(ScalerCH, "scaler1")
# mca2 = Cpt(EpicsMCARecord, "mca2") # mca2 = Cpt(EpicsMCARecord, "mca2")
@ -127,6 +130,7 @@ class McsCsaxs(SIS38XX):
# mca30 = Cpt(EpicsMCARecord, "mca30") # mca30 = Cpt(EpicsMCARecord, "mca30")
# mca31 = Cpt(EpicsMCARecord, "mca31") # mca31 = Cpt(EpicsMCARecord, "mca31")
# mca32 = Cpt(EpicsMCARecord, "mca32") # mca32 = Cpt(EpicsMCARecord, "mca32")
current_channel = Cpt(EpicsSignalRO, "CurrentChannel", auto_monitor=True)
num_lines = Cpt( num_lines = Cpt(
bec_utils.ConfigSignal, bec_utils.ConfigSignal,
@ -164,7 +168,6 @@ class McsCsaxs(SIS38XX):
parent=parent, parent=parent,
**kwargs, **kwargs,
) )
if device_manager is None and not sim_mode: if device_manager is None and not sim_mode:
raise MCSError("Add DeviceManager to initialization or init with sim_mode=True") raise MCSError("Add DeviceManager to initialization or init with sim_mode=True")
@ -188,6 +191,8 @@ class McsCsaxs(SIS38XX):
self._stopped = False self._stopped = False
self._acquisition_done = False self._acquisition_done = False
self._lock = threading.RLock() self._lock = threading.RLock()
self.counter = 0
self.n_points = 0
self._init_mcs() self._init_mcs()
def _init_mcs(self) -> None: def _init_mcs(self) -> None:
@ -212,7 +217,17 @@ class McsCsaxs(SIS38XX):
for mca in self.mca_names: for mca in self.mca_names:
signal = getattr(self, mca) signal = getattr(self, mca)
signal.subscribe(self._on_mca_data, run=False) signal.subscribe(self._on_mca_data, run=False)
self._counter = 0 self.current_channel.subscribe(self._progress_update, run=False)
def _progress_update(self, value, **kwargs) -> None:
num_lines = self.num_lines.get()
max_value = self.scaninfo.num_points
self._run_subs(
sub_type=self.SUB_PROGRESS,
value=self.counter * int(self.scaninfo.num_points / num_lines) + max(value - 1, 0),
max_value=max_value,
done=bool(max_value == self.counter),
)
@threadlocked @threadlocked
def _on_mca_data(self, *args, obj=None, **kwargs) -> None: def _on_mca_data(self, *args, obj=None, **kwargs) -> None:
@ -229,19 +244,18 @@ class McsCsaxs(SIS38XX):
# return # return
self._updated = True self._updated = True
self._counter += 1 self.counter += 1
logger.info(f"counter {self._counter}") if (self.scaninfo.scan_type == "fly" and self.counter == self.num_lines.get()) or (
if (self.scaninfo.scan_type == "fly" and self._counter == self.num_lines.get()) or ( self.scaninfo.scan_type == "step" and self.counter == self.scaninfo.num_points
self.scaninfo.scan_type == "step" and self._counter == self.scaninfo.num_points
): ):
self._acquisition_done = True self._acquisition_done = True
self.stop_all.put(1, use_complete=False) self.stop_all.put(1, use_complete=False)
self._send_data_to_bec() self._send_data_to_bec()
self.erase_all.set(1) self.erase_all.put(1)
# Require wait for # Require wait for
# time.sleep(0.01) # time.sleep(0.01)
self.mca_data = defaultdict(lambda: []) self.mca_data = defaultdict(lambda: [])
self._counter = 0 self.counter = 0
return return
self.erase_start.set(1) self.erase_start.set(1)
self._send_data_to_bec() self._send_data_to_bec()
@ -257,7 +271,6 @@ class McsCsaxs(SIS38XX):
"num_lines": self.num_lines.get(), "num_lines": self.num_lines.get(),
} }
) )
logger.info(f"{self.mca_data}")
msg = BECMessage.DeviceMessage( msg = BECMessage.DeviceMessage(
signals=dict(self.mca_data), signals=dict(self.mca_data),
metadata=self.scaninfo.scan_msg.metadata, metadata=self.scaninfo.scan_msg.metadata,
@ -276,16 +289,16 @@ class McsCsaxs(SIS38XX):
def _set_acquisition_params(self) -> None: def _set_acquisition_params(self) -> None:
if self.scaninfo.scan_type == "step": if self.scaninfo.scan_type == "step":
n_points = int(self.scaninfo.frames_per_trigger + 1) self.n_points = int(self.scaninfo.frames_per_trigger + 1)
elif self.scaninfo.scan_type == "fly": elif self.scaninfo.scan_type == "fly":
n_points = int(self.scaninfo.num_points / int(self.num_lines.get()) + 1) self.n_points = int(self.scaninfo.num_points / int(self.num_lines.get()) + 1)
else: else:
raise MCSError(f"Scantype {self.scaninfo} not implemented for MCS card") raise MCSError(f"Scantype {self.scaninfo} not implemented for MCS card")
if n_points > 10000: if self.n_points > 10000:
raise MCSError( raise MCSError(
f"Requested number of points N={n_points} exceeds hardware limit of mcs card 10000 (N-1)" f"Requested number of points N={self.n_points} exceeds hardware limit of mcs card 10000 (N-1)"
) )
self.num_use_all.set(n_points) self.num_use_all.set(self.n_points)
self.preset_real.set(0) self.preset_real.set(0)
def _set_trigger(self, trigger_source: TriggerSource) -> None: def _set_trigger(self, trigger_source: TriggerSource) -> None:
@ -299,7 +312,7 @@ class McsCsaxs(SIS38XX):
Check ReadoutMode class for more information about options Check ReadoutMode class for more information about options
""" """
# self.read_mode.set(ReadoutMode.EVENT) # self.read_mode.set(ReadoutMode.EVENT)
self.erase_all.set(1) self.erase_all.put(1)
self.read_mode.set(ReadoutMode.EVENT) self.read_mode.set(ReadoutMode.EVENT)
def _force_readout_mcs_card(self) -> None: def _force_readout_mcs_card(self) -> None:
@ -307,7 +320,7 @@ class McsCsaxs(SIS38XX):
def stage(self) -> List[object]: def stage(self) -> List[object]:
"""stage the detector and file writer""" """stage the detector and file writer"""
logger.info("Stage Eiger") logger.info("Stage mcs")
self.scaninfo.load_scan_metadata() self.scaninfo.load_scan_metadata()
self._prep_det() self._prep_det()
self._prep_readout() self._prep_readout()
@ -347,7 +360,7 @@ class McsCsaxs(SIS38XX):
Start: start_all Start: start_all
Erase/Start: erase_start Erase/Start: erase_start
""" """
self._counter = 0 self.counter = 0
self.erase_start.set(1) self.erase_start.set(1)
# self.start_all.set(1) # self.start_all.set(1)
@ -359,7 +372,7 @@ class McsCsaxs(SIS38XX):
# self.erase_all.set(1) # self.erase_all.set(1)
self._stopped = True self._stopped = True
self._acquisition_done = True self._acquisition_done = True
self._counter = 0 self.counter = 0
super().stop(success=success) super().stop(success=success)

View File

@ -6,11 +6,12 @@ from typing import List
import requests import requests
import numpy as np import numpy as np
from ophyd.areadetector import ADComponent as ADCpt, PilatusDetectorCam, DetectorBase from ophyd import EpicsSignal, EpicsSignalRO, EpicsSignalWithRBV
from ophyd.areadetector.plugins import FileBase from ophyd import DetectorBase, Device
from ophyd import ADComponent as ADCpt
from ophyd_devices.utils import bec_utils as bec_utils from ophyd_devices.utils import bec_utils as bec_utils
from bec_lib.core import BECMessage, MessageEndpoints, RedisConnector from bec_lib.core import BECMessage, MessageEndpoints
from bec_lib.core.file_utils import FileWriterMixin from bec_lib.core.file_utils import FileWriterMixin
from bec_lib.core import bec_logger from bec_lib.core import bec_logger
@ -24,10 +25,6 @@ class PilatusError(Exception):
pass pass
class PilatusDetectorCamEx(PilatusDetectorCam, FileBase):
pass
class TriggerSource(int, enum.Enum): class TriggerSource(int, enum.Enum):
INTERNAL = 0 INTERNAL = 0
EXT_ENABLE = 1 EXT_ENABLE = 1
@ -36,6 +33,72 @@ class TriggerSource(int, enum.Enum):
ALGINMENT = 4 ALGINMENT = 4
class SlsDetectorCam(Device): # CamBase, FileBase):
# detector_type = ADCpt(EpicsSignalRO, "DetectorType_RBV")
# setting = ADCpt(EpicsSignalWithRBV, "Setting")
# beam_energy = ADCpt(EpicsSignalWithRBV, "BeamEnergy")
# enable_trimbits = ADCpt(EpicsSignalWithRBV, "Trimbits")
# bit_depth = ADCpt(EpicsSignalWithRBV, "BitDepth")
# trigger_software = ADCpt(EpicsSignal, "TriggerSoftware")
# high_voltage = ADCpt(EpicsSignalWithRBV, "HighVoltage")
# Receiver and data callback
# receiver_mode = ADCpt(EpicsSignalWithRBV, "ReceiverMode")
# receiver_stream = ADCpt(EpicsSignalWithRBV, "ReceiverStream")
# enable_data = ADCpt(EpicsSignalWithRBV, "UseDataCallback")
# missed_packets = ADCpt(EpicsSignalRO, "ReceiverMissedPackets_RBV")
# # Direct settings access
# setup_file = ADCpt(EpicsSignal, "SetupFile")
# load_setup = ADCpt(EpicsSignal, "LoadSetup")
# command = ADCpt(EpicsSignal, "Command")
# Mythen 3
# counter_mask = ADCpt(EpicsSignalWithRBV, "CounterMask")
# counter1_threshold = ADCpt(EpicsSignalWithRBV, "Counter1Threshold")
# counter2_threshold = ADCpt(EpicsSignalWithRBV, "Counter2Threshold")
# counter3_threshold = ADCpt(EpicsSignalWithRBV, "Counter3Threshold")
# gate1_delay = ADCpt(EpicsSignalWithRBV, "Gate1Delay")
# gate1_width = ADCpt(EpicsSignalWithRBV, "Gate1Width")
# gate2_delay = ADCpt(EpicsSignalWithRBV, "Gate2Delay")
# gate2_width = ADCpt(EpicsSignalWithRBV, "Gate2Width")
# gate3_delay = ADCpt(EpicsSignalWithRBV, "Gate3Delay")
# gate3_width = ADCpt(EpicsSignalWithRBV, "Gate3Width")
# Moench
# json_frame_mode = ADCpt(EpicsSignalWithRBV, "JsonFrameMode")
# json_detector_mode = ADCpt(EpicsSignalWithRBV, "JsonDetectorMode")
# Eiger9M
# delay_time = ADCpt(EpicsSignalWithRBV, "DelayTime")
# num_frames = ADCpt(EpicsSignalWithRBV, "NumFrames")
# acquire = ADCpt(EpicsSignal, "Acquire")
# acquire_time = ADCpt(EpicsSignal, 'AcquireTime')
# detector_state = ADCpt(EpicsSignalRO, "DetectorState_RBV")
# threshold_energy = ADCpt(EpicsSignalWithRBV, "ThresholdEnergy")
# num_gates = ADCpt(EpicsSignalWithRBV, "NumGates")
# num_cycles = ADCpt(EpicsSignalWithRBV, "NumCycles")
# timing_mode = ADCpt(EpicsSignalWithRBV, "TimingMode")
# Pilatus_2 300k
num_images = ADCpt(EpicsSignalWithRBV, "NumImages")
num_exposures = ADCpt(EpicsSignalWithRBV, "NumExposures")
delay_time = ADCpt(EpicsSignalWithRBV, "NumExposures")
trigger_mode = ADCpt(EpicsSignalWithRBV, "TriggerMode")
acquire = ADCpt(EpicsSignal, "Acquire")
armed = ADCpt(EpicsSignalRO, "Armed")
read_file_timeout = ADCpt(EpicsSignal, "ImageFileTmot")
detector_state = ADCpt(EpicsSignalRO, "StatusMessage_RBV")
status_message_camserver = ADCpt(EpicsSignalRO, "StringFromServer_RBV")
acquire_time = ADCpt(EpicsSignal, "AcquireTime")
acquire_period = ADCpt(EpicsSignal, "AcquirePeriod")
threshold_energy = ADCpt(EpicsSignalWithRBV, "ThresholdEnergy")
file_path = ADCpt(EpicsSignalWithRBV, "FilePath")
file_name = ADCpt(EpicsSignalWithRBV, "FileName")
file_number = ADCpt(EpicsSignalWithRBV, "FileNumber")
auto_increment = ADCpt(EpicsSignalWithRBV, "AutoIncrement")
file_template = ADCpt(EpicsSignalWithRBV, "FileTemplate")
file_format = ADCpt(EpicsSignalWithRBV, "FileNumber")
gap_fill = ADCpt(EpicsSignalWithRBV, "GapFill")
class PilatusCsaxs(DetectorBase): class PilatusCsaxs(DetectorBase):
"""Pilatus_2 300k detector for CSAXS """Pilatus_2 300k detector for CSAXS
@ -43,12 +106,12 @@ class PilatusCsaxs(DetectorBase):
Device class: PilatusDetectorCamEx Device class: PilatusDetectorCamEx
Attributes: Attributes:
name str: 'eiger' name str: 'pilatus_2'
prefix (str): PV prefix (X12SA-ES-PILATUS300K:) prefix (str): PV prefix (X12SA-ES-PILATUS300K:)
""" """
cam = ADCpt(PilatusDetectorCamEx, "cam1:") cam = ADCpt(SlsDetectorCam, "cam1:")
def __init__( def __init__(
self, self,
@ -91,7 +154,7 @@ class PilatusCsaxs(DetectorBase):
self.service_cfg = {"base_path": f"/sls/X12SA/data/{self.scaninfo.username}/Data10/"} self.service_cfg = {"base_path": f"/sls/X12SA/data/{self.scaninfo.username}/Data10/"}
self.scaninfo = BecScaninfoMixin(device_manager, sim_mode) self.scaninfo = BecScaninfoMixin(device_manager, sim_mode)
self.filepath = "" self.filepath_h5 = ""
self.filewriter = FileWriterMixin(self.service_cfg) self.filewriter = FileWriterMixin(self.service_cfg)
self.readout = 1e-3 # 3 ms self.readout = 1e-3 # 3 ms
@ -100,28 +163,6 @@ class PilatusCsaxs(DetectorBase):
msg = self.device_manager.producer.get(MessageEndpoints.scan_status()) msg = self.device_manager.producer.get(MessageEndpoints.scan_status())
return BECMessage.ScanStatusMessage.loads(msg) return BECMessage.ScanStatusMessage.loads(msg)
# def _load_scan_metadata(self) -> None:
# 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"],
# }
# self.scanID = scan_msg.content["scanID"]
# self.scan_number = scan_msg.content["info"]["scan_number"]
# self.exp_time = scan_msg.content["info"]["exp_time"]
# self.num_frames = scan_msg.content["info"]["num_points"]
# self.username = self.device_manager.producer.get(
# MessageEndpoints.account()
# ).decode()
# self.device_manager.devices.mokev.read()["mokev"]["value"]
# # self.triggermode = scan_msg.content["info"]["trigger_mode"]
# # self.filename = self.filewriter.compile_full_filename(
# # self.scan_number, "pilatus_2", 1000, 5, True
# # )
# # TODO fix with BEC running
# # self.filename = '/sls/X12SA/Data10/e21206/data/test.h5'
def _prep_det(self) -> None: def _prep_det(self) -> None:
# TODO slow reaction, seemed to have timeout. # TODO slow reaction, seemed to have timeout.
self._set_det_threshold() self._set_det_threshold()
@ -143,7 +184,7 @@ class PilatusCsaxs(DetectorBase):
# self.cam.acquire_period.set(self.exp_time + self.readout) # self.cam.acquire_period.set(self.exp_time + self.readout)
self.cam.num_images.set(int(self.scaninfo.num_points * self.scaninfo.frames_per_trigger)) self.cam.num_images.set(int(self.scaninfo.num_points * self.scaninfo.frames_per_trigger))
self.cam.num_exposures.set(1) self.cam.num_exposures.set(1)
self._set_trigger(TriggerSource.INTERNAL) # EXT_TRIGGER) self._set_trigger(TriggerSource.EXT_ENABLE) # EXT_TRIGGER)
def _set_trigger(self, trigger_source: TriggerSource) -> None: def _set_trigger(self, trigger_source: TriggerSource) -> None:
"""Set trigger source for the detector, either directly to value or TriggerSource.* with """Set trigger source for the detector, either directly to value or TriggerSource.* with
@ -164,12 +205,12 @@ class PilatusCsaxs(DetectorBase):
self.filepath_h5 = self.filewriter.compile_full_filename( self.filepath_h5 = self.filewriter.compile_full_filename(
self.scaninfo.scan_number, "pilatus_2.h5", 1000, 5, True self.scaninfo.scan_number, "pilatus_2.h5", 1000, 5, True
) )
self.cam.file_path.set(f"/dev/shm/zmq/") self.cam.file_path.put(f"/dev/shm/zmq/")
self.cam.file_name.set(f"{self.scaninfo.username}_2_{self.scaninfo.scan_number:05d}") self.cam.file_name.put(f"{self.scaninfo.username}_2_{self.scaninfo.scan_number:05d}")
self.cam.auto_increment.set(1) # auto increment self.cam.auto_increment.put(1) # auto increment
self.cam.file_number.set(0) # first iter self.cam.file_number.put(0) # first iter
self.cam.file_format.set(0) # 0: TIFF self.cam.file_format.put(0) # 0: TIFF
self.cam.file_template.set("%s%s_%5.5d.cbf") self.cam.file_template.put("%s%s_%5.5d.cbf")
# compile filename # compile filename
basepath = f"/sls/X12SA/data/{self.scaninfo.username}/Data10/pilatus_2/" basepath = f"/sls/X12SA/data/{self.scaninfo.username}/Data10/pilatus_2/"
@ -254,17 +295,19 @@ class PilatusCsaxs(DetectorBase):
if not res.ok: if not res.ok:
res.raise_for_status() res.raise_for_status()
except Exception as exc: except Exception as exc:
logger.info("exc") logger.info(f"Pilatus2 wait threw Exception: {exc}")
def _close_file_writer(self) -> None: def _close_file_writer(self) -> None:
"""Close the file writer for pilatus_2 """Close the file writer for pilatus_2
a zmq service is running on xbl-daq-34 that is waiting a zmq service is running on xbl-daq-34 that is waiting
for a zmq message to stop the writer for the pilatus_2 x12sa-pd-2 for a zmq message to stop the writer for the pilatus_2 x12sa-pd-2
""" """
try:
res = requests.delete(url="http://x12sa-pd-2:8080/stream/pilatus_2") res = requests.delete(url="http://x12sa-pd-2:8080/stream/pilatus_2")
if not res.ok: if not res.ok:
res.raise_for_status() res.raise_for_status()
except Exception as exc:
logger.info(f"Pilatus2 delete threw Exception: {exc}")
def _stop_file_writer(self) -> None: def _stop_file_writer(self) -> None:
res = requests.put( res = requests.put(
@ -278,34 +321,48 @@ class PilatusCsaxs(DetectorBase):
def stage(self) -> List[object]: def stage(self) -> List[object]:
"""stage the detector and file writer""" """stage the detector and file writer"""
self._close_file_writer()
self._stop_file_writer()
self.scaninfo.load_scan_metadata() self.scaninfo.load_scan_metadata()
self.mokev = self.device_manager.devices.mokev.obj.read()[ self.mokev = self.device_manager.devices.mokev.obj.read()[
self.device_manager.devices.mokev.name self.device_manager.devices.mokev.name
]["value"] ]["value"]
logger.info("Waiting for pilatus2 to be armed")
self._prep_det() self._prep_det()
logger.info("Pilatus2 armed")
logger.info("Waiting for pilatus2 zmq stream to be ready")
self._prep_file_writer() self._prep_file_writer()
self.acquire() logger.info("Pilatus2 zmq ready")
msg = BECMessage.FileMessage(
file_path=self.filepath_h5, done=False, metadata={"input_path": self.destination_path}
)
return super().stage() return super().stage()
def pre_scan(self) -> None:
self.acquire()
def unstage(self) -> List[object]: def unstage(self) -> List[object]:
"""unstage the detector and file writer""" """unstage the detector and file writer"""
# Reset to software trigger # Reset to software trigger
self.triggermode = 0 self.triggermode = 0
# TODO if images are missing, consider adding delay
self._close_file_writer() self._close_file_writer()
self._stop_file_writer() self._stop_file_writer()
# Only sent this out once data is written to disk since cbf to hdf5 converter will be triggered # Only sent this out once data is written to disk since cbf to hdf5 converter will be triggered
msg = BECMessage.FileMessage(file_path=self.filepath, done=True) msg = BECMessage.FileMessage(
file_path=self.filepath_h5, done=True, metadata={"input_path": self.destination_path}
)
self._producer.set_and_publish( self._producer.set_and_publish(
MessageEndpoints.public_file(self.scaninfo.scanID, self.name), MessageEndpoints.public_file(self.scaninfo.scanID, self.name),
msg.dumps(), msg.dumps(),
) )
msg = BECMessage.FileMessage(file_path=self.filepath, done=True)
self._producer.set_and_publish( self._producer.set_and_publish(
MessageEndpoints.file_event(self.name), MessageEndpoints.file_event(self.name),
msg.dumps(), msg.dumps(),
) )
logger.info("Pilatus2 done")
return super().unstage() return super().unstage()
def acquire(self) -> None: def acquire(self) -> None:

View File

@ -155,7 +155,8 @@ class GalilController(Controller):
def stop_all_axes(self) -> str: def stop_all_axes(self) -> str:
# return self.socket_put_and_receive(f"XQ#STOP,1") # return self.socket_put_and_receive(f"XQ#STOP,1")
# Command stops all threads and motors! # Command stops all threads and motors!
return self.socket_put_and_receive(f"ST") # self.socket_put_and_receive(f"ST")
return self.socket_put_and_receive(f"AB")
def axis_is_referenced(self) -> bool: def axis_is_referenced(self) -> bool:
return bool(float(self.socket_put_and_receive(f"MG allaxref").strip())) return bool(float(self.socket_put_and_receive(f"MG allaxref").strip()))
@ -405,7 +406,7 @@ class GalilSetpointSignal(GalilSignalBase):
Returns: Returns:
float: setpoint / target value float: setpoint / target value
""" """
return self.setpoint return self.setpoint * self.parent.sign
@retry_once @retry_once
@threadlocked @threadlocked