class Stopper(InOutPVStatePositioner): """ Controls Stopper A base class for a device with two limits switches controlled via an external command PV. This fully encompasses the controls `Stopper` installations as well as un-interlocked `GateValves` Parameters ---------- prefix : ``str`` Full PPS Stopper PV name : ``str`` Alias for the stopper Attributes ---------- commands : ``Enum`` An enum with integer values for ``open_valve``, ``close_valve`` values """ # Default attributes _default_read_attrs = ['open_limit', 'closed_limit'] # Limit-based states open_limit = C(EpicsSignalRO, ':OPEN') closed_limit = C(EpicsSignalRO, ':CLOSE') # Information on device control command = C(EpicsSignal, ':CMD') commands = Commands _state_logic = { 'open_limit': { 0: 'defer', 1: 'OUT' }, 'closed_limit': { 0: 'defer', 1: 'IN' } } def _do_move(self, state): if state.name == 'IN': self.command.put(self.commands.close_valve.value) elif state.name == 'OUT': self.command.put(self.commands.open_valve.value) def open(self, **kwargs): """ Open the stopper """ return self.remove(**kwargs) def close(self, **kwargs): """ Close the stopper """ return self.insert(**kwargs)
class Highland(Device): """Class for the MEC Highland pulse shaper.""" # Epics Signals pulse_heights = C(EpicsSignal, ':PulseHeights') pulse_heights_rbv = C(EpicsSignalRO, ':PulseHeights_RBV') fiducial_delay_rbv = C(EpicsSignalRO, ':FiducialDelay_RBV') fiducial_height_rbv = C(EpicsSignalRO, ':FiducialHeight_RBV') def write_pulse(self, pulse): """Write list of pulse heights to Highland.""" self.pulse_heights.put(pulse) @property def pulse_rbv(self): """Returns list of current pulse heights.""" heights = self.pulse_heights_rbv.get() return heights @property def fiducial_delay(self): """Return current fiducial delay.""" delay = self.fiducial_delay_rbv.get() return delay @property def fiducial_height(self): """Return current fiducial height.""" height = self.fiducial_height_rbv.get() return height
class GateValve(Stopper): """ Basic Vacuum Valve This inherits directly from :class:`.Stopper` but adds additional logic to check the state of the interlock before requesting motion. This is not a safety feature, just a notice to the operator. """ # Limit based states open_limit = C(EpicsSignalRO, ':OPN_DI') closed_limit = C(EpicsSignalRO, ':CLS_DI') # Commands and Interlock information command = C(EpicsSignal, ':OPN_SW') interlock = C(EpicsSignalRO, ':OPN_OK') @property def interlocked(self): """ Whether the interlock on the valve is active, preventing the valve from opening """ return bool(self.interlock.get()) def remove(self, **kwargs): """ Remove the valve from the beam """ if self.interlocked: raise InterlockError('Valve is currently forced closed') return super().remove(**kwargs)
class SrxXspress3Detector(XspressTrigger, Xspress3Detector): roi_data = Cpt(PluginBase, 'ROIDATA:') channel1 = C(Xspress3Channel, 'C1_', channel_num=1, read_attrs=['rois']) channel2 = C(Xspress3Channel, 'C2_', channel_num=2, read_attrs=['rois']) channel3 = C(Xspress3Channel, 'C3_', channel_num=3, read_attrs=['rois']) channel4 = C(Xspress3Channel, 'C4_', channel_num=4, read_attrs=['rois']) # create_dir = Cpt(EpicsSignal, 'HDF5:FileCreateDir') hdf5 = Cpt(Xspress3FileStore, 'HDF5:', read_path_template='/nsls2/xf04bm/data/x3m/%Y/%m/%d/', root='/nsls2/xf04bm/data/', write_path_template='/nsls2/xf04bm/data/x3m/%Y/%m/%d/', ) def __init__(self, prefix, *, configuration_attrs=None, read_attrs=None, **kwargs): if configuration_attrs is None: configuration_attrs = ['external_trig', 'total_points', 'spectra_per_point', 'settings', 'rewindable'] if read_attrs is None: read_attrs = ['channel1', 'channel2', 'channel3', 'channel4', 'hdf5'] super().__init__(prefix, configuration_attrs=configuration_attrs, read_attrs=read_attrs, **kwargs) # self.create_dir.put(-3) def stop(self): ret = super().stop() self.hdf5.stop() return ret def stage(self): ret = super().stage() # self._resource_uid = self._resource return ret
class MyPositioner(PVPositioner): '''Setpoint, readback, done, stop. No put completion''' setpoint = C(EpicsSignal, '.VAL') readback = C(EpicsSignalRO, '.RBV') done = C(EpicsSignalRO, '.MOVN') stop_signal = C(EpicsSignal, '.STOP') stop_value = 1 done_value = 0
class XPDShutter(Device): cmd = C(EpicsSignal, 'Cmd-Cmd') close_sts = C(EpicsSignalRO, 'Sw:Cls1-Sts') open_sts = C(EpicsSignalRO, 'Sw:Opn1-Sts') def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._st = None self._target = None self.close_sts.subscribe(self._watcher_close, self.close_sts.SUB_VALUE) self.open_sts.subscribe(self._watcher_open, self.open_sts.SUB_VALUE) def set(self, value, *, wait=False, **kwargs): if value not in ('Open', 'Close'): raise ValueError( "must be 'Open' or 'Close', not {!r}".format(value)) if wait: raise RuntimeError() if self._st is not None: raise RuntimeError() self._target = value self._st = st = DeviceStatus(self, timeout=None) self.cmd.put(value) return st def _watcher_open(self, *, old_value=None, value=None, **kwargs): print("in open watcher", old_value, value) if self._target != 'Open': return if self._st is None: return if new_value: self._st._finished() self._target = None self._st = None print("in open watcher") def _watcher_close(self, *, old_value=None, value=None, **kwargs): print("in close watcher", old_value, value) if self._target != 'Close': return if self._st is None: return if new_value: self._st._finished() self._target = None self._st = None pass
class MPSLimits(MPSBase, Device): """ Logical combination of two MPS bits For devices that are inserted and removed from the beam, the MPS system The MPSLimits class is to determine what action is to be taken based on the MPS values of a device pertaining to a single device. If a device has two MPS values, there is certain logic that needs to be followed to determine whether or not the beam is allowed through. Parameters ---------- prefix : ``str`` Base of the MPS PVs name : ``str`` Name of the MPS combination logic: ``callable`` Determine whether the MPS is faulted based on the state of each limit. The function signature should look like: .. code:: def logic(in_limit: bool, out_limit: bool) -> bool """ # Individual limits in_limit = C(MPS, '_IN') out_limit = C(MPS, '_OUT') def __init__(self, prefix, logic, **kwargs): self.logic = logic super().__init__(prefix, **kwargs) @property def faulted(self): """ This property determines whether the two MPS values are faulted and applies a logic function depending on the states of mps_A and mps_B. """ return self.logic(self.in_limit.faulted, self.out_limit.faulted) @property def bypassed(self): """ Whether either limit is bypassed """ return self.in_limit.bypassed or self.out_limit.bypassed def _sub_to_children(self): self.in_limit.subscribe(self._fault_change, event_type=self.in_limit.SUB_FAULT_CH) self.in_limit.subscribe(self._fault_change, event_type=self.out_limit.SUB_FAULT_CH)
class MPS(MPSBase, Device): """ Class to interpret a single bit of MPS information There are three major attributes of each MPS bit that are relevant to operations; :attr:`.faulted` , :attr:`.bypassed` and :attr:`.veto_capable`. The first is the most obvious, when the device is faulted it reports as such to the MPS system. However, how this is actually interpreted by the MPS is determined by whether the bit is bypassed, and if there is a ``veto`` device upstream such that the fault can be safely ignored. The summary of both the `bypass` and `fault` signals is contained within :attr:`.tripped`. The bypassed state is reported through EPICS as well but unfortunately whether a device is considered capable of "veto-ing" or is vetoed by another device is not broadcast by EPICS so this is held within this device and the ``lighpath`` module Parameters ---------- prefix : ``str`` PV prefix of MPS information name : ``str``, required keyword Name of MPS bit veto : ``bool``, optional Whether or not the the device is capable of vetoing downstream faults """ # Signals fault = C(EpicsSignalRO, '_MPSC') bypass = C(EpicsSignal, '_BYPS') # Default read and configuration attributes _default_read_attrs = ['read'] _default_configuration_attrs = ['bypass'] @property def faulted(self): """ Whether the MPS bit is faulted or not """ return bool(self.fault.value) @property def bypassed(self): """ Bypass state of the MPS bit """ return bool(self.bypass.value) def _sub_to_children(self): """ Subscribe to child signals """ self.fault.subscribe(self._fault_change, run=False) self.bypass.subscribe(self._fault_change, run=False)
class M824_Axis(PVPositionerComparator): """Axis subclass for PI_M824_Hexapod class.""" setpoint = C(EpicsSignal, '') readback = C(EpicsSignal, ':rbv') atol = 0.001 # one micron seems close enough def done_comparator(self, readback, setpoint): if setpoint - self.atol < readback and readback < setpoint + self.atol: return True else: return False
class MyPositioner(PVPositioner): '''Setpoint, readback, no put completion. No done pv.''' setpoint = C(EpicsSignal, fm['setpoint']) readback = C(EpicsSignalRO, fm['readback']) actuate = C(EpicsSignal, fm['actuate']) stop_signal = C(EpicsSignal, fm['stop']) done = C(EpicsSignal, fm['moving']) actuate_value = 1 stop_value = 1 done_value = 1
class PI_M824_Hexapod(Device): """Class for the main MEC TC hexapod. Model M-824 from PI.""" def __init__(self, prefix, **kwargs): # Setup axes self.x = M824_Axis(prefix + ':Xpr', name='x', limits=(-22.5, 22.5)) # Hexapod "Z", LUSI "Y" self.y = M824_Axis(prefix + ':Ypr', name='y', limits=(-12.5, 12.5)) # Hexapod "Y", LUSI "Z" self.z = M824_Axis(prefix + ':Zpr', name='z', limits=(-22.5, 22.5)) self.u = M824_Axis(prefix + ':Upr', name='u', limits=(-7.5, 7.5)) # Hexapod "Z", LUSI "Y" self.v = M824_Axis(prefix + ':Vpr', name='v', limits=(-12.5, 12.5)) # Hexapod "Y", LUSI "Z" self.w = M824_Axis(prefix + ':Wpr', name='w', limits=(-7.5, 7.5)) super().__init__(prefix, **kwargs) # Setup controller level properties moving_rbk = C(EpicsSignal, ':moving.RVAL') velocity = C(EpicsSignal, ':vel') velocity_rbk = C(EpicsSignal, ':vel:rbv') error_rbk = C(EpicsSignal, ':error.RVAL') # Control functions def vel(self, velo): """Set velocity, e.g. hexapod.velo(5.0)""" self.velocity.put(velo) @property def vel(self): """Returns the current velocity.""" velocity = self.velocity_rbk.get() return velocity @property def moving(self): """Returns True if hexapod is moving, False otherwise.""" moving = self.moving_rbk.get() if moving == 1: return True elif moving == 0: return False else: print("Unknown moving status of %d" % moving) @property def haserror(self): """Returns current error status. True if error, False otherwise.""" error = self.error_rbk.get() if error != 0: return True else: return False
class PolyScienceChiller(Device): """Class for the MEC Polyscience chillers.""" # Epics Signals presure_psi = C(EpicsSignalRO, ':PressurePSI') presure_kpa = C(EpicsSignalRO, ':PressureKPA') temp_setpoint = C(EpicsSignal, ':TempSetpoint') temp_rbv = C(EpicsSignalRO, ':CurrentTemp') on_off = C(EpicsSignal, ':TurnOnOff') run_status = C(EpicsSignalRO, ':RunStatus') fault_code = C(EpicsSignalRO, ':FaultStatusCode') fault_status = C(EpicsSignalRO, ':FaultStatus') def set_temp(self, temp): """Set temperature setpoint (in Celsius).""" self.temp_setpoint.put(temp) def turn_on(self): """Turn on the chiller.""" self.on_off.put(1) def turn_off(self): """Turn off the chiller.""" self.on_off.put(0) @property def temp(self): """Readback the current temperature (in Celsius).""" curr_temp = self.temp_rbv.get() return curr_temp @property def status(self): """Readback the run status.""" stat = self.run_status.get() return stat @property def pressure_psi(self): """Readback of the pressure in PSI.""" psi = self.pressure_psi.get() return psi @property def pressure_kpa(self): """Readback of the pressure in KPA.""" kpa = self.pressure_kpa.get() return kpa @property def fault_status(self): """Readback of the current fault status string.""" string = self.fault_status.get() return string @property def fault_code(self): """Readback of the current fault code.""" code = self.fault_code.get() return code
class XPDPerkinElmer2(XPDPerkinElmer): tiff = C( XPDTIFFPlugin, 'TIFF1:', #- MA #write_path_template='Z:/data/pe2_data/%Y/%m/%d', #- DO write_path_template='Z:\\data\\pe2_data\\%Y\\%m\\%d\\', #- DO #write_path_template='Z:/img/%Y/%m/%d/', #- MA #read_path_template='/SHARE/img/%Y/%m/%d/', #- MA read_path_template='/nsls2/xf28id1/data/pe2_data/%Y/%m/%d/', #- DO root='/nsls2/xf28id1/data/pe2_data/', #-DO #root='/SHARE/img/', #-MA cam_name='cam', # used to configure "tiff squashing" #-MA proc_name='proc', # ditto #-MA read_attrs=[], #- MA #tiff = C(XPDTIFFPlugin, 'TIFF1:', #write_path_template='/home/xf28id1/Documents/Milinda/PE1Data', #read_path_template='/SHARE/img/%Y/%m/%d/', #root='/SHARE/img/', #cam_name='cam', # used to configure "tiff squashing" #proc_name='proc', # ditto #read_attrs=[], # TODO: switch to this configuration using GPFS later # once G:\ drive is mounted to the Windows IOC # (a new Windows 10 machine in the rack upstairs) # write_path_template='G:\\img\\%Y\\%m\\%d\\', # read_path_template='/nsls2/xf28id1/data/pe2_data/%Y/%m/%d/', # root='/nsls2/xf28id1/data/pe1_data', )
class LaserShutter(InOutPositioner): """Controls shutter controlled by Analog Output""" # EpicsSignals voltage = C(EpicsSignal, '') state = FC(AttributeSignal, 'voltage_check') # Constants out_voltage = 5.0 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 LedLights(Device): """LED lights controlled by turning AC PDU channel on/off""" # Epics Signals control_pv = C(EpicsSignal, ':SetControlAction') on_value = 1 off_value = 2 # Control functions def on(self): self.control_pv.put(self.on_value) def off(self): self.control_pv.put(self.off_value) @property def ison(self): if self.control_pv.get() == self.on_value: return True else: return False @property def isoff(self): if self.control_pv.get() == self.off_value: return True else: return False
class CS700TemperatureController(PVPositioner): readback = C(EpicsSignalRO, 'T-I') setpoint = C(EpicsSignal, 'T-SP') done = C(EpicsSignalRO, 'Cmd-Busy') stop_signal = C(EpicsSignal, 'Cmd-Cmd') def set(self, *args, timeout=None, **kwargs): return super().set(*args, timeout=timeout, **kwargs) def trigger(self): # There is nothing to do. Just report that we are done. # Note: This really should not necessary to do -- # future changes to PVPositioner may obviate this code. status = DeviceStatus(self) status._finished() return status
class Piezo(Device): """ Device for controlling piezo injector motors """ velocity = C(EpicsSignalRO, ':VELOCITYGET') req_velocity = C(EpicsSignal, ':VELOCITYSET') open_loop_step = C(EpicsSignal, ':OPENLOOPSTEP') _default_read_attrs = ['open_loop_step'] _default_configuration_attrs = ['velocity'] def tweak(self, distance): """ Tweak the Piezo by a distance """ return self.open_loop_step.set(distance)
class SlitPositioner(FltMvInterface, PVPositioner, Device): """ Abstraction of 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, i.e MFX:DG2 slit_type : ``'XWIDTH'``, ``'YWIDTH'``, ``'XCENTER'``, ``'YCENTER'`` The aspect of the slit position you would like to control with this specific motor name : ``str`` Alias for the axis 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 ``PVPositioner``. """ setpoint = FC(EpicsSignal, "{self.prefix}:{self._dirshort}_REQ") readback = FC(EpicsSignalRO, "{self.prefix}:ACTUAL_{self._dirlong}") done = C(EpicsSignalRO, ":DMOV") _default_read_attrs = ['readback'] 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 PI_M824_Hexapod(Device): """Class for the main MEC TC hexapod. Model M-824 from PI.""" # Setup axes x = C(M824_Axis, ':Xpr') y = C(M824_Axis, ':Ypr') z = C(M824_Axis, ':Zpr') u = C(M824_Axis, ':Upr') v = C(M824_Axis, ':Vpr') w = C(M824_Axis, ':Wpr') # Setup controller level properties moving_rbk = C(EpicsSignal, ':moving.RVAL') velocity = C(EpicsSignal, ':vel') velocity_rbk = C(EpicsSignal, ':vel:rbv') error_rbk = C(EpicsSignal, ':error.RVAL') # Control functions def vel(self, velo): """Set velocity, e.g. hexapod.velo(5.0)""" self.velocity.put(velo) @property def vel(self): """Returns the current velocity.""" velocity = self.velocity_rbk.get() return velocity @property def moving(self): """Returns True if hexapod is moving, False otherwise.""" moving = self.moving_rbk.get() if moving == 1: return True elif moving == 0: return False else: print("Unknown moving status of %d" % moving) @property def haserror(self): """Returns current error status. True if error, False otherwise.""" error = self.error_rbk.get() if error != 0: return True else: return False
class Pseudo1x3(PseudoPositioner): pseudo1 = C(PseudoSingle, limits=(-10, 10)) real1 = C(EpicsMotor, motor_recs[0]) real2 = C(EpicsMotor, motor_recs[1]) real3 = C(EpicsMotor, motor_recs[2]) def forward(self, pseudo_pos): pseudo_pos = self.PseudoPosition(*pseudo_pos) # logger.debug('forward %s', pseudo_pos) return self.RealPosition(real1=-pseudo_pos.pseudo1, real2=-pseudo_pos.pseudo1, real3=-pseudo_pos.pseudo1) def inverse(self, real_pos): real_pos = self.RealPosition(*real_pos) # logger.debug('inverse %s', real_pos) return self.PseudoPosition(pseudo1=-real_pos.real1)
class LinkamFurnace(PVPositioner): readback = C(EpicsSignalRO, 'TEMP') setpoint = C(EpicsSignal, 'RAMP:LIMIT:SET') done = C(EpicsSignalRO, 'STATUS') stop_signal = C(EpicsSignal, 'RAMP:CTRL:SET') temperature = C(EpicsSignal, "TEMP") def set(self, *args, timeout=None, **kwargs): return super().set(*args, timeout=timeout, **kwargs) def trigger(self): # There is nothing to do. Just report that we are done. # Note: This really should not necessary to do -- # future changes to PVPositioner may obviate this code. status = DeviceStatus(self) status._finished() return status
class OMMotor(FltMvInterface, PVPositioner): """ Base class for each motor in the LCLS offset mirror system. """ __doc__ += basic_positioner_init # position readback = C(EpicsSignalRO, ':RBV', auto_monitor=True) setpoint = C(EpicsSignal, ':VAL', limits=True) done = C(EpicsSignalRO, ':DMOV', auto_monitor=True) motor_egu = C(EpicsSignal, ':RBV.EGU') # status interlock = C(EpicsSignalRO, ':INTERLOCK') enabled = C(EpicsSignalRO, ':ENABLED') # limit switches low_limit_switch = C(EpicsSignalRO, ":LLS") high_limit_switch = C(EpicsSignalRO, ":HLS") @property def egu(self): """ Engineering units of the readback PV, as reported by EPICS. Returns ------- egu: ``str`` """ return self.motor_egu.get() def check_value(self, position): """ Checks to make sure the inputted value is both valid and within the soft limits of the motor. Parameters ---------- position: ``float`` Position to check for validity Raises ------ ``ValueError`` If position is ``None``, ``NaN`` or ``Inf`` ``LimitError`` If the position is outside the soft limits """ # Check that we do not have a NaN or an Inf as those will # will make the PLC very unhappy ... if position is None or np.isnan(position) or np.isinf(position): raise ValueError("Invalid value inputted: '{0}'".format(position)) # Use the built-in PVPositioner check_value super().check_value(position)
class SPseudo1x3(PseudoPositioner): pseudo1 = C(PseudoSingle, limits=(-10, 10)) real1 = C(SoftPositioner, init_pos=0) real2 = C(SoftPositioner, init_pos=0) real3 = C(SoftPositioner, init_pos=0) @pseudo_position_argument def forward(self, pseudo_pos): pseudo_pos = self.PseudoPosition(*pseudo_pos) # logger.debug('forward %s', pseudo_pos) return self.RealPosition(real1=-pseudo_pos.pseudo1, real2=-pseudo_pos.pseudo1, real3=-pseudo_pos.pseudo1) @real_position_argument def inverse(self, real_pos): real_pos = self.RealPosition(*real_pos) # logger.debug('inverse %s', real_pos) return self.PseudoPosition(pseudo1=-real_pos.real1)
class SrxXspress3Detector(XspressTrigger, Xspress3Detector): # TODO: garth, the ioc is missing some PVs? # det_settings.erase_array_counters # (XF:05IDD-ES{Xsp:1}:ERASE_ArrayCounters) # det_settings.erase_attr_reset (XF:05IDD-ES{Xsp:1}:ERASE_AttrReset) # det_settings.erase_proc_reset_filter # (XF:05IDD-ES{Xsp:1}:ERASE_PROC_ResetFilter) # det_settings.update_attr (XF:05IDD-ES{Xsp:1}:UPDATE_AttrUpdate) # det_settings.update (XF:05IDD-ES{Xsp:1}:UPDATE) channel1 = C(Xspress3Channel, 'C1_', channel_num=1, read_attrs=['rois']) channel2 = C(Xspress3Channel, 'C2_', channel_num=2, read_attrs=['rois']) channel3 = C(Xspress3Channel, 'C3_', channel_num=3, read_attrs=['rois']) hdf5 = Cpt(Xspress3FileStore, 'HDF5:', read_path_template='/data/XSPRESS3/2016-1/', write_path_template='/epics/data/2016-1/', root='/data') def __init__(self, prefix, *, configuration_attrs=None, read_attrs=None, **kwargs): if configuration_attrs is None: configuration_attrs = [ 'external_trig', 'total_points', 'spectra_per_point', 'settings' ] if read_attrs is None: read_attrs = ['channel1', 'channel2', 'channel3', 'hdf5'] super().__init__(prefix, configuration_attrs=configuration_attrs, read_attrs=read_attrs, **kwargs) def stop(self): ret = super.stop() self.hdf5.stop() return ret
class M824_Axis(Device): """Axis subclass for PI_M824_Hexapod class.""" axis = C(EpicsSignal, '') axis_rbv = C(EpicsSignal, ':rbv') def mv(self, pos): """Absolute move to specified position.""" self.axis.put(pos) def mvr(self, inc): """Move relative distance.""" curr_pos = self.axis_rbv.get() next_pos = curr_pos + inc self.axis.put(next_pos) def wm(self): """Return current axis position (where motor).""" curr_pos = self.axis_rbv.get() return curr_pos
class LinkamFurnace(PVPositioner): readback = C(EpicsSignalRO, 'TEMP') setpoint = C(EpicsSignal, 'RAMP:LIMIT:SET') done = C(EpicsSignalRO, 'STATUS') stop_signal = C(EpicsSignal, 'RAMP:CTRL:SET') ramp_rate = C(EpicsSignal, 'RAMP:RATE:SET') def set(self, new_position, *args, timeout=None, **kwargs): if abs(new_position - self.setpoint.value) < 1: return DeviceStatus(self, done=True, success=True) else: return super().set(new_position, *args, timeout=timeout, **kwargs) def trigger(self): # There is nothing to do. Just report that we are done. # Note: This really should not necessary to do -- # future changes to PVPositioner may obviate this code. status = DeviceStatus(self) status._finished() return status
class BPMCam(SingleTrigger, AreaDetector): cam = C(AreaDetectorCam, '') image_plugin = C(ImagePlugin, 'image1:') # tiff = C(SRXTIFFPlugin, 'TIFF1:', # #write_path_template='/epicsdata/bpm1-cam1/2016/2/24/') # #write_path_template='/epicsdata/bpm1-cam1/%Y/%m/%d/', # #root='/epicsdata', reg=db.reg) # write_path_template='/nsls2/xf05id1/data/bpm1-cam1/%Y/%m/%d/', # root='/nsls2/xf05id1') roi1 = C(ROIPlugin, 'ROI1:') roi2 = C(ROIPlugin, 'ROI2:') roi3 = C(ROIPlugin, 'ROI3:') roi4 = C(ROIPlugin, 'ROI4:') stats1 = C(StatsPlugin, 'Stats1:') stats2 = C(StatsPlugin, 'Stats2:') stats3 = C(StatsPlugin, 'Stats3:') stats4 = C(StatsPlugin, 'Stats4:') # this is flakey? # stats5 = C(StatsPlugin, 'Stats5:') pass
class tstEpicsMotor(EpicsMotor): user_readback = C(CustomAlarmEpicsSignalRO, '.RBV') high_limit_switch = C(Signal, value=0) low_limit_switch = C(Signal, value=0) direction_of_travel = C(Signal, value=0) high_limit_value = C(EpicsSignalRO, '.HLM') low_limit_value = C(EpicsSignalRO, '.LLM')
class tstEpicsMotor(EpicsMotor): user_readback = C(CustomAlarmEpicsSignalRO, '.RBV', kind='hinted') high_limit_switch = C(Signal, value=0, kind='omitted') low_limit_switch = C(Signal, value=0, kind='omitted') direction_of_travel = C(Signal, value=0, kind='omitted') high_limit_value = C(EpicsSignalRO, '.HLM', kind='config') low_limit_value = C(EpicsSignalRO, '.LLM', kind='config')
class SRXHFVLMCam(SingleTrigger, AreaDetector): cam = C(AreaDetectorCam, '') image_plugin = C(ImagePlugin, 'image1:') stats1 = C(StatsPlugin, 'Stats1:') stats2 = C(StatsPlugin, 'Stats2:') stats3 = C(StatsPlugin, 'Stats3:') stats4 = C(StatsPlugin, 'Stats4:') tiff = C(SRXTIFFPlugin, 'TIFF1:', write_path_template='/epicsdata/hfvlm/%Y/%m/%d/', root='/epicsdata')