Ejemplo n.º 1
0
    def addPv(self, pvs):
        """add a pv or list of pvs"""
        if not pvs: return

        kw_cg = {"format": cothread.catools.FORMAT_CTRL,
                 "timeout": self.timeout,
                 "throw": False}
        kw_cm = {"format": cothread.catools.FORMAT_TIME }

        if isinstance(pvs, (list, tuple, set)):
            newpvs = [ pv for pv in pvs if pv not in self.data ]
        elif isinstance(pvs, str) and pvs not in self.data:
            newpvs = [ pvs ]
        else:
            newpvs = []
        
        if len(newpvs) == 0: return

        d = caget(newpvs, **kw_cg)
        newmons = camonitor(newpvs, self._ca_update, **kw_cm)
        for i,pv in enumerate(newpvs):
            if not d[i].ok:
                self._dead.add(newpvs[i])
            else:
                self._monitors[pv] = newmons[i]
                self.data[pv] = deque([d[i]], self.samples)
                try:
                    self._wfsize[pv] = len(d[i])
                except:
                    self._wfsize[pv] = None
                for fhk in self.hook.get(pv, []):
                    fhk(d[i], None)
        d1 = caget(self.data.keys(), timeout = self.timeout, **kw_cm)
        for i,v in enumerate(d1):
            self.data[v.name].append(v)
Ejemplo n.º 2
0
    def __init__(self, brick_pv_root, pv_root, axis_no, cs_no):
        self.brick_pv_root = brick_pv_root
        self.pv_root = pv_root
        self.axis_no = axis_no
        self.cs_no = cs_no
        self.demand = pv_root
        self.rbv = pv_root + '.RBV'
        self.acc = pv_root + '.ACCL'
        self.stop_pv = pv_root + '.STOP'
        self.velo = pv_root + '.VELO'
        self.vmax = pv_root + '.VMAX'
        self.off = pv_root + '.OFF'
        self.mres = pv_root + '.MRES'
        self.lo_limit = pv_root + '.LLM'
        self.hi_limit = pv_root + '.HLM'
        self.pv_done_moving = pv_root + '.DMOV'
        self.pv_use_encoder = pv_root + '.UEIP'
        if cs_no > 0:
            cs_name = 'CS{}:'.format(cs_no)
        else:
            cs_name = ''
        self.cs_assignment = brick_pv_root + 'M{}:CsAxis'.format(axis_no)
        self.cs_port = brick_pv_root + 'M{}:CsPort'.format(axis_no)
        self.direct_demand = brick_pv_root + '{}M{}:DirectDemand'.format(cs_name,
                                                                           axis_no)

        # the following helps to avoid waiting for a timeout if the IOC is down
        ca.caget(self.rbv, timeout=.1)
 def feedback_inputs(self, val, index):
     if (catools.caget('BL' + self.XBPMSharedPVs.beamline_num +
                       'I-EA-XBPM-' + str(self.xbpm_num) +
                       ':SumAll:MeanValue_RBV') >
             self.XBPMSharedPVs.minXCurr.get()
             and catools.caget('SR-DI-DCCT-01:SIGNAL') >
             self.XBPMSharedPVs.minSRCurr.get()
             and catools.caget('FE' + self.XBPMSharedPVs.beamline_num +
                               'I-PS-SHTR-02:STA') == 1
             and catools.caget('BL' + self.XBPMSharedPVs.beamline_num +
                               'I-PS-SHTR-01:STA') == 1
             and self.XBPMSharedPVs.fb_enable_status.get() == 1
             and self.XBPMSharedPVs.fb_pause_status.get() == 1 and
             self.XBPMSharedPVs.fb_mode_status.get() in self.mode_range):
         self.set_run_status(1)
         logging.info('Feedback OK to Run')
         logging.debug("Run for XBPM" + str(int(self.xbpm_num)) +
                       " Started")
     elif (self.XBPMSharedPVs.fb_enable_status.get() == 1
           and self.XBPMSharedPVs.fb_pause_status.get() == 0
           and self.XBPMSharedPVs.fb_mode_status.get() in self.mode_range):
         self.set_run_status(2)
         logging.debug("Run for XBPM" + str(int(self.xbpm_num)) + " Paused")
     else:
         self.set_run_status(0)
         logging.debug("Run for XBPM" + str(int(self.xbpm_num)) +
                       " Stopped")
def pv_xysb_values_with_caget(bpms):
    ''' Method to return lists of values for x, y and sb properties of a BPM
        using caget '''
    x_bpm_values = list()
    y_bpm_values = list()
    sb_bpm_values = list()

    enabled_bpms = bpms_enabled(bpms)
    i = 0
    for bpm in bpms:
        pvs = bpm.pv()
        # Check if the pv is enabled
        if(enabled_bpms[i] == 1):
            # Get its value and store it in the list
            if ':Y' in pvs[0]:
                y_bpm_values.append(pvs[0])
                x_bpm_values.append(pvs[1])
                sb_bpm_values.append(bpm.sb)
            else:
                x_bpm_values.append(pvs[0])
                y_bpm_values.append(pvs[1])
                sb_bpm_values.append(bpm.sb)
        else:
            print "Found a pv value which is not enabled"
        i += 1

    x_bpm_values = caget(x_bpm_values)
    y_bpm_values = caget(y_bpm_values)

    return x_bpm_values, y_bpm_values, sb_bpm_values
Ejemplo n.º 5
0
def theoretical_strength(lat, hclst, theta):
    betax = [v for v in catools.caget("SR:C00-Glb:G00<BETA:00>RB:X")]
    phix = [
        v * 2.0 * 3.1415926
        for v in catools.caget("SR:C00-Glb:G00<PHI:00>RB:X")
    ]
    bpm_idx = lat.group_index("BPMX")
    ch_idx = lat.group_index("TRIMX")

    # three kicker
    ic1 = lat.pvindex(hclst[0])
    ic2 = lat.pvindex(hclst[1])
    ic3 = lat.pvindex(hclst[2])
    if ic1 == -1 or ic2 == -1 or ic3 == -1:
        print "Can not find PV"
        return None

    print "index:", ic1, ic2, ic3
    print "beta", betax[ic1], betax[ic2], betax[ic3]
    print "s_end", lat.s_end(hc1), lat.s_end(hc2), lat.s_end(hc3)
    print "phase:", phix[ic1], phix[ic2], phix[ic3]
    c1 = theta
    c2 = sqrt(
        betax[ic1] / betax[ic2]) * sin(phix[ic3] - phix[ic1]) / sin(phix[ic3] -
                                                                    phix[ic2])
    c3 = sqrt(
        betax[ic1] / betax[ic3]) * sin(phix[ic2] - phix[ic1]) / sin(phix[ic3] -
                                                                    phix[ic2])
    return -c1 * c2, c1 * c3
Ejemplo n.º 6
0
def theo_local_bump1(lat):
    """Given a lattice list, calculate the theoretical local bump
    """
    # all elements
    betax = [v for v in catools.caget("SR:C00-Glb:G00<BETA:00>RB:X")]
    phix = [v for v in catools.caget("SR:C00-Glb:G00<PHI:00>RB:X")]
    bpm_idx = lat.group_index("BPMX")
    ch_idx = lat.group_index("TRIMX")

    # two kicker, 11*2pi phase advance.
    hc1="SR:C01-MG:G02A<HCM:H1>Fld:SP"
    hc2=hc1
    hc3="SR:C10-MG:G06A<HCM:H2>Fld:SP"
    
    ic1 = lat.pvindex(hc1)
    ic2 = lat.pvindex(hc2)
    ic3 = lat.pvindex(hc3)
    print "index:", ic1, ic2, ic3
    print "beta", betax[ic1], betax[ic2], betax[ic3]
    print "s_end", lat.s_end(hc1), lat.s_end(hc2), lat.s_end(hc3)
    print "phase:", phix[ic1], phix[ic2], phix[ic3]
    c1 = 1e-5
    catools.caput(hc1, c1)
    catools.caput(hc3, -c1*sqrt(betax[ic1]/betax[ic3]))
    time.sleep(4)
    s,x1,y1 = get_orbit(lat, 4)
    print "get orbit"
Ejemplo n.º 7
0
def theo_local_bump1(lat):
    """Given a lattice list, calculate the theoretical local bump
    """
    # all elements
    betax = [v for v in catools.caget("SR:C00-Glb:G00<BETA:00>RB:X")]
    phix = [v for v in catools.caget("SR:C00-Glb:G00<PHI:00>RB:X")]
    bpm_idx = lat.group_index("BPMX")
    ch_idx = lat.group_index("TRIMX")

    # two kicker, 11*2pi phase advance.
    hc1 = "SR:C01-MG:G02A<HCM:H1>Fld:SP"
    hc2 = hc1
    hc3 = "SR:C10-MG:G06A<HCM:H2>Fld:SP"

    ic1 = lat.pvindex(hc1)
    ic2 = lat.pvindex(hc2)
    ic3 = lat.pvindex(hc3)
    print "index:", ic1, ic2, ic3
    print "beta", betax[ic1], betax[ic2], betax[ic3]
    print "s_end", lat.s_end(hc1), lat.s_end(hc2), lat.s_end(hc3)
    print "phase:", phix[ic1], phix[ic2], phix[ic3]
    c1 = 1e-5
    catools.caput(hc1, c1)
    catools.caput(hc3, -c1 * sqrt(betax[ic1] / betax[ic3]))
    time.sleep(4)
    s, x1, y1 = get_orbit(lat, 4)
    print "get orbit"
Ejemplo n.º 8
0
    def update(self):
        kw_cg = {"format": cothread.catools.FORMAT_CTRL,
                 "timeout": self.timeout,
                 "throw": False}
        kw_cm = {"format": cothread.catools.FORMAT_TIME }

        newpvs = self.data.keys() + list(self._dead)
        d = caget(newpvs, **kw_cg)
        # try 3 times
        for k in range(3):
            tmppvs = []
            for i,pv in enumerate(newpvs):
                if not d[i].ok:
                    tmppvs.append(pv)
                elif pv in self.data:
                    self.data[pv].append(d[i])
                else:
                    self.data[pv] = deque([d[i]], self.samples)
            newpvs = tmppvs
            if not tmppvs: break
            d = caget(newpvs, **kw_cg)

        for pv in newpvs:
            if pv in self.data: self.data.pop(pv)
        self._dead = set(newpvs)
Ejemplo n.º 9
0
 def test_xsel(self):
     pvs = ["SR:" + s + "Enbl:Ps1OC-Cmd"
            for s in self._cor_dev]
     xsel_vec = caget(pvs)
     xsel_wfm = caget(P + "SR:APHLA:SOFB{COR}XSel-I")
     self.assertEqual(len(xsel_vec), len(xsel_wfm))
     for i in range(len(xsel_vec)):
         self.assertEqual(xsel_vec[i], xsel_wfm[i])
Ejemplo n.º 10
0
def caget(pvs, timeout=CA_TIMEOUT, datatype=None, format=ct.FORMAT_TIME,
           count=0, throw=False, verbose=0):
    """channel access read
    
    This is a simple wrap of cothread.catools, support UTF8 string

    Throw cothread.Timedout exception when timeout. This is a wrap of original
    `cothread.catools.caget`.

    seealso :func:`~aphla.catools.caput`

    Parameters
    -----------
    pvs : str, list. process variables
    timeout : int. timeout in seconds
    throw : bool. throw exception or not
    count : specify number of waveform points
    
    Returns
    ---------
    val : list or value. channel value

    Examples
    ----------
    >>> caget('SR:C01-MG:G04B{Quad:M1}Fld-I')
    >>> caget(['SR:PV1', 'SR:PV2', 'SR:PV3'])

    """
    #print "AA"
    #logger.info("caget %s" % str(pvs))
    #logging.getLogger("aphla").info("testing")

    # in case of testing ...
    if CA_OFFLINE: return _ca_get_sim(pvs)

    if isinstance(pvs, str):
        return ct.caget(pvs, timeout=timeout, datatype=datatype,
                        format=format, count=count, throw=throw)
    elif isinstance(pvs, unicode):
        pvs2 = pvs.encode("ascii")
        return ct.caget(pvs2, timeout=timeout, datatype=datatype,
                        format=format, count=count, throw=throw)
    elif isinstance(pvs, (tuple, list)):
        pvs2 = [pv.encode("ascii") for pv in pvs if pv]
        dr = ct.caget(pvs2, timeout=timeout, datatype=datatype,
                      format=format, count=count, throw=throw)
        if len(pvs2) == len(pvs): return [v for v in dr]

        j, rt = 0, []
        for i,pv in enumerate(pvs):
            if not pv: 
                rt.append(None)
                continue
            rt.append(dr[j])
            j += 1
        return rt
    else:
        raise ValueError("Unknown type " + str(type(pvs)))
Ejemplo n.º 11
0
 def testDx(self):
     v1 = [v + 0.1 for v in self._v0]
     caput(self._pvs, v1, wait=True)
     time.sleep(5)
     v1r = caget(self._pvsrb)
     v1w = caget(self._pvs)
     for i,vi in enumerate(v1):
         self.assertAlmostEqual(v1[i], v1r[i], places=1,
                                msg= "{0} != {1} for {2}".format(v1[i], v1r[i], self._pvs[i]))
         self.assertAlmostEqual(v1[i], v1w[i], places=5)
Ejemplo n.º 12
0
 def getPV(self):
     try:
         caget(str(self._pv))
         return self._pv
     except:
         logInstance.logger.error(
             'Connection with IOC failed. Make sure EPICS motor record PVs are accessible under this subnet')
         #raise RuntimeWarning(
         #    'Connection with IOC failed. Make sure EPICS motor record PVs are accessible under this subnet')
         return None
Ejemplo n.º 13
0
 def __init__(self, device):
     self.device = device
     self.bunch_nb = catools.caget(device + ":BUNCHES")
     hostname_l = catools.caget(device + ":HOSTNAME")
     hostname = "".join(map(chr, hostname_l))
     hostname = hostname.rstrip("\0")
     port = catools.caget(device + ":SOCKET")
     self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     self.s.settimeout(6.)
     self.s.connect((hostname, port))
Ejemplo n.º 14
0
    def test_si(self):
        self.assertIOCRunning()
        si = self.testprefix+'si'

        v = catools.caget(si)
        self.assertNotEqual(v, 'hello world')

        catools.caput(si, 'hello world')

        v = catools.caget(si)
        self.assertEqual(v, 'hello world')
Ejemplo n.º 15
0
    def test_si(self):
        self.assertIOCRunning()
        si = self.testprefix + 'si'

        v = catools.caget(si)
        self.assertNotEqual(v, 'hello world')

        catools.caput(si, 'hello world')

        v = catools.caget(si)
        self.assertEqual(v, 'hello world')
Ejemplo n.º 16
0
def main(args):
    Gclk = caget('%s{%s-EvtClk}Frequency-RB'%(args.sys, args.evg))
    Rclk = caget('%s{%s}Link:Clk-I'%(args.sys, args.evr))
    diff = (Rclk - Gclk)/Gclk
    if diff>0.1:
        raise RuntimeError("EVR (%s) and EVG (%s) clocks differ"%(Rclk, Gclk))
    link = caget('%s{%s}Link-Sts'%(args.sys, args.evr))
    if link!=1:
        raise RuntimeError('EVR link not OK (%s)'%link)

    sys.argv = sys.argv[:1] + args.extra
    unittest.main()
Ejemplo n.º 17
0
def lifetime_proxy():
    data = read_data()

    vert_beam_size = data[0]
    sy = caget('SR-DI-EMIT-01:P1:SIGMAY_MEAN')
    I_beam = caget('SR-DI-DCCT-01:SIGNAL')
    PMT_count = caget('SR-DI-COUNT-01:MEAN') + 0.001
    objective = PMT_count / PMT_ref(
        I_beam
    ) * vert_beam_size / sy  # rescaled n. of losses (note it was sy / sy_ref, corrected after IPAC)
    print('LT_proxy_resc=' + str(objective))
    return objective
Ejemplo n.º 18
0
def get_orbit(lat, delay=2):
    time.sleep(delay)
    vs = [v for v in catools.caget("SR:C00-Glb:G00<POS:00>RB:S")]
    vx = [v for v in catools.caget("SR:C00-Glb:G00<ORBIT:00>RB:X")]
    vy = [v for v in catools.caget("SR:C00-Glb:G00<ORBIT:00>RB:Y")]
    #print len(vs), len(vx), len(vy)
    bpm = lat.group_index("BPMX")
    #print bpm
    s = [vs[i] for i in bpm]
    x = [vx[i] for i in bpm]
    y = [vy[i] for i in bpm]
    return s, x, y
Ejemplo n.º 19
0
def get_orbit(lat, delay=2):
    time.sleep(delay)
    vs = [v for v in catools.caget("SR:C00-Glb:G00<POS:00>RB:S")]
    vx = [v for v in catools.caget("SR:C00-Glb:G00<ORBIT:00>RB:X")]
    vy = [v for v in catools.caget("SR:C00-Glb:G00<ORBIT:00>RB:Y")]
    #print len(vs), len(vx), len(vy)
    bpm = lat.group_index("BPMX")
    #print bpm
    s = [vs[i] for i in bpm]
    x = [vx[i] for i in bpm]
    y = [vy[i] for i in bpm]
    return s, x, y
Ejemplo n.º 20
0
    def test_1(self):
        caput(P+"SR:APHLA:SOFB{BPM}Index", [1, 3, 2, 4, 0])
        caput("l:SR:APHLA:SOFB{BPM}Sel", [1, 1, 1, 0, 0])
        caput("l:SR:APHLA:SOFB{BPM}Index_", [5, 5, 5, 5, 5])

        caput("l:SR:APHLA:SOFB{BPM}_index_asub_.PROC", 1)
        print caget("l:SR:APHLA:SOFB{BPM}Index_")

        caput("l:SR:APHLA:SOFB{BPM}X_", [10., 11., 12., 13., 14.])
        caput("l:SR:APHLA:SOFB{BPM}_shuffle_asub_.PROC", 1)
        for s in range(1, 21):
            print caget("l:SR:APHLA:SOFB{BPM}X" + chr(ord('A') + s))
Ejemplo n.º 21
0
def test_cothread_ioc(cothread_ioc):
    import cothread
    from cothread.catools import ca_nothing, caget, caput, camonitor

    pre = cothread_ioc.pv_prefix

    with Listener(ADDRESS) as listener, listener.accept() as conn:

        select_and_recv(conn, "R")  # "Ready"

        # Start
        assert caget(pre + ":UPTIME").startswith("00:00:0")
        # WAVEFORM
        caput(pre + ":SINN", 4, wait=True)
        q = cothread.EventQueue()
        m = camonitor(pre + ":SIN", q.Signal, notify_disconnect=True)
        assert len(q.Wait(1)) == 4
        # STRINGOUT
        assert caget(pre + ":STRINGOUT") == "watevah"
        caput(pre + ":STRINGOUT", "something", wait=True)
        assert caget(pre + ":STRINGOUT") == "something"
        # Check pvaccess works
        from p4p.client.cothread import Context
        with Context("pva") as ctx:
            assert ctx.get(pre + ":STRINGOUT") == "something"

        conn.send("D")  # "Done"

        select_and_recv(conn, "D")  # "Done"

        # Stop
        cothread_ioc.proc.send_signal(signal.SIGINT)
        # Disconnect
        assert isinstance(q.Wait(10), ca_nothing)
        m.close()

    # check closed and output
    out, err = cothread_ioc.proc.communicate()
    out = out.decode()
    err = err.decode()
    # check closed and output
    try:
        assert "%s:SINN.VAL 1024 -> 4" % pre in out
        assert 'update_sin_wf 4' in out
        assert "%s:STRINGOUT.VAL watevah -> something" % pre in out
        assert 'on_update \'something\'' in out
        assert 'Starting iocInit' in err
        assert 'iocRun: All initialization complete' in err
    except Exception:
        # Useful printing for when things go wrong!
        print("Out:", out)
        print("Err:", err)
        raise
Ejemplo n.º 22
0
def main(args):
    Gclk = caget('%s{%s-EvtClk}Frequency-RB' % (args.sys, args.evg))
    Rclk = caget('%s{%s}Link:Clk-I' % (args.sys, args.evr))
    diff = (Rclk - Gclk) / Gclk
    if diff > 0.1:
        raise RuntimeError("EVR (%s) and EVG (%s) clocks differ" %
                           (Rclk, Gclk))
    link = caget('%s{%s}Link-Sts' % (args.sys, args.evr))
    if link != 1:
        raise RuntimeError('EVR link not OK (%s)' % link)

    sys.argv = sys.argv[:1] + args.extra
    unittest.main()
Ejemplo n.º 23
0
def get_NCO_bunch(device, dev_axis):
    nco_ena = catools.caget(device+':'+dev_axis+':NCO:ENABLE_S')
    bank_n = catools.caget(device+':'+dev_axis+':SEQ:1:BANK_S')
    bank_n_str = "{}".format(int(bank_n))
    outwf = catools.caget(device+':'+dev_axis+':BUN:'+bank_n_str+':OUTWF_S')
    bunch_not_off = where(outwf != 0)[0]
    if bunch_not_off.size == 1:
        bunch_i = bunch_not_off[0]
        if outwf[bunch_i] == 2:
            if nco_ena != 1:
                raise NameError("Please switch ON NCO.")
            return bunch_i
    raise NameError("You need one bunch with NCO, others OFF")
Ejemplo n.º 24
0
def update_spos(dbf, src):
    from cothread.catools import caget
    sp = ","
    lines = open(src, 'r').readlines()
    head = [v.strip() for v in lines[0].split(sp)]
    if head[0] != "#pv_name":
        raise RuntimeError("unknown data format: {0}".format(
                lines[0]))
    ipv, iidx, ielem, itype, ifld = [
        head.index(v) for v in (
            "#pv_name", "el_idx_va", "el_name_va", 
            "el_type_va", "el_field_va")]
    pv_name, pv_spos = None, None
    names, spos, idx = [], [], []
    for line in lines[1:]:
        r = [v.strip() for v in line.split(sp)]
        idx.append(r[iidx])
        names.append(r[ielem])
        if (r[itype], r[ifld]) == ("", "NAME"): pv_name = r[ipv]
        if (r[itype], r[ifld]) == ("", "S"): pv_spos = r[ipv]

    if pv_name is None:
        raise RuntimeError("can not find PV for names")
    if pv_spos is None: 
        raise RuntimeError("can not find PV for sposition")

    ca_names = caget(pv_name)
    ca_spos  = caget(pv_spos)

    if len(ca_names) != len(ca_spos):
        raise RuntimeError("names does not agree with spos")

    conn = sqlite3.connect(dbf)
    # save byte string instead of the default unicode
    conn.text_factory = str
    c = conn.cursor()
    print "Name Size:", len(ca_names)
    print "Spos Size:", len(ca_spos)
    for i,ix in enumerate(idx):
        j = int(ix)
        if j < 0: continue
        if j >= len(ca_spos): continue
        L = ca_spos[j] - ca_spos[j-1]
        #print ix, names[i], ca_names[j-1], L
        c.execute("""UPDATE elements set elemPosition=?,elemLength=? """
                  """where elemIndex=?""",
                  (ca_spos[j-1], L, ix))

    conn.commit()
    conn.close()
Ejemplo n.º 25
0
def update_spos(dbf, src):
    from cothread.catools import caget
    sp = ","
    lines = open(src, 'r').readlines()
    head = [v.strip() for v in lines[0].split(sp)]
    if head[0] != "#pv_name":
        raise RuntimeError("unknown data format: {0}".format(lines[0]))
    ipv, iidx, ielem, itype, ifld = [
        head.index(v) for v in ("#pv_name", "el_idx_va", "el_name_va",
                                "el_type_va", "el_field_va")
    ]
    pv_name, pv_spos = None, None
    names, spos, idx = [], [], []
    for line in lines[1:]:
        r = [v.strip() for v in line.split(sp)]
        idx.append(r[iidx])
        names.append(r[ielem])
        if (r[itype], r[ifld]) == ("", "NAME"): pv_name = r[ipv]
        if (r[itype], r[ifld]) == ("", "S"): pv_spos = r[ipv]

    if pv_name is None:
        raise RuntimeError("can not find PV for names")
    if pv_spos is None:
        raise RuntimeError("can not find PV for sposition")

    ca_names = caget(pv_name)
    ca_spos = caget(pv_spos)

    if len(ca_names) != len(ca_spos):
        raise RuntimeError("names does not agree with spos")

    conn = sqlite3.connect(dbf)
    # save byte string instead of the default unicode
    conn.text_factory = str
    c = conn.cursor()
    print "Name Size:", len(ca_names)
    print "Spos Size:", len(ca_spos)
    for i, ix in enumerate(idx):
        j = int(ix)
        if j < 0: continue
        if j >= len(ca_spos): continue
        L = ca_spos[j] - ca_spos[j - 1]
        #print ix, names[i], ca_names[j-1], L
        c.execute(
            """UPDATE elements set elemPosition=?,elemLength=? """
            """where elemIndex=?""", (ca_spos[j - 1], L, ix))

    conn.commit()
    conn.close()
Ejemplo n.º 26
0
 def configure_file(self, outputfile, xmldef=None):
     if xmldef:
         caput( self.pv['xmlfile'], os.path.abspath(xmldef), datatype=dbr.DBR_CHAR_STR, wait=True)
         validxml = caget( self.pv['xmlvalid'])
         if validxml is 0:
             errmsg = caget( self.pv['xmlerror'] )
             raise StrException(errmsg)
         
     outputfile = os.path.abspath(outputfile)
     fname = os.path.basename(outputfile)
     dname = os.path.dirname(outputfile)
     caput( self.pv['template'], "%s%s", datatype = dbr.DBR_CHAR_STR )
     caput( self.pv['path'], dname, datatype = dbr.DBR_CHAR_STR)
     caput( self.pv['name'], fname, datatype = dbr.DBR_CHAR_STR)
     caput( self.pv['mode'], "Stream", wait=True)
Ejemplo n.º 27
0
 def test_xsel_1x1(self):
     pvs = ["SR:" + s + "Enbl:Ps1OC-Cmd"
            for s in self._cor_dev]
     jl = random.sample(range(len(pvs)), 20)
     pvjl = [pvs[j] for j in jl]
     x0 = caget(pvjl)
     x1 = [1 - x for x in x0]
     caput(pvjl, x1)
     time.sleep(1.5)
     x2 = caget(pvjl)
     x2wfm = caget(P + "SR:APHLA:SOFB{COR}XSel-I")
     for i,j in enumerate(jl):
         self.assertNotEqual(x2[i], x0[i])
         self.assertEqual(x2[i], x2wfm[j])
     caput(pvjl, x0)
Ejemplo n.º 28
0
def start_observation():
    print("start_observation")
    pvs_to_watch = []
    init_data = {}
    for pv in PVS:
        pv_val = ca.caget(pv)
        pv_name = "".join(chr(_) for _ in pv_val).strip()
        if len(pv_name) > 0:
            print("pv_name: {}".format(pv_name))
            dm_map[pv_name] = pv
            pvs_to_watch.append(pv_name)
            init_data[pv] = ca.caget(pv_name)
    dm.append_data(datetime.utcnow(), init_data)
    for pv_name in pvs_to_watch:
        subscription_obj.append(ca.camonitor(str(pv_name), process, format=ca.FORMAT_TIME))
Ejemplo n.º 29
0
def config(name,geometry,engine,tag,author):    
    diff=Diffractometer(name, geometry, engine, tag, author)
    diff.pvList=pvList
    diff.dummySetup(name, geometry, engine, tag, author)
    i=0
    for angle in diff.getangleList():
        angle.setPV(pvList[i])
        try:
            caget(pvList[i],timeout=1.5)
        except:
            raise RuntimeWarning('Unable to connect'+pvList[i])
            diff.logger.warning('Unable to connect'+pvList[i])
            connect(pvList[i],wait=False,cainfo=True)
        i+=1
    return diff
def lifetime_proxy():

    PMT_count = caget('SR-DI-COUNT-01:MEAN') + 0.001
    I_beam = caget('SR-DI-DCCT-01:SIGNAL')
    epsilon_y = caget('SR-DI-EMIT-01:VEMIT_MEAN')

    bunch_length_value = bunch_length(I_beam)
    #print 'PMT ',PMT_count
    #print 'I_beam', I_beam
    #print 'emittance', epsilon_y
    #print 'bunch_length', bunch_length_value

    objective = I_beam / (PMT_count * bunch_length_value *
                          math.sqrt(epsilon_y))

    return objective
def capture_one_image_single():
    settings = [
        ("13SIM1:cam1:ImageMode", "Single", None),
        ("13SIM1:cam1:ArrayCallbacks", "Enable", None),
        ("13SIM1:cam1:ArrayCounter", 0, None),
        ("13SIM1:HDF1:EnableCallbacks", "Enable", None),
        ("13SIM1:HDF1:ArrayCounter", 0, None),
    ]
    load_settings(settings)
    timeout = caget("13SIM1:cam1:AcquirePeriod_RBV") * 1.5 + 1.0
    print "Acquiring and storing a single image in 'Single' mode"
    caput("13SIM1:cam1:Acquire", 1, wait=True, timeout=timeout)
    # Wait for a brief moment to allow the file saving to complete
    cothread.Sleep(1.0)
    fname = caget("13SIM1:HDF1:FullFileName_RBV", datatype=dbr.DBR_CHAR_STR)
    print "Captured into image file: ", fname
Ejemplo n.º 32
0
def animate(i, ax1, thread_1):
    if thread_1.new_data == 1:
        axis_bk = axis()
        ax1.clear()
        sca(ax1)
        xlabel('Bunch #')
        ylabel('Amplitude')
        title("Bunch " + thread_1.axis +
              " oscillation amplitude @ NCO={:.5f}".format(thread_1.tune))
        plot(thread_1.I, '-o')
        plot(thread_1.Q, '-o')
        if not thread_1.reset_axis:
            axis(axis_bk)
        else:
            thread_1.reset_axis = False
        thread_1.new_data = 0
    # Ask for a new capture as soon as previous mem_read is finished
    with thread_1.trigger_cdt:
        thread_1.tune = catools.caget(thread_1.device + ':' + thread_1.axis +
                                      ':NCO:FREQ_S')
        # Capture command doesn't work so well (mis-aligned data)
        #catools.caput(thread_1.device+':MEM:CAPTURE_S', 1, wait=True)
        catools.caput(thread_1.device + ':TRG:MEM:ARM_S', 1, wait=True)
        catools.caput(thread_1.device + ':TRG:SOFT_S', 1, wait=True)
        # Wait for memory to be actually triggered
        Sleep(0.05)
        thread_1.trigger_cdt.notify()
Ejemplo n.º 33
0
    def reconnect(self):
        # release old monitor
        self.disconnect()
        # make the connection in cothread's thread, use caget for initial value
        pvs = [self.rbv]
        if self.pv and self.pv != self.rbv:
            pvs.append(self.pv)
        ca_values = assert_connected(
            catools.caget(
                pvs,
                format=catools.FORMAT_CTRL,
                datatype=self.datatype,
                throw=self.throw,
            ),
            self.throw,
        )

        if self.on_connect:
            self.on_connect(ca_values[0])
        self._update_value(ca_values[0])
        # now setup monitor on rbv
        self.monitor = catools.camonitor(
            self.rbv,
            self._monitor_callback,
            format=catools.FORMAT_TIME,
            datatype=self.datatype,
            notify_disconnect=True,
        )
Ejemplo n.º 34
0
    def reconnect(self):
        # release old monitor
        self.disconnect()
        # make the connection in cothread's thread, use caget for initial
        ca_values = assert_connected(
            catools.caget(
                self.pv_list,
                format=catools.FORMAT_CTRL,
                datatype=self.datatype,
                throw=self.throw,
            ),
            self.throw,
        )

        for ind, value in enumerate(ca_values):
            if self.on_connect:
                self.on_connect(value)
            self._local_value[self.name_list[ind]] = value
            self._local_value.severity = max(self._local_value.severity, value.severity)
            self._local_value.ok = self._local_value.ok or value.ok
        self._update_value(self._local_value)
        # now setup monitors for all the things
        self.monitor = catools.camonitor(
            self.pv_list,
            self._monitor_callback,
            format=catools.FORMAT_TIME,
            datatype=self.datatype,
            notify_disconnect=True,
        )
Ejemplo n.º 35
0
    def get_multiple(self, pvs, throw=True):
        """Get the value for given PVs.

        Args:
            pvs (sequence): PVs to get values of.
            throw (bool): On failure: if True, raise ControlSystemException; if
                           False, None will be returned for any PV that fails
                           and a warning will be logged.

        Returns:
            sequence: the current values of the PVs.

        Raises:
            ControlSystemException: if it cannot connect to one or more PVs.
        """
        results = caget(pvs, timeout=self._timeout, throw=False)
        return_values = []
        failures = []
        for result in results:
            if isinstance(result, ca_nothing):
                logging.warning(f"Cannot connect to {result.name}.")
                if throw:
                    failures.append(result)
                else:
                    return_values.append(None)
            else:
                return_values.append(result)
        if throw and failures:
            raise ControlSystemException(
                f"{len(failures)} caget calls failed.")
        return return_values
Ejemplo n.º 36
0
    def runBba(self, bpms):
        """create local bump"""
        inp = {'bpms': [], 'quads': [], 'cors': [], 'quad_dkicks': [],
               'cor_dkicks': []}
        for bpm in bpms:
            inp['bpms'].extend([(bpm, 'x'), (bpm, 'y')])
            quad = ap.getClosest(bpm, 'QUAD')
            inp['quads'].extend([(quad, 'k1'), (quad, 'k1')])
            cor = ap.getNeighbors(bpm, 'HCOR', 1)[0]
            inp['cors'].append((cor, 'x'))
            cor = ap.getNeighbors(bpm, 'VCOR', 1)[0]
            inp['cors'].append((cor, 'y'))
            inp['quad_dkicks'].extend([1e-2, 1e-2])
            inp['cor_dkicks'].extend([np.linspace(-6e-5, 6e-5, 4),
                                     np.linspace(-6e-5, 6e-5, 4)])
                                     
        if self.bbadlg is None:
            #print self.obtdata.elem_names
            # assuming BPM has both x and y, the following s are same
            self.bbadlg = ApBbaDlg()
            self.bbadlg.resize(500, 200)
            self.bbadlg.setWindowTitle("Beam based alignment")
            #self.obtxplot.plotDesiredOrbit(self.orbitx_data.golden(), 
            #                            self.orbitx_data.x)
            #self.obtyplot.plotDesiredOrbit(self.orbity_data.golden(), 
            #                            self.orbity_data.x)

        self.bbadlg.show()
        self.bbadlg.raise_()
        self.bbadlg.activateWindow()

        from cothread.catools import caget, caput
        print __file__, "BBA align", caget('V:2-SR:C30-BI:G2{PH1:11}SA:X')

        self.bbadlg.runAlignment(**inp)
Ejemplo n.º 37
0
    def test_non_existant(self):
        self.assertIOCRunning()

        if sys.version_info > (2, 7):
            ne = self.testprefix + 'ne'
            with self.assertRaises(catools.ca_nothing) as cm:
                catools.caget(ne, timeout=0.1)

            self.assertEqual(repr(cm.exception), "ca_nothing('%s', 80)" % ne)
            self.assertEqual(
                str(cm.exception),
                "%s: User specified timeout on IO operation expired" % ne)
            self.assertFalse(bool(cm.exception))
            with self.assertRaises(TypeError):
                for _ in cm.exception:
                    pass
def lifetime_proxy():

    sy_ref = 12.2  # 8/5/2018 vertical beam size in um
    sy = caget('SR-DI-EMIT-01:P1:SIGMAY_MEAN')
    I_beam = caget('SR-DI-DCCT-01:SIGNAL')
    PMT_count = caget('SR-DI-COUNT-01:MEAN') + 0.001
    objective = PMT_count / PMT_ref(
        I_beam
    ) * sy_ref / sy  # rescaled n. of losses (note it was sy / sy_ref, corrected after IPAC)
    print('LT_proxy_resc=' + str(objective))

    #    epsilon_y = caget('SR-DI-EMIT-01:VEMIT_MEAN')
    #    bunch_length_value = bunch_length(I_beam)
    #    objective = I_beam/(PMT_count*bunch_length_value*math.sqrt(epsilon_y))

    return objective
Ejemplo n.º 39
0
    def test_dbuf32(self):
        dlen = randrange(1,3)*4
        expect = [randrange(0, 0xffffffff) for i in range(dlen)]

        caput(self.evg('%s{%s}dbus:send:u32'), expect)
        time.sleep(0.1)
        actual = list(caget(self.evr('%s{%s}dbus:recv:u32')))
        self.assertListEqual(actual, expect)
Ejemplo n.º 40
0
def abstract_caget(pv):
    """
    standard channel access 'get' function using cothread
    """
    if pv in ca_abstraction_mapping.name_to_function_mapping:
        return ca_abstraction_mapping.name_to_function_mapping[pv]()
    else:
        return caget(pv)
Ejemplo n.º 41
0
 def getValue(self):
     try:
         self._value = caget(self._pv + '.RBV')
         return self._value
     except:
         logInstance.logger.error('Process Variable ' + str(self._pv) + ' not connected')
         raise RuntimeWarning('Process Variable ' + str(self._pv) + ' not connected')
         return None
Ejemplo n.º 42
0
    def test_dbuf32(self):
        dlen = randrange(1, 3) * 4
        expect = [randrange(0, 0xffffffff) for i in range(dlen)]

        caput(self.evg('%s{%s}dbus:send:u32'), expect)
        time.sleep(0.1)
        actual = list(caget(self.evr('%s{%s}dbus:recv:u32')))
        self.assertListEqual(actual, expect)
Ejemplo n.º 43
0
    def do_test_sequence(self, single=True):
        """Setup a software triggered sequencer in Single mode
        """
        # watch EVR counter to ensure EVR FIFO IRQ works
        prev11 = caget(self.evr('%s{%s}EvtBCnt-I'))
        prev12 = caget(self.evr('%s{%s}EvtCCnt-I'))
        # watch EVG counter to ensure that EVG start/end of seqeunce IRQ works
        starts = caget(self.evg('%s{%s-SoftSeq:0}NumOfStarts-I'))
        ends = caget(self.evg('%s{%s-SoftSeq:0}NumOfRuns-I'))

        caput(self.evg('%s{%s-SoftSeq:0}RunMode-Sel'),
              'Single' if single else 'Normal')
        caput(self.evg('%s{%s-SoftSeq:0}TrigSrc:0-Sel'), 'Software')
        caput(self.evg('%s{%s-SoftSeq:0}TsResolution-Sel'), 'Ticks')
        self.load_seq([
            (0, 11),
            (1, 12),
        ])  # commits
        caput(self.evg('%s{%s-SoftSeq:0}Load-Cmd'), 1)
        caput(self.evg('%s{%s-SoftSeq:0}Enable-Cmd'), 1)

        self.assertPVEqual(self.evr('%s{%s}EvtBCnt-I'), prev11)
        self.assertPVEqual(self.evr('%s{%s}EvtCCnt-I'), prev12)
        self.assertPVEqual(self.evg('%s{%s-SoftSeq:0}NumOfStarts-I'), starts)
        self.assertPVEqual(self.evg('%s{%s-SoftSeq:0}NumOfRuns-I'), ends)

        caput(self.evg('%s{%s-SoftSeq:0}SoftTrig-Cmd'), 1)
        time.sleep(0.1)

        self.assertPVEqual(self.evr('%s{%s}EvtBCnt-I'), prev11 + 1)
        self.assertPVEqual(self.evr('%s{%s}EvtCCnt-I'), prev12 + 1)
        self.assertPVEqual(self.evg('%s{%s-SoftSeq:0}NumOfStarts-I'),
                           starts + 1)
        self.assertPVEqual(self.evg('%s{%s-SoftSeq:0}NumOfRuns-I'), ends + 1)

        # When Single mode, so now disabled
        self.assertPVEqual(self.evg('%s{%s-SoftSeq:0}Enable-RB'),
                           0 if single else 1)

        # try to trigger again, no-op in Single
        caput(self.evg('%s{%s-SoftSeq:0}SoftTrig-Cmd'), 1)

        self.assertPVEqual(self.evr('%s{%s}EvtBCnt-I'),
                           prev11 + 1 if single else prev11 + 2)
        self.assertPVEqual(self.evr('%s{%s}EvtCCnt-I'),
                           prev12 + 1 if single else prev12 + 2)
Ejemplo n.º 44
0
def abstract_caget(pv, throw=False):
    """
    standard channel access 'get' function using cothread
    """
    print('caget {}'.format(pv))
    if pv in ca_abstraction_mapping.name_to_function_mapping:
        return ca_abstraction_mapping.name_to_function_mapping[pv]()
    else:
        return caget(pv, throw=True)
def enable_asyn_trace():
    hdfport = caget("13SIM1:HDF1:PortName_RBV")
    settings = [
        ("13SIM1:cam1:AsynIO.PORT", hdfport, None),
        ("13SIM1:HDF1:PoolUsedMem.SCAN", "Passive", None),
        ("13SIM1:cam1:AsynIO.TMSK", 0x31, None),
        ("13SIM1:cam1:AsynIO.TINM", 0x4, None),
    ]
    load_settings(settings)
Ejemplo n.º 46
0
    def validate_test_runner(
            self,
            creation_func,
            new_value,
            expected_value,
            validate_pass: bool):

        parent_conn, child_conn = multiprocessing.Pipe()

        device_name = create_random_prefix()

        process = multiprocessing.Process(
            target=self.validate_ioc_test_func,
            args=(device_name, creation_func, child_conn, validate_pass),
        )

        process.start()

        from cothread.catools import caget, caput, _channel_cache

        try:
            # Wait for message that IOC has started
            select_and_recv(parent_conn, "R")


            # Suppress potential spurious warnings
            _channel_cache.purge()

            kwargs = {}
            if creation_func in [builder.longStringIn, builder.longStringOut]:
                from cothread.dbr import DBR_CHAR_STR
                kwargs.update({"datatype": DBR_CHAR_STR})

            put_ret = caput(
                device_name + ":VALIDATE-RECORD",
                new_value,
                wait=True,
                **kwargs,
            )
            assert put_ret.ok, "caput did not succeed"

            ret_val = caget(
                device_name + ":VALIDATE-RECORD",
                timeout=TIMEOUT,
                **kwargs
            )

            if creation_func in [builder.WaveformOut, builder.WaveformIn]:
                assert numpy.array_equal(ret_val, expected_value)
            else:
                assert ret_val == expected_value

        finally:
            # Suppress potential spurious warnings
            _channel_cache.purge()
            parent_conn.send("D")  # "Done"
            process.join(timeout=TIMEOUT)
Ejemplo n.º 47
0
    def test_non_existant(self):
        self.assertIOCRunning()

        if sys.version_info > (2, 7):
            ne = self.testprefix+'ne'
            with self.assertRaises(catools.ca_nothing) as cm:
                catools.caget(ne, timeout=0.1)

            self.assertEqual(
                repr(cm.exception),
                "ca_nothing('%s', 80)" % ne)
            self.assertEqual(
                str(cm.exception),
                "%s: User specified timeout on IO operation expired" % ne)
            self.assertFalse(bool(cm.exception))
            with self.assertRaises(TypeError):
                for _ in cm.exception:
                    pass
Ejemplo n.º 48
0
 def planecallback(self, value):
     """Set source plane when it is changed."""
     self.plane = value
     cothread.Sleep(2.0)
     if self.selecteddevice != "NULL":
         try:
             ca.caput(self.pvmapping.__shift__, ca.caget(self.pvmapping.__positionrb__))
             ca.caput(self.pvmapping.__angle__, ca.caget(self.pvmapping.__anglerb__))
         except ca.ca_nothing:
             # do not do anything for this exception.
             pass
     else:
         try:
             ca.caput(self.pvmapping.__shift__, 0.0)
             ca.caput(self.pvmapping.__angle__, 0.0)
         except ca.ca_nothing:
             # do not do anything for this exception.
             pass
Ejemplo n.º 49
0
    def __init__(self):
        """Monitor values of PVs: offsets, scales etc."""
        if self.__guard:
            raise RuntimeError('Do not instantiate. ' +
                               'If you require an instance use get_instance.')

        self.arrays = {
            Arrays.OFFSETS: caget(
                [ctrl + ':OFFSET' for ctrl in PvReferences.CTRLS]),
            Arrays.SCALES: caget(
                [ctrl + ':WFSCA' for ctrl in PvReferences.CTRLS]),
            Arrays.SET_SCALES: caget(
                [name + ':SETWFSCA' for name in PvReferences.NAMES]),
            Arrays.WAVEFORMS: caget(PvReferences.TRACES),
            Arrays.SETI: caget([name + ':SETI' for name in PvReferences.NAMES]),
            Arrays.IMIN: caget([name + ':IMIN' for name in PvReferences.NAMES]),
            Arrays.IMAX: caget([name + ':IMAX' for name in PvReferences.NAMES]),
            Arrays.ERRORS: caget(
                [name + ':ERRGSTR' for name in PvReferences.NAMES])
        }

        self.listeners = {'straight': [], 'trace': []}

        for i in range(len(PvReferences.CTRLS)):
            camonitor(PvReferences.CTRLS[i] + ':OFFSET',
                      lambda x, i=i: self.update_values(
                    x, Arrays.OFFSETS, i, 'straight'))
            camonitor(PvReferences.CTRLS[i] + ':WFSCA',
                      lambda x, i=i: self.update_values(
                    x, Arrays.SCALES, i, 'straight'))

        for idx, ioc in enumerate(PvReferences.NAMES):
            camonitor(ioc + ':SETWFSCA',
                      lambda x, i=idx: self.update_values(
                    x, Arrays.SET_SCALES, i, 'straight'))
            camonitor(ioc + ':SETI',
                      lambda x, i=idx: self.update_values(
                    x, Arrays.SETI, i, 'straight'))
            camonitor(ioc + ':IMIN',
                      lambda x, i=idx: self.update_values(
                    x, Arrays.IMIN, i, 'straight'))
            camonitor(ioc + ':IMAX',
                      lambda x, i=idx: self.update_values(
                    x, Arrays.IMAX, i, 'straight'))
            camonitor(ioc + ':ERRGSTR',
                      lambda x, i=idx: self.update_values(
                    x, Arrays.ERRORS, i, 'straight'), format=FORMAT_TIME)

        camonitor(PvReferences.TRACES[0],
                  lambda x: self.update_values(x, Arrays.WAVEFORMS, 0, 'trace'))
        camonitor(PvReferences.TRACES[1],
                  lambda x: self.update_values(x, Arrays.WAVEFORMS, 1, 'trace'))

        cothread.Yield()  # Ensure monitored values are connected
Ejemplo n.º 50
0
 def get_turn_min_max(self):
     if self.layer == 'tango':
         runout_ = self.dev_tango.MEM_RUNOUT_S
     elif self.layer == 'epics':
         from cothread import catools
         runout_ = catools.caget(self.device_name + ":MEM:RUNOUT_S")
     runout = [0.125, 0.25, 0.5, 0.75, 255./256][runout_]
     min_turn = np.ceil(((runout-1)*2.**29)/self.bunch_nb)
     max_turn = np.floor((runout*2.**29)/self.bunch_nb)
     return min_turn, max_turn
Ejemplo n.º 51
0
    def epicsGet(self, pv, default):
        """Do an epics caget and return value

        pv : string : process variable
        default : string : return this is there is an error"""
        s = catools.caget(pv, throw = False)
        if s.ok == False:
            logging.warning("Failed to get '%s' error = %s", s.name, str(s))
            return False, default
        return True, s
def bpms_enabled(bpms):
    ''' Return a list of ones and zeros representing the 
    BPMs with enabled pv values (0 for enabled, 1 for disabled). '''
    pvs_enabled = list()
    for bpm in bpms:
        pv = bpm.pv()
        # Assume that all PVs have the same prefix
        pvs_enabled.append('{0}:CF:ENABLED_S'.format(pv[0].split(':')[0]))

    return caget(pvs_enabled)
Ejemplo n.º 53
0
 def setUp(self):
     # read cor device, e.g. C29-MG{PS:CH1B}
     self._cor_dev = [s.strip() for s in 
                      open("dev_cor.txt", "r").readlines()]
     #SR:C17-MG{PS:CL1A}I:Sp1-SP  (Sp2)
     #SR:C17-MG{PS:CL1A}I:Ps1DCCT1-I (Ps2)
     self._pvs = ["SR:" + s + "I:Sp1-SP" for s in self._cor_dev] + \
         ["SR:" + s + "I:Sp2-SP" for s in self._cor_dev]
     self._pvsrb = ["SR:" + s + "I:Ps1DCCT1-I" for s in self._cor_dev] + \
         ["SR:" + s + "I:Ps2DCCT1-I" for s in self._cor_dev]
     self._v0 = caget(self._pvs)
Ejemplo n.º 54
0
    def get(self, pv):
        """ Get the value of a given pv.

        Args:
            pv(string): The process variable given as a string. It can be
                a readback or a setpoint pv.

        Returns:
            float: Represents the current value of the given pv.
        """
        return caget(pv)
Ejemplo n.º 55
0
    def do_test_sequence(self, single=True):
        """Setup a software triggered sequencer in Single mode
        """
        # watch EVR counter to ensure EVR FIFO IRQ works
        prev11 = caget(self.evr('%s{%s}EvtBCnt-I'))
        prev12 = caget(self.evr('%s{%s}EvtCCnt-I'))
        # watch EVG counter to ensure that EVG start/end of seqeunce IRQ works
        starts = caget(self.evg('%s{%s-SoftSeq:0}NumOfStarts-I'))
        ends = caget(self.evg('%s{%s-SoftSeq:0}NumOfRuns-I'))

        caput(self.evg('%s{%s-SoftSeq:0}RunMode-Sel'), 'Single' if single else 'Normal')
        caput(self.evg('%s{%s-SoftSeq:0}TrigSrc:0-Sel'), 'Software')
        caput(self.evg('%s{%s-SoftSeq:0}TsResolution-Sel'), 'Ticks')
        self.load_seq([
            (0, 11),
            (1, 12),
        ]) # commits
        caput(self.evg('%s{%s-SoftSeq:0}Load-Cmd'), 1)
        caput(self.evg('%s{%s-SoftSeq:0}Enable-Cmd'), 1)

        self.assertPVEqual(self.evr('%s{%s}EvtBCnt-I'), prev11)
        self.assertPVEqual(self.evr('%s{%s}EvtCCnt-I'), prev12)
        self.assertPVEqual(self.evg('%s{%s-SoftSeq:0}NumOfStarts-I'), starts)
        self.assertPVEqual(self.evg('%s{%s-SoftSeq:0}NumOfRuns-I'), ends)

        caput(self.evg('%s{%s-SoftSeq:0}SoftTrig-Cmd'), 1)
        time.sleep(0.1)

        self.assertPVEqual(self.evr('%s{%s}EvtBCnt-I'), prev11+1)
        self.assertPVEqual(self.evr('%s{%s}EvtCCnt-I'), prev12+1)
        self.assertPVEqual(self.evg('%s{%s-SoftSeq:0}NumOfStarts-I'), starts+1)
        self.assertPVEqual(self.evg('%s{%s-SoftSeq:0}NumOfRuns-I'), ends+1)

        # When Single mode, so now disabled
        self.assertPVEqual(self.evg('%s{%s-SoftSeq:0}Enable-RB'), 0 if single else 1)

        # try to trigger again, no-op in Single
        caput(self.evg('%s{%s-SoftSeq:0}SoftTrig-Cmd'), 1)

        self.assertPVEqual(self.evr('%s{%s}EvtBCnt-I'), prev11+1 if single else prev11+2)
        self.assertPVEqual(self.evr('%s{%s}EvtCCnt-I'), prev12+1 if single else prev12+2)