class Motor(object): def __init__(self, name='SOL1B_M1'): if name not in mtc.MOTORS.keys(): raise ValueError('You have not specified a valid motor') motor_dict = mtc.MOTORS[name] self._name = name self._set = PV(motor_dict['set']) self._rbv = PV(motor_dict['rbv']) self._status = PV(motor_dict['status']) self._status_vars = self._status.get_ctrlvars() self._logger = logger.custom_logger(__name__) @property def name(self): return self._name @property def pos_set(self): return self._set.get() @pos_set.setter def pos_set(self, val): if not isinstance(val, int) or isinstance(val, float): self._logger('position must be int or float') return self._set.put(val) @property def pos_rbv(self): return self._rbv.get() @property def status_vars(self): return self._status_vars
def test_DoubleVal(self): pvn = pvnames.double_pv pv = PV(pvn) pv.get() cdict = pv.get_ctrlvars() write('Testing CTRL Values for a Double (%s)\n' % (pvn)) self.failUnless('severity' in cdict) self.failUnless(len(pv.host) > 1) self.assertEqual(pv.count, 1) self.assertEqual(pv.precision, pvnames.double_pv_prec) units = ca.BYTES2STR(pv.units) self.assertEqual(units, pvnames.double_pv_units) self.failUnless(pv.access.startswith('read'))
def test_DoubleVal(self): pvn = pvnames.double_pv pv = PV(pvn) pv.get() cdict = pv.get_ctrlvars() write( 'Testing CTRL Values for a Double (%s)\n' % (pvn)) self.failUnless('severity' in cdict) self.failUnless(len(pv.host) > 1) self.assertEqual(pv.count,1) self.assertEqual(pv.precision, pvnames.double_pv_prec) units= ca.BYTES2STR(pv.units) self.assertEqual(units, pvnames.double_pv_units) self.failUnless(pv.access.startswith('read'))
class StopperCon(object): def __init__(self, stopper='AOM'): if stopper not in sc.STOPPERS.keys(): raise ValueError('{0} is not a recognized stopper'.format(stopper)) stopper_dict = sc.STOPPERS[stopper] self._stopper = stopper self._ctrl_pv = PV(stopper_dict['ctrl']) self._closed = stopper_dict['closed'] self._opened = stopper_dict['open'] self._ctrl_vars = self._ctrl_pv.get_ctrlvars()['enum_strs'] self._ctrl_pv.add_callback(self._ctrl_clbk, index=0) self._logger = logger.custom_logger(__name__) @property def enabled(self): """Get enabled state""" return self._ctrl_pv.get() @enabled.setter def enabled(self, val): """Set enabled state, unfortunately they're disabeld and allowed""" if val not in self._ctrl_vars: self._logger.info('You must provide a value that is in {0}'.format( self._ctrl_vars)) return state = self._ctrl_pv.get() if val and state == self._closed: self._logger.info('The stopper is already closed') return if val and state == self._opened: self._logger.info('The stopper is alaredy opened') return self._ctrl_pv.put(val) def _ctrl_clbk(self, pv_name=None, value=None, char_value=None, **kw): """Default callback to announce stopper change status""" self._logger.info('Stopper {0} is now {1}'.format( self._stopper, self._ctrl_vars[value]))
class Magnet(object): """Magnet control""" def __init__(self, name='SOL1B'): if name not in mc.MAGNETS.keys(): raise ValueError('You have not specified a valid magnet') mag_dict = mc.MAGNETS[name] self._name = name self._bctrl = PV(mag_dict['bctrl']) self._bact = PV(mag_dict['bact']) self._bdes = PV(mag_dict['bdes']) self._bcon = PV(mag_dict['bcon']) self._ctrl = PV(mag_dict['ctrl']) self._tol = mag_dict['tol'] self._length = mag_dict['length'] self._ctrl_vars = self._ctrl.get_ctrlvars()['enum_strs'] self._pv_attrs = self.find_pv_attrs() def check_state(f): """Decorator to only allow transitions in 'Ready' state""" def decorated(self, *args, **kwargs): if self.ctrl_value != 'Ready': print('Unable to perform action, magnet not in Ready state') return return f(self, *args, **kwargs) return decorated @property def name(self): """Get the magnet name""" return self._name @property def bctrl(self): """Get BCTRL value""" return self._bctrl.get() @bctrl.setter @check_state def bctrl(self, val): """Set bctrl value""" if not isinstance(val, float) or isinstance(val, int): print('you need to provide an in or float') return self._bctrl.put(val) @property def bact(self): """Get the BACT value""" return self._bact.get() @property def bdes(self): """Get BDES value""" return self._bdes.get() @property def ctrl_value(self): """Get the current action on magnet""" return self._ctrl_vars[self._ctrl.get()] @property def length(self): """Magnetic Length, should be from model""" return self._length @length.setter def length(self, length): """Set the magnetic length for a magnet""" if not isinstance(length, float): print('You must provide a float for magnet length') return self._length = length @property def pv_props(self): """All the properties that are PV objects/can have callbacks""" return self._pv_props @property def tol(self): return self._tol @tol.setter def tol(self, tol): """Set the magnetic length for a magnet""" if not isinstance(tol, float): print('You must provide a float for magnet tol') return False self._tol = tol @check_state def trim(self): """Issue trim command""" self._ctrl.put(mc.CTRL.index('TRIM')) @check_state def perturb(self): """Issue perturb command""" self._ctrl.put(mc.CTRL.index('PERTURB')) def con_to_des(self): """Issue con to des commands""" self._ctrl.put(mc.CTRL.index('BCOM_TO_BDES')) def save_bdes(self): """Save BDES""" self._ctrl.put(mc.CTRL.index('SAVE_BDES')) def load_bdes(self): """Load BDES""" self._ctrl.put(mc.CTRL.index('LOAD_BDES')) def undo_bdes(self): """Save BDES""" self._ctrl.put(mc.CTRL.index('UNDO_BDES')) @check_state def dac_zero(self): """DAC zero magnet""" self._ctrl.put(mc.CTRL.index('DAC_ZERO')) @check_state def calibrate(self): """Calibrate magnet""" self._ctrl.put(mc.CTRL.index('CALIB')) @check_state def standardize(self): """Standardize magnet""" self._ctrl.put(mc.CTRL.index('STDZ')) def reset(self): """Reset magnet""" self._ctrl.put(mc.CTRL.index('RESET')) def find_pv_attrs(self): """Get all the PV object attributes""" pv_attrs = [] for mem in getmembers(self): if len(mem) > 1 and isinstance(mem[1], PV): pv_attrs.append(mem[0]) return pv_attrs ################## Actions ################# def add_clbk(self, fn, attr='_bact'): """Add a callback function to a given attribute""" if attr not in self._pv_attrs: print('this attribute is not a pv object, ignored') return fns = [val[0] for val in getattr(self, attr).callbacks.values()] if fn in fns: print('this is a duplicate callback assignment, ignored') return print('adding callback {0}'.format(fn)) getattr(self, attr).add_callback(fn, with_ctrlvars=False) def remove_clbk(self, fn, attr='_bact'): """Add a callback function to a given attribute""" if attr not in self._pv_attrs: print('this attribute is not a pv object, ignored') return index = None for k, v in getattr(self, attr).callbacks.items(): if v[0] == fn: index = k if not index: print('function not found in callbacks, ignored') return print('remvong callback {0}'.format(fn)) getattr(self, attr).remove_callback(index=index)
class ProfMon(object): """Generic Profile Monitor Object Class that references profile monitor MAD name""" def __init__(self, prof_name='OTR02'): if prof_name not in pc.PROFS.keys(): raise ValueError('You have not specified a valid profile monitor') prof_dict = pc.PROFS[prof_name] self._prof_name = prof_name self._prof_set = PV(prof_dict['set']) self._prof_get = PV(prof_dict['get']) self._prof_image = PV(prof_dict['image']) self._prof_res = PV(prof_dict['res']) self._x_size = PV(prof_dict['xsize']) self._y_size = PV(prof_dict['ysize']) self._rate = PV(prof_dict['rate']) self._images = [] self._data_thread = None self._gathering_data = False self._get_vars = self._prof_get.get_ctrlvars()['enum_strs'] self._set_vars = self._prof_set.get_ctrlvars()['enum_strs'] self._motion_state = self._get_vars[self._prof_get.get()] self._prof_get.add_callback(self._state_clbk, index=1) self._insert_clbk = None self._extract_clbk = None def _state_clbk(self, pvName=None, value=None, char_value=None, **kw): """Keep track of position/motion state""" self._motion_state = self._get_vars[value] @property def prof_name(self): """Get the profile monitor MAD name""" return self._prof_name @property def cur_image(self): """Get the current image array""" return self._prof_image.get() @property def saved_images(self): """Get the images collected""" return self._images @property def resolution(self): """Get the resolution""" return self._prof_res.get() @property def arr_dims(self): """Get the x and y dimensions""" return (self._x_size.get(), self._y_size.get()) @property def rate(self): """Get the current rate""" return self._rate.get() @property def motion_state(self): """Get the current motion state of the profile monitor""" return self._motion_state @property def state(self): """Get the overall state of the profile monitor""" return self.__dict__ def insert(self, user_clbk=None): """Generic call to insert profile monitor, can specify callback to be run""" if self._motion_state == pc.IN: print('{0}: {1}'.format(self._prof_name, pc.ALREADY_INSERTED)) return if user_clbk: self._insert_clbk = user_clbk self._prof_get.add_callback(self._inserted, index=0) self._prof_set.put(pc.IN) def _inserted(self, pv_name=None, value=None, char_value=None, **kw): """Generic callback after profile monitor has been inserted, default""" if self._get_vars[value] == pc.IN: print('{0}: {1}'.format(self._prof_name, pc.INSERTED)) if self._insert_clbk: self._insert_clbk() self._insert_clbk = None self._prof_get.remove_callback(index=0) def extract(self, usr_clbk=None): """Extract profile monitor command, can specify callback to be run""" if self._motion_state == pc.OUT: print('{0}: {1}'.format(self._prof_name, pc.ALREADY_EXTRACTED)) return if user_clbk: self._extract_clbk = user_clbk self._prof_get.add_callback(self._extracted, index=0) self._prof_set.put(pc.OUT) def _extracted(self, pv_name=None, value=None, char_value=None, **kw): """Generic Callback for profile monitor that has been extracted, default""" if self._get_vars[value] == pc.OUT: print('{0}: {1}'.format(self._prof_name, pc.EXTRACTED)) if self._extract_clbk: self._extract_clbk() self._extract_clbk = None self._prof_get.remove_callback(index=0) def acquire_images(self, images=1): """Start the thread""" self._data_thread = Thread(target=self._collect_image_data, args=(images, )) self._data_thread.start() def _collect_image_data(self, images, callback): """Threaded data collection""" self._gathering_data = True delay = 1.0 / self._rate.get() # Rate must be in Hz i = 0 while i < images: image = self._prof_image.get() if len(self._images) > 0 and array_equal(image, self._images[-1]): sleep(0.01) else: self._images.append(image) sleep(delay) i += 1 if callback: # Would want this to be pyqtSignal or Event notification type thing callback() self._gathering_data = False return # No join, waste of a function
class LampCon(object): """Lamp Control for lcls""" def __init__(self, lamp_dict): # I hate using dicts as default data structures, but... self._channel = PV(lamp_dict['channel']) self._t_enable = PV(lamp_dict['t_enable']) self._t_dim = PV(lamp_dict['t_dim']) self._t_bright = PV(lamp_dict['t_bright']) self._g_enable = PV(lamp_dict['g_enable']) self._g_dim = PV(lamp_dict['g_dim']) self._g_bright = PV(lamp_dict['g_bright']) self._lamp_name = lamp_dict['name'] self._channel_vars = self._channel.get_ctrlvars()['enum_strs'] self._g_lamp_vars = self._g_enable.get_ctrlvars()['enum_strs'] self._t_lamp_vars = self._t_enable.get_ctrlvars()['enum_strs'] self._logger = logger.custom_logger(__name__) @property def lamp_name(self): """Get generic lamp name""" return self._lamp_name @property def channel(self): """Get current lamp channel (profile monitor)""" return self._channel_vars[self._channel.get()] @channel.setter def channel(self, val): """Set lamp channel""" if val not in self._channel_vars: self._logger.info('Profile Monitor {0}, not available channel for lamp {1}' \ .format(val, self._lamp_name)) return self._logger.info('Setting lamp {0} channel to {1}'.format(self._lamp_name, val)) self._channel.put(val) @property def channels(self): """Get list of available channels""" return self._channel_vars @property def t_lamp_enable(self): """Get t lamp enable status""" return self._t_lamp_vars[self._t_enable.get()] @t_lamp_enable.setter def t_lamp_enable(self, val): """Set the T Lamp to enabled/disabled""" state = self._t_lamp_vars[self._t_enable.get()] if state == val == pc.ENABLE: self._logger.info('{0}: T Lamp Already Enabled'.format(self._lamp_name)) return if state == val == pc.DISABLE: self._logger.info('{0}: T Lamp Already Disabled'.format(self._lamp_name)) return self._t_enable.put(val) self._logger.info('T Lamp now {0}'.format(val)) @property def g_lamp_enable(self): """Get g lamp enabled status""" return self._g_lamp_vars[self._g_enable.get()] @g_lamp_enable.setter def g_lamp_enable(self, val): """Set the G Lamp to enabled/disabled""" state = self._g_lamp_vars[self._g_enable.get()] if state == val == pc.ENABLE: self._logger.info('{0}: G Lamp Already Enabled'.format(self._lamp_name)) return if state == val == pc.DISABLE: self._logger.info('{0}: G Lamp Already Disabled'.format(self._lamp_name)) return self._g_enable.put(val) self._logger.info('G Lamp now {0}'.format(val))
class LampCon2(object): """Lamp Control for lcls2 lamp""" def __init__(self, lamp_dict): self._lamp_power = PV(lamp_dict['lamp_power']) self._power_vars = self._lamp_power.get_ctrlvars()['enum_strs'] self._bright_pv = PV(lamp_dict['lamp_brightness']) self._bright_vars = self._bright_pv.get_ctrlvars() self._bright_upper = self._bright_vars[pc.HI] self._bright_lower = self._bright_vars[pc.LO] self._lamp_name = lamp_dict['name'] self._logger = logger.custom_logger(__name__) @property def lamp_name(self): """Generic name for lamp""" return self._lamp_name @property def brightness(self): """Get the current setting for the brightness""" return self._bright_pv.get() @brightness.setter def brightness(self, val): if not self._bright_lower < val < self._bright_upper: self._logger.info('{0} is not in range'.format(val)) return self._bright_pv.put(val) @property def bright_up_lim(self): """Get the upper limit for the brightness""" return self._bright_upper @property def bright_lo_lim(self): """Get the lower limit for the brightness""" return self._bright_lower @property def lamp_power(self): """Get the on/off state for the lamp""" return self._power_vars[self._lamp_power.get()] @lamp_power.setter def lamp_power(self, val): """Power On/Off setter. Val must be 'On' or 'Off'""" if val not in self._power_vars: self._logger.info('You must provide a value that is "On" or "Off"') return state = self._power_vars[self._lamp_power.get()] if val == state == pc.ON: self._logger.info("The lamp is already on") return if val == state == pc.OFF: self._logger.info("The lamp is already off") return self._logger.info('Turning lamp {0}'.format(val)) self._lamp_power.put(val) @property def state(self): """Get the current state of the object class""" return self.__dict__ def dim_lamp(self, step=pc.LAMP_STEP, callback_fn=None): """Dim lamp by a step""" new_val = self._bright_pv.get() - step if new_val < self._bright_lower: self._logger.info('You can not dim any further') return self._bright_pv.put(new_val) def brighten_lamp(self, step=pc.LAMP_STEP, callback=None): """Brighten the lamp""" new_val = self._bright_pv.get() + step if new_val > self._bright_upper: self._logger.info('You can not brighten any further') return self._bright_pv.put(new_val)