diff --git a/pxiii_bec/device_configs/x06da_device_config.yaml b/pxiii_bec/device_configs/x06da_device_config.yaml index 0f61b68..3221db5 100644 --- a/pxiii_bec/device_configs/x06da_device_config.yaml +++ b/pxiii_bec/device_configs/x06da_device_config.yaml @@ -57,7 +57,7 @@ sldi_sizex: softwareTrigger: false sldi_ceny: description: FE slit-diaphragm vertical center - deviceClass: ophyd_devices.EpicsMotorEC + deviceClass: ophyd.EpicsMotor deviceConfig: {prefix: 'X06DA-FE-SLDI:CENTERY'} onFailure: buffer enabled: true diff --git a/pxiii_bec/devices/A3200.py b/pxiii_bec/devices/A3200.py index 0303d8e..1241d1c 100644 --- a/pxiii_bec/devices/A3200.py +++ b/pxiii_bec/devices/A3200.py @@ -51,9 +51,9 @@ Examples """ import time -from ophyd import Component, EpicsSignal, EpicsSignalRO, Kind +from ophyd import Device, Component, EpicsSignal, EpicsSignalRO, Kind from ophyd.status import SubscriptionStatus -from ophyd_devices.interfaces.base_classes.bec_device_base import BECDeviceBase, CustomPrepare +from ophyd_devices.interfaces.base_classes.psi_device_base import PSIDeviceBase try: from .A3200enums import AbrCmd, AbrMode @@ -67,90 +67,7 @@ logger = bec_logger.logger # pylint: disable=logging-fstring-interpolation -class AerotechAbrMixin(CustomPrepare): - """Configuration class for the Aerotech A3200 controller for the ABR stage""" - - def on_stage(self): - """ - - NOTE: Zac's request is that stage is essentially ARM, i.e. get ready and don't do anything. - """ - - logger.warning(f"Configuring {self.parent.scaninfo.scan_msg.info['scan_name']} on ABR") - - d = {} - if self.parent.scaninfo.scan_type in ("measure", "measurement", "fly"): - scanargs = self.parent.scaninfo.scan_msg.info["kwargs"] - scanname = self.parent.scaninfo.scan_msg.info["scan_name"] - - if scanname in ( - "standardscan", - "helicalscan", - "helicalscan1", - "helicalscan2", - "helicalscan3", - ): - d["scan_command"] = AbrCmd.MEASURE_STANDARD - d["var_1"] = scanargs["start"] - d["var_2"] = scanargs["range"] - d["var_3"] = scanargs["move_time"] - d["var_4"] = scanargs.get("ready_rate", 500) - d["var_5"] = 0 - d["var_6"] = 0 - d["var_7"] = 0 - # d["var_8"] = 0 - # d["var_9"] = 0 - if scanname in ("verticallinescan", "vlinescan"): - d["scan_command"] = AbrCmd.VERTICAL_LINE_SCAN - d["var_1"] = scanargs["range"] / scanargs["steps"] - d["var_2"] = scanargs["steps"] - d["var_3"] = scanargs["exp_time"] - d["var_4"] = 0 - d["var_5"] = 0 - d["var_6"] = 0 - d["var_7"] = 0 - # d["var_8"] = 0 - # d["var_9"] = 0 - if scanname in ("screeningscan"): - d["scan_command"] = AbrCmd.SCREENING - d["var_1"] = scanargs["start"] - d["var_2"] = scanargs["oscrange"] - d["var_3"] = scanargs["exp_time"] - d["var_4"] = scanargs["range"] / scanargs["steps"] - d["var_5"] = scanargs["steps"] - d["var_6"] = scanargs.get("delta", 0.5) - d["var_7"] = 0 - # d["var_8"] = 0 - # d["var_9"] = 0 - if scanname in ("rasterscan", "rastersimplescan"): - d["scan_command"] = AbrCmd.RASTER_SCAN_SIMPLE - d["var_1"] = scanargs["exp_time"] - d["var_2"] = scanargs["range_x"] / scanargs["steps_x"] - d["var_3"] = scanargs["range_y"] / scanargs["steps_y"] - d["var_4"] = scanargs["steps_x"] - d["var_5"] = scanargs["steps_y"] - d["var_6"] = 0 - d["var_7"] = 0 - # d["var_8"] = 0 - # d["var_9"] = 0 - - # Reconfigure if got a valid scan config - if len(d) > 0: - self.parent.configure(d) - - # Stage the parent - self.parent.bluestage() - - def on_kickoff(self): - """Kick off parent""" - self.parent.bluekickoff() - - def on_unstage(self): - """Unstage the ABR controller""" - self.parent.blueunstage() - - -class AerotechAbrStage(BECDeviceBase): +class AerotechAbrStage(PSIDeviceBase, Device): """Standard PX stage on A3200 controller This is the wrapper class for the standard rotation stage layout for the PX @@ -161,8 +78,7 @@ class AerotechAbrStage(BECDeviceBase): it via 10+1 global variables. """ - custom_prepare_cls = AerotechAbrMixin - USER_ACCESS = ["reset", "kickoff", "bluekickoff", "complete", "set_axis_mode", "arm", "disarm"] + USER_ACCESS = ["reset", "kickoff", "complete", "set_axis_mode", "arm", "disarm"] taskStop = Component(EpicsSignal, "-AERO:TSK-STOP", put_complete=True, kind=Kind.omitted) status = Component(EpicsSignal, "-AERO:STAT", put_complete=True, kind=Kind.omitted) @@ -214,6 +130,30 @@ class AerotechAbrStage(BECDeviceBase): task4 = Component(EpicsSignalRO, "-AERO:TSK4-DONE", auto_monitor=True) scan_done = Component(EpicsSignal, "-GRD:SCAN-DONE", kind=Kind.config) + def __init__( + self, + prefix="", + *, + name, + kind=None, + read_attrs=None, + configuration_attrs=None, + parent=None, + scan_info=None, + **kwargs, + ): + # super() will call the mixin class + super().__init__( + prefix=prefix, + name=name, + kind=kind, + read_attrs=read_attrs, + configuration_attrs=configuration_attrs, + parent=parent, + scan_info=scan_info, + **kwargs, + ) + def set_axis_mode(self, mode: str, settle_time=0.1) -> None: """Set axis mode to direct/measurement mode. @@ -230,6 +170,86 @@ class AerotechAbrStage(BECDeviceBase): if mode == "measuring": self.axisAxesMode.set(AbrMode.MEASURING, settle_time=settle_time).wait() + def on_stage(self): + """ + + NOTE: Zac's request is that stage is essentially ARM, i.e. get ready and don't do anything. + """ + + logger.warning(f"Configuring {self.scaninfo.scan_msg.info['scan_name']} on ABR") + + d = {} + if self.scan_info.scan_type in ("measure", "measurement", "fly"): + # FIXME: I don't care about how we fish out config parameters from scan info + scan_args = { + **self.scan_info.msg.request_inputs["inputs"], + **self.scan_info.msg.request_inputs["kwargs"], + **self.scan_info.msg.scan_parameters, + } + scanname = self.scan_info.scan_msg.info["scan_name"] + + if scanname in ( + "standardscan", + "helicalscan", + "helicalscan1", + "helicalscan2", + "helicalscan3", + ): + d["scan_command"] = AbrCmd.MEASURE_STANDARD + d["var_1"] = scan_args["start"] + d["var_2"] = scan_args["range"] + d["var_3"] = scan_args["move_time"] + d["var_4"] = scan_args.get("ready_rate", 500) + d["var_5"] = 0 + d["var_6"] = 0 + d["var_7"] = 0 + # d["var_8"] = 0 + # d["var_9"] = 0 + if scanname in ("verticallinescan", "vlinescan"): + d["scan_command"] = AbrCmd.VERTICAL_LINE_SCAN + d["var_1"] = scan_args["range"] / scan_args["steps"] + d["var_2"] = scan_args["steps"] + d["var_3"] = scan_args["exp_time"] + d["var_4"] = 0 + d["var_5"] = 0 + d["var_6"] = 0 + d["var_7"] = 0 + # d["var_8"] = 0 + # d["var_9"] = 0 + if scanname in ("screeningscan"): + d["scan_command"] = AbrCmd.SCREENING + d["var_1"] = scan_args["start"] + d["var_2"] = scan_args["oscrange"] + d["var_3"] = scan_args["exp_time"] + d["var_4"] = scan_args["range"] / scan_args["steps"] + d["var_5"] = scan_args["steps"] + d["var_6"] = scan_args.get("delta", 0.5) + d["var_7"] = 0 + # d["var_8"] = 0 + # d["var_9"] = 0 + if scanname in ("rasterscan", "rastersimplescan"): + d["scan_command"] = AbrCmd.RASTER_SCAN_SIMPLE + d["var_1"] = scan_args["exp_time"] + d["var_2"] = scan_args["range_x"] / scan_args["steps_x"] + d["var_3"] = scan_args["range_y"] / scan_args["steps_y"] + d["var_4"] = scan_args["steps_x"] + d["var_5"] = scan_args["steps_y"] + d["var_6"] = 0 + d["var_7"] = 0 + # d["var_8"] = 0 + # d["var_9"] = 0 + + # Reconfigure if got a valid scan config + if len(d) > 0: + self.configure(d) + + # Stage the ABR stage + self.arm() + + def on_unstage(self): + """Unstage the ABR controller""" + self.disarm() + def configure(self, d: dict) -> tuple: """ " Configure the exposure scripts @@ -284,14 +304,14 @@ class AerotechAbrStage(BECDeviceBase): new = self.read_configuration() return old, new - def bluestage(self): + def arm(self): """Bluesky-style stage Since configuration synchronization is not guaranteed, this does nothing. The script launched by kickoff(). """ - def bluekickoff(self, timeout=1) -> SubscriptionStatus: + def on_kickoff(self, timeout=1) -> SubscriptionStatus: """Kick off the set program""" self.start_command.set(1).wait() @@ -304,7 +324,7 @@ class AerotechAbrStage(BECDeviceBase): status.wait() # return status - def blueunstage(self, settle_time=0.1): + def disarm(self, settle_time=0.1): """Stops current script and releases the axes""" # Disarm commands self.scan_command.set(AbrCmd.NONE, settle_time=settle_time).wait()