예제 #1
0
def test_epicssignal_set(put_complete):
    sim_pv = EpicsSignal(write_pv='XF:31IDA-OP{Tbl-Ax:X1}Mtr.VAL',
                         read_pv='XF:31IDA-OP{Tbl-Ax:X1}Mtr.RBV',
                         put_complete=put_complete)
    sim_pv.wait_for_connection()

    logging.getLogger('ophyd.signal').setLevel(logging.DEBUG)
    logging.getLogger('ophyd.utils.epics_pvs').setLevel(logging.DEBUG)
    print('tolerance=', sim_pv.tolerance)
    assert sim_pv.tolerance is not None

    start_pos = sim_pv.get()

    # move to +0.2 and check the status object
    target = sim_pv.get() + 0.2
    st = sim_pv.set(target, timeout=1, settle_time=0.001)
    wait(st, timeout=5)
    assert st.done
    assert st.success
    print('status 1', st)
    assert abs(target - sim_pv.get()) < 0.05

    # move back to -0.2, forcing a timeout with a low value
    target = sim_pv.get() - 0.2
    st = sim_pv.set(target, timeout=1e-6)
    time.sleep(0.1)
    print('status 2', st)
    assert st.done
    assert not st.success

    # keep the axis in position
    st = sim_pv.set(start_pos)
    wait(st, timeout=5)
예제 #2
0
def pair_signal(cleanup, signal_test_ioc):
    sig = EpicsSignal(read_pv=signal_test_ioc.pvs['pair_rbv'],
                      write_pv=signal_test_ioc.pvs['pair_set'],
                      name='pair')
    cleanup.add(sig)
    sig.wait_for_connection()
    return sig
예제 #3
0
def test_epicssignal_waveform():
    def update_cb(value=None, **kwargs):
        assert value in FakeEpicsWaveform.strings

    signal = EpicsSignal('readpv', string=True)

    signal.wait_for_connection()

    signal.subscribe(update_cb, event_type=signal.SUB_VALUE)
    assert signal.value in FakeEpicsWaveform.strings
예제 #4
0
def test_enum_strs():
    sig = EpicsSignal('connects')
    sig.wait_for_connection()

    enums = ['enum_strs']

    # hack this onto the FakeEpicsPV
    sig._read_pv.enum_strs = enums

    assert sig.enum_strs == enums
예제 #5
0
def test_epicssignal_sub_setpoint(cleanup, fake_motor_ioc):
    pvs = fake_motor_ioc.pvs
    pv = EpicsSignal(write_pv=pvs['setpoint'], read_pv=pvs['readback'],
                     name='pv')
    cleanup.add(pv)

    setpoint_called = []
    setpoint_meta_called = []

    def sub_setpoint(old_value, value, **kwargs):
        setpoint_called.append((old_value, value))

    def sub_setpoint_meta(timestamp, **kwargs):
        setpoint_meta_called.append(timestamp)

    pv.subscribe(sub_setpoint, event_type=pv.SUB_SETPOINT)
    pv.subscribe(sub_setpoint_meta, event_type=pv.SUB_SETPOINT_META)

    pv.wait_for_connection()

    pv.put(1, wait=True)
    pv.put(2, wait=True)
    time.sleep(0.5)

    assert len(setpoint_called) >= 3
    assert len(setpoint_meta_called) >= 3
예제 #6
0
    def test_enum_strs(self):
        epics.PV = FakeEpicsPV
        sig = EpicsSignal('connects')
        sig.wait_for_connection()

        enums = ['enum_strs']

        # hack this onto the FakeEpicsPV
        sig._read_pv.enum_strs = enums

        self.assertEquals(sig.enum_strs, enums)
예제 #7
0
    def test_epicssignal_waveform(self):
        epics.PV = FakeEpicsWaveform

        def update_cb(value=None, **kwargs):
            self.assertIn(value, FakeEpicsWaveform.strings)

        signal = EpicsSignal('readpv', string=True)
        signal.wait_for_connection()

        signal.subscribe(update_cb)
        self.assertIn(signal.value, FakeEpicsWaveform.strings)
예제 #8
0
def test_fakepv_signal():
    sig = EpicsSignal(write_pv='XF:31IDA-OP{Tbl-Ax:X1}Mtr.VAL',
                      read_pv='XF:31IDA-OP{Tbl-Ax:X1}Mtr.RBV')
    st = sig.set(1)

    for j in range(10):
        if st.done:
            break
        time.sleep(.1)

    assert st.done
예제 #9
0
    def test_setpoint(self):
        epics.PV = FakeEpicsPV
        sig = EpicsSignal('connects')
        sig.wait_for_connection()

        sig.get_setpoint()
        sig.get_setpoint(as_string=True)
예제 #10
0
def test_epicssignal_get_in_callback(cleanup, fake_motor_ioc):
    pvs = fake_motor_ioc.pvs
    sig = EpicsSignal(write_pv=pvs['setpoint'], read_pv=pvs['readback'],
                      name='motor')
    cleanup.add(sig)

    called = []

    def generic_sub(sub_type, **kwargs):
        called.append((sub_type, sig.get(), sig.get_setpoint()))

    for event_type in (sig.SUB_VALUE, sig.SUB_META,
                       sig.SUB_SETPOINT, sig.SUB_SETPOINT_META):
        sig.subscribe(generic_sub, event_type=event_type)

    sig.wait_for_connection()

    sig.put(1, wait=True)
    sig.put(2, wait=True)
    time.sleep(0.5)

    print(called)
    # Arbitrary threshold, but if @klauer screwed something up again, this will
    # blow up
    assert len(called) < 20
    print('total', len(called))
예제 #11
0
def test_epicssignal_waveform(cleanup, signal_test_ioc):
    def update_cb(value=None, **kwargs):
        assert len(value) > 1

    signal = EpicsSignal(signal_test_ioc.pvs['waveform'], string=True)
    cleanup.add(signal)
    signal.wait_for_connection()

    sub = signal.subscribe(update_cb, event_type=signal.SUB_VALUE)
    assert len(signal.value) > 1
    signal.unsubscribe(sub)
예제 #12
0
def set_severity_signal(cleanup, signal_test_ioc):
    sig = EpicsSignal(signal_test_ioc.pvs['set_severity'], name='set_severity')
    cleanup.add(sig)
    sig.wait_for_connection()
    return sig
예제 #13
0
def rw_signal(cleanup, signal_test_ioc):
    sig = EpicsSignal(signal_test_ioc.pvs['read_write'], name='read_write')
    cleanup.add(sig)
    sig.wait_for_connection()
    return sig
예제 #14
0
def bool_enum_signal(cleanup, signal_test_ioc):
    sig = EpicsSignal(signal_test_ioc.pvs['bool_enum'], name='bool_enum')
    cleanup.add(sig)
    sig.wait_for_connection()
    return sig
예제 #15
0
파일: lv8018.py 프로젝트: slactjohnson/mec
 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
예제 #16
0
def liveMonitor(sigList=['29idd:tc1:setVal_SP.VAL', '29idd:tc1:getVal_B'],
                displayList=['TC1 setpoint', 'TC1 readback'],
                delay=1,
                points=None,
                testPlot=False,
                liveTab=False,
                ylab=True,
                verbose=False):
    '''	liveMonitor plots (with live updates) PVs. 

	Inputs:

	sigList: 		List of PVs to plot. Defaults are two signals from 29ID.
	displayList: 	Display names for the plots for each PV. Defaults are two 
					signals from 29ID.
	delay: 			delay in seconds between data acquisitions. Defaults 
					to 1 second
	points: 		number of points to acquire, Defaults to infinite
	testPlot:       boolean set to True for using bluesky test signals (det1, 
					noisy_det). Defaults to False
	liveTab			boolean for adding a LiveTable callback during plan. 
					Defaults to False (no LiveTable).
	ylab:			boolean for using EGU field of 1st PV as y-label of plot.  
					Defaults to True (use EGU field)
	verbose:		boolean for showing tracebacks. Default is false which
					suppresses traceback listing
	'''

    if not verbose:
        sys.tracebacklimit = 0
    else:
        sys.tracebacklimit = 1000

    #setup PVs to be monitored
    pvList = []
    if not testPlot:
        for j in range(len(sigList)):
            sig = EpicsSignal(sigList[j], name=displayList[j])
            pvList.append(sig)
            if j == 0:
                ylabel = 'EGU'  #need to add code to use value of EGU field of
                #first PV as y-axis label
    else:
        pvList = [noisy_det, det1, det2]
        displayList = ['noisy_det', 'det1', 'det2']
        ylabel = 'Arb. units'

    #create plot object
    fig, ax = plt.subplots()

    #Rescaling operation -- needs to be here to get ax object
    class AutoScaleAxes(object):
        def resetAxes(self, event):
            ax.set_xlim(auto=True)
            ax.set_ylim(auto=True)

    #Rescale button
    ASA = AutoScaleAxes()
    axreset = plt.axes([0.62, 0.91, 0.14, 0.07])
    breset = Button(axreset, 'Reset Axes')
    breset.on_clicked(ASA.resetAxes)

    #Quit button
    DFC = DataFlowControl()
    axquit = plt.axes([0.79, 0.91, 0.18, 0.07])
    bquit = Button(axquit, 'Quit Monitor')
    bquit.on_clicked(DFC.quitMon)

    lm_callbacks = []

    #Define LiveTable callback
    if liveTab:
        lm_callbacks.append(LiveTable(pvList))

    #Define multi-plot callback
    for i in pvList:
        lm_callbacks.append(LivePlot2(i, x='time', ax=ax, label=i.name))

    #set axis labels
    ax.set_xlabel('Time')
    if ylab:
        ax.set_ylabel(ylabel)
    else:
        ax.set_ylabel(' ')

    #reformat axis tick labels and data
    lmformat = mdates.DateFormatter('%m/%d %H:%M:%S')
    ax.xaxis.set_major_formatter(lmformat)
    ax.format_xdata = lmformat
    labels = ax.get_xticklabels()
    plt.setp(labels, rotation=30, ha='right')
    plt.subplots_adjust(bottom=0.20)

    #start Run Engine
    RE(count(pvList, delay=delay, num=points), lm_callbacks)

    return
예제 #17
0
class _OptionalEpicsSignal(Signal):
    """
    An EPICS Signal which may or may not exist.

    The init parameters mirror those of :class:`~ophyd.EpicsSignal`.

    Notes
    -----
    This should be considered for internal use only, and not for
    user-facing device components.  If you use this in your new device,
    there is a good chance we will reject your PR.
    """
    def __init__(self,
                 read_pv,
                 write_pv=None,
                 *,
                 name,
                 parent=None,
                 kind=None,
                 **kwargs):
        self._saw_connection = False
        self._epics_signal = EpicsSignal(read_pv=read_pv,
                                         write_pv=write_pv,
                                         parent=self,
                                         name=name,
                                         kind=kind,
                                         **kwargs)
        super().__init__(name=name, parent=parent, kind=kind)
        self._epics_signal.subscribe(
            self._epics_meta_update,
            event_type=self._epics_signal.SUB_META,
        )

    def _epics_value_update(self, **kwargs):
        """The EpicsSignal value updated."""
        super().put(value=kwargs['value'],
                    timestamp=kwargs['timestamp'],
                    force=True)
        # Note: the above internally calls run_subs
        # self._run_subs(**kwargs)

    def _epics_meta_update(self, sub_type=None, **kwargs):
        """The EpicsSignal metadata updated; reflect that here."""
        self._metadata.update(**kwargs)
        self._run_subs(sub_type=self.SUB_META, **kwargs)

        if not self._saw_connection and kwargs.get('connected', False):
            self._epics_signal.subscribe(self._epics_value_update)
            self._saw_connection = True

    def destroy(self):
        super().destroy()
        self._epics_signal.destroy()
        self._epics_signal = None

    def should_use_epics_signal(self) -> bool:
        """
        Tell `_OptionalEpicsSignal` whether or not to use the `EpicsSignal`.

        By default, the `EpicsSignal` will be used if the PV has connected.

        Note
        ----
        * Subclasses should override this with their own functionality.
        * This value should not change during the lifetime of the
          `_OptionalEpicsSignal`.
        """
        return self._saw_connection

    def _proxy_method(method_name):  # noqa
        """
        Proxy a method from either the EpicsSignal or the superclass Signal.
        """
        def method_selector(self, *args, **kwargs):
            owner = (self._epics_signal
                     if self.should_use_epics_signal() else super())
            return getattr(owner, method_name)(*args, **kwargs)

        return method_selector

    describe = _proxy_method('describe')
    describe_configuration = _proxy_method('describe_configuration')
    get = _proxy_method('get')
    put = _proxy_method('put')
    set = _proxy_method('set')
    read = _proxy_method('read')
    read_configuration = _proxy_method('read_configuration')
    wait_for_connection = _proxy_method('wait_for_connection')

    def _proxy_property(prop_name, value):  # noqa
        """Read-only property proxy for the internal EPICS Signal."""
        def getter(self):
            if self.should_use_epics_signal():
                return getattr(self._epics_signal, prop_name)
            return value

        # Only support read-only properties for now.
        return property(getter)

    connected = _proxy_property('connected', True)
    read_access = _proxy_property('read_access', True)
    write_access = _proxy_property('write_access', True)
    precision = _proxy_property('precision', 4)
    enum_strs = _proxy_property('enum_strs', ())
    limits = _proxy_property('limits', (0, 0))

    @property
    def kind(self):
        """The EPICS signal's kind."""
        return self._epics_signal.kind

    @kind.setter
    def kind(self, value):
        self._epics_signal.kind = value
예제 #18
0
def test_describe():
    sig = EpicsSignal('my_pv')
    sig._write_pv.enum_strs = ('enum1', 'enum2')
    sig.wait_for_connection()

    sig.put(1)
    desc = sig.describe()['my_pv']
    assert desc['dtype'] == 'integer'
    assert desc['shape'] == []
    assert 'precision' in desc
    assert 'enum_strs' in desc
    assert 'upper_ctrl_limit' in desc
    assert 'lower_ctrl_limit' in desc

    sig.put('foo')
    desc = sig.describe()['my_pv']
    assert desc['dtype'] == 'string'
    assert desc['shape'] == []

    sig.put(3.14)
    desc = sig.describe()['my_pv']
    assert desc['dtype'] == 'number'
    assert desc['shape'] == []

    import numpy as np
    sig.put(np.array([
        1,
    ]))
    desc = sig.describe()['my_pv']
    assert desc['dtype'] == 'array'
    assert desc['shape'] == [
        1,
    ]
예제 #19
0
def bool_enum_signal(cleanup, signal_test_ioc):
    sig = EpicsSignal(signal_test_ioc.pvs['bool_enum'], name='bool_enum')
    cleanup.add(sig)
    sig.wait_for_connection()
    return sig
예제 #20
0
def test_epicssignal_set(cleanup, motor, put_complete):
    sim_pv = EpicsSignal(write_pv=motor.user_setpoint.pvname,
                         read_pv=motor.user_readback.pvname,
                         put_complete=put_complete)
    cleanup.add(sim_pv)
    sim_pv.wait_for_connection()

    logging.getLogger('ophyd.signal').setLevel(logging.DEBUG)
    logging.getLogger('ophyd.utils.epics_pvs').setLevel(logging.DEBUG)
    print('tolerance=', sim_pv.tolerance)
    assert sim_pv.tolerance is not None

    start_pos = sim_pv.get()

    # move to +0.2 and check the status object
    target = sim_pv.get() + 0.2
    st = sim_pv.set(target, timeout=1, settle_time=0.001)
    wait(st, timeout=5)
    assert st.done
    assert st.success
    print('status 1', st)
    assert abs(target - sim_pv.get()) < 0.05

    # move back to -0.2, forcing a timeout with a low value
    target = sim_pv.get() - 0.2
    st = sim_pv.set(target, timeout=1e-6)
    time.sleep(0.5)
    print('status 2', st)
    assert st.done
    assert not st.success

    # keep the axis in position
    st = sim_pv.set(start_pos)
    wait(st, timeout=5)
예제 #21
0
def test_describe(cleanup, signal_test_ioc):
    sig = EpicsSignal(signal_test_ioc.pvs['bool_enum'], name='my_pv')
    cleanup.add(sig)
    sig.wait_for_connection()

    sig.put(1)
    desc = sig.describe()['my_pv']
    assert desc['dtype'] == 'integer'
    assert desc['shape'] == []
    # assert 'precision' in desc
    assert desc['enum_strs'] == ['Off', 'On']
    assert 'upper_ctrl_limit' in desc
    assert 'lower_ctrl_limit' in desc

    sig = Signal(name='my_pv')
    sig.put('Off')
    desc = sig.describe()['my_pv']
    assert desc['dtype'] == 'string'
    assert desc['shape'] == []

    sig.put(3.14)
    desc = sig.describe()['my_pv']
    assert desc['dtype'] == 'number'
    assert desc['shape'] == []

    import numpy as np
    sig.put(np.array([
        1,
    ]))
    desc = sig.describe()['my_pv']
    assert desc['dtype'] == 'array'
    assert desc['shape'] == [
        1,
    ]
예제 #22
0
def test_enum_strs(cleanup, signal_test_ioc):
    sig = EpicsSignal(signal_test_ioc.pvs['bool_enum'])
    cleanup.add(sig)
    sig.wait_for_connection()

    assert sig.enum_strs == ('Off', 'On')
예제 #23
0
def test_epicssignal_readwrite(cleanup, signal_test_ioc):
    signal = EpicsSignal(read_pv=signal_test_ioc.pvs['read_only'],
                         write_pv=signal_test_ioc.pvs['read_write'],
                         limits=True)
    cleanup.add(signal)

    signal.wait_for_connection()
    assert signal.setpoint_pvname == signal_test_ioc.pvs['read_write']
    assert signal.pvname == signal_test_ioc.pvs['read_only']
    signal.value

    signal._update_rate = 2
    time.sleep(0.2)

    value = 10
    signal.value = value
    signal.setpoint = value
    assert signal.setpoint == value
    signal.setpoint_ts

    signal.limits
    signal.precision
    signal.timestamp

    signal.read()
    signal.describe()
    signal.read_configuration()
    signal.describe_configuration()

    eval(repr(signal))
    time.sleep(0.2)
예제 #24
0
def test_epicssignal_readwrite_limits(cleanup, signal_test_ioc):
    signal = EpicsSignal(read_pv=signal_test_ioc.pvs['read_only'],
                         write_pv=signal_test_ioc.pvs['read_write'],
                         limits=True)
    cleanup.add(signal)

    signal.wait_for_connection()
    signal.check_value((signal.low_limit + signal.high_limit) / 2)

    with pytest.raises(ValueError):
        signal.check_value(None)

    with pytest.raises(ValueError):
        signal.check_value(signal.low_limit - 1)

    with pytest.raises(ValueError):
        signal.check_value(signal.high_limit + 1)
예제 #25
0
def test_epicssignal_readwrite_limits():
    signal = EpicsSignal('readpv', write_pv='readpv', limits=True)

    signal.wait_for_connection()
    signal.check_value((signal.low_limit + signal.high_limit) / 2)

    try:
        signal.check_value(None)
    except ValueError:
        pass
    else:
        raise ValueError('value=None')

    try:
        signal.check_value(signal.low_limit - 1)
    except ValueError:
        pass
    else:
        raise ValueError('lower limit %s' % (signal.limits, ))

    try:
        signal.check_value(signal.high_limit + 1)
    except ValueError:
        pass
    else:
        raise ValueError('upper limit')
예제 #26
0
def test_epicssignal_readwrite_limits():
    signal = EpicsSignal('readpv', write_pv='readpv', limits=True)

    signal.wait_for_connection()
    signal.check_value((signal.low_limit + signal.high_limit) / 2)

    try:
        signal.check_value(None)
    except ValueError:
        pass
    else:
        raise ValueError('value=None')

    try:
        signal.check_value(signal.low_limit - 1)
    except ValueError:
        pass
    else:
        raise ValueError('lower limit %s' % (signal.limits, ))

    try:
        signal.check_value(signal.high_limit + 1)
    except ValueError:
        pass
    else:
        raise ValueError('upper limit')
예제 #27
0
def test_no_connection(cleanup, signal_test_ioc):
    sig = EpicsSignal('does_not_connect')
    cleanup.add(sig)

    with pytest.raises(TimeoutError):
        sig.wait_for_connection()

    sig = EpicsSignal('does_not_connect')
    cleanup.add(sig)

    with pytest.raises(TimeoutError):
        sig.put(0.0)

    with pytest.raises(TimeoutError):
        sig.get()

    sig = EpicsSignal(signal_test_ioc.pvs['read_only'], write_pv='does_not_connect')
    cleanup.add(sig)
    with pytest.raises(TimeoutError):
        sig.wait_for_connection()
예제 #28
0
def test_setpoint():
    sig = EpicsSignal('connects')
    sig.wait_for_connection()

    sig.get_setpoint()
    sig.get_setpoint(as_string=True)
예제 #29
0
def rw_signal(cleanup, signal_test_ioc):
    sig = EpicsSignal(signal_test_ioc.pvs['read_write'], name='read_write')
    cleanup.add(sig)
    sig.wait_for_connection()
    return sig
예제 #30
0
class User():

    target_x = Motor('MEC:USR:MMS:17', name='target_x_motor')

    YFEon = YFEon
    YFEoff = YFEoff
    HWPon = HWPon
    SHG_opt = SHG_opt
    save_scope_to_eLog = save_scope_to_eLog

    def start_seq(self, rate=120, wLPLaser=False):
        if rate == 120:
            sync_mark = 6  #int(_sync_markers[120])
        elif rate == 60:
            sync_mark = 5
        elif rate == 30:
            sync_mark = 4
        elif rate == 10:
            sync_mark = 3
        elif rate == 5:
            sync_mark = 2
        elif rate == 1:
            sync_mark = 1
        elif rate == 0.5:
            sync_mark = 0
        seq.sync_marker.put(sync_mark)
        seq.play_mode.put(2)  # Run sequence forever
        ff_seq = [[169, 0, 0, 0]]
        if wLPLaser:
            ff_seq.append([182, 0, 0, 0])
        seq.sequence.put_seq(ff_seq)
        seq.start()

    _seq = Sequence()
    _sync_markers = {0.5: 0, 1: 1, 5: 2, 10: 3, 30: 4, 60: 5, 120: 6, 360: 7}

    nsl = NanoSecondLaser()
    fsl = FemtoSecondLaser()

    shutters = [1, 2, 3, 4, 5, 6]
    _shutters = {
        1: shutter1,
        2: shutter2,
        3: shutter3,
        4: shutter4,
        5: shutter5,
        6: shutter6
    }

    seq_a_pvs = [
        EpicsSignal('MEC:ECS:IOC:01:EC_6:00'),
        EpicsSignal('MEC:ECS:IOC:01:EC_6:01'),
        EpicsSignal('MEC:ECS:IOC:01:EC_6:02'),
        EpicsSignal('MEC:ECS:IOC:01:EC_6:03'),
        EpicsSignal('MEC:ECS:IOC:01:EC_6:04'),
        EpicsSignal('MEC:ECS:IOC:01:EC_6:05'),
        EpicsSignal('MEC:ECS:IOC:01:EC_6:06'),
        EpicsSignal('MEC:ECS:IOC:01:EC_6:07'),
        EpicsSignal('MEC:ECS:IOC:01:EC_6:08'),
        EpicsSignal('MEC:ECS:IOC:01:EC_6:09')
    ]

    seq_b_pvs = [
        EpicsSignal('MEC:ECS:IOC:01:BD_6:00'),
        EpicsSignal('MEC:ECS:IOC:01:BD_6:01'),
        EpicsSignal('MEC:ECS:IOC:01:BD_6:02'),
        EpicsSignal('MEC:ECS:IOC:01:BD_6:03'),
        EpicsSignal('MEC:ECS:IOC:01:BD_6:04'),
        EpicsSignal('MEC:ECS:IOC:01:BD_6:05'),
        EpicsSignal('MEC:ECS:IOC:01:BD_6:06'),
        EpicsSignal('MEC:ECS:IOC:01:BD_6:07'),
        EpicsSignal('MEC:ECS:IOC:01:BD_6:08'),
        EpicsSignal('MEC:ECS:IOC:01:BD_6:09')
    ]

    def open_shutters(self):
        print("Opening shutters...")
        for shutter in self.shutters:
            self._shutters[shutter].open()
        time.sleep(5)

    def close_shutters(self):
        print("Closing shutters...")
        for shutter in self.shutters:
            self._shutters[shutter].close()
        time.sleep(5)

    def seq_wait(self):
        time.sleep(0.5)
        while seq.play_status.get() != 0:
            time.sleep(0.5)

    def scalar_sequence_write(self, s):
        for i in range(len(s)):
            self.seq_a_pvs[i].put(s[i][0])
        for j in range(len(s)):
            self.seq_b_pvs[j].put(s[j][1])

        seq.sequence_length.put(len(s))
예제 #31
0
    def test_epicssignal_readwrite(self):
        epics.PV = FakeEpicsPV

        signal = EpicsSignal('readpv', write_pv='writepv')
        signal.wait_for_connection()

        self.assertEquals(signal.setpoint_pvname, 'writepv')
        self.assertEquals(signal.pvname, 'readpv')
        signal.value

        signal._update_rate = 2
        time.sleep(0.2)

        value = 10
        signal.value = value
        signal.setpoint = value
        self.assertEquals(signal.setpoint, value)
        signal.setpoint_ts

        signal.limits
        signal.precision
        signal.timestamp

        signal.read()
        signal.describe()
        signal.read_configuration()
        signal.describe_configuration()

        eval(repr(signal))
        time.sleep(0.2)
예제 #32
0
파일: lv8018.py 프로젝트: slactjohnson/mec
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))
예제 #33
0
class FuncPositioner(FltMvInterface, SoftPositioner):
    """
    Class for hacking together a positioner-like object.

    Before you use this, make sure your use case cannot be easily handled by a
    `PVPositioner` or by a `PseudoPositioner`.

    This should be fast to set up, but has the following limitations:
    - Inspection tools will not work properly, in general
    - typhos, happi, and similar tools will not work
    - It is not possible to know ahead of time if any control layer signals
      poked by this device are connected.
    - Metadata about the control layer will not be provided.
    - It's not possible to intelligently subscribe to control layer signals.
      Everything will be periodic polls on background threads.
    - Session performance may be negatively impacted by slow polling functions.

    Parameters
    ----------
    name : str, keyword-only
        The name to use when we refer to this positioner.

    move : func, keyword-only
        The function to call to cause the device to move.
        The signature must be def fn(position)

    get_pos : func, keyword-only
        The function to call to check the device's position.
        The signature must be def fn()

    set_pos : func, optional, keyword-only
        If provided, the function to call to change the device's shown
        position without moving it. The signature must be def fn(position)

    stop : func, optional, keyword-only
        If provided, the function to call to stop the motor.
        The signature must be def fn()

    done : func, optional, keyword-only
        If provided, the function to call to check if the device
        is done moving. The signature must be def fn() -> bool, and it
        must return True when motion is complete and false otherwise.

    check_value : func, optional, keyword-only
        If provided, an extra function to call to check if it is safe to
        move. The signature must be def fn(position) -> raise ValueError

    info : func, optional, keyword-only
        If provided, an extra function to add data to the ipython console
        pretty-print. The signature must be def fn() -> dict{str: value}.

    egu : str, optional
        If provided, the metadata units for the positioner.

    limits : tuple of floats, optional
        If provided, we'll raise an exception to reject moves outside of this
        range.

    update_rate : float, optional
        How often to update the position and check for move completion during a
        move. Defaults to 1 second.

    timeout : float, optional
        How long to wait before marking an in-progress move as failed.
        Defaults to 60 seconds.

    notepad_pv : str, optional
        If provided, a PV to put to whenever we move. This can be used to allow
        other elements in the control system to see what this positioner is
        doing.
    """
    def __init__(self,
                 *,
                 name,
                 move,
                 get_pos,
                 set_pos=None,
                 stop=None,
                 done=None,
                 check_value=None,
                 info=None,
                 egu='',
                 limits=None,
                 update_rate=1,
                 timeout=60,
                 notepad_pv=None,
                 parent=None,
                 kind=None,
                 **kwargs):
        self._check_signature('move', move, 1)
        self._move = move
        self._check_signature('get_pos', get_pos, 0)
        self._get_pos = get_pos
        self._check_signature('set_pos', set_pos, 1)
        self._set_pos = set_pos
        self._check_signature('stop', stop, 0)
        self._stop = stop
        self._check_signature('done', done, 0)
        self._done = done
        self._check_signature('check_value', check_value, 1)
        self._check = check_value
        self._info = info
        self._last_update = 0
        self._goal = None
        self.update_rate = 1
        notepad_name = name + '_notepad'
        if notepad_pv is None:
            self.notepad_signal = Signal(name=notepad_name)
        else:
            self.notepad_signal = EpicsSignal(notepad_pv, name=notepad_name)
        if parent is None and kind is None:
            kind = 'hinted'
        super().__init__(name=name,
                         egu=egu,
                         limits=limits,
                         source='func',
                         timeout=timeout,
                         parent=parent,
                         kind=kind,
                         **kwargs)

    def _check_signature(self, name, func, nargs):
        if func is None:
            return
        sig = inspect.signature(func)
        try:
            sig.bind(*(0, ) * nargs)
        except TypeError:
            raise ValueError(
                f'FuncPositioner recieved {name} with an incorrect. '
                f'signature. Must be able to take {nargs} args.') from None

    def _setup_move(self, position, status):
        self._run_subs(sub_type=self.SUB_START, timestamp=time.time())
        self._goal = position
        self._started_moving = True
        self._moving = True
        self._finished = False
        self._move(position)
        self._new_update(status)

    def _new_update(self, status):
        schedule_task(self._update_task,
                      args=(status, ),
                      delay=self.update_rate)

    def _update_task(self, status):
        self._update_position()
        if self._check_finished():
            try:
                status.set_finished()
            except InvalidState:
                pass
        if status.done:
            self._started_moving = False
            self._moving = False
        else:
            self._new_update(status)

    @property
    def position(self):
        self._update_position()
        return self._position

    def _update_position(self):
        if time.monotonic() - self._last_update > self.update_rate:
            self._last_update = time.monotonic()
            pos = self._get_pos()
            self._set_position(pos)
            self.notepad_signal.put(pos)

    def _check_finished(self):
        if self._done is None:
            finished = np.isclose(self._goal, self.position)
        else:
            finished = self._done()
        if finished:
            self._done_moving()
        return finished

    def set_position(self, position):
        if self._set_pos is None:
            raise NotImplementedError(f'FuncPositioner {self.name} was not '
                                      'given a set_pos argument.')
        else:
            self._set_pos(position)

    def stop(self, *args, **kwargs):
        if self._stop is None:
            # Often called by bluesky, don't throw an exception
            self.log.warning(f'Called stop on FuncPositioner {self.name}, '
                             'but was not given a stop argument.')
        else:
            self._stop()
        super().stop(*args, **kwargs)

    def check_value(self, pos):
        super().check_value(pos)
        if self._check is not None:
            self._check(pos)

    def status_info(self):
        info = super().status_info()
        if self._info is not None:
            info.update(self._info())
        return info
예제 #34
0
파일: lv0818.py 프로젝트: slactjohnson/mec
class User():

    target_x = Motor('MEC:USR:MMS:17', name='target_x_motor')

    YFEon = YFEon
    YFEoff = YFEoff
    HWPon = HWPon
    SHG_opt = SHG_opt
    save_scope_to_eLog = save_scope_to_eLog

    def start_seq(self, rate=120, wLPLaser=False):
        if rate==120:
            sync_mark = 6#int(_sync_markers[120])
        elif rate==60:
            sync_mark = 5
        elif rate==30:
            sync_mark = 4
        elif rate==10:
            sync_mark = 3
        elif rate==5:
            sync_mark = 2
        elif rate==1:
            sync_mark = 1
        elif rate==0.5:
            sync_mark = 0
        seq.sync_marker.put(sync_mark)
        seq.play_mode.put(2) # Run sequence forever
        ff_seq = [[169, 0, 0, 0]]
        if wLPLaser:
            ff_seq.append([182, 0, 0, 0])
        seq.sequence.put_seq(ff_seq)
        seq.start()

    def start_seq_120Hz(self):
        #self.start_seq_120Hz(120)
        sync_mark = 6#int(_sync_markers[120])
        seq.sync_marker.put(sync_mark)
        seq.play_mode.put(2) # Run sequence forever
        ff_seq = [[169, 0, 0, 0]]
        seq.sequence.put_seq(ff_seq)
        seq.start()

    def start_seq_10Hz(self, wLPLaser=False):
        sync_mark = 3#int(_sync_markers[10])
        seq.sync_marker.put(sync_mark)
        seq.play_mode.put(2) # Run sequence forever
        ff_seq = [[169, 0, 0, 0]]
        if wLPLaser:
            ff_seq.append([182, 0, 0, 0])
        seq.sequence.put_seq(ff_seq)
        seq.start()

    _seq = Sequence()
    _sync_markers = {0.5:0, 1:1, 5:2, 10:3, 30:4, 60:5, 120:6, 360:7}

    nsl = NanoSecondLaser()
    fsl = FemtoSecondLaser()

    shutters = [1,2,3,4,5,6]
    _shutters = {1: shutter1,
                 2: shutter2,
                 3: shutter3,
                 4: shutter4,
                 5: shutter5,
                 6: shutter6}

    seq_a_pvs = [EpicsSignal('MEC:ECS:IOC:01:EC_6:00'),
                 EpicsSignal('MEC:ECS:IOC:01:EC_6:01'),
                 EpicsSignal('MEC:ECS:IOC:01:EC_6:02'),
                 EpicsSignal('MEC:ECS:IOC:01:EC_6:03'),
                 EpicsSignal('MEC:ECS:IOC:01:EC_6:04'),
                 EpicsSignal('MEC:ECS:IOC:01:EC_6:05'),
                 EpicsSignal('MEC:ECS:IOC:01:EC_6:06'),
                 EpicsSignal('MEC:ECS:IOC:01:EC_6:07'),
                 EpicsSignal('MEC:ECS:IOC:01:EC_6:08'),
                 EpicsSignal('MEC:ECS:IOC:01:EC_6:09')]

    seq_b_pvs = [EpicsSignal('MEC:ECS:IOC:01:BD_6:00'),
                 EpicsSignal('MEC:ECS:IOC:01:BD_6:01'),
                 EpicsSignal('MEC:ECS:IOC:01:BD_6:02'),
                 EpicsSignal('MEC:ECS:IOC:01:BD_6:03'),
                 EpicsSignal('MEC:ECS:IOC:01:BD_6:04'),
                 EpicsSignal('MEC:ECS:IOC:01:BD_6:05'),
                 EpicsSignal('MEC:ECS:IOC:01:BD_6:06'),
                 EpicsSignal('MEC:ECS:IOC:01:BD_6:07'),
                 EpicsSignal('MEC:ECS:IOC:01:BD_6:08'),
                 EpicsSignal('MEC:ECS:IOC:01:BD_6:09')]

    def open_shutters(self):
        print("Opening shutters...")
        for shutter in self.shutters:
            self._shutters[shutter].open()
        time.sleep(5)

    def close_shutters(self):
        print("Closing shutters...")
        for shutter in self.shutters:
            self._shutters[shutter].close()
        time.sleep(5)

    def seq_wait(self):
        time.sleep(0.5)
        while seq.play_status.get() != 0:
            time.sleep(0.5)

    def scalar_sequence_write(self, s):
        for i in range(len(s)):
            self.seq_a_pvs[i].put(s[i][0])
        for j in range(len(s)):
            self.seq_b_pvs[j].put(s[j][1])

        seq.sequence_length.put(len(s))

    def uxi_shot(self, delta=0.3, record=True, lasps=True):
        """
        Returns a BlueSky plan to run a scan for the LV08 experiment. Used for
        the UXI camera which requires near continuous acquisition for stable
        camera behavior. The following shots are combined in a single run.

        Shot sequence:
        --------------
        1) 10 dark frames    # Warm up camera
        2) 10 X-ray frames
        3) Sample moves in
        4) 10 dark frames    # Warm up camera
        5) 1 X-ray + Optical laser frame
        6) 10 dark frames
        7) Sample moves out
        8) 10 dark frames    # Warm up camera
        9) 10 X-ray frames
        
        Parameters:
        -----------
        delta : float <default: 0.3>
            The relative distance in mm to move the sample in and out.

        record : bool <default: True>
            Flag to record the data (or not).

        lasps : bool <default: True>
            Flag to perform pre-and post shot pulse shaping routines. 
        """
        logging.debug("Calling User.shot with parameters:")
        logging.debug("delta: {}".format(delta))        
        logging.debug("record: {}".format(record))        
        logging.debug("lasps: {}".format(lasps))        

        print("Configuring DAQ...")
#        yield from bps.configure(daq,events=0, record=record) # run infinitely, let sequencer
                                               # control number of events
        daq.begin_infinite(record=record)

        long_seq = [[0, 240, 0, 0],
                    [0, 0, 0, 0],
                    [0, 0, 0, 0],
                    [0, 0, 0, 0],
                    [0, 0, 0, 0],
                    [0, 0, 0, 0],
                    [0, 0, 0, 0],
                    [0, 0, 0, 0]]
        
        print("Configuring sequencer...")
        # Setup the pulse picker for single shots in flip flop mode
        pp.flipflop(wait=True)
        # Setup sequencer for requested rate
        sync_mark = int(self._sync_markers[0.5])
        seq.sync_marker.put(sync_mark)
        seq.play_mode.put(1) # Run N times
        seq.rep_count.put(10) 
        # Setup sequence
        self._seq.rate = 0.5

        # close the shutters specified by the user
        for shutter in self.shutters:
            self._shutters[shutter].close()
        # Shutters are slow; give them time to close
        time.sleep(5)

        if lasps:
            print("Running mecps.pspreshot()...")
            pspreshot()

        # Run 10 Pre-laser dark shots (step 1 above)
        s = self._seq.darkSequence(1, preshot=False)
#        seq.sequence.put_seq(long_seq)
#        seq.sequence.put_seq(s)
        self.scalar_sequence_write(s)
        print("Taking 10 dark shots...")
        time.sleep(1)
        seq.start()
        self.seq_wait()
 #       yield from bps.trigger_and_read([daq, seq])

        # Run 10 Pre-laser x-ray shots (step 2 above)
        s = self._seq.darkXraySequence(1, preshot=False)
#        seq.sequence.put_seq(long_seq)
#        seq.sequence.put_seq(s)
        self.scalar_sequence_write(s)
        print("Taking 10 x-ray shots...")
        time.sleep(1)
        seq.start()
        self.seq_wait()
        #yield from bps.trigger_and_read([daq, seq])
        
        # Move sample in (step 3 above)
        print("Moving sample in...")
        yield from bps.mvr(self.target_x, delta) #TODO Check direction

        # Run 10 Pre-laser dark shots (step 4 above)
        print("Taking 10 dark shots...")
        s = self._seq.darkSequence(1, preshot=False)
#        seq.sequence.put_seq(long_seq)
#        seq.sequence.put_seq(s)
        self.scalar_sequence_write(s)
        time.sleep(1)
        seq.start()
        self.seq_wait()
 #       yield from bps.trigger_and_read([daq, seq])

        # Run x-ray + optical sequence (step 5 above)
        print("Taking optical laser shots...")
        seq.rep_count.put(1) 
        s = self._seq.duringSequence(1, 'longpulse')
#        seq.sequence.put_seq(long_seq)
#        seq.sequence.put_seq(s)
        self.scalar_sequence_write(s)
        time.sleep(1)
        seq.start()
        self.seq_wait()
 #       yield from bps.trigger_and_read([daq, seq])

        # Run 10 Post-laser dark shots (step 6 above)
        print("Taking 10 dark shots...")
        seq.rep_count.put(10) 
        s = self._seq.darkSequence(1, preshot=False)
#        seq.sequence.put_seq(long_seq)
#        seq.sequence.put_seq(s)
        self.scalar_sequence_write(s)
        time.sleep(1)
        seq.start()
        self.seq_wait()
 #       yield from bps.trigger_and_read([daq, seq])

        # Move sample out (step 7 above)
        print("Moving sample out...")
        yield from bps.mvr(self.target_x, -delta) #TODO Check direction

        # Run 10 Pre-x-ray dark shots (step 8 above)
        print("Taking 10 dark shots...")
        seq.rep_count.put(10) 
        s = self._seq.darkSequence(1, preshot=False)
#        seq.sequence.put_seq(long_seq)
#        seq.sequence.put_seq(s)
        self.scalar_sequence_write(s)
        time.sleep(1)
        seq.start()
        self.seq_wait()
 #       yield from bps.trigger_and_read([daq, seq])

        # Run 10 Pre-laser x-ray shots (step 9 above)
        print("Taking 10 x-ray shots...")
        s = self._seq.darkXraySequence(1, preshot=False)
#        seq.sequence.put_seq(long_seq)
#        seq.sequence.put_seq(s)
        self.scalar_sequence_write(s)
        time.sleep(1)
        seq.start()
        self.seq_wait()
 #       yield from bps.trigger_and_read([daq, seq])

        daq.end_run()

        if lasps:
            print("Running mecps.pspostshot()...")
            pspostshot()

        # open the shutters specified by the user
        for shutter in self.shutters:
            self._shutters[shutter].open()
예제 #35
0
def motor_pair_signal(cleanup, motor):
    sig = EpicsSignal(write_pv=motor.user_setpoint.pvname,
                      read_pv=motor.user_readback.pvname)
    cleanup.add(sig)
    sig.wait_for_connection()
    return sig
예제 #36
0
def test_no_connection(cleanup, signal_test_ioc):
    sig = EpicsSignal('does_not_connect')
    cleanup.add(sig)

    with pytest.raises(TimeoutError):
        sig.wait_for_connection()

    sig = EpicsSignal('does_not_connect')
    cleanup.add(sig)

    with pytest.raises(TimeoutError):
        sig.put(0.0)

    with pytest.raises(TimeoutError):
        sig.get()

    sig = EpicsSignal(signal_test_ioc.pvs['read_only'],
                      write_pv='does_not_connect')
    cleanup.add(sig)
    with pytest.raises(TimeoutError):
        sig.wait_for_connection()
예제 #37
0
def test_epicssignal_set(put_complete):
    sim_pv = EpicsSignal(write_pv='XF:31IDA-OP{Tbl-Ax:X1}Mtr.VAL',
                         read_pv='XF:31IDA-OP{Tbl-Ax:X1}Mtr.RBV',
                         put_complete=put_complete)
    sim_pv.wait_for_connection()

    logging.getLogger('ophyd.signal').setLevel(logging.DEBUG)
    logging.getLogger('ophyd.utils.epics_pvs').setLevel(logging.DEBUG)
    print('tolerance=', sim_pv.tolerance)
    assert sim_pv.tolerance is not None

    start_pos = sim_pv.get()

    # move to +0.2 and check the status object
    target = sim_pv.get() + 0.2
    st = sim_pv.set(target, timeout=1, settle_time=0.001)
    wait(st)
    assert st.done
    assert st.success
    print('status 1', st)
    assert abs(target - sim_pv.get()) < 0.05

    # move back to -0.2, forcing a timeout with a low value
    target = sim_pv.get() - 0.2
    st = sim_pv.set(target, timeout=1e-6)
    time.sleep(0.1)
    print('status 2', st)
    assert st.done
    assert not st.success

    # keep the axis in position
    st = sim_pv.set(start_pos)
    wait(st)
예제 #38
0
def motor_pair_signal(cleanup, motor):
    sig = EpicsSignal(write_pv=motor.user_setpoint.pvname,
                      read_pv=motor.user_readback.pvname)
    cleanup.add(sig)
    sig.wait_for_connection()
    return sig
예제 #39
0
        ''' Start the Ramping process on all channels '''
        self.start_ramp.put(1)

    def stop(self):
        ''' Stops the Ramping process on all channels '''
        self.stop_ramp.put(1)

    def is_ramping(self):
        ''' Returns wether the power supply is ramping or not '''
        return (int(self.unit_status.get()) >> 30) == 1

    def is_interlock_ok(self):
        ''' Returns the interlock state '''
        st = int(self.unit_status.get())
        return (st & 1) & ((st >> 1) & 1) == 1

    def is_on(self):
        ''' Returns wether the Channels are ON or OFF '''
        return (int(self.unit_status.get()) >> 29) == 1

    def wait(self):
        while self.is_ramping():
            sleep(0.1)


hfm_bimorph = Bimorph('XF:17IDA-OP:FMX{Mir:HFM-PS}', name='hfm_bimorph')
kb_bimorph = Bimorph('XF:17IDC-OP:FMX{Mir:KB-PS}', name='kb_bimorph')

vkb_piezo_tweak = EpicsSignal('XF:17IDC-BI:FMX{Best:2}:PreDAC0:OutCh1')
hkb_piezo_tweak = EpicsSignal('XF:17IDC-BI:FMX{Best:2}:PreDAC0:OutCh2')
예제 #40
0
def alarm_status_signal(cleanup, signal_test_ioc):
    sig = EpicsSignal(signal_test_ioc.pvs['alarm_status'], name='alarm_status')
    cleanup.add(sig)
    sig.wait_for_connection()
    return sig
예제 #41
0
def alarm_status_signal(cleanup, signal_test_ioc):
    sig = EpicsSignal(signal_test_ioc.pvs['alarm_status'], name='alarm_status')
    cleanup.add(sig)
    sig.wait_for_connection()
    return sig
예제 #42
0
def test_epicssignal_readwrite():
    signal = EpicsSignal('readpv', write_pv='writepv')

    signal.wait_for_connection()
    assert signal.setpoint_pvname == 'writepv'
    assert signal.pvname == 'readpv'
    signal.value

    signal._update_rate = 2
    time.sleep(0.2)

    value = 10
    signal.value = value
    signal.setpoint = value
    assert signal.setpoint == value
    signal.setpoint_ts

    signal.limits
    signal.precision
    signal.timestamp

    signal.read()
    signal.describe()
    signal.read_configuration()
    signal.describe_configuration()

    eval(repr(signal))
    time.sleep(0.2)
예제 #43
0
class User():
    def __init__(self):
        #switch to trigger instead of full evr
        self._sync_markers = {0.5:0, 1:1, 5:2, 10:3, 30:4, 60:5, 120:6, 360:7}
        self.trigger_mag = Trigger('XCS:R42:EVR:01:TRIG4', name='trigger_mag')
        self.trigger_pp = Trigger('XCS:USR:EVR:TRIG1', name='trigger_pp')
        self.nemptyshots = actions(0, name='nemptyshots')
        self.isfire = actions(False, name='isfire')
        self.emptyshotspacing = actions(0, name='emptyshotspacing')
        self.nshots = actions(0, name='nshots')
        self.shotspacing = actions(0, name='shotspacing')
        #with safe_load('Pirani and Cold Cathode Gauges'):
        #    self.mag_pirani = BaseGauge('XCS:USR:GPI:01', name='mag_pirani')
        #    self.mag_cc = BaseGauge('XCS:USR:GCC:01', name='mag_cc')
        self.sample_temp = LakeShoreChannel('XCS:USR:TCT:02', name='A')
        self.mag_temp = LakeShoreChannel('XCS:USR:TCT:02', name='B')
        self.ttl_high = 2.0
        self.ttl_low = 0.8
        self._ready_sig = EpicsSignal('XCS:USR:ai1:0', name='User Analog Input channel 0', kind = 'omitted')
        self._ipm4_threshold = IPM4_Threshold(0) #default threshold is 0
        self.ipm4_pv = EpicsSignal('XCS:SB1:BMMON:SUM', name='ipm4_sum')
        self.ipm4_mag_retry = 10
        self._gdet_threshold_pv = EpicsSignal('XCS:VARS:J78:GDET_THRES', kind = 'normal')
        self.gdet_avg_count = 30
        self.gdet_mag_retry = 10
        self.gdet = GasDetector('GDET:FEE1', name='gas detector')
        #self._bykik_pv = Cpt(EpicsSignal('IOC:IN20:EV01:BYKIK_ABTACT', kind = 'normal', string=True, doc='BYKIK: Abort Active')
        self._req_burst_rate = 'Full'
        self._test_burst_rate = EpicsSignal('PATT:SYS0:1:TESTBURSTRATE', name='test_burst_rate', kind='normal')
        self._mps_burst_rate = EpicsSignal('PATT:SYS0:1:MPSBURSTRATE', name='mps_burst_rate')
        # number of seconds to pause between empty and magnet
        self.pause_time = 2.
        self._min_empty_delay = 4 
        self._beam_owner = EpicsSignal('ECS:SYS0:0:BEAM_OWNER_ID', name='beam_owner', kind = 'normal')
        self._att = att
        self.hutch = 'xcs'
        self._hutch_id = EpicsSignal('ECS:SYS0:4:HUTCH_ID', name='hutch_id', kind = 'normal')
        self.aliases = ['BEAM']
        self.gainmodes = ''

#use lcls.(tab) to find bykik controls

    @property
    def machine_burst_rate(self):
        if self._beam_owner.get() == self._hutch_id.get():
            self._mps_burst_rate.get()
        else:
            self._test_burst_rate.get()

    @machine_burst_rate.setter
    def machine_burst_rate(self, rate):
        if self._beam_owner.get() == self._hutch_id.get():
            self._mps_burst_rate.put(rate)
        else:
            self._test_burst_rate.put(rate)

    def check_burst_rate(self):
        if self.machine_burst_rate != self._req_burst_rate:
            print('Machine burst frequency not set to %s! - fixing...' %self._req_burst_rate)
            if self._beam_owner.get() == self._hutch_id.get():
                set_and_wait(self._mps_burst_rate, self._req_burst_rate)  #ophyd set and wait() - ophyd.utils.epics_pvs.set_and_wait
            else:
                set_and_wait(self._test_burst_rate, self._req_burst_rate)
            print('done.')

    @property
    def ready_sig(self):
        self._ready_sig.get()

#    def prepare_burst(self, nShots=None, nWaitShots=None):
#        sync_mark = int(self._sync_markers[120])
#        seq.sync_marker.put(sync_mark)
#        seq.play_mode.put(0)
#        ff_seq = [[84,0,0,0]]
#        ff_seq = ff_seq.append([86, 2, 0, 0])
#        if nShots is not None:
#            if isinstance(nShots, int):
#                ff_seq.append([84, nShots-2, 0, 0])
#        else:
#            ff_seq.append([84, int(nShots*120)-2, 0, 0])
#        if isinstance(nWaitShots, int):
#            ff_seq.append([86, nWaitShots-2, 0, 0])
#        seq.sequence.put_seq(ff_seq)
        
    def _prepare_burst(self, Nshots, Nbursts=1, freq=120, delay=None, burstMode=False):
        if Nshots == 1:
            pp.flipflop()
        elif Nshots > 1:
            pp.burst()
        beamrate = lcls.beam_event_rate.get()
        if Nbursts == 1:
            seq.play_mode.put(0)
        elif Nbursts > 1:
            seq.play_mode.put(1)
            seq.rep_count.put(Nbursts)
        elif Nbursts < 0:
            seq.play_mode.put(2)
        if burstMode:
            burst = Nshots + 2
        else:
            burst = 0
        if not freq == 120:
            raise(NotImplementedError('Not implemented yet!'))
        if Nshots == 1:
            if delay is None:
                delay = 3
            elif delay < 2:
                raise ValueError('Delay between flip flops of less than two is not allowed')
            ff_seq = [[84,delay,0,burst],
                       [86,0,0,burst],
                       [85,2,0,burst]]
        elif Nshots > 1:
            if delay is None:
                delay = 1
            elif delay < 1:
                raise ValueError('Delay between bursts of less than one is not allowed')
            ff_seq = [ [84,delay,0,burst],
                       [86,0,0,burst],
                       [86,1,0,burst] ]
            for shotNo in range(Nshots):
                ff_seq.append([85, 1, 0, burst])
                if shotNo==Nshots-2:
                    ff_seq.append([84, 0, 0, burst])

        seq.sequence.put_seq(ff_seq)
    def _prepNonMagShots(self, nshots):
        #copy code from old pulsepicker.py file in (blinst) and change where needed or xpp experiment
        self._prepare_burst(nshots, burstMode=True)

    def _prepSpacedNonMagShots(self, nshots_per_burst, spacing):
        nshots = 1
        burstDelay = spacing - 2
        self.prepare_burst(nshots, Nbursts=nshots_per_burst, delay=burstDelay, burstMode=True)

    def _takeNonMagShots(self):
        seq.start()

    def _prepMagShot(self, isfire, delay=1):
        playcount = int(seq.play_count.get())
        
        pp.flipflop()
        seq.play_mode.put(0)
        ff_seq = [ [84,delay,0,3],
                       [86,0,0,0] ]
        if isfire:
            ff_seq.append([self.trigger_mag.get_eventcode(), 2, 0, 0])
            ff_seq.append([85, 0, 0, 0])
        else:
            ff_seq.append([85, 2, 0, 0])
        seq.sequence.put_seq(ff_seq)
        playcount += 1
        seq.play_count.put(playcount)
    

    def _takeMagShot(self):
        seq.start()

    def takeEmptyShots(self, nshots, shotspacing, use_daq=False, record=None):
        self.nshots.value = nshots
        self.shotspacing.value = shotspacing
        calibcontrols=[
            (self.nshots),
            (self.shotspacing)
           ]
        if shotspacing > 0:
            self._prepSpacedNonMagShots(self.nshots.value, self.shotspacing.value)
        else:
            self._prepNonMagShots(self.nshots.value)
        #configure daq if being used
        if use_daq:
            daq.record = record
            daq.configure(events=0, controls=calibcontrols)
        try:
            if use_daq:
                daq.begin(event=nshots,controls=calibcontrols)
            seq.start()
            seq.pause()
            if use_daq:
                daq.wait()
        except KeyboardInterrupt:
            seq.stop()
        finally:
            if use_daq:
                daq.record = None
                daq.disconnect()

    def takeMagnetShot(self, nemptyshots, emptyshotspacing=0, isfire=False, record=None):
        self.isfire.value = isfire
        self.nemptyshots.value = nemptyshots
        self.emptyshotspacing.value=emptyshotspacing
        calibcontrols=[
            (self.isfire),
            (self.trigger_mag),
            (self.trigger_mag),
            (self.trigger_mag),
            (self.nemptyshots),
            (self.emptyshotspacing)
           ]
        # check the machine burst rate and set to Full rate if not
        self.check_burst_rate()
        # disable BYKIK before taking shots
        lcls.bykik_disable()
          # check if emptyshotspacing is valid
        if 0 < self.emptyshotspacing.value < self._min_empty_delay:
            raise ValueError("When using spacing between empty shots it must be >= %d" %self._min_empty_delay)
        spacer = "*********************************"
        print("\n%s\n* Preparing to take magnet shot *\n%s\n" %(spacer, spacer))
        if emptyshotspacing > 0:
            mag_status  = "Taking %d shots, with a spacing between each of %d beam pulses, before firing the magnet\n" %(self.nemptyshots.value, self.emptyshotspacing.value)
        else:
            mag_status  = "Taking %d shots before firing the magnet\n" %self.nemptyshots.value
        mag_status += "Magnet pulse eventcode: %d\n" %self.trigger_mag.get_eventcode()
        mag_status += "Magnet pulse trigger delay: %f\n" %self.trigger_mag.get_delay()
        mag_status += "Magnet pulse trigger width: %f\n" %self.trigger_mag.get_width()
        mag_status += "Magnet to be fired: %s\n" %self.isfire.value
        print(mag_status)
        try:
            daq.record = record
            daq.configure(events=0, controls=calibcontrols)
            # Pre empty shots
            if self.nemptyshots.value > 0:
                print("\nPreparing sequencer for pre-firing, non-magnet shots")
                if self.emptyshotspacing.value > 0:
                    self._prepSpacedNonMagShots(self.nemptyshots.value, self.emptyshotspacing.value)
                else:
                    self._prepNonMagShots(self.nemptyshots.value)
                daq.begin(events=self.nemptyshots.value,controls=calibcontrols)
                print("\nTaking %d pre-firing, non-magnet shots\n" %self.nemptyshots.value)
                # pause after changing pulse picker mode
                time.sleep(self.pause_time)
                self._takeNonMagShots()
                seq.pause()
                daq.wait()
            else:
                print("\nSkipping prefiring, non-magnet shots\n")
            # pause after empty shots
            time.sleep(self.pause_time)
            # Fire the magnet sequence based on isfire flag
            if isfire:
                print("Start magnet firing sequence\n")
            else:
                print("Start magnet test 'firing' sequence\n")
            print("\nPreparing sequencer for magnet shot")
            if self.emptyshotspacing.value > 0:
                self._prepMagShot(self.isfire.value, self.emptyshotspacing.value)
            else:
                self._prepMagShot(self.isfire.value)
            # pause after changing pulse picker mode
            time.sleep(self.pause_time)
            #checking ipm4??
            num_tries = 0
            ipm4_good = False
            while num_tries < self.ipm4_mag_retry:
                if self.ipm4_pv < self._ipm4_threshold:
                    print("\nNot firing magnet due to low beam current (ipm4): %.3f \n" %(self.ipm4_pv.get()))
                    backoff_time = 2 ** num_tries
                    print("Sleeping for %d seconds...\n" %backoff_time)
                    time.sleep(backoff_time)
                    num_tries += 1
                else:
                    #ipm4 is good - fire!
                    ipm4_good = True
                    print("\nIPM4 looks good (ipm4): %.3f\n" %self.ipm4_pv.get())
                    break
            if not ipm4_good:
                print("Max number of ipm4 checks (%d) exceeded! - Abort shot attempt.\n" %self.ipm4_mag_retry)
                return False
            # take the magnet shot
            daq.begin(events=1,controls=calibcontrols)
            print("\nTaking magnet shot\n")
            self._takeMagShot()
            seq.pause()
            daq.wait()
            #pause after magnet shots
            time.sleep(self.pause_time)
            #post empty shots
            if nemptyshots > 0:
                print("\nPreparing sequencer for post-firing, non-magnet shots")
                if self.emptyshotspacing.value > 0:
                    self._prepSpacedNonMagShots(self.nemptyshots.value, self.emptyshotspacing.value)
                else:
                    self._prepNonMagShots(self.nemptyshots.value)
                daq.begin(events=self.nemptyshots.value,controls=calibcontrols)
                print("\nTaking %d post-firing, non-magnet shots\n" %self.nemptyshots.value)
                # pause after changing pulse picker mode
                time.sleep(self.pause_time)
                self._takeNonMagShots()
                seq.pause()
                daq.wait()
            else:
                print("\nSkipping post-firing, non-magnet shots\n")
            return True
        except KeyboardInterrupt:
            seq.stop()
            daq.stop()
            return False
        finally:
            daq.record = None
            daq.disconnect()
            lcls.bykik_enable()
    def takeMagnetShotMulti(self, nemptyshots, emptyshotspacing=0, isfire=False, record=None, ignore_ready=False):
        """
        Takes magnet shots in a continous fashion waiting for a ready signal from the magnet controller
        """
        self.nemptyshots.value = nemptyshots
        self.emptyshotspacing.value = emptyshotspacing
        self.isfire.value = isfire
        latch = False
        nmagshots = 0
        shotgood = True
        spacer = '##############################'
        try:
            while shotgood:
                if not latch and (self.ready_sig > self.ttl_high or ignore_ready):
                    if self.ipm4_pv < self._ipm4_threshold:
                        print("\nNot firing magnet due to low beam current (ipm4): %.3f \n" %(self.ipm4_pv.get()))
                        backoff_time = 1
                        print("Sleeping for %d second...\n" %backoff_time)
                        time.sleep(backoff_time)
                        continue
                    latch = True
                    print("\n%s\nStarting shot %d\n%s\n" %(spacer,nmagshots,spacer))
                    start_time = time.time()
                    shotgood = self.takeMagnetShot(self.nemptyshots.value, self.emptyshotspacing.value, self.isfire.value, record)
                    stop_time = time.time()
                    print("\n%s\nCompleted shot %d in %.2f s\n%s\n" %(spacer,nmagshots,(stop_time-start_time),spacer))
                    nmagshots += 1
                if latch and (self.ready_sig < self.ttl_low or ignore_ready):
                    latch = False
                time.sleep(0.25)
        except KeyboardInterrupt:
            print('\nExiting...\n')
        finally:
            print('Took %d total magnet shots\n' %nmagshots)  

    def takeRun(self, nEvents, record=None, use_l3t=False):
        daq.configure(events=120, record=record, use_l3t=use_l3t)
        daq.begin(events=nEvents)
        daq.wait()
        daq.end_run()

    def ascan(self, motor, start, end, nsteps, nEvents, record=None, use_l3t=False):
        self.cleanup_RE()
        currPos = motor.wm()
        daq.configure(nEvents, record=record, controls=[motor], use_l3t=use_l3t)
        try:
            RE(scan([daq], motor, start, end, nsteps))
        except Exception:
            logger.debug('RE Exit', exc_info=True)
        finally:
            self.cleanup_RE()
        motor.mv(currPos)

    def pv_ascan(self, signal, start, end, nsteps, nEvents, record=None, use_l3t=False):
        self.cleanup_RE()
        currPos = signal.get()
        daq.configure(nEvents, record=record, controls=[signal], use_l3t=use_l3t)
        try:
            RE(scan([daq], signal, start, end, nsteps))
        except Exception:
            logger.debug('RE Exit', exc_info=True)
        finally:
            self.cleanup_RE()
        signal.put(currPos)

    def listscan(self, motor, posList, nEvents, record=None, use_l3t=False):
        self.cleanup_RE()
        currPos = motor.wm()
        daq.configure(nEvents, record=record, controls=[motor], use_l3t=use_l3t)
        try:
            RE(list_scan([daq], motor, posList))
        except Exception:
            logger.debug('RE Exit', exc_info=True)
        finally:
            self.cleanup_RE()
        motor.mv(currPos)

    def list3scan(self, m1, p1, m2, p2, m3, p3, nEvents, record=None, use_l3t=False):
        self.cleanup_RE()
        currPos1 = m1.wm()
        currPos2 = m2.wm()
        currPos3 = m3.wm()
        daq.configure(nEvents, record=record, controls=[m1,m2,m3], use_l3t=use_l3t)
        try:
            RE(list_scan([daq], m1,p1,m2,p2,m3,p3))
        except Exception:
            logger.debug('RE Exit', exc_info=True)
        finally:
            self.cleanup_RE()
        m1.mv(currPos1)
        m2.mv(currPos2)
        m3.mv(currPos3)

    def dscan(self, motor, start, end, nsteps, nEvents, record=None, use_l3t=False):
        self.cleanup_RE()
        daq.configure(nEvents, record=record, controls=[motor], use_l3t=use_l3t)
        currPos = motor.wm()
        try:
            RE(scan([daq], motor, currPos+start, currPos+end, nsteps))
        except Exception:
            logger.debug('RE Exit', exc_info=True)
        finally:
            self.cleanup_RE()
        motor.mv(currPos)

    def pv_dscan(self, signal, start, end, nsteps, nEvents, record=None, use_l3t=False):
        self.cleanup_RE()
        daq.configure(nEvents, record=record, controls=[signal], use_l3t=use_l3t)
        currPos = signal.get()
        try:
            RE(scan([daq], signal, currPos+start, currPos+end, nsteps))
        except Exception:
            logger.debug('RE Exit', exc_info=True)
        finally:
            self.cleanup_RE()
        signal.put(currPos)

    def a2scan(self, m1, a1, b1, m2, a2, b2, nsteps, nEvents, record=True, use_l3t=False):
        self.cleanup_RE()
        daq.configure(nEvents, record=record, controls=[m1, m2], use_l3t=use_l3t)
        try:
            RE(scan([daq], m1, a1, b1, m2, a2, b2, nsteps))
        except Exception:
            logger.debug('RE Exit', exc_info=True)
        finally:
            self.cleanup_RE()

    def a3scan(self, m1, a1, b1, m2, a2, b2, m3, a3, b3, nsteps, nEvents, record=True):
        self.cleanup_RE()
        daq.configure(nEvents, record=record, controls=[m1, m2, m3])
        try:
            RE(scan([daq], m1, a1, b1, m2, a2, b2, m3, a3, b3, nsteps))
        except Exception:
            logger.debug('RE Exit', exc_info=True)
        finally:
            self.cleanup_RE()

    def delay_scan(self, start, end, sweep_time, record=None, use_l3t=False,
                   duration=None):
        """Delay scan with the daq."""
        self.cleanup_RE()
        daq.configure(events=None, duration=None, record=record,
                      use_l3t=use_l3t, controls=[lxt_fast])
        try:
            RE(delay_scan(daq, lxt_fast, [start, end], sweep_time,
                          duration=duration))
        except Exception:
            logger.debug('RE Exit', exc_info=True)
        finally:
            self.cleanup_RE()

    def empty_delay_scan(self, start, end, sweep_time, record=None,
                         use_l3t=False, duration=None):
        """Delay scan without the daq."""
        self.cleanup_RE()
        #daq.configure(events=None, duration=None, record=record,
        #              use_l3t=use_l3t, controls=[lxt_fast])
        try:
            RE(delay_scan(None, lxt_fast, [start, end], sweep_time,
                          duration=duration))
        except Exception:
            logger.debug('RE Exit', exc_info=True)
        finally:
            self.cleanup_RE()

    def cleanup_RE(self):
        if not RE.state.is_idle:
            print('Cleaning up RunEngine')
            print('Stopping previous run')
            try:
                RE.stop()
            except Exception:
                pass
예제 #44
0
def test_epicssignal_readwrite():
    signal = EpicsSignal('readpv', write_pv='writepv')

    signal.wait_for_connection()
    assert signal.setpoint_pvname == 'writepv'
    assert signal.pvname == 'readpv'
    signal.value

    signal._update_rate = 2
    time.sleep(0.2)

    value = 10
    signal.value = value
    signal.setpoint = value
    assert signal.setpoint == value
    signal.setpoint_ts

    signal.limits
    signal.precision
    signal.timestamp

    signal.read()
    signal.describe()
    signal.read_configuration()
    signal.describe_configuration()

    eval(repr(signal))
    time.sleep(0.2)
예제 #45
0
 def __init__(self):
     #switch to trigger instead of full evr
     self._sync_markers = {0.5:0, 1:1, 5:2, 10:3, 30:4, 60:5, 120:6, 360:7}
     self.trigger_mag = Trigger('XCS:R42:EVR:01:TRIG4', name='trigger_mag')
     self.trigger_pp = Trigger('XCS:USR:EVR:TRIG1', name='trigger_pp')
     self.nemptyshots = actions(0, name='nemptyshots')
     self.isfire = actions(False, name='isfire')
     self.emptyshotspacing = actions(0, name='emptyshotspacing')
     self.nshots = actions(0, name='nshots')
     self.shotspacing = actions(0, name='shotspacing')
     #with safe_load('Pirani and Cold Cathode Gauges'):
     #    self.mag_pirani = BaseGauge('XCS:USR:GPI:01', name='mag_pirani')
     #    self.mag_cc = BaseGauge('XCS:USR:GCC:01', name='mag_cc')
     self.sample_temp = LakeShoreChannel('XCS:USR:TCT:02', name='A')
     self.mag_temp = LakeShoreChannel('XCS:USR:TCT:02', name='B')
     self.ttl_high = 2.0
     self.ttl_low = 0.8
     self._ready_sig = EpicsSignal('XCS:USR:ai1:0', name='User Analog Input channel 0', kind = 'omitted')
     self._ipm4_threshold = IPM4_Threshold(0) #default threshold is 0
     self.ipm4_pv = EpicsSignal('XCS:SB1:BMMON:SUM', name='ipm4_sum')
     self.ipm4_mag_retry = 10
     self._gdet_threshold_pv = EpicsSignal('XCS:VARS:J78:GDET_THRES', kind = 'normal')
     self.gdet_avg_count = 30
     self.gdet_mag_retry = 10
     self.gdet = GasDetector('GDET:FEE1', name='gas detector')
     #self._bykik_pv = Cpt(EpicsSignal('IOC:IN20:EV01:BYKIK_ABTACT', kind = 'normal', string=True, doc='BYKIK: Abort Active')
     self._req_burst_rate = 'Full'
     self._test_burst_rate = EpicsSignal('PATT:SYS0:1:TESTBURSTRATE', name='test_burst_rate', kind='normal')
     self._mps_burst_rate = EpicsSignal('PATT:SYS0:1:MPSBURSTRATE', name='mps_burst_rate')
     # number of seconds to pause between empty and magnet
     self.pause_time = 2.
     self._min_empty_delay = 4 
     self._beam_owner = EpicsSignal('ECS:SYS0:0:BEAM_OWNER_ID', name='beam_owner', kind = 'normal')
     self._att = att
     self.hutch = 'xcs'
     self._hutch_id = EpicsSignal('ECS:SYS0:4:HUTCH_ID', name='hutch_id', kind = 'normal')
     self.aliases = ['BEAM']
     self.gainmodes = ''
예제 #46
0
def test_setpoint():
    sig = EpicsSignal('connects')
    sig.wait_for_connection()

    sig.get_setpoint()
    sig.get_setpoint(as_string=True)
예제 #47
0
 def __init__(self, door_state, voltage_read, voltage_write, voltage_scale):
     self.door_state = EpicsSignalRO(door_state)
     self.mesh_voltage = EpicsSignal(voltage_read, write_pv=voltage_write)
     self.voltage_scale = EpicsSignal(voltage_scale)
     print('Using door pv {}'.format(door_state))
예제 #48
0
def test_describe():
    sig = EpicsSignal('my_pv')
    sig._write_pv.enum_strs = ('enum1', 'enum2')
    sig.wait_for_connection()

    sig.put(1)
    desc = sig.describe()['my_pv']
    assert desc['dtype'] == 'integer'
    assert desc['shape'] == []
    assert 'precision' in desc
    assert 'enum_strs' in desc
    assert 'upper_ctrl_limit' in desc
    assert 'lower_ctrl_limit' in desc

    sig.put('foo')
    desc = sig.describe()['my_pv']
    assert desc['dtype'] == 'string'
    assert desc['shape'] == []

    sig.put(3.14)
    desc = sig.describe()['my_pv']
    assert desc['dtype'] == 'number'
    assert desc['shape'] == []

    import numpy as np
    sig.put(np.array([1,]))
    desc = sig.describe()['my_pv']
    assert desc['dtype'] == 'array'
    assert desc['shape'] == [1,]
예제 #49
0
    def test_describe(self):
        epics.PV = FakeEpicsPV
        sig = EpicsSignal('my_pv')
        sig._write_pv.enum_strs = ('enum1', 'enum2')
        sig.wait_for_connection()

        sig.put(1)
        desc = sig.describe()['my_pv']
        self.assertEquals(desc['dtype'], 'integer')
        self.assertEquals(desc['shape'], [])
        self.assertIn('precision', desc)
        self.assertIn('enum_strs', desc)
        self.assertIn('upper_ctrl_limit', desc)
        self.assertIn('lower_ctrl_limit', desc)

        sig.put('foo')
        desc = sig.describe()['my_pv']
        self.assertEquals(desc['dtype'], 'string')
        self.assertEquals(desc['shape'], [])

        sig.put(3.14)
        desc = sig.describe()['my_pv']
        self.assertEquals(desc['dtype'], 'number')
        self.assertEquals(desc['shape'], [])

        import numpy as np
        sig.put(np.array([1,]))
        desc = sig.describe()['my_pv']
        self.assertEquals(desc['dtype'], 'array')
        self.assertEquals(desc['shape'], [1,])
예제 #50
0
def set_severity_signal(cleanup, signal_test_ioc):
    sig = EpicsSignal(signal_test_ioc.pvs['set_severity'], name='set_severity')
    cleanup.add(sig)
    sig.wait_for_connection()
    return sig
예제 #51
0
class User():

    target_x = Motor('MEC:USR:MMS:17', name='target_x_motor')

    YFEon = YFEon
    YFEoff = YFEoff
    HWPon = HWPon
    SHG_opt = SHG_opt
    save_scope_to_eLog = save_scope_to_eLog

    def start_seq(self, rate=120, wLPLaser=False):
        if rate == 120:
            sync_mark = 6  #int(_sync_markers[120])
        elif rate == 60:
            sync_mark = 5
        elif rate == 30:
            sync_mark = 4
        elif rate == 10:
            sync_mark = 3
        elif rate == 5:
            sync_mark = 2
        elif rate == 1:
            sync_mark = 1
        elif rate == 0.5:
            sync_mark = 0
        seq.sync_marker.put(sync_mark)
        seq.play_mode.put(2)  # Run sequence forever
        ff_seq = [[169, 0, 0, 0]]
        if wLPLaser:
            ff_seq.append([182, 0, 0, 0])
        seq.sequence.put_seq(ff_seq)
        seq.start()

    _seq = Sequence()
    _sync_markers = {0.5: 0, 1: 1, 5: 2, 10: 3, 30: 4, 60: 5, 120: 6, 360: 7}

    nsl = NanoSecondLaser()
    fsl = FemtoSecondLaser()

    shutters = [1, 2, 3, 4, 5, 6]
    _shutters = {
        1: shutter1,
        2: shutter2,
        3: shutter3,
        4: shutter4,
        5: shutter5,
        6: shutter6
    }

    seq_a_pvs = [
        EpicsSignal('MEC:ECS:IOC:01:EC_6:00'),
        EpicsSignal('MEC:ECS:IOC:01:EC_6:01'),
        EpicsSignal('MEC:ECS:IOC:01:EC_6:02'),
        EpicsSignal('MEC:ECS:IOC:01:EC_6:03'),
        EpicsSignal('MEC:ECS:IOC:01:EC_6:04'),
        EpicsSignal('MEC:ECS:IOC:01:EC_6:05'),
        EpicsSignal('MEC:ECS:IOC:01:EC_6:06'),
        EpicsSignal('MEC:ECS:IOC:01:EC_6:07'),
        EpicsSignal('MEC:ECS:IOC:01:EC_6:08'),
        EpicsSignal('MEC:ECS:IOC:01:EC_6:09')
    ]

    seq_b_pvs = [
        EpicsSignal('MEC:ECS:IOC:01:BD_6:00'),
        EpicsSignal('MEC:ECS:IOC:01:BD_6:01'),
        EpicsSignal('MEC:ECS:IOC:01:BD_6:02'),
        EpicsSignal('MEC:ECS:IOC:01:BD_6:03'),
        EpicsSignal('MEC:ECS:IOC:01:BD_6:04'),
        EpicsSignal('MEC:ECS:IOC:01:BD_6:05'),
        EpicsSignal('MEC:ECS:IOC:01:BD_6:06'),
        EpicsSignal('MEC:ECS:IOC:01:BD_6:07'),
        EpicsSignal('MEC:ECS:IOC:01:BD_6:08'),
        EpicsSignal('MEC:ECS:IOC:01:BD_6:09')
    ]

    def open_shutters(self):
        print("Opening shutters...")
        for shutter in self.shutters:
            self._shutters[shutter].open()
        time.sleep(5)

    def close_shutters(self):
        print("Closing shutters...")
        for shutter in self.shutters:
            self._shutters[shutter].close()
        time.sleep(5)

    def seq_wait(self):
        time.sleep(0.5)
        while seq.play_status.get() != 0:
            time.sleep(0.5)

    def scalar_sequence_write(self, s):
        for i in range(len(s)):
            self.seq_a_pvs[i].put(s[i][0])
        for j in range(len(s)):
            self.seq_b_pvs[j].put(s[j][1])

        seq.sequence_length.put(len(s))

    tx_motor = target.x
    ty_motor = target.y

    grid = XYTargetGrid(x=tx_motor,
                        y=ty_motor,
                        x_init=0.0,
                        y_init=0.0,
                        x_spacing=-0.363,
                        y_spacing=0.363,
                        x_comp=0.01,
                        y_comp=0.01,
                        name='lv25_targetgrid')

    def x_scan(self,
               nshots=1,
               record=True,
               xrays=False,
               carriage_return=False):
        """
        Returns a BlueSky plan to perform a scan in X. Collects a 
        number of short pulse laser shots while moving from target to target. 
        
        Parameters:
        -----------
        nshots : int <default: 1>
            The number of shots that you would like to take in the run.

        record : bool <default: True>
            Flag to record the data (or not).

        xrays : bool <default: False>
            Flag to do an optical or x-ray shot. If False, does an optical only
            shot. If True, you do a optical + x-ray shot.

        carriage_return : bool <default: False>
            Flag to return to initial position. 
        """
        logging.debug("Calling User.x_scan with parameters:")
        logging.debug("nshots: {}".format(nshots))
        logging.debug("record: {}".format(record))
        logging.debug("xrays: {}".format(xrays))

        print("Configuring DAQ...")
        daq.configure(events=0, record=record,
                      begin_sleep=0.1)  # run infinitely
        #        daq.configure(events=nshots, record=record)
        #        daq.begin_infinite()

        print("Configuring sequencer...")
        # Setup the pulse picker for single shots in flip flop mode
        pp.flipflop(wait=True)
        # Setup sequencer for requested rate
        sync_mark = int(self._sync_markers[5])
        seq.sync_marker.put(sync_mark)
        seq.play_mode.put(0)  # Run once
        # Setup sequence
        self._seq.rate = 5
        if xrays:
            s = self._seq.duringSequence(1, 'shortpulse')
        else:
            s = self._seq.opticalSequence(1, 'shortpulse')
        seq.sequence.put_seq(s)

        self._shutters[6].close()
        time.sleep(5)

        # Get starting positions
        start = self.grid.wm()
        yield from scan([daq, seq],
                        self.grid.x,
                        start['x'],
                        (start['x'] + self.grid.x_spacing * (nshots - 1)),
                        num=nshots)

        #        for i in range(nshots):
        #            if i is not 0:
        #                yield from bps.mv(start['x']+self.grid.x_spacing*i)
        ##            yield from bps.trigger_and_read([daq,seq])
        ##            yield from bps.trigger(seq, wait=True)
        #            yield from count([daq,seq], num=1)

        if carriage_return:
            # Return to start
            print("Returning to starting position")
            yield from bps.mv(self.grid.x, start['x'])
            yield from bps.mv(self.grid.y, start['y'])

        daq.end_run()

        self._shutters[6].open()

    def _x_position(self, xstart, xspacing, ix, iy, dxx=0.0, dxy=0.0):
        """
        Determine the appropriate X position of a motor on a grid, given
        regular, measured deviations from the ideal grid due to mounting, etc.
        If deviations are omitted, then this will simply return the ideal grid
        position given the defined spacing.

        Parameters
        ----------
        xstart : float
            Initial x position (e.g. x position of target "zero").

        xspacing : float
            Ideal spacing for grid.

        ix : int
            Zero-indexed target x-index. 

        iy : int
            Zero-indexed target y-index.

        dxx : float (default=0.0)
            Deviation in x position per x-index from ideal. 

        dxy : float (deafult=0.0)
            Deviation in x position per y-index from ideal.
        """
        return xstart + (xspacing + dxx) * ix + dxy * iy

    def _y_position(self, ystart, yspacing, ix, iy, dyy=0.0, dyx=0.0):
        """
        Determine the appropriate Y position of a motor on a grid, given
        regular, measured deviations from the ideal grid due to mounting, etc.
        If deviations are omitted, then this will simply return the ideal grid
        position given the defined spacing.

        Parameters
        ----------
        ystart : float
            Initial y position (e.g. y position of target "zero").

        yspacing : float
            Ideal spacing for grid.

        ix : int
            Zero-indexed target x-index. 

        iy : int
            Zero-indexed target y-index.

        dyy : float (default=0.0)
            Deviation in y position per y-index from ideal. 

        dyx : float (deafult=0.0)
            Deviation in y position per x-index from ideal.
        """
        return ystart + (yspacing + dyy) * iy + dyx * ix

    def _list_scan_positions(self,
                             xstart,
                             xspacing,
                             ystart,
                             yspacing,
                             nx,
                             ny,
                             dxx=0.0,
                             dxy=0.0,
                             dyy=0.0,
                             dyx=0.0):
        """
        Return lists of x and y positions for use in a BlueSky list_scan plan.
        Calculates x and y positions for a sample grid given any non-idealities
        in the grid alignment. 

        Parameters
        ----------
        xstart : float
            Initial x position (e.g. x position of target "zero").

        xspacing : float
            Ideal spacing for grid.

        ystart : float
            Initial y position (e.g. y position of target "zero").

        yspacing : float
            Ideal spacing for grid.

        nx : int
            The number of x positions in the grid.

        ny : int
            The number of y positions in the grid. 

        dxx : float (default=0.0)
            Deviation in x position per x-index from ideal. 

        dxy : float (deafult=0.0)
            Deviation in x position per y-index from ideal.

        dyy : float (default=0.0)
            Deviation in y position per y-index from ideal. 

        dyx : float (deafult=0.0)
            Deviation in y position per x-index from ideal.
        """
        xl = []
        yl = []
        for i in range(ny):
            for j in range(nx):
                xl.append(
                    self._x_position(xstart, xspacing, j, i, dxx=dxx, dxy=dxy))
                yl.append(
                    self._y_position(ystart, yspacing, j, i, dyy=dyy, dyx=dyx))

        return xl, yl

    def xy_scan(self,
                nxshots=1,
                nyshots=1,
                record=True,
                xrays=False,
                carriage_return=False):
        """
        Returns a BlueSky plan to perform a scan in X and Y. Collects a 
        number of short pulse laser shots while moving from target to target. 
        
        Parameters:
        -----------
        nxshots : int <default: 1>
            The number of shots that you would like to take on the x axis for
            each "line" on the target stage.

        nyshots : int <default: 1>
            The number of lines that you want to move on the y axis.

        record : bool <default: True>
            Flag to record the data (or not).

        xrays : bool <default: False>
            Flag to do an optical or x-ray shot. If false, does an optical only
            shot. If true, you do a optical + x-ray shot.

        carriage_return : bool <default: False>
            Flag to return to initial position. 
        """
        logging.debug("Calling User.xy_scan with parameters:")
        logging.debug("nxshots: {}".format(nxshots))
        logging.debug("nyshots: {}".format(nyshots))
        logging.debug("record: {}".format(record))
        logging.debug("xrays: {}".format(xrays))

        print("Configuring DAQ...")
        daq.configure(events=0, record=record)  # run infinitely
        #        daq.begin_infinite()

        print("Configuring sequencer...")
        # Setup the pulse picker for single shots in flip flop mode
        pp.flipflop(wait=True)
        # Setup sequencer for requested rate
        sync_mark = int(self._sync_markers[5])
        seq.sync_marker.put(sync_mark)
        seq.play_mode.put(0)  # Run once
        # Setup sequence
        self._seq.rate = 5
        if xrays:
            s = self._seq.duringSequence(1, 'shortpulse')
        else:
            s = self._seq.opticalSequence(1, 'shortpulse')
        seq.sequence.put_seq(s)

        # Get starting positions
        start = self.grid.wm()

        # Get lists of scan positions
        xl, yl = self._list_scan_positions(start['x'],
                                           self.grid.x_spacing,
                                           start['y'],
                                           self.grid.y_spacing,
                                           nxshots,
                                           nyshots,
                                           dxx=0.0,
                                           dxy=self.grid.x_comp,
                                           dyy=0.0,
                                           dyx=self.grid.y_comp)

        # Close shutter 6 (requested)
        self._shutters[6].close()
        time.sleep(5)

        # Scan the thing
        def inner():
            yield from list_scan([daq, seq], self.grid.y, yl, self.grid.x, xl)

        yield from inner()

        if carriage_return:
            # Return to start
            print("Returning to starting position")
            yield from bps.mv(self.grid.x, start['x'])
            yield from bps.mv(self.grid.y, start['y'])

        daq.end_run()

        self._shutters[6].open()

    def xy_fly_scan(self,
                    nshots,
                    nrows=2,
                    y_distance=None,
                    rate=5,
                    record=True,
                    xrays=True):
        """
        Plan for doing a 2D fly scan. Uses the target x motor as the flying
        axis, running for a specified distance at a specified velocity, taking
        shots at a specified rate. 

        Parameters
        ----------
        nshots : int
            The number of shots to take in the x scan. 

        rate : int <default : 5>
            The rate at which to take shots (120, 30, 10, 5, 1)

        y_distance : float <default : x.grid.y_spacing>
            The distance to move the y stage down. 

        nrows : int <default : 2>
            The number of "rows" to scan the x stage on.

        record : bool <default : True>
            Flag to record the data. 

        xrays : bool <default : True>
            Flag to take an x-ray + optical (True) shot or optical only (False).
        """
        logging.debug("rate: {}".format(rate))
        logging.debug("nshots: {}".format(nshots))
        logging.debug("nrows: {}".format(nrows))
        logging.debug("record: {}".format(record))
        logging.debug("xrays: {}".format(xrays))

        if not y_distance:
            y_distance = self.grid.y_spacing
        logging.debug("y_distance: {}".format(y_distance))

        assert rate in [120, 30, 10, 5,
                        1], "Please choose a rate in {120, 30, 10,5,1}"

        print("Configuring DAQ...")
        daq.configure(events=0, record=record)  # run infinitely
        daq.begin_infinite()

        print("Configuring sequencer...")
        # Setup the pulse picker for single shots in flip flop mode
        pp.flipflop(wait=True)
        # Setup sequencer for requested rate
        sync_mark = int(self._sync_markers[rate])
        seq.sync_marker.put(sync_mark)
        seq.play_mode.put(1)  # Run for n shots
        seq.rep_count.put(nshots)
        # Setup sequence
        self._seq.rate = rate
        if xrays:
            s = self._seq.duringSequence(1, 'shortpulse')
        else:
            s = self._seq.opticalSequence(1, 'shortpulse')
        seq.sequence.put_seq(s)

        # Get starting positions
        start = self.grid.wm()

        # Calculate and set velocity
        vel = self.grid.x_spacing * rate  # mm * (1/s) = mm/s
        self.grid.x.velocity.put(vel)

        # Estimate distance to move given requested shots and rate
        dist = (nshots / rate) * vel  # (shots/(shots/sec))*mm/s = mm

        # Close shutter 6 (requested)
        self._shutters[6].close()
        time.sleep(5)

        for i in range(nrows):
            if i != 0:
                yield from bps.mvr(self.grid.y, y_distance)
            # Play the sequencer
            seq.play_control.put(1)

            # Start the move
            yield from bps.mvr(self.grid.x, dist)  # Waits for move to complete

            # Make sure the sequencer stopped
            seq.play_control.put(0)

            yield from bps.mv(self.grid.x, start['x'])

        # Return to start
        print("Returning to starting position")
        yield from bps.mv(self.grid.x, start['x'])
        yield from bps.mv(self.grid.y, start['y'])

        daq.end_run()

        self._shutters[6].open()