class SolenoidValve: """ this works for both gate valves and solenoid valves status of the valve is given by PV [deviceName]Pos-Sts open the valve by setting PV [deviceName]Cmd:Opn-Cmd to 1 close the valve by setting PV [deviceName]Cmd:Cls-Cmd to 1 """ def __init__(self, devName): """ for soft pump valves devName should be a list some valves have """ if isinstance(devName, list): # soft pump valves if len(devName) != 2: raise Exception( "2 device names must be given for a soft pump valve.") self.has_soft = True self.soft_valve = SolenoidValve(devName[1]) devName = devName[0] self.devName = devName else: self.has_soft = False self.devName = devName self.sig_status = EpicsSignal(devName + 'Pos-Sts') self.sig_open = EpicsSignal(devName + 'Cmd:Opn-Cmd') self.sig_close = EpicsSignal(devName + 'Cmd:Cls-Cmd') def open(self, softOpen=False): print("request to open valve: ", self.devName) if sim_on: print("simulation mode on, the valve state will not change.") return if softOpen and self.has_soft: self.close() self.soft_valve.open() else: if self.has_soft: self.soft_valve.close() self.sig_open.put(1) check_sig_status(self.sig_status, 1) def close(self): print("request to close valve: ", self.devName) if sim_on: return if self.has_soft: if self.soft_valve.status == 1: self.soft_valve.close() if self.status == 1: self.sig_close.put(1) check_sig_status(self.sig_status, 0) @property def status(self): if self.has_soft: return 0.5 * self.soft_valve.status + self.sig_status.get() else: return self.sig_status.get()
class ValueReader(metaclass=Singleton): def __init__(self, signals): self.signals = signals self.PVs = dict() self.PV_signals = list() self.live_data = True self.signals.run_live.connect(self.run_live_data) def run_live_data(self, live): self.live_data = live def live_data_stream(self): self.PVs = GetPVs() gatt = self.PVs.get('gatt', None) self.signal_gatt = EpicsSignal(gatt) #wave8 = self.PVs.get('wave8', None) #self.signal_wave8 = EpicsSignal(wave8) diff = self.PVs.get('diff', None) self.signal_diff = EpicsSignal(diff) self.gatt = self.signal_gatt.get() self.diff = self.signal_diff.get() def sim_data_stream(self): """ context_data = zmq.Context() socket_data = context_data.socket(zmq.SUB) socket_data.connect(".join(['tcp://localhost:', '8123'])") socket_data.subscribe("") while True: md = socket_data.rev_json(flags=0) msg = socket.recv(flags=0,copy=false, track=false) buf = memoryview(msg) data = np.frombuffer(buf, dtype=md['dtype']) data = np.ndarray.tolist(data.reshape(md['shape'])) self.gatt = data[0] self.diff = data[1] """ x = 0.8 y = 0.4 self.gatt = sinwv(x) self.diff = sinwv(y) def read_value(self): # needs to initialize first maybe using a decorator? if self.live_data: self.live_data_stream() return({'gatt': self.gatt, 'diff': self.diff}) else: self.sim_data_stream() return({'gatt': self.gatt, 'diff': self.diff})
def test_write_pv_timestamp_no_monitor(motor): sp = EpicsSignal(motor.user_setpoint.pvname, name='test') sp_value0 = sp.get() ts0 = sp.timestamp sp.put(sp_value0 + 0.1, wait=True) time.sleep(0.1) sp_value1 = sp.get() ts1 = sp.timestamp assert ts1 > ts0 assert_almost_equal(sp_value0 + 0.1, sp_value1) sp.put(sp.value - 0.1, wait=True)
def test_read_pv_timestamp_no_monitor(motor): motor.set(0, wait=True) sp = EpicsSignal(motor.user_setpoint.pvname, name='test') rbv = EpicsSignalRO(motor.user_readback.pvname, name='test') assert rbv.get() == sp.get() rbv_value0 = rbv.get() ts0 = rbv.timestamp sp.put(sp.get() + 0.1) time.sleep(.5) rbv_value1 = rbv.get() ts1 = rbv.timestamp assert ts1 > ts0 assert_almost_equal(rbv_value0 + 0.1, rbv_value1) sp.put(sp.get() - 0.1)
def fug_fil_degas(I_target, pressure_pv, max_pressure, max_voltage, current=fug_current, voltage=fug_voltage, enable=fug_enable): """ fug_fil_degas(1 (in A), prep_pressure, 1*10**-8, 10 (in Volts)) """ # pressure_pv_dict = { # ['Load_Lock_1']= 'XF:21IDD-VA{LOCK1:4A-CCG:EA4_1}P-I', # ['Load_Lock_2']= 'XF:21IDD-VA{LOCK2:3A-CCG:EA3_1}P-I', # ['Preparation']= 'XF:21IDD-VA{PREP:2A-CCG:EA5_1}P-I', # ['Low_Temp']= 'XF:21IDD-VA{LOWT:5A-CCG:EA5_1}P-I', # ['Analysis']= 'XF:21IDD-VA{ANAL:1A-CCG:EA1_1}P-I' } pressure_pv = EpicsSignal(pressure_pv_dict[pressure_pv]) voltage.put(max_voltage) current.put(0) enable.put(1) while I_target > current.get(): incr = .1 print("Current value: " + str(round(current.get(), 2)) + ". Going to " + str(round(current.get() + incr, 2))) while (pressure_pv.get() >= max_pressure): time.sleep(10) current.put(current.get() + incr) time.sleep(10) current.put(0) voltage.put(0) enable.put(0)
def test_write_pv_timestamp_no_monitor(self): mtr = EpicsMotor(config.motor_recs[0], name='test') mtr.wait_for_connection() sp = EpicsSignal(mtr.user_setpoint.pvname, name='test') sp_value0 = sp.get() ts0 = sp.timestamp sp.put(sp_value0 + 0.1, wait=True) time.sleep(0.1) sp_value1 = sp.get() ts1 = sp.timestamp self.assertGreater(ts1, ts0) self.assertAlmostEqual(sp_value0 + 0.1, sp_value1) sp.put(sp.value - 0.1, wait=True)
def test_write_pv_timestamp_monitor(self): mtr = EpicsMotor(config.motor_recs[0]) mtr.wait_for_connection() sp = EpicsSignal(mtr.user_setpoint.pvname, auto_monitor=True) sp_value0 = sp.get() ts0 = sp.timestamp sp.put(sp_value0 + 0.1, wait=True) time.sleep(0.1) sp_value1 = sp.get() ts1 = sp.timestamp self.assertGreater(ts1, ts0) self.assertAlmostEqual(sp_value0 + 0.1, sp_value1) sp.put(sp.value - 0.1, wait=True)
class MKSGauge: """ can read pressure, status of the gauge "OFF", "NO GAUGE" turn on and off """ def __init__(self, devName): self.pres_sig = EpicsSignal(devName + 'P:Raw-I') self.power_ctrl = EpicsSignal(devName + 'Pwr-Cmd') def pressure(self): """ raise exception if the gause if not present or off """ Pr = self.pres_sig.get() if Pr == "NO_GAUGE" or Pr == "OFF": raise Exception(Pr, self.pres_sig.name) elif Pr == "LO<E-03": P0 = 1.0e-3 elif Pr == ">1.0E+03": P0 = 1.1e3 else: P0 = np.float(Pr) return P0 def power(self, state, max_try=10): """ turn the gauge on or off """ if max_try <= 0: raise Exception("could not change gauge state to ", state) self.power_on = self.power_ctrl.get() if state == "ON" or state == "on": if self.power_on: return else: self.power_ctrl.put(1) time.sleep(1.5) return self.power(state, max_try - 1) else: if self.power_on: self.power_ctrl.put(0) time.sleep(1.5) return self.power(state, max_try - 1) else: return
class MaxiGauge: def __init__(self, devName): self.pres_sig = EpicsSignal(devName + 'P:Raw-I') def pressure(self): msg = self.pres_sig.get() if msg == "UNDER": return 1.0e-3 elif msg == "OVER": return 1.1e3 else: return float(msg)
class TimingChannel(object): def __init__(self, setpoint_PV, readback_PV, name): self.control_PV = EpicsSignal(setpoint_PV) # DG/Vitara PV self.storage_PV = EpicsSignal(readback_PV) # Notepad PV self.name = name def save_t0(self, val=None): """ Set the t0 value directly, or save the current value as t0. """ if not val: # Take current value to be t0 if not provided val = self.control_PV.get() self.storage_PV.put(val) # Save t0 value def restore_t0(self): """ Restore the t0 value from the current saved value for t0. """ val = self.storage_PV.get() self.control_PV.put(val) # write t0 value def mvr(self, relval): """ Move the control PV relative to it's current value. """ currval = self.control_PV.get() self.control_PV.put(currval - relval) def mv(self, val): t0 = self.storage_PV.get() self.control_PV.put(t0 - val) def get_delay(self, verbose=False): delay = self.control_PV.get() - self.storage_PV.get() if delay > 0: print("X-rays arrive {} s before the optical laser".format( abs(delay))) elif delay < 0: print("X-rays arrive {} s after the optical laser".format( abs(delay))) else: # delay is 0 print("X-rays arrive at the same time as the optical laser") if verbose: control_data = (self.name, self.control_PV.pvname, self.control_PV.get()) storage_data = (self.name, self.storage_PV.pvname, self.storage_PV.get()) print("{} Control PV: {}, Control Value: {}".format(*control_data)) print("{} Storage PV: {}, Storage Value: {}".format(*storage_data))
class User: SCALE = 1000.0 """Generic User Object""" sequencer = sequencer def __init__(self): self.mesh_raw = EpicsSignal(name='mesh_raw', read_pv='MFX:USR:ai1:0', write_pv='MFX:USR:ao1:0') @property def current_rate(self): """Current configured EventSequencer rate""" return sequencer.sync_marker.get(as_string=True) def configure_sequencer(self, rate='30Hz', readout_all=False): """ Setup EventSequencer (30Hz default) with event codes to tag the Rayonix readout and each of the preceeding 3 shots. Parameters ---------- rate : str, optional default is "30Hz", or optionally "10Hz" readout_all : bool, optional Readout all events with ec198 if True otherwise readout only ec198 at same time as Rayonix ec210 """ logger.info("Configure EventSequencer ...") # Setup sequencer sequencer.sync_marker.put(rate) if rate == '10Hz': delta0 = 120 / 10 elif rate == '30Hz': delta0 = 120 / 30 else: delta0 = 120 / 30 # Set sequence # delta0 is the number of shots until the next event code # for the desired rate, e.g., ec42 for 30 Hz and ec43 for 10 Hz # seqstep = 0 seq_steps[seqstep].configure({ 'eventcode': 213, 'delta_beam': delta0 - 3, 'fiducial': 0, 'comment': 'Rayonix-3' }) seqstep += 1 seq_steps[seqstep].configure({ 'eventcode': 197, 'delta_beam': 1, 'fiducial': 0, 'comment': 'PulsePicker' }) if readout_all: seqstep += 1 seq_steps[seqstep].configure({ 'eventcode': 198, 'delta_beam': 0, 'fiducial': 0, 'comment': 'DAQ Readout' }) seqstep += 1 seq_steps[seqstep].configure({ 'eventcode': 212, 'delta_beam': 0, 'fiducial': 0, 'comment': 'Rayonix-2' }) if readout_all: seqstep += 1 seq_steps[seqstep].configure({ 'eventcode': 198, 'delta_beam': 0, 'fiducial': 0, 'comment': 'DAQ Readout' }) seqstep += 1 seq_steps[seqstep].configure({ 'eventcode': 211, 'delta_beam': 1, 'fiducial': 0, 'comment': 'Rayonix-1' }) if readout_all: seqstep += 1 seq_steps[seqstep].configure({ 'eventcode': 198, 'delta_beam': 0, 'fiducial': 0, 'comment': 'DAQ Readout' }) seqstep += 1 seq_steps[seqstep].configure({ 'eventcode': 210, 'delta_beam': 1, 'fiducial': 0, 'comment': 'Rayonix' }) if readout_all: seqstep += 1 seq_steps[seqstep].configure({ 'eventcode': 198, 'delta_beam': 0, 'fiducial': 0, 'comment': 'DAQ Readout' }) seqstep += 1 seq_steps[seqstep].configure({ 'eventcode': 198, 'delta_beam': 0, 'fiducial': 0, 'comment': 'DAQ Readout' }) # Clear other sequence steps seqstep += 1 sequencer.sequence_length.put(seqstep) for i in range(seqstep, 20): seq_steps[i].clear() ###################### # Scanning Functions # ###################### def perform_run(self, events, record=True, comment='', post=True, **kwargs): """ Perform a single run of the experiment Parameters ---------- events: int Number of events to include in run record: bool, optional Whether to record the run comment : str, optional Comment for ELog post: bool, optional Whether to post to the experimental ELog or not. Will not post if not recording """ # time.sleep(3) / a leftover from original script # Create descriptive message comment = comment or '' # Start recording try: logger.info("Starting DAQ run, -> record=%s", record) daq.begin(events=events, record=record) time.sleep( 2) # Wait for the DAQ to get spinnign before sending events logger.debug("Starting EventSequencer ...") sequencer.start() time.sleep(1) # Post to ELog if desired runnum = daq._control.runnumber() info = [runnum, comment, events, self.current_rate] post_msg = post_template.format(*info) print(post_msg) if post and record: elog.post(post_msg, run=runnum) # Wait for the DAQ to finish logger.info("Waiting or DAQ to complete %s events ...", events) daq.wait() logger.info("Run complete!") daq.end_run() logger.debug("Stopping Sequencer ...") sequencer.stop() # allow short time after sequencer stops time.sleep(0.5) except KeyboardInterrupt: logger.warning("Scan interrupted by user request!") logger.info("Stopping DAQ ...") daq.stop() # Return the DAQ to the original state finally: logger.info("Disconnecting from DAQ ...") daq.disconnect() logger.info("Closing all laser shutters ...") self.configure_shutters(pulse1=False, pulse2=False, pulse3=False, opo=False) logger.info("Restarting the EventSequencer ...") sequencer.start() def get_mesh_voltage(self): """ Get the current power supply voltage """ return self.mesh_raw.get() def set_mesh_voltage(self, sigIn, wait=True, do_print=True): """ Set voltage on power supply to an absolute value Parameters ---------- sigIn: int or float Power supply voltage in Volts """ if do_print: print('Setting voltage...') sigInScaled = sigIn / self.SCALE # in V self.mesh_raw.put(sigInScaled) if wait: time.sleep(2.5) finalVolt = self.mesh_raw.get() finalVoltSupply = finalVolt * self.SCALE if do_print: print('Power Supply Setpoint: %s V' % sigIn) print('Power Supply Voltage: %s V' % finalVoltSupply) def set_rel_mesh_voltage(self, deltaVolt, wait=True, do_print=True): """ Increase/decrease power supply voltage by a specified amount Parameters ---------- deltaVolt: int or float Amount to increase/decrease voltage (in Volts) from its current value. Use positive value to increase and negative value to decrease """ if do_print: print('Setting voltage...') curr_set = self.mesh_raw.get_setpoint() curr_set_supply = curr_set * self.SCALE if do_print: print('Previous Power Supply Setpoint: %s V' % curr_set_supply) new_voltage = round(curr_set_supply + deltaVolt) self.set_mesh_voltage(new_voltage, wait=wait, do_print=do_print) def tweak_mesh_voltage(self, deltaVolt): """ Continuously Increase/decrease power supply voltage by specifed amount using arrow keys Parameters ---------- deltaVolt: int or float Amount to change voltage (in Volts) from its current value at each step. After calling with specified step size, use arrow keys to keep changing ^C: exits tweak mode """ print('Use arrow keys (left, right) to step voltage (-, +)') while True: key = key_press.get_input() if key in ('q', None): return elif key == key_press.arrow_right: self.set_rel_mesh_voltage(deltaVolt, wait=False, do_print=False) elif key == key_press.arrow_left: self.set_rel_mesh_voltage(-deltaVolt, wait=False, do_print=False)
from bluesky.plan_stubs import mvr, read, sleep from ophyd import EpicsMotor, EpicsSignal # from bluesky.log import config_bluesky_logging print = functools.partial(print, file=sys.stderr) # Create ophyd devices pm = EpicsMotor("XF:08BMA-OP{Mono:1-Ax:Pico}Mtr", name="pm") inb = EpicsSignal("XF:08BMES-BI{PSh:1-BPM:1}V-I", name="inb") outb = EpicsSignal("XF:08BMES-BI{PSh:1-BPM:2}V-I", name="outb") pm.wait_for_connection() inb.wait_for_connection() outb.wait_for_connection() print(f"pico starting position {pm.position:.6}") inb_initial = inb.get() outb_initial = outb.get() print(f"inboard signal {inb_initial:.6}") print(f"outboard signal {outb_initial:.6}") BPMpos = (outb_initial - inb_initial) / (outb_initial + inb_initial) * 1000000 print(f"position {BPMpos:.4}") source_pos = EpicsSignal("SR:APHLA:SOFB{BUMP:C08-BMB}offset:X-I", name="source_pos") print(f"source position {source_pos.get():.6}") print(datetime.now().isoformat()) def plan(FBref): # The loop variable, FBi, is changed from within the loop. FBi = 90 while 90 <= FBi <= 100:
class PilatusGrabber(): '''Crude tool for grabbing images from the Pilatus. Largely following the standard BlueSky AreaDetector interface, but monkey-patching functionality for the bits that Bruce is too dim to figure out. Define the Pilatus Detector pilatus = MyDetector('XF:06BMB-ES{Det:PIL100k}:', name='Pilatus') Make an PilatusGrabber opbject pil = PilatusGrabber(pilatus) Take an exposure pil.snap() Show the image (and maybe copy it elsewhere) pil.fetch() Properties: path: AreaDetector's file path (cannot have spaces) fname: file name template: substitution template for constructing the resolved file name fullname: AreaDetector's fully resolved file name number: file extension (auto increments) threshold: detector energy threshold in keV time: exposure time, sets the exposure time and acquire time ready: flag with a simple check to see if camera is ready to take a picture ''' def __init__(self, source): self.source = source self.image = EpicsSignal(self.source.prefix + 'image1:ArrayData', name=self.source.name + ' image') self._path = EpicsSignal(self.source.prefix + 'cam1:FilePath') self._fname = EpicsSignal(self.source.prefix + 'cam1:FileName') self._number = EpicsSignal(self.source.prefix + 'cam1:FileNumber') self._template = EpicsSignal(self.source.prefix + 'cam1:FileTemplate') self._threshold = EpicsSignal(self.source.prefix + 'cam1:ThresholdEnergy') self._fullname = EpicsSignalRO(self.source.prefix + 'cam1:FullFileName_RBV') self._statusmsg = EpicsSignalRO(self.source.prefix + 'cam1:StatusMessage_RBV') self._busy = EpicsSignalRO(self.source.prefix + 'cam1:AcquireBusy') @property def path(self): return (''.join( [chr(x) for x in self._path.value[self._path.value.nonzero()]])) @path.setter def path(self, path): a = numpy.pad(array([ord(x) for x in path]), (0, 256 - len(path)), mode='constant') self._path.put(a) @property def fname(self): return (''.join( [chr(x) for x in self._fname.value[self._fname.value.nonzero()]])) @fname.setter def fname(self, fname): a = numpy.pad(array([ord(x) for x in fname]), (0, 256 - len(fname)), mode='constant') self._fname.put(a) @property def template(self): return (''.join([ chr(x) for x in self._template.value[self._template.value.nonzero()] ])) @template.setter def template(self, template): a = numpy.pad(array([ord(x) for x in template]), (0, 256 - len(template)), mode='constant') self._template.put(a) @property def fullname(self): return (''.join([ chr(x) for x in self._fullname.value[self._fullname.value.nonzero()] ])) @property def statusmsg(self): return (''.join([ chr(x) for x in self._statusmsg.value[self._statusmsg.value.nonzero()] ])) @property def number(self): return (self._number.value) @number.setter def number(self, number): self._number.put(number) @property def threshold(self): return (self._threshold.value) @threshold.setter def threshold(self, threshold): self._threshold.put(threshold) @property def time(self): return (self.source.cam.acquire_time.value) @time.setter def time(self, exposure_time): self.source.cam.acquire_time.put(exposure_time) self.source.cam.acquire_period.put(exposure_time + 0.004) @property def numimages(self): return (self.source.cam.num_images.value) @time.setter def numimages(self, numimages): self.source.cam.num_images.put(numimages) @property def ready(self): if self._busy.value == 1: return False elif 'Error' in self.statusmsg: return False else: return True def snap(self): self.source.stage() st = self.source.trigger() while not st.done: time.sleep(.1) ret = self.source.read() desc = self.source.describe() self.source.unstage() def fetch(self, fname='/home/xf06bm/test.tif'): array = self.image.get() size = (self.source.image.height.value, self.source.image.width.value) img = np.reshape(array, size).astype('float') #Image.fromarray(img).save(fname, "TIFF") ## symlink to file on /nist ??? copy??? fig, ax = plt.subplots(1) # Create figure and axes rotated_img = ndimage.rotate(img, 90) plt.imshow( rotated_img, cmap='bone' ) ## https://matplotlib.org/3.1.0/tutorials/colors/colormaps.html imfile = os.path.basename(self.fullname) plt.title(imfile) plt.colorbar() plt.clim(0, array.max()) plt.show()
class RamperIOC(PVGroup): """ An IOC for executing ramps of pv_setpoints """ pv_sp = pvproperty( value=25.0, doc='pv setpoint', ) pv_sp_rate = pvproperty( value=0.0, doc='pv setpoint change rate', ) go = pvproperty( value=0, doc='flag indicating whether ramping is actually taking place') time_elapsed = pvproperty( value=0.0, doc= 'timer for measuring the elapsed time since the beginning of the program' ) pause = pvproperty(value=0, doc='flag indicating whether ramping is paused') time_paused = pvproperty(value=0.0, doc='timer for measuring the paused time') tprog = pvproperty(value=[0.0, 60.0], doc='time array of the ramp program', max_length=25) pvprog = pvproperty(value=[25.0, 25.0], doc='pv setpoint array of the ramp program', max_length=25) dwell = pvproperty(value=0.05, doc="dwell time for the pv setpoint update") safety_timer = pvproperty( value=0.0, doc='timer for stopping the program in case if ipython session dies') safety_thresh = pvproperty(value=10.0, doc='time threshold for turning the heater off') pid_enable_name = pvproperty(value='', dtype=ChannelType.STRING, doc='pv name for pid enable') pid_output_name = pvproperty( value='', dtype=ChannelType.STRING, # dtype=_LongStringChannelType.LONG_STRING, doc='pv name for pid output') # pid_output_name_ext = pvproperty( # value='', # dtype=ChannelType.STRING, # # dtype=_LongStringChannelType.LONG_STRING, # doc='pv name for pid output (extension)' # ) pv_test = pvproperty(value=0, doc='pv for output testing') _previous_elapsed_time = None time_start = None pid_enable = None pid_output = None @pv_sp.startup async def pv_sp(self, instance, async_lib): """This is a startup hook which periodically updates the value.""" rate = 0 while True: await self.pv_sp_rate.write(rate) await async_lib.sleep(self.dwell.value) if self.go.value == 1: if self.time_start is None: self.time_start = ttime.time() if self.pause.value == 0: await self.time_elapsed.write(ttime.time() - self.time_start) dt = self.time_elapsed.value - self.time_paused.value if dt < np.max(self.tprog.value): pv_sp = np.interp(dt, self.tprog.value, self.pvprog.value) else: pv_sp = self.pvprog.value[-1] if self._previous_elapsed_time is not None: rate = (pv_sp - self.pv_sp.value) / ( dt - self._previous_elapsed_time) * 60 self._previous_elapsed_time = dt await instance.write(value=pv_sp) else: rate = 0 else: self.time_start = None await self.time_elapsed.write(0.0) await self.time_paused.write(0.0) rate = 0 @pid_enable_name.startup async def pid_enable_name(self, instance, async_lib): while self.pid_enable_name.value == '': await async_lib.sleep(1) self.pid_enable = EpicsSignal(self.pid_enable_name.value, name='pid_enable') def subscription(value, **kwargs): if value == 0: if self.pid_output is not None: if self.pid_output.get() != 0: self.pid_output.put(0) self.pid_enable.subscribe(subscription) @pid_output_name.startup async def pid_output_name(self, instance, async_lib): while (self.pid_output_name.value == ''): await async_lib.sleep(1) self.pid_output = EpicsSignal(self.pid_output_name.value, name='pid_output') def subscription(value, **kwargs): if value != 0: if self.pid_enable is not None: if self.pid_enable.get() == 0: self.pid_output.put(0) self.pid_output.subscribe(subscription) @safety_timer.startup async def safety_timer(self, instance, async_lib): while self.safety_timer.value < self.safety_thresh.value: safety_timer = self.safety_timer.value + 1 await instance.write(value=safety_timer) await async_lib.sleep(1) if self.pid_enable is not None: self.pid_enable.put(0) @time_paused.startup async def time_paused(self, instance, async_lib): while True: cur_time = ttime.time() if self.pause.value == 1: while True: if self.pause.value == 0: break await async_lib.sleep(self.dwell.value / 2) time_paused = self.time_paused.value + (ttime.time() - cur_time) await instance.write(value=time_paused) await async_lib.sleep(self.dwell.value)
class ICAmplifier(Device): """Keithely 428 Current Amplifier Ophyd device""" def __init__(self, *args, gain_set_pv, gain_get_pv, autoFilter_set_pv, autoFilter_get_pv, riseTime_set_pv, riseTime_get_pv, zcheck_set_pv, zcheck_get_pv, filter_set_pv, filter_get_pv, x10_set_pv, x10_get_pv, autoSupEnable_set_pv, autoSupEnable_get_pv, suppression_enable_set_pv, suppression_enable_get_pv, suppressionValue_set_pv, suppressionExponent_set_pv, suppression_set_pv, suppression_get_pv, overload_get_pv, **kwargs): super().__init__(*args, **kwargs) self.gain = EpicsSignal(write_pv=self.prefix + gain_set_pv, read_pv=self.prefix + gain_get_pv, auto_monitor=True, name=self.name) self.autoFilter = EpicsSignal(write_pv=self.prefix + autoFilter_set_pv, read_pv=self.prefix + autoFilter_get_pv, auto_monitor=True, name=self.name) self.filter = EpicsSignal(write_pv=self.prefix + filter_set_pv, read_pv=self.prefix + filter_get_pv, auto_monitor=True, name=self.name) self.riseTime = EpicsSignal(write_pv=self.prefix + riseTime_set_pv, read_pv=self.prefix + riseTime_get_pv, auto_monitor=True, name=self.name) self.zeroCheck = EpicsSignal(write_pv=self.prefix + zcheck_set_pv, read_pv=self.prefix + zcheck_get_pv, auto_monitor=True, name=self.name) self.x10 = EpicsSignal(write_pv=self.prefix + x10_set_pv, read_pv=self.prefix + x10_get_pv, auto_monitor=True, name=self.name) self.suppressionValue = EpicsSignal( write_pv=self.prefix + suppressionValue_set_pv, read_pv=self.prefix + suppressionValue_set_pv, auto_monitor=True, name=self.name) self.suppressionExponent = EpicsSignal( write_pv=self.prefix + suppressionExponent_set_pv, read_pv=self.prefix + suppressionExponent_set_pv, auto_monitor=True, name=self.name) self.autoSupEnable = EpicsSignal( write_pv=self.prefix + autoSupEnable_set_pv, read_pv=self.prefix + autoSupEnable_get_pv, auto_monitor=True, name=self.name) self.suppression = EpicsSignal( write_pv=self.prefix + suppression_set_pv, read_pv=self.prefix + suppression_get_pv, auto_monitor=True, name=self.name) self.overload = EpicsSignalRO(read_pv=self.prefix + overload_get_pv, auto_monitor=True, name=self.name) def set_gain(self, value: int): val = int(value) self.gain.put(val) def get_gain(self): return self.gain.get() def set_suppress(self, value: int): """Set current suppression depending on gain""" if value == 0: # Suppression : -0.05E-3 self.suppressionValue.set(-0.05) self.suppressionExponent.set(6) elif value == 1: # Suppression : -5E-6 self.suppressionValue.set(-5) self.suppressionExponent.set(3) elif value == 2: # Suppression : -0.5E-6 self.suppressionValue.set(-0.5) self.suppressionExponent.set(3) elif value == 3: # Suppression : -0.05E-6 self.suppressionValue.set(-0.05) self.suppressionExponent.set(3) elif value == 4: # Suppression : -5E-9 self.suppressionValue.set(-5) self.suppressionExponent.set(0) elif value == 5: # Suppression : -0.5E-9 self.suppressionValue.set(-0.5) self.suppressionExponent.set(0) elif value == 6: # Suppression : -0.05E-9 self.suppressionValue.set(-0.05) self.suppressionExponent.set(0) elif value == 7: # Suppression : -0.005E-9 self.suppressionValue.set(-0.005) self.suppressionExponent.set(0) else: pass def do_correct(self): self.zeroCheck.put(2) def set_zcheck(self, value: int): val = int(value) self.zeroCheck.put(val) def get_zcheck(self): return self.zeroCheck.enum_strs[self.zeroCheck.get()]
class ValueReader(metaclass=Singleton): def __init__(self, context, signals): self.signals = signals self.context = context self.live_data = True self.live_initialized = False self.signal_diff = None self.signal_i0 = None self.signal_ratio = None self.signal_dropped = None self.simgen = SimulationGenerator(self.context, self.signals) self.sim_vals = {"i0": 1, "diff": 1, "ratio": 1} self.diff = 1 self.i0 = 1 self.ratio = 1 self.dropped = False self.make_connections() def make_connections(self): self.signals.changeRunLive.connect(self.run_live_data) def initialize_live_connections(self): """ Function for making connections when running in live mode. It should also handle the error that happens when you try to click start when the PVs are not active """ i0 = self.context.PV_DICT.get('i0', None) self.signal_i0 = EpicsSignal(i0) diff = self.context.PV_DICT.get('diff', None) self.signal_diff = EpicsSignal(diff) ratio = self.context.PV_DICT.get('ratio', None) self.signal_ratio = EpicsSignal(ratio) dropped = self.context.PV_DICT.get('dropped', None) self.signal_dropped = EpicsSignal(dropped) self.live_initialized = True def run_live_data(self, live): self.live_data = live def live_data_stream(self): if not self.live_initialized: self.initialize_live_connections() self.i0 = self.signal_i0.get() self.diff = self.signal_diff.get() self.ratio = self.signal_ratio.get() def sim_data_stream(self): """Run with offline data""" # Adam's code for running simulations offline data # TODO: Add flag to enable this # # context_data = zmq.Context() # socket_data = context_data.socket(zmq.SUB) # socket_data.connect(''.join(['tcp://localhost:', '8123'])) # socket_data.subscribe("") # while True: # md = socket_data.recv_json(flags=0) # msg = socket_data.recv(flags=0, copy=False, track=False) # buf = memoryview(msg) # data = np.frombuffer(buf, dtype=md['dtype']) # data = np.ndarray.tolist(data.reshape(md['shape'])) # self.i0 = data[0] # self.diff = data[1] self.sim_vals = self.simgen.sim() self.i0 = self.sim_vals["i0"] self.diff = self.sim_vals["diff"] self.ratio = self.sim_vals["ratio"] self.dropped = self.sim_vals["dropped"] # self.motor_position = self.sim_vals["motor_position"] def read_value(self): # needs to initialize first maybe using a decorator? if self.context.live_data: self.live_data_stream() return {'i0': self.i0, 'diff': self.diff, 'ratio': self.ratio, 'dropped': self.dropped} else: self.sim_data_stream() return {'i0': self.i0, 'diff': self.diff, 'ratio': self.ratio, 'dropped': self.dropped}
class User: """Generic User Object""" def __init__(self): self.sc1_mesh_raw = EpicsSignal(name='sc1_mesh_raw', read_pv='CXI:SC1:AIO:04:RAW:ANALOGIN', write_pv='CXI:SC1:AIO:04:ANALOGOUT') self.sc1_mesh_scale = EpicsSignal(name='sc1_mesh_scale', read_pv='CXI:SC1:AIO:04:SCALE') def get_sc1_mesh_voltage(self): """ Get the current power supply voltage """ return self.sc1_mesh_raw.get() def set_sc1_mesh_voltage(self, sigIn, wait=True, do_print=True): """ Set voltage on power supply to an absolute value Parameters ---------- sigIn: int or float Power supply voltage in Volts """ if do_print: print('Setting voltage...') sigInScaled = sigIn / self.sc1_mesh_scale.get() # in V self.sc1_mesh_raw.put(sigInScaled) if wait: time.sleep(2.5) finalVolt = self.sc1_mesh_raw.get() finalVoltSupply = finalVolt * self.sc1_mesh_scale.get() if do_print: print('Power Supply Setpoint: %s V' % sigIn) print('Power Supply Voltage: %s V' % finalVoltSupply) def set_sc1_rel_mesh_voltage(self, deltaVolt, wait=True, do_print=True): """ Increase/decrease power supply voltage by a specified amount Parameters ---------- deltaVolt: int or float Amount to increase/decrease voltage (in Volts) from its current value. Use positive value to increase and negative value to decrease """ if do_print: print('Setting voltage...') curr_set = self.sc1_mesh_raw.get_setpoint() curr_set_supply = curr_set * self.sc1_mesh_scale.get() if do_print: print('Previous Power Supply Setpoint: %s V' % curr_set_supply) new_voltage = round(curr_set_supply + deltaVolt) self.set_sc1_mesh_voltage(new_voltage, wait=wait, do_print=do_print) def tweak_mesh_voltage(self, deltaVolt): """ Continuously Increase/decrease power supply voltage by specifed amount using arrow keys Parameters ---------- deltaVolt: int or float Amount to change voltage (in Volts) from its current value at each step. After calling with specified step size, use arrow keys to keep changing ^C: exits tweak mode """ print('Use arrow keys (left, right) to step voltage (-, +)') while True: key = key_press.get_input() if key in ('q', None): return elif key == key_press.arrow_right: self.set_sc1_rel_mesh_voltage(deltaVolt, wait=False, do_print=False) elif key == key_press.arrow_left: self.set_sc1_rel_mesh_voltage(-deltaVolt, wait=False, do_print=False)