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()
Exemple #2
0
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})
Exemple #3
0
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)
Exemple #4
0
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)
Exemple #6
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)
Exemple #7
0
    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)
Exemple #10
0
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))
Exemple #11
0
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)
Exemple #15
0
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()]
Exemple #16
0
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}
Exemple #17
0
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)