class MPODChannelHV(MPODChannel): """ MPOD High Voltage Channel Object. Parameters ---------- channel_prefix : str The EPICS base of the MPOD Channel. E.g.: `XPP:R39:MPD:CH:100` card_prefix : str The EPICS base of the MPOD HV Module. E.g.: `XPP:R39:MPD:MOD:10` name: str A name to refer to the device. """ tab_component_names = True tab_whitelist = ['set_voltage_rise_rate', 'set_voltage_fall_rate'] voltage_rise_rate = FCpt(EpicsSignal, '{self._card_prefix}' + ':GetVoltageRiseRate', kind='normal', write_pv='{self._card_prefix}:SetVoltageRiseRate', doc='MPOD Channel Voltage Rise Rate [V/sec]') voltage_fall_rate = FCpt(EpicsSignal, '{self._card_prefix}' + ':GetVoltageFallRate', kind='normal', write_pv='{self._card_prefix}:SetVoltageFallRate', doc='MPOD Channel Set Voltage Fall Rate [V/sec]') def __init__(self, channel_prefix, card_prefix, name='mpod_hv_channel', **kwargs): self._card_prefix = card_prefix super().__init__(channel_prefix, name=name, **kwargs)
class SamPhi(BaseInterface, GroupDevice): """ Sample Phi stage. Parameters ---------- name : str A name to refer to the Sample Phi stage device. prefix_samz : str The EPICS base PV of the Sample Phi stage's z motor. prefix_samphi : str The EPICS base PV of the Sample Phi stage's phi motor. """ sam_z = FCpt(IMS, '{self._prefix_samz}', kind='normal') sam_phi = FCpt(IMS, '{self._prefix_samphi}', kind='normal') tab_component_names = True def __init__(self, *, name, prefix_samz, prefix_samphi, **kwargs): self._prefix_samz = prefix_samz self._prefix_samphi = prefix_samphi super().__init__('', name=name, **kwargs)
class Gantry(OMMotor): """ Gantry Axis. The horizontal and vertical motion of the OffsetMirror are controlled by two coupled stepper motors. Instructions are sent to both by simply requesting a move on the primary so they are represented here as a single motor with additional diagnostics and interlock. Parameters ---------- prefix : str Base prefix for both stepper motors e.g. 'XRT:M1H'. Do not include the 'P' or 'S' to indicate primary or secondary steppers. gantry_prefix : str, optional Prefix for the shared gantry diagnostics if it is different than the stepper motor prefix. """ # Readbacks for gantry information gantry_difference = FCpt(EpicsSignalRO, '{self.gantry_prefix}:GDIF', kind='normal') decoupled = FCpt(EpicsSignalRO, '{self.gantry_prefix}:DECOUPLE', kind='config') # Readbacks for the secondary motor follower_readback = FCpt(EpicsSignalRO, '{self.follow_prefix}:RBV', kind='normal') follower_low_limit_switch = FCpt(EpicsSignalRO, '{self.follow_prefix}:LLS', kind='omitted') follower_high_limit_switch = FCpt(EpicsSignalRO, '{self.follow_prefix}:HLS', kind='omitted') def __init__(self, prefix, *, gantry_prefix=None, **kwargs): self.gantry_prefix = gantry_prefix or 'GANTRY:' + prefix self.follow_prefix = prefix + ':S' super().__init__(prefix + ':P', **kwargs) def check_value(self, pos): """ Add additional check for the gantry coupling. This is not a safety measure, but instead just here largely for bookkeeping and to give the operator further feedback on why the requested move is not completed. """ # Check that the gantry is not decoupled if self.decoupled.get(): raise PermissionError("The gantry is not currently coupled") # Allow OMMotor to check the value super().check_value(pos)
class PPSStopper2PV(LightpathMixin, BaseInterface, Device): """ PPS Stopper with two PVs defining the state together. One PV is the state of the IN limit switch, one is the state of the OUT limit switch. By default, these stoppers have IN/NOT_IN and OUT/NOT_OUT PVs with a PV suffix of 'INSUM' and 'OUTSUM', but often this is not true and there are init arguments to get around these inconsistencies. We have no direct control over these from the photon side, so this Device only serves as a way to check status and display in the lightpath. In addition to standard device args, note the following additions: Parameters ---------- in_suffix : str, optional The suffix for the in_signal that tells us if the stopper is inserted or not. Defaults to 'INSUM'. out_suffix : str, optional The suffix for the out_signal that tells us if the stopper is removed or not. Defaults to 'OUTSUM' in_value : int, optional The value of the in_signal that tells us that the stopper is inserted. Defaults to 1. out_value : int, optional The value of the out_signal that tells us that the stopper is removed. Defaults to 1. """ in_signal = FCpt(EpicsSignalRO, '{prefix}{in_suffix}', kind='hinted', doc='Tells us if the stopper is IN or NOT_IN') out_signal = FCpt(EpicsSignalRO, '{prefix}{out_suffix}', kind='hinted', doc='Tells us if the stopper is OUT or NOT_OUT') # QIcon for UX _icon = 'fa.times-circle' # Lightpath settings lightpath_cpts = ['in_signal', 'out_signal'] def __init__(self, prefix, *, in_suffix='INSUM', out_suffix='OUTSUM', in_value=1, out_value=1, **kwargs): self.in_suffix = in_suffix self.out_suffix = out_suffix self.in_value = in_value self.out_value = out_value super().__init__(prefix, **kwargs) def _set_lightpath_states(self, lightpath_values): self._inserted = (lightpath_values[self.in_signal]['value'] == self.in_value) self._removed = (lightpath_values[self.out_signal]['value'] == self.out_value)
class SlitPositioner(PVPositioner, FltMvInterface): """ Abstraction of a Slit axis. Each adjustable parameter of the slit (center, width) can be modeled as a motor in itself, even though each controls two different actual motors in reality, this gives a convienent interface for adjusting the aperture size and location with out backwards calculating motor positions. Parameters ---------- prefix : str The prefix location of the slits, e.g. 'MFX:DG2'. name : str Alias for the axis. slit_type : {'XWIDTH', 'YWIDTH', 'XCENTER', 'YCENTER'} The aspect of the slit position you would like to control with this specific motor. limits : tuple, optional Limits on the motion of the positioner. By default, the limits on the setpoint PV are used if `None` is given. See Also -------- `ophyd.PVPositioner` SlitPositioner inherits directly from `~ophyd.PVPositioner`. """ readback = FCpt(EpicsSignalRO, '{self.prefix}:ACTUAL_{self._dirlong}', auto_monitor=True, kind='hinted') setpoint = FCpt(EpicsSignal, '{self.prefix}:{self._dirshort}_REQ', auto_monitor=True, kind='normal') done = Cpt(EpicsSignalRO, ':DMOV', auto_monitor=True, kind='omitted') def __init__(self, prefix, *, slit_type="", name=None, limits=None, **kwargs): # Private PV names to deal with complex naming schema self._dirlong = slit_type self._dirshort = slit_type[:4] # Initalize PVPositioner super().__init__(prefix, limits=limits, name=name, **kwargs) @property def egu(self): """EnGineering Units.""" return self._egu or self.readback._read_pv.units def _setup_move(self, position): # This is subclassed because we need `wait` to be set to False unlike # the default PVPositioner method. `wait` set to True will not return # until the move has completed logger.debug('%s.setpoint = %s', self.name, position) self.setpoint.put(position, wait=False)
class GonWithDetArm(BaseGon): """ Goniometer with a detector arm, as present in XCS. This requires eleven motor PV prefixes to be passed in as keyword arguments, and they are all labelled accordingly. Parameters ---------- name : str A name to refer to the goniometer device. prefix_hor : str The EPICS base PV of the common-horizontal motor. prefix_ver : str The EPICS base PV of the common-vertical motor. prefix_rot : str The EPICS base PV of the common-rotation motor. prefix_tip : str The EPICS base PV of the sample-stage's tip motor. prefix_tilt : str The EPICS base PV of the sample-stage's tilt motor. prefix_2theta : str The EPICS base PV of the detector arm's 2theta rotation motor. prefix_dettilt : str The EPICS base PV of the detector stage's tilt motor. prefix_detver : str The EPICS base PV of the detector stage's vertical motor. """ rot_2theta = FCpt(IMS, '{self._prefix_2theta}', kind='normal') det_tilt = FCpt(IMS, '{self._prefix_dettilt}', kind='normal') det_ver = FCpt(IMS, '{self._prefix_detver}', kind='normal') def __init__(self, *, name, prefix_2theta, prefix_dettilt, prefix_detver, prefix_hor, prefix_ver, prefix_rot, prefix_tip, prefix_tilt, **kwargs): self._prefix_2theta = prefix_2theta self._prefix_dettilt = prefix_dettilt self._prefix_detver = prefix_detver super().__init__(name=name, prefix_hor=prefix_hor, prefix_ver=prefix_ver, prefix_rot=prefix_rot, prefix_tip=prefix_tip, prefix_tilt=prefix_tilt, **kwargs)
class BadSlitPositionerBase(FltMvInterface, PVPositioner): """Base class for slit positioner with awful PV names.""" readback = FCpt(EpicsSignalRO, '{prefix}:ACTUAL_{_dirlong}', auto_monitor=True, kind='normal') setpoint = FCpt(EpicsSignal, '{prefix}:{_dirshort}_REQ', auto_monitor=True, kind='normal') def __init__(self, prefix, *, slit_type="", limits=None, **kwargs): # Private PV names to deal with complex naming schema self._dirlong = slit_type self._dirshort = slit_type[:4] # Initalize PVPositioner super().__init__(prefix, limits=limits, **kwargs)
class PIM(PIMMotor): """ Profile intensity monitor, fully motorized and with a detector. Parameters ---------- prefix : str The EPICS base of the motor name : str A name to refer to the device prefix_det : str, optional The EPICS base PV of the detector. If None, it will be inferred from the motor prefix """ detector = FCpt(PCDSDetector, "{self._prefix_det}") _default_read_attrs = ['state', 'readback', 'detector'] def __init__(self, prefix, *, name, prefix_det=None, **kwargs): # Infer the detector PV from the motor PV if not prefix_det: self._section = prefix.split(":")[0] self._imager = prefix.split(":")[1] self._prefix_det = "{0}:{1}:CVV:01".format( self._section, self._imager) else: self._prefix_det = prefix_det super().__init__(prefix, name=name, **kwargs)
class IPM(InOutRecordPositioner): """ Standard intensity position monitor. This is an `InOutRecordPositioner` that moves the target position to any of the four set positions, or out. Valid states are (1, 2, 3, 4, 5) or the equivalent (TARGET1, TARGET2, TARGET3, TARGET4, OUT). IPMs each also have a diode, which is implemented as the diode attribute of this class. This can easily be controlled using ``ipm.diode.insert()`` or ``ipm.diode.remove()``. """ __doc__ += basic_positioner_init state = Cpt(EpicsSignal, ':TARGET', write_pv=':TARGET:GO', kind='hinted') diode = Cpt(InOutRecordPositioner, ':DIODE', kind='omitted') readback = FCpt(EpicsSignalRO, '{self.prefix}:TARGET:{self._readback}', kind='normal') in_states = ['TARGET1', 'TARGET2', 'TARGET3', 'TARGET4'] states_list = in_states + ['OUT'] # Assume that having any target in gives transmission 0.8 _transmission = {st: 0.8 for st in in_states}
def mps_factory(clsname, cls, *args, mps_prefix, veto=False, **kwargs): """ Create a new object of arbitrary class capable of storing MPS information. A new class identical to the provided one is created, but with additional attribute ``mps`` that relies upon the provided `.mps_prefix`. All other information is passed through to the class constructor as args and kwargs Parameters ---------- clsname : str Name of new class to create. cls : type Device class to add ``mps``. mps_prefix : str Prefix for MPS subcomponent. veto : bool, optional Whether the MPS bit is capable of veto. args : Passed to device constructor. kwargs: Passed to device constructor. """ comp = FCpt(MPS, mps_prefix, veto=veto) cls = type(clsname, (cls, ), {'mps': comp}) return cls(*args, **kwargs)
class LaserShutter(InOutPositioner): """Controls shutter controlled by Analog Output""" # EpicsSignals voltage = Cpt(EpicsSignal, '') state = FCpt(AttributeSignal, 'voltage_check') # Constants out_voltage = 4.5 in_voltage = 0.0 barrier_voltage = 1.4 @property def voltage_check(self): """Return the position we believe shutter based on the channel""" if self.voltage.get() >= self.barrier_voltage: return 'OUT' else: return 'IN' def _do_move(self, state): """Override to just put to the channel""" if state.name == 'IN': self.voltage.put(self.in_voltage) elif state.name == 'OUT': self.voltage.put(self.out_voltage) else: raise ValueError("%s is in an invalid state", state)
class EllBase(Device): """ Base class for Elliptec stages. """ set_position = FCpt(EpicsSignal, '{prefix}:M{self._channel}:CURPOS', write_pv='{prefix}:M{self._channel}:MOVE', kind='normal') jog_fwd = FCpt(EpicsSignal, '{prefix}:M{self._channel}:MOVE_FWD', kind='normal') set_metadata(jog_fwd, dict(variety='command-proc', value=1)) jog_bwd = FCpt(EpicsSignal, '{prefix}:M{self._channel}:MOVE_BWD', kind='normal') set_metadata(jog_bwd, dict(variety='command-proc', value=1)) status = FCpt(EpicsSignalRO, '{prefix}:M{self._channel}:STATUS', kind='normal') optimize = FCpt(EpicsSignal, '{prefix}:M{self._channel}:OPTIMIZE', kind='omitted') set_metadata(optimize, dict(variety='command-proc', value=1)) _from_addr = FCpt(EpicsSignal, '{prefix}:PORT{self._port}:FROM_ADDR', kind='omitted') _to_addr = FCpt(EpicsSignal, '{prefix}:PORT{self._port}:TO_ADDR', kind='omitted') _save = FCpt(EpicsSignal, '{prefix}:PORT{self._port}:SAVE', kind='omitted') _command = FCpt(EpicsSignal, '{prefix}:PORT{self._port}:CMD', kind='omitted') _response = FCpt(EpicsSignalRO, '{prefix}:PORT{self._port}:RESPONSE', kind='omitted') def __init__(self, prefix, port=0, channel=1, **kwargs): self._port = port self._channel = channel super().__init__(prefix, **kwargs)
class Pitch(OMMotor): """ HOMS Pitch Mechanism The axis is actually a piezo actuator and a stepper motor in series, and this is reflected in the PV naming """ __doc__ += basic_positioner_init piezo_volts = FCpt(EpicsSignalRO, "{self._piezo}:VRBV", kind='normal') stop_signal = FCpt(EpicsSignal, "{self._piezo}:STOP", kind='omitted') # TODO: Limits will be added soon, but not present yet def __init__(self, prefix, **kwargs): # Predict the prefix of all piezo pvs self._piezo = prefix.replace('MIRR', 'PIEZO') super().__init__(prefix, **kwargs)
class MCMBase(PVPositioner): setpoint = FCpt(EpicsSignal, '{self.prefix}{self._ch_name}') readback = FCpt(EpicsSignal, '{self.prefix}{self._ch_name}') actuate = Cpt(EpicsSignal, '}Mov') actuate_value = 1 stop_signal = Cpt(EpicsSignal, '}Kill') stop_value = 1 # all six axes are coupled, so 'InPos' is an array of six values done = Cpt(EpicsSignal, '}InPos') done_value = True def __init__(self, prefix, ch_name=None, **kwargs): self._ch_name = ch_name super().__init__(prefix, **kwargs) @property def moving(self): return (self.done_value != all(self.done.get(use_monitor=False)))
class PowerSlits(Device, BaseInterface): """ 'SL*:POWER'. Power slits variant of slits. The XTES design. Parameters ---------- prefix : str The PV base of the device. """ top = FCpt(EpicsMotor, '{self.prefix}:MMS:TOP', kind='normal') bottom = FCpt(EpicsMotor, '{self.prefix}:MMS:BOTTOM') north = FCpt(EpicsMotor, '{self.prefix}:MMS:NORTH') south = FCpt(EpicsMotor, '{self.prefix}:MMS:SOUTH') rtds = DDCpt(_rtd_fields(RTD, 'rtd', range(1, 9))) fsw = Cpt(EpicsSignalRO, ':FSW', kind='normal')
class BaseGon(Device, BaseInterface): """ Basic goniometer, as present in XPP. This requires eight motor PV prefixes to be passed in as keyword arguments, and they are all labelled accordingly. Parameters ---------- name : str A name to refer to the goniometer device. prefix_hor : str The EPICS base PV of the common-horizontal motor. prefix_ver : str The EPICS base PV of the common-vertical motor. prefix_rot : str The EPICS base PV of the common-rotation motor. prefix_tip : str The EPICS base PV of the sample-stage's tip motor. prefix_tilt : str The EPICS base PV of the sample-stage's tilt motor. """ hor = FCpt(IMS, '{self._prefix_hor}', kind='normal') ver = FCpt(IMS, '{self._prefix_ver}', kind='normal') rot = FCpt(IMS, '{self._prefix_rot}', kind='normal') tip = FCpt(IMS, '{self._prefix_tip}', kind='normal') tilt = FCpt(IMS, '{self._prefix_tilt}', kind='normal') tab_component_names = True def __init__(self, *, name, prefix_hor, prefix_ver, prefix_rot, prefix_tip, prefix_tilt, **kwargs): self._prefix_hor = prefix_hor self._prefix_ver = prefix_ver self._prefix_rot = prefix_rot self._prefix_tip = prefix_tip self._prefix_tilt = prefix_tilt super().__init__('', name=name, **kwargs)
class ICTChannel(Device): """ Class to define a particular channel of the ICT Parameters --------- prefix : ``str`` The PV base of the relevant ICT channel : ``str`` The output channel on the ICT, e.g. '1A', '3B', etc Usage --------- ICTChannel('TST:PWR:ICT:01', '2B' ) """ ch_current = FCpt(EpicsSignalRO, '{self.prefix}:Output{self._ch}:Current', kind='hinted') ch_status = FCpt(EpicsSignal, '{self.prefix}:Output{self._ch}:GetState', write_pv='{self.prefix}:Output{self._ch}:SetState', kind='hinted', string=True) ch_name = FCpt(EpicsSignal, '{self.prefix}:Output{self._ch}.DESC', kind='hinted') breaker_status = FCpt(EpicsSignalRO, '{self.prefix}:Output{self._ch}:BreakerStatus', kind='hinted', string=True) def __init__(self, prefix, channel, name='ICT_channel', **kwargs): self._ch = f'{channel.upper()}' super().__init__(prefix, name=name, **kwargs) def on(self): self.ch_status.put(0) def off(self): self.ch_status.put(1) def current(self): return self.ch_current.get()
class SmarpodBase(PVPositionerPC): readback = FCpt(EpicsSignal, '') # readback placeholder actuate = Cpt(EpicsSignal, 'XF:03IDC-ES{SPod:1}Move-Cmd.PROC') actuate_value = 1 done = Cpt(EpicsSignalRO, 'XF:03IDC-ES{SPod:1}Moving-I') done_value = 1 def __init__(self, prefix='', axis=0, **kwargs): self.axis = axis super().__init__(prefix='', **kwargs)
class QminiWithEvr(QminiSpectrometer): """ A class for Qmini spectrometers that use an EVR for hardware triggering. """ def __init__(self, prefix, *args, evr_pv=None, evr_ch=None, **kwargs): self._evr_pv = evr_pv self._evr_ch = evr_ch super().__init__(prefix, **kwargs) event_code = FCpt(EpicsSignal, '{self._evr_pv}:TRIG{self._evr_ch}:EC_RBV', write_pv='{self._evr_pv}:TRIG{self._evr_ch}:TEC', kind='config') evr_width = FCpt(EpicsSignal, '{self._evr_pv}:TRIG{self._evr_ch}:BW_TWIDCALC', write_pv='{self._evr_pv}:TRIG{self._evr_ch}:TWID', kind='config') evr_delay = FCpt(EpicsSignal, '{self._evr_pv}:TRIG{self._evr_ch}:BW_TDES', write_pv='{self._evr_pv}:TRIG{self._evr_ch}:TDES', kind='config')
class GaugeSetPirani(GaugeSetBase): """ %s """ __doc__ = __doc__ % GaugeSet_base gpi = FCpt(GaugePirani, '{self.prefix}:GPI:{self.index}') tab_component_names = True def pressure(self): if self.gcc.state.get() == 0: return self.gcc.pressure.get() else: return self.gpi.pressure.get()
class XYZStage(BaseInterface, Device): """ Sample XYZ stage. Parameters ---------- name : str A name to refer to the device prefix_x : str The EPICS base PV of the sample-stage's x motor. prefix_y : str The EPICS base PV of the sample-stage's y motor. prefix_z : str The EPICS base PV of the sample-stage's z motor. """ x = FCpt(IMS, '{self._prefix_x}', kind='normal') y = FCpt(IMS, '{self._prefix_y}', kind='normal') z = FCpt(IMS, '{self._prefix_z}', kind='normal') tab_component_names = True def __init__(self, *, name, prefix_x, prefix_y, prefix_z, **kwargs): self._prefix_x = prefix_x self._prefix_y = prefix_y self._prefix_z = prefix_z super().__init__('', name=name, **kwargs) def format_status_info(self, status_info): """Override status info handler to render the `XYZStage`.""" x = get_status_float(status_info, 'x', 'position') y = get_status_float(status_info, 'y', 'position') z = get_status_float(status_info, 'z', 'position') units = get_status_value(status_info, 'x', 'user_setpoint', 'units') return f"""\
class BeckhoffSlitPositioner(BadSlitPositionerBase): """ Abstraction of a Slit axis from LCLS-II. This class needs a BeckhoffSlits parent to function properly. """ readback = FCpt(PytmcSignal, BadSlitPositionerBase.readback.suffix, io='i', auto_monitor=True, kind='normal') setpoint = FCpt(PytmcSignal, BadSlitPositionerBase.setpoint.suffix, io='io', auto_monitor=True, kind='normal') done = Cpt(Signal, kind='omitted') actuate = Cpt(Signal, kind='omitted') @actuate.sub_value def _execute_move(self, *args, value, **kwargs): if value == 1: self.parent.exec_queue.put(1) @done.sub_value def _reset_actuate(self, *args, value, old_value, **kwargs): if value == 1 and old_value == 0: self.actuate.put(0)
class M5_axis(PVPositioner): done = FCpt(EpicsSignalRO, '{self._sliced_prefix}Sts:MoveDone-Sts') def __init__(self, prefix, *args, **kwargs): self._sliced_prefix = ''.join(prefix.partition('}')[:2]) super().__init__(prefix, *args, **kwargs) self.readback.name = self.name readback = Cpt(EpicsSignalRO, "-I") setpoint = Cpt(EpicsSignal, "-SP") done_value=1 # Define the class properties here @property def hints(self): return{'fields':[self.readback.name]}
class Ell6(EllBase): """ Class for Thorlabs ELL6 2 position filter slider. Parameters ---------- prefix : str The PV base of the stage. channel : str The motor channel on the controller (0-F) port : str The port of the Elliptec controller (typically 0) Examples -------- ell6 = Ell6('LM1K4:COM_DP1_TF1_SL1:ELL', port=0, channel=1, name='ell6') """ # Names for slider positions name_0 = FCpt(EpicsSignal, '{prefix}:M{self._channel}:NAME0', kind='config') name_1 = FCpt(EpicsSignal, '{prefix}:M{self._channel}:NAME1', kind='config')
class GaugeSetPiraniMks(GaugeSetPirani): """ %s prefix_controller : ``str`` Base PV for the controller """ __doc__ = (__doc__ % GaugeSet_base).replace( 'Set', 'Set including the controller') controller = FCpt(MKS937a, '{self.prefix_controller}') tab_component_names = True def __init__(self, prefix, *, name, index, prefix_controller, **kwargs): self.prefix_controller = prefix_controller super().__init__(prefix, name=name, index=index, **kwargs) def egu(self): return self.controller.unit.get()
class IonPumpWithController(IonPumpBase): """ %s prefix_controller : str Ion Pump Controller base PV. """ __doc__ = (__doc__ % IonPump_base).replace('Pump', 'Pump w/ controller') controller = FCpt(GammaController, '{self.prefix_controller}') tab_component_names = True def __init__(self, prefix, *, prefix_controller, **kwargs): # base PV for ion pump controller self.prefix_controller = prefix_controller # Load Ion Pump itself super().__init__(prefix, **kwargs) def egu(self): return self.controller.unit.get()
class Kappa(Device, BaseInterface): """ Kappa stage. Parameters ---------- name : str A name to refer to the Kappa stage device. prefix_x : str The EPICS base PV of the Kappa stage's x motor. prefix_y : str The EPICS base PV of the Kappa stage's y motor. prefix_z : str The EPICS base PV of the Kappa stage's z motor. prefix_eta : str The EPICS base PV of the Kappa stage's eta motor. prefix_kappa : str The EPICS base PV of the Kappa stage's kappa motor. prefix_phi : str The EPICS base PV of the Kappa stage's phi motor. """ x = FCpt(IMS, '{self._prefix_x}', kind='normal') y = FCpt(IMS, '{self._prefix_y}', kind='normal') z = FCpt(IMS, '{self._prefix_z}', kind='normal') eta = FCpt(IMS, '{self._prefix_eta}', kind='normal') kappa = FCpt(IMS, '{self._prefix_kappa}', kind='normal') phi = FCpt(IMS, '{self._prefix_phi}', kind='normal') tab_component_names = True def __init__(self, *, name, prefix_x, prefix_y, prefix_z, prefix_eta, prefix_kappa, prefix_phi, **kwargs): self._prefix_x = prefix_x self._prefix_y = prefix_y self._prefix_z = prefix_z self._prefix_eta = prefix_eta self._prefix_kappa = prefix_kappa self._prefix_phi = prefix_phi super().__init__('', name=name, **kwargs)
class GaugeSetBase(Device, BaseInterface): """ %s """ __doc__ = __doc__ % GaugeSet_base gcc = FCpt(GaugeColdCathode, '{self.prefix}:GCC:{self.index}') tab_component_names = True def __init__(self, prefix, *, name, index, **kwargs): if isinstance(index, int): self.index = '%02d' % index else: self.index = index super().__init__(prefix, name=name, **kwargs) def pressure(self): if self.gcc.state.get() == 0: return self.gcc.pressure.get() else: return -1. def egu(self): return self.gcc.egu.get()
class LaserShutterMPD(InOutPositioner): """Controls shutter controlled by Mpod""" # EpicsSignals voltage = Cpt(EpicsSignal, ':GetVoltageMeasurement', write_pv=':SetVoltage', kind='normal') switch = Cpt(EpicsSignal, ':GetSwitch', write_pv=':SetSwitch', kind='normal') #voltage = Cpt(EpicsSignal, '') vstate = FCpt(AttributeSignal, 'voltage_check') # Constants out_voltage = 24.0 in_voltage = 1.0 barrier_voltage = 1.4 @property def voltage_check(self): """Return the position we believe shutter based on the channel""" if self.switch.get() != 1: print('Channel not on, fixing it') self.switch.put(1) if self.voltage.get() >= self.barrier_voltage: return 'OUT' else: return 'IN' def _do_move(self, state): """Override to just put to the channel""" if state.name == 'IN': self.voltage.put(self.in_voltage) elif state.name == 'OUT': self.voltage.put(self.out_voltage) else: raise ValueError("%s is in an invalid state", state)
class EllLinear(EllBase): """ Class for Thorlabs ELL17/20 (28/60mm) linear stage. Parameters ---------- prefix : str The PV base of the stage. channel : str The motor channel on the controller (0-F) port : str The port of the Elliptec controller (typically 0) Examples -------- ell17 = EllLinear('LM1K4:COM_DP1_TF1_LIN1:ELL', port=0, channel=1, name='ell17') """ home = FCpt(EpicsSignal, '{prefix}:M{self._channel}:HOME', kind='config') set_metadata(home, dict(variety='command-proc', value=1)) jog_step = FCpt(EpicsSignal, '{prefix}:M{self._channel}:GET_JOG', write_pv='{prefix}:M{self._channel}:SET_JOG', kind='config') clean = FCpt(EpicsSignal, '{prefix}:M{self._channel}:CLEAN_MECH', kind='omitted') set_metadata(clean, dict(variety='command-proc', value=1)) stop_optimize = FCpt(EpicsSignal, '{prefix}:M{self._channel}:STOP', kind='omitted') set_metadata(stop_optimize, dict(variety='command-proc', value=1)) current_egu = FCpt(EpicsSignal, '{prefix}:M{self._channel}:CURPOS.EGU', kind='omitted') target_egu = FCpt(EpicsSignal, '{prefix}:M{self._channel}:MOVE.EGU', kind='omitted')