Source code for dodal.devices.i24.pmac

from enum import Enum

from bluesky.protocols import Triggerable
from ophyd_async.core import AsyncStatus, StandardReadable
from ophyd_async.core.signal import SignalRW
from ophyd_async.core.signal_backend import SignalBackend
from ophyd_async.core.soft_signal_backend import SoftSignalBackend
from ophyd_async.core.utils import DEFAULT_TIMEOUT
from ophyd_async.epics.motion import Motor
from ophyd_async.epics.signal import epics_signal_r, epics_signal_rw

HOME_STR = r"\#1hmz\#2hmz\#3hmz"  # Command to home the PMAC motors
ZERO_STR = "!x0y0z0"  # Command to blend any ongoing move into new position


[docs] class LaserSettings(str, Enum): """PMAC strings to switch laser on and off. Note. On the PMAC, M-variables usually have to do with position compare set up. For example, for laser1: Use M712 = 0 if triggering on falling edge. Use M712 = 1 if on rising edge. """ LASER_1_ON = " M712=1 M711=1" LASER_1_OFF = " M712=0 M711=1" LASER_2_ON = " M812=1 M811=1" LASER_2_OFF = " M812=0 M811=1"
[docs] class EncReset(str, Enum): """PMAC strings for position compare on encoder channels in the controller. For example, for ENC5: m508 sets position A to be compared with value in Channel5 in the controller. m509 sets position B to be compared with value in Channel5 in the controller. Note. These settings are usually used for initialisation. """ ENC5 = "m508=100 m509=150" ENC6 = "m608=100 m609=150" ENC7 = "m708=100 m709=150" ENC8 = "m808=100 m809=150"
[docs] class PMACStringMove(Triggerable): """Trigger a PMAC move by setting the pmac_string.""" def __init__( self, pmac_str_sig: SignalRW, string_to_send: str, ) -> None: self.signal = pmac_str_sig self.cmd_string = string_to_send @AsyncStatus.wrap async def trigger(self): await self.signal.set(self.cmd_string, wait=True)
[docs] class PMACStringLaser(SignalRW): """Set the pmac_string to control the laser.""" def __init__( self, pmac_str_sig: SignalRW, backend: SignalBackend, timeout: float | None = DEFAULT_TIMEOUT, name: str = "", ) -> None: self.signal = pmac_str_sig super().__init__(backend, timeout, name) @AsyncStatus.wrap async def set(self, laser_setting: LaserSettings): await self.signal.set(laser_setting.value, wait=True)
[docs] class PMACStringEncReset(SignalRW): """""" def __init__( self, pmac_str_sig: SignalRW, backend: SignalBackend, timeout: float | None = DEFAULT_TIMEOUT, name: str = "", ) -> None: self.signal = pmac_str_sig super().__init__(backend, timeout, name) @AsyncStatus.wrap async def set(self, enc_string: EncReset): await self.signal.set(enc_string.value, wait=True)
[docs] class PMAC(StandardReadable): """Device to control the chip stage on I24.""" def __init__(self, prefix: str, name: str = "") -> None: self.pmac_string = epics_signal_rw(str, prefix + "PMAC_STRING") self.home = PMACStringMove( self.pmac_string, HOME_STR, ) self.to_xyz_zero = PMACStringMove(self.pmac_string, ZERO_STR) self.laser = PMACStringLaser(self.pmac_string, backend=SoftSignalBackend(str)) self.enc_reset = PMACStringEncReset( self.pmac_string, backend=SoftSignalBackend(str) ) self.x = Motor(prefix + "X") self.y = Motor(prefix + "Y") self.z = Motor(prefix + "Z") # These next signals are readback values on PVARS which are set by the motion # program. self.scanstatus = epics_signal_r(float, "BL24I-MO-STEP-14:signal:P2401") self.counter = epics_signal_r(float, "BL24I-MO-STEP-14:signal:P2402") super().__init__(name)