Compare commits
No commits in common. "90d5d885a311f00db2629a8fa8ad78e871012977" and "7826cce063991b9e74901b994521d46ac675774e" have entirely different histories.
90d5d885a3
...
7826cce063
3 changed files with 394 additions and 458 deletions
452
dorn.py
452
dorn.py
|
|
@ -1,452 +0,0 @@
|
||||||
import math
|
|
||||||
|
|
||||||
AHEPAM_CONFIG = {
|
|
||||||
dorn_addr: 0x2000,
|
|
||||||
verbose: True,
|
|
||||||
slices: (0,1),
|
|
||||||
n_channels: 24
|
|
||||||
}
|
|
||||||
|
|
||||||
def dorn_config(a, v=None, m=None, slice=0):
|
|
||||||
verb = AHEPAM_CONFIG.verbose
|
|
||||||
a |= AHEPAM_CONFIG.dorn_addr | (slice<<11)
|
|
||||||
a &= 0xfff
|
|
||||||
if v is None:
|
|
||||||
if not m:
|
|
||||||
m = f"dorn[0x{a:03x}]"
|
|
||||||
return int(ecmd(f"alt/cmd/del[10] 0x{a:03x}", task=m, verb=verb).split()[-1], 0)
|
|
||||||
if not m:
|
|
||||||
m = f"dorn[0x{a:03x}] = 0x{v:04x}"
|
|
||||||
if v is False:
|
|
||||||
ecmd(f"alt/cmd/inj/del[1] 0x{a:03x}", task=m, verb=verb)
|
|
||||||
else:
|
|
||||||
ecmd(f"alt/cmd/inj/del[1] 0x{a:03x} 0x{v:04x}", task=m, verb=verb)
|
|
||||||
|
|
||||||
def thres(sl, ch, v):
|
|
||||||
dorn_config(0x040 | ch, v, slice=sl)
|
|
||||||
|
|
||||||
def write_l2(sl, ch, i, a, b):
|
|
||||||
dorn_config(0x400 | (ch<<3) | (i<<1) | 0, a & 0xffff, slice=sl)
|
|
||||||
dorn_config(0x400 | (ch<<3) | (i<<1) | 1, b & 0xffff, slice=sl)
|
|
||||||
|
|
||||||
l2_set6 = (
|
|
||||||
(0, -1203, 0),
|
|
||||||
(1, -1203, 0),
|
|
||||||
(2, -1203, 0),
|
|
||||||
(3, -1186, 0),
|
|
||||||
(4, -39, 2000),
|
|
||||||
(5, 1709, 970),
|
|
||||||
(6, 2000, -1082),
|
|
||||||
(7, 1125, -1888),
|
|
||||||
)
|
|
||||||
|
|
||||||
l2cal = [
|
|
||||||
[
|
|
||||||
0.99964,
|
|
||||||
None,
|
|
||||||
0.99117,
|
|
||||||
None,
|
|
||||||
None, None, None, None,
|
|
||||||
1.00178,
|
|
||||||
None, None, None,
|
|
||||||
None, None, None, None,
|
|
||||||
],
|
|
||||||
[], [], [],
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def calib_l2(cal, l2_set6):
|
|
||||||
if cal is None:
|
|
||||||
return coeff
|
|
||||||
from numpy import array, floor, add, any
|
|
||||||
c = array(coeff)[:,1:] * cal
|
|
||||||
i = floor(c+0.5)
|
|
||||||
e = add.reduce(i)
|
|
||||||
v = e>0
|
|
||||||
w = e<0
|
|
||||||
while any(v) or any(w):
|
|
||||||
d = i - c
|
|
||||||
vv = d.argmax(axis=0)
|
|
||||||
ww = d.argmin(axis=0)
|
|
||||||
for x,f in enumerate(v):
|
|
||||||
if f:
|
|
||||||
i[vv[x],x] -= 1
|
|
||||||
for x,f in enumerate(w):
|
|
||||||
if f:
|
|
||||||
i[ww[x],x] += 1
|
|
||||||
e = add.reduce(i)
|
|
||||||
v = e>0
|
|
||||||
w = e<0
|
|
||||||
return [(x, int(ii[0]), int(ii[1])) for x, ii in enumerate(i)]
|
|
||||||
|
|
||||||
def l2filter(coeff=l2_set6, cal=None):
|
|
||||||
for sl in AHEPAM_CONFIG.slices:
|
|
||||||
for ch in range(AHEPAM_CONFIG.n_channels):
|
|
||||||
c = coeff
|
|
||||||
if cal and cal[sl] and cal[sl][ch]:
|
|
||||||
c = calib_l2(cal[sl][ch])
|
|
||||||
for cc in c:
|
|
||||||
write_l2(sl, ch, *cc)
|
|
||||||
|
|
||||||
def write_l3(sl, ch, *p):
|
|
||||||
scales = (14, 16, 14, 15)
|
|
||||||
for i,pp in enumerate(p):
|
|
||||||
if isinstance(pp, float):
|
|
||||||
pp = int(pp * 2**scales[i])
|
|
||||||
dorn_config(0x100 | (ch<<2) | i, pp & 0xffff, slice=sl)
|
|
||||||
|
|
||||||
def l3banana(
|
|
||||||
# iterated F-banana 2022-03-13-aha-bi207-18,
|
|
||||||
p0 = -4007,
|
|
||||||
p1 = 0,
|
|
||||||
p2 = 12737,
|
|
||||||
p3 = -3698 ):
|
|
||||||
for sl in AHEPAM_CONFIG.slices:
|
|
||||||
for ch in range(12):
|
|
||||||
write_l3(sl, ch, p0, p1, p2, p3)
|
|
||||||
|
|
||||||
def c16log2(A):
|
|
||||||
return int(math.ceil(16*math.log(1024*A)/math.log(2)))
|
|
||||||
|
|
||||||
def enable_trigger(sl, triggers, det=False, sa=False):
|
|
||||||
i = 2 if sa else 0 if det else 1
|
|
||||||
dorn_config(0x008 | i | sl<<4, triggers, slice=sl)
|
|
||||||
|
|
||||||
def nsamples(sl, n=None, m=None, **slice):
|
|
||||||
if n is None:
|
|
||||||
return dorn_config(0x00b | sl<<4, slice=sl)
|
|
||||||
if m is None:
|
|
||||||
m = 0xfff if n else 0
|
|
||||||
enable_trigger(sl, m, sa=True)
|
|
||||||
dorn_config(0x00b | sl<<4, n, slice=sl)
|
|
||||||
|
|
||||||
def triggers(sl, atrig=0x3ff, dtrig=0, sam=0, nsa=32):
|
|
||||||
enable_trigger(sl, dtrig, det=True)
|
|
||||||
enable_trigger(sl, atrig)
|
|
||||||
nsamples(sl, nsa, sam)
|
|
||||||
|
|
||||||
def hist_bins(sl, bin0=4.0, res=1, cwin=6, xtalk=6):
|
|
||||||
"""configure dorn_l4 histogramming
|
|
||||||
bin0: float: A-value of bin 0, int: 16LOG2(A)
|
|
||||||
res: bin = 16×log₂(A) >> res
|
|
||||||
cwin: anti-coincidence window [µs]
|
|
||||||
xtalk: x-talk ratio cut: reject if S > (S>>xtalk)
|
|
||||||
"""
|
|
||||||
if isinstance(bin0, float):
|
|
||||||
bin0=c16log2(bin0)
|
|
||||||
dorn_config(0x00c | sl<<4, (xtalk<<8) | cwin)
|
|
||||||
dorn_config(0x00d | sl<<4, (res<<9) | bin0)
|
|
||||||
|
|
||||||
def base_address(hists=None, counters=None, hmask=None, cmask=None):
|
|
||||||
if hists is not None:
|
|
||||||
if counters is None:
|
|
||||||
counters = hists
|
|
||||||
r = dorn_config(0x088, (counters<<3) | hists)
|
|
||||||
else:
|
|
||||||
if hmask is not None:
|
|
||||||
r = dorn_config(0x088, 0x4000 | hmask)
|
|
||||||
if cmask is not None:
|
|
||||||
r = dorn_config(0x088, 0x8000 | cmask)
|
|
||||||
if cmask is None and hmask is None:
|
|
||||||
r = dorn_config(0x088, 0x8000)
|
|
||||||
return r & 7, r >> 3
|
|
||||||
|
|
||||||
def fifo_status(i=None):
|
|
||||||
e = dorn_config(0x084)
|
|
||||||
p = dorn_config(0x085)
|
|
||||||
f = dorn_config(0x086)
|
|
||||||
if i is None:
|
|
||||||
return e,p,f
|
|
||||||
return (e>>i)&1, (p>>i)&1, (f>>i)&1
|
|
||||||
|
|
||||||
def fifo_select(hi=False, sl=None, hk=False, ev=False, sa=False, i=None):
|
|
||||||
if i is not None:
|
|
||||||
f = 1<<i
|
|
||||||
else:
|
|
||||||
f = (sa<<2) | (ev<<1) | hk
|
|
||||||
if sl is not None:
|
|
||||||
f <<= 3*sl+1
|
|
||||||
else:
|
|
||||||
f *= 18
|
|
||||||
f |= hi
|
|
||||||
return f
|
|
||||||
|
|
||||||
def fifo_enable(en=False, rfifo=False, sl=None, **aa):
|
|
||||||
f = fifo_select(sl=sl, **aa)
|
|
||||||
if sl is None and en:
|
|
||||||
en = 3
|
|
||||||
elif sl is not None:
|
|
||||||
en <<= sl
|
|
||||||
dorn_config(0x087, (f<<6) | (rfifo<<5) | en)
|
|
||||||
|
|
||||||
STROBES = {
|
|
||||||
"read_fifos": 0,
|
|
||||||
"incr": 1,
|
|
||||||
"resync": 2,
|
|
||||||
"clock_reset": 3,
|
|
||||||
"hk": 4,
|
|
||||||
"dorn_reset": 8,
|
|
||||||
"mem_reset": 12,
|
|
||||||
"rb_reset": 13,
|
|
||||||
"fifo_reset": 14,
|
|
||||||
}
|
|
||||||
|
|
||||||
def strobe(sl=None, **aa):
|
|
||||||
s = 0
|
|
||||||
for k in aa:
|
|
||||||
if not k in STROBES:
|
|
||||||
raise KeyError(f"No STROBE: {k}")
|
|
||||||
if aa[k]:
|
|
||||||
b = 1
|
|
||||||
if k=="hk":
|
|
||||||
if sl is None:
|
|
||||||
b = 15;
|
|
||||||
else:
|
|
||||||
b <<= sl
|
|
||||||
s |= b << STROBES[k]
|
|
||||||
dorn_config(0x08b, s)
|
|
||||||
|
|
||||||
def fifo_reset(**aa):
|
|
||||||
f = fifo_select(**aa)
|
|
||||||
if not f:
|
|
||||||
strobe(fifo_reset=True)
|
|
||||||
else:
|
|
||||||
dorn_config(0x084, f)
|
|
||||||
|
|
||||||
def fifo_read(**aa):
|
|
||||||
f = fifo_select(**aa)
|
|
||||||
if not f:
|
|
||||||
ecmd("alt/cmd/inj 0x8800", verb=_verbose)
|
|
||||||
else:
|
|
||||||
dorn_config(0x085, f)
|
|
||||||
|
|
||||||
def degC(a, R1=10e3, R25=10e3, B25=3750, res=0x1000):
|
|
||||||
R=R1*a/(res-(a&(res-1)))
|
|
||||||
return B25/(math.log(R/R25)+B25/298) - 273
|
|
||||||
|
|
||||||
#TO DO: Adjust
|
|
||||||
def nmahepam_hk(sl, what="data", data=none, ND=8, NV=8, Vref=3.3):
|
|
||||||
if not data:
|
|
||||||
ecmd("alt/stream/off")
|
|
||||||
fifo_enable(en=True, sl=sl, hk=True)
|
|
||||||
fifo_reset(sl=sl, hk=True)
|
|
||||||
strobe(sl=sl, hk=True)
|
|
||||||
sleep(0.001)
|
|
||||||
fifo_read(sl=sl, hk=True)
|
|
||||||
data=read_fifo()
|
|
||||||
if (data[0] & 0xfffc) != 0x5710:
|
|
||||||
raise ValueError("Read HK packet error", data)
|
|
||||||
if what=="data":
|
|
||||||
return data
|
|
||||||
data = [d & 0xfff for d in data]
|
|
||||||
data = [data[ND*i+1:ND*i+1+NV] for i in range(8)]
|
|
||||||
if what=="raw":
|
|
||||||
return data
|
|
||||||
#NMAHEPAM:data[7][0] *= 2*Vref/4096 # Vcore
|
|
||||||
data[7][1] = degC(data[7][1]) # Tana
|
|
||||||
data[7][2] *= 2*Vref/4096 # V+6
|
|
||||||
data[7][3] *= 2.5*Vref/4096 # V-6
|
|
||||||
data[7][3] -= 1.5*data[7][2]
|
|
||||||
data[6][0] *= Vref/4096/0.0206 # Vbias
|
|
||||||
data[6][1] = degC(data[6][1]) # Tpa
|
|
||||||
data[6][3] *= 2*Vref/4096 # Vcc
|
|
||||||
data[6][2] *= 2.5*Vref/4096 # Vss
|
|
||||||
data[6][2] -= 1.5*data[6][3]
|
|
||||||
if what=="cooked":
|
|
||||||
return data
|
|
||||||
sys.stderr.write("""nmahepam HK:
|
|
||||||
Vcore = %6.3f V
|
|
||||||
Tana = %6.2f °C
|
|
||||||
V+6 = %6.3f V
|
|
||||||
V-6 = %6.3f V
|
|
||||||
Vbias = %6.2f V
|
|
||||||
Tpa = %6.2f °C
|
|
||||||
Vss = %6.3f V
|
|
||||||
Vcc = %6.3f V
|
|
||||||
""" % tuple(data[7]+data[6]))
|
|
||||||
|
|
||||||
def default_config(thr=0x7ff):
|
|
||||||
for sl in range(AHEPAM_CONFIG.slices):
|
|
||||||
for ch in range(AHEPAM_CONFIG.n_channels):
|
|
||||||
thres(sl, ch, thr)
|
|
||||||
l2filter()
|
|
||||||
l3banana()
|
|
||||||
for sl in range(AHEPAM_CONFIG.slices):
|
|
||||||
hist_bins(sl)
|
|
||||||
triggers(sl, 0)
|
|
||||||
|
|
||||||
def print_trigger_config():
|
|
||||||
tri = [[dorn_config(0x008 + i + (sl<<4)) for i in range(4)] for sl in range(2)]
|
|
||||||
ff = [dorn_config(0x084+i) for i in range(4)]
|
|
||||||
tri.append(ff)
|
|
||||||
e = ff[3]
|
|
||||||
df = [Areg(0x11+i) for i in range(3)]
|
|
||||||
df.append(Areg(5))
|
|
||||||
tri.append(df)
|
|
||||||
print(f"""narena trigger config:
|
|
||||||
trigger detector masks:
|
|
||||||
det triggers: 0x{tri[0][0]:x} 0x{tri[1][0]:x}
|
|
||||||
channel triggers: 0x{tri[0][1]:03x} 0x{tri[1][1]:03x}
|
|
||||||
sample readout triggers: 0x{tri[0][2]:03x} 0x{tri[1][2]:03x}
|
|
||||||
number of sample records: {tri[0][3]:-5d} {tri[1][3]:-5d}
|
|
||||||
enable: {e&1} {(e>>1)&1}
|
|
||||||
fifos enable SA/EV/HK HI {(e>>7)&7:03b} {(e>>10)&7:03b} {(e>>6)&1}
|
|
||||||
empty {(ff[0]>>1)&7:03b} {(ff[0]>>4)&7:03b} {ff[0]&1} {(df[3]>>9)&7:03b}
|
|
||||||
packet {(ff[1]>>1)&7:03b} {(ff[1]>>4)&7:03b} {ff[1]&1} {(df[3]>>13)&7:03b}
|
|
||||||
full {(ff[2]>>1)&7:03b} {(ff[2]>>4)&7:03b} {ff[2]&1} {(df[3]>>5)&7:03b}
|
|
||||||
dig fifo status {df[2]&0x3ff} {df[1]&0x3ff} {df[0]&0x3ff}
|
|
||||||
""", file=sys.stderr)
|
|
||||||
return tri
|
|
||||||
|
|
||||||
def read_event(sl=None, ev=None):
|
|
||||||
if ev is None:
|
|
||||||
fifo_read(sl=sl, ev=True)
|
|
||||||
ev = read_fifo(2)
|
|
||||||
if (ev[0] & 0xfffc) != 0x5718:
|
|
||||||
raise ValueError(f"EV packet magic mismatch {ev[0]:04x}")
|
|
||||||
Ba = ev[5]
|
|
||||||
Ph = ev[6]
|
|
||||||
A = ev[7]<<8 | ev[9]>>8
|
|
||||||
B = ev[8]<<8 | ev[9]&0xff
|
|
||||||
E = ev[10] | ev[11]<<16
|
|
||||||
if Ba & 0x8000:
|
|
||||||
Ba -= 0x10000
|
|
||||||
if Ph & 0x8000:
|
|
||||||
Ph -= 0x10000
|
|
||||||
if A & 0x800000:
|
|
||||||
A -= 0x1000000
|
|
||||||
if B & 0x800000:
|
|
||||||
B -= 0x1000000
|
|
||||||
if E & 0x80000000:
|
|
||||||
E -= 0x100000000
|
|
||||||
print(f"""PHA Event slice {ev[0]&3} ch {ev[4]&15}
|
|
||||||
time: {ev[1] | ev[2]<<16}
|
|
||||||
Δtime: {ev[3]}
|
|
||||||
lost: {ev[4]>>4}
|
|
||||||
A: {A/1024:.2f}
|
|
||||||
B: {B/1024:.2f}
|
|
||||||
banana: {Ba/0x4000:.4f}
|
|
||||||
φ: {Ph/0x4000:.4f}
|
|
||||||
E: {E/0x20000:.2f}
|
|
||||||
""", file=sys.stderr)
|
|
||||||
return ev
|
|
||||||
|
|
||||||
def read_samples(sl=0, n=None, sa=None):
|
|
||||||
if not sa:
|
|
||||||
if not n:
|
|
||||||
n = nsamples(sl)
|
|
||||||
sa = []
|
|
||||||
while n:
|
|
||||||
ff = dorn_config(0x085)
|
|
||||||
if not (ff & (8 << (3*sl))):
|
|
||||||
break;
|
|
||||||
fifo_read(sl=sl, sa=True)
|
|
||||||
sa.append(read_fifo(3))
|
|
||||||
n -= 1
|
|
||||||
for s in sa:
|
|
||||||
if (s[0] & 0xfffc) != 0x5714:
|
|
||||||
raise ValueError(f"SA magic mismatch {s[0]:04x}")
|
|
||||||
t = s[1] | s[2]<<16
|
|
||||||
print(f"{t} ", " ".join([f"{ss&0xfff:5d}" for ss in s[3:]]), file=sys.stderr)
|
|
||||||
return sa
|
|
||||||
|
|
||||||
def make_pulser():
|
|
||||||
global pu
|
|
||||||
try:
|
|
||||||
pu.ID
|
|
||||||
except:
|
|
||||||
import agilent3322A
|
|
||||||
pu = agilent3322A.pulser()
|
|
||||||
return pu
|
|
||||||
|
|
||||||
from usbterm import DataJob
|
|
||||||
|
|
||||||
class pulser_test(DataJob):
|
|
||||||
|
|
||||||
cadence = 600
|
|
||||||
coffset = None
|
|
||||||
nsamples = 16
|
|
||||||
thres = 16
|
|
||||||
|
|
||||||
def __init__(self,
|
|
||||||
amplitudes=(0.25, 0.5, 1., 2., 4., 5.),
|
|
||||||
fn = None):
|
|
||||||
self.filename = fn
|
|
||||||
self.pu = make_pulser()
|
|
||||||
super().__init__(amplitudes)
|
|
||||||
self.connect(ifc)
|
|
||||||
|
|
||||||
def iniz(self):
|
|
||||||
disable()
|
|
||||||
self.pu.cmd("OUTPUT ON")
|
|
||||||
self.info("agilent pulser on")
|
|
||||||
self.next_time(10)
|
|
||||||
if self.filename:
|
|
||||||
ifc._data.Open()
|
|
||||||
enable()
|
|
||||||
|
|
||||||
def fini(self):
|
|
||||||
self.pu.cmd("OUTPUT OFF")
|
|
||||||
self.info("agilent pulser off")
|
|
||||||
if self.filename:
|
|
||||||
ifc._data.Open()
|
|
||||||
disable()
|
|
||||||
|
|
||||||
def Start(self, fn=None):
|
|
||||||
if fn is not None:
|
|
||||||
self.filename = fn
|
|
||||||
self.start()
|
|
||||||
|
|
||||||
def func(self, a):
|
|
||||||
if self.filename:
|
|
||||||
ifc._data.Open()
|
|
||||||
disable()
|
|
||||||
pu.set_highlevel(a)
|
|
||||||
self.info("agilent pa %.3f" % a)
|
|
||||||
if self.filename:
|
|
||||||
ifc._data.Open(self.filename % a)
|
|
||||||
enable()
|
|
||||||
Status()
|
|
||||||
|
|
||||||
def mem_op(addr=None, hist=None, bank=None, data=None, read=None, clear=None, base=0x88c, WH=7):
|
|
||||||
|
|
||||||
a = 0
|
|
||||||
if read:
|
|
||||||
a |= 0x8000
|
|
||||||
if clear:
|
|
||||||
a |= 0x4000
|
|
||||||
|
|
||||||
if hist is True and addr is None:
|
|
||||||
dorn_config(base+2, False, "mem addr next histogram")
|
|
||||||
hist = None
|
|
||||||
|
|
||||||
if hist is not None:
|
|
||||||
a |= 0x2000
|
|
||||||
if addr is not None:
|
|
||||||
a |= addr >> WH
|
|
||||||
else:
|
|
||||||
a |= hist
|
|
||||||
elif bank is not None:
|
|
||||||
a |= 0x1000
|
|
||||||
if addr is not None:
|
|
||||||
a |= addr >> (WH+6)
|
|
||||||
else:
|
|
||||||
a |= bank
|
|
||||||
|
|
||||||
if a:
|
|
||||||
dorn_config(base+3, a, "mem address and command")
|
|
||||||
|
|
||||||
if data is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
dd = data.__iter__()
|
|
||||||
except:
|
|
||||||
dd = (data,)
|
|
||||||
dh = 0x10000
|
|
||||||
for d in dd:
|
|
||||||
h = d >> 16
|
|
||||||
if h != dh:
|
|
||||||
dorn_config(base+1, h, "mem data high")
|
|
||||||
dh = h
|
|
||||||
dorn_config(base, d & 0xffff, "mem data write")
|
|
||||||
398
narena.py
398
narena.py
|
|
@ -5,7 +5,6 @@ from arena import *
|
||||||
import math
|
import math
|
||||||
from time import sleep
|
from time import sleep
|
||||||
import arena, scangen
|
import arena, scangen
|
||||||
from dorn import *
|
|
||||||
|
|
||||||
ifc,_oo = armlib.init_irena(scope = globals(), name = "NARENA", prod = 0xee02)
|
ifc,_oo = armlib.init_irena(scope = globals(), name = "NARENA", prod = 0xee02)
|
||||||
arena._connect(ifc)
|
arena._connect(ifc)
|
||||||
|
|
@ -25,10 +24,29 @@ from lasc import SCstart, SCread
|
||||||
def SCplot(sc, CDIV=6, **kk):
|
def SCplot(sc, CDIV=6, **kk):
|
||||||
osc.LASCplot(None, sc, CDIV=CDIV, **kk)
|
osc.LASCplot(None, sc, CDIV=CDIV, **kk)
|
||||||
|
|
||||||
AHEPAM_CONFIG.update({
|
_verbose = True
|
||||||
"dorn_addr": 0x800,
|
def dorn_config(a, v=None, m=None):
|
||||||
"n_channels": 12
|
a |= 0x800
|
||||||
})
|
a &= 0xfff
|
||||||
|
if v is None:
|
||||||
|
if not m:
|
||||||
|
m = f"dorn[0x{a:03x}]"
|
||||||
|
return int(ecmd(f"alt/cmd/del[10] 0x{a:03x}", task=m, verb=_verbose).split()[-1], 0)
|
||||||
|
if not m:
|
||||||
|
m = f"dorn[0x{a:03x}] = 0x{v:04x}"
|
||||||
|
if v is False:
|
||||||
|
ecmd(f"alt/cmd/inj/del[1] 0x{a:03x}", task=m, verb=_verbose)
|
||||||
|
else:
|
||||||
|
ecmd(f"alt/cmd/inj/del[1] 0x{a:03x} 0x{v:04x}", task=m, verb=_verbose)
|
||||||
|
|
||||||
|
def thres(sl, ch, v, verb=True):
|
||||||
|
ch |= sl<<4
|
||||||
|
dorn_config(0x040 | ch, v)
|
||||||
|
|
||||||
|
def write_l2(sl, ch, i, a, b, verb=True):
|
||||||
|
ch |= sl<<4
|
||||||
|
dorn_config(0x400 | (ch<<3) | (i<<1) | 0, a & 0xffff)
|
||||||
|
dorn_config(0x400 | (ch<<3) | (i<<1) | 1, b & 0xffff)
|
||||||
|
|
||||||
l2_set6 = (
|
l2_set6 = (
|
||||||
(0, -1203, 0),
|
(0, -1203, 0),
|
||||||
|
|
@ -41,6 +59,190 @@ l2_set6 = (
|
||||||
(7, 1125, -1888),
|
(7, 1125, -1888),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
l2cal = [
|
||||||
|
[
|
||||||
|
0.99964,
|
||||||
|
None,
|
||||||
|
0.99117,
|
||||||
|
None,
|
||||||
|
None, None, None, None,
|
||||||
|
1.00178,
|
||||||
|
None, None, None,
|
||||||
|
None, None, None, None,
|
||||||
|
],
|
||||||
|
[], [], [],
|
||||||
|
]
|
||||||
|
|
||||||
|
def calib_l2(cal, coeff=l2_set6):
|
||||||
|
if cal is None:
|
||||||
|
return coeff
|
||||||
|
from numpy import array, floor, add, any
|
||||||
|
c = array(coeff)[:,1:] * cal
|
||||||
|
i = floor(c+0.5)
|
||||||
|
e = add.reduce(i)
|
||||||
|
v = e>0
|
||||||
|
w = e<0
|
||||||
|
while any(v) or any(w):
|
||||||
|
d = i - c
|
||||||
|
vv = d.argmax(axis=0)
|
||||||
|
ww = d.argmin(axis=0)
|
||||||
|
for x,f in enumerate(v):
|
||||||
|
if f:
|
||||||
|
i[vv[x],x] -= 1
|
||||||
|
for x,f in enumerate(w):
|
||||||
|
if f:
|
||||||
|
i[ww[x],x] += 1
|
||||||
|
e = add.reduce(i)
|
||||||
|
v = e>0
|
||||||
|
w = e<0
|
||||||
|
return [(x, int(ii[0]), int(ii[1])) for x, ii in enumerate(i)]
|
||||||
|
|
||||||
|
def l2filter(coeff=l2_set6, cal=None):
|
||||||
|
for sl in range(2):
|
||||||
|
for ch in range(12):
|
||||||
|
c = coeff
|
||||||
|
if cal and cal[sl] and cal[sl][ch]:
|
||||||
|
c = calib_l2(cal[sl][ch])
|
||||||
|
for cc in c:
|
||||||
|
write_l2(sl, ch, *cc)
|
||||||
|
|
||||||
|
def write_l3(sl, ch, *p):
|
||||||
|
ch |= sl<<4
|
||||||
|
scales = (14, 16, 14, 15)
|
||||||
|
for i,pp in enumerate(p):
|
||||||
|
if isinstance(pp, float):
|
||||||
|
pp = int(pp * 2**scales[i])
|
||||||
|
dorn_config(0x100 | (ch<<2) | i, pp & 0xffff)
|
||||||
|
|
||||||
|
def l3banana(
|
||||||
|
# iterated F-banana 2022-03-13-aha-bi207-18,
|
||||||
|
p0 = -4007,
|
||||||
|
p1 = 0,
|
||||||
|
p2 = 12737,
|
||||||
|
p3 = -3698 ):
|
||||||
|
for sl in range(2):
|
||||||
|
for ch in range(12):
|
||||||
|
write_l3(sl, ch, p0, p1, p2, p3)
|
||||||
|
|
||||||
|
def c16log2(A):
|
||||||
|
return int(math.ceil(16*math.log(1024*A)/math.log(2)))
|
||||||
|
|
||||||
|
def enable_trigger(sl, triggers, det=False, sa=False):
|
||||||
|
i = 2 if sa else 0 if det else 1
|
||||||
|
dorn_config(0x008 | i | sl<<4, triggers)
|
||||||
|
|
||||||
|
def nsamples(sl, n=None, m=None):
|
||||||
|
if n is None:
|
||||||
|
return dorn_config(0x00b | sl<<4)
|
||||||
|
if m is None:
|
||||||
|
m = 0xfff if n else 0
|
||||||
|
enable_trigger(sl, m, sa=True)
|
||||||
|
dorn_config(0x00b | sl<<4, n)
|
||||||
|
|
||||||
|
def triggers(sl, atrig=0x3ff, dtrig=0, sam=0, nsa=32):
|
||||||
|
enable_trigger(sl, dtrig, det=True)
|
||||||
|
enable_trigger(sl, atrig)
|
||||||
|
nsamples(sl, nsa, sam)
|
||||||
|
|
||||||
|
def hist_bins(sl, bin0=4.0, res=1, cwin=6, xtalk=6):
|
||||||
|
"""configure dorn_l4 histogramming
|
||||||
|
bin0: float: A-value of bin 0, int: 16LOG2(A)
|
||||||
|
res: bin = 16×log₂(A) >> res
|
||||||
|
cwin: anti-coincidence window [µs]
|
||||||
|
xtalk: x-talk ratio cut: reject if S > (S>>xtalk)
|
||||||
|
"""
|
||||||
|
if isinstance(bin0, float):
|
||||||
|
bin0=c16log2(bin0)
|
||||||
|
dorn_config(0x00c | sl<<4, (xtalk<<8) | cwin)
|
||||||
|
dorn_config(0x00d | sl<<4, (res<<9) | bin0)
|
||||||
|
|
||||||
|
def base_address(hists=None, counters=None, hmask=None, cmask=None):
|
||||||
|
if hists is not None:
|
||||||
|
if counters is None:
|
||||||
|
counters = hists
|
||||||
|
r = dorn_config(0x088, (counters<<3) | hists)
|
||||||
|
else:
|
||||||
|
if hmask is not None:
|
||||||
|
r = dorn_config(0x088, 0x4000 | hmask)
|
||||||
|
if cmask is not None:
|
||||||
|
r = dorn_config(0x088, 0x8000 | cmask)
|
||||||
|
if cmask is None and hmask is None:
|
||||||
|
r = dorn_config(0x088, 0x8000)
|
||||||
|
return r & 7, r >> 3
|
||||||
|
|
||||||
|
def fifo_status(i=None):
|
||||||
|
e = dorn_config(0x084)
|
||||||
|
p = dorn_config(0x085)
|
||||||
|
f = dorn_config(0x086)
|
||||||
|
if i is None:
|
||||||
|
return e,p,f
|
||||||
|
return (e>>i)&1, (p>>i)&1, (f>>i)&1
|
||||||
|
|
||||||
|
def fifo_select(hi=False, sl=None, hk=False, ev=False, sa=False, i=None):
|
||||||
|
if i is not None:
|
||||||
|
f = 1<<i
|
||||||
|
else:
|
||||||
|
f = (sa<<2) | (ev<<1) | hk
|
||||||
|
if sl is not None:
|
||||||
|
f <<= 3*sl+1
|
||||||
|
else:
|
||||||
|
f *= 18
|
||||||
|
f |= hi
|
||||||
|
return f
|
||||||
|
|
||||||
|
def fifo_enable(en=False, rfifo=False, sl=None, **aa):
|
||||||
|
f = fifo_select(sl=sl, **aa)
|
||||||
|
if sl is None and en:
|
||||||
|
en = 3
|
||||||
|
elif sl is not None:
|
||||||
|
en <<= sl
|
||||||
|
dorn_config(0x087, (f<<6) | (rfifo<<5) | en)
|
||||||
|
|
||||||
|
STROBES = {
|
||||||
|
"read_fifos": 0,
|
||||||
|
"incr": 1,
|
||||||
|
"resync": 2,
|
||||||
|
"clock_reset": 3,
|
||||||
|
"hk": 4,
|
||||||
|
"dorn_reset": 8,
|
||||||
|
"mem_reset": 12,
|
||||||
|
"rb_reset": 13,
|
||||||
|
"fifo_reset": 14,
|
||||||
|
}
|
||||||
|
|
||||||
|
def strobe(sl=None, **aa):
|
||||||
|
s = 0
|
||||||
|
for k in aa:
|
||||||
|
if not k in STROBES:
|
||||||
|
raise KeyError(f"No STROBE: {k}")
|
||||||
|
if aa[k]:
|
||||||
|
b = 1
|
||||||
|
if k=="hk":
|
||||||
|
if sl is None:
|
||||||
|
b = 15;
|
||||||
|
else:
|
||||||
|
b <<= sl
|
||||||
|
s |= b << STROBES[k]
|
||||||
|
dorn_config(0x08b, s)
|
||||||
|
|
||||||
|
def fifo_reset(**aa):
|
||||||
|
f = fifo_select(**aa)
|
||||||
|
if not f:
|
||||||
|
strobe(fifo_reset=True)
|
||||||
|
else:
|
||||||
|
dorn_config(0x084, f)
|
||||||
|
|
||||||
|
def fifo_read(**aa):
|
||||||
|
f = fifo_select(**aa)
|
||||||
|
if not f:
|
||||||
|
ecmd("alt/cmd/inj 0x8800", verb=_verbose)
|
||||||
|
else:
|
||||||
|
dorn_config(0x085, f)
|
||||||
|
|
||||||
|
def degC(a, R1=10e3, R25=10e3, B25=3750, res=0x1000):
|
||||||
|
R=R1*a/(res-(a&(res-1)))
|
||||||
|
return B25/(math.log(R/R25)+B25/298) - 273
|
||||||
|
|
||||||
def narena_hk(sl, what="data", data=None, ND=4, NV=8, Vref=3.3):
|
def narena_hk(sl, what="data", data=None, ND=4, NV=8, Vref=3.3):
|
||||||
"""what="data", "raw", "cooked", "print" (default)"""
|
"""what="data", "raw", "cooked", "print" (default)"""
|
||||||
if not data:
|
if not data:
|
||||||
|
|
@ -82,3 +284,189 @@ Tpa = %6.2f °C
|
||||||
Vss = %6.3f V
|
Vss = %6.3f V
|
||||||
Vcc = %6.3f V
|
Vcc = %6.3f V
|
||||||
""" % tuple(data[7]+data[6]))
|
""" % tuple(data[7]+data[6]))
|
||||||
|
|
||||||
|
def default_config(thr=0x7ff):
|
||||||
|
for sl in range(2):
|
||||||
|
for ch in range(12):
|
||||||
|
thres(sl, ch, thr)
|
||||||
|
l2filter()
|
||||||
|
l3banana()
|
||||||
|
for sl in range(2):
|
||||||
|
hist_bins(sl)
|
||||||
|
triggers(sl, 0)
|
||||||
|
|
||||||
|
def print_trigger_config():
|
||||||
|
tri = [[dorn_config(0x008 + i + (sl<<4)) for i in range(4)] for sl in range(2)]
|
||||||
|
ff = [dorn_config(0x084+i) for i in range(4)]
|
||||||
|
tri.append(ff)
|
||||||
|
e = ff[3]
|
||||||
|
df = [Areg(0x11+i) for i in range(3)]
|
||||||
|
df.append(Areg(5))
|
||||||
|
tri.append(df)
|
||||||
|
print(f"""narena trigger config:
|
||||||
|
trigger detector masks:
|
||||||
|
det triggers: 0x{tri[0][0]:x} 0x{tri[1][0]:x}
|
||||||
|
channel triggers: 0x{tri[0][1]:03x} 0x{tri[1][1]:03x}
|
||||||
|
sample readout triggers: 0x{tri[0][2]:03x} 0x{tri[1][2]:03x}
|
||||||
|
number of sample records: {tri[0][3]:-5d} {tri[1][3]:-5d}
|
||||||
|
enable: {e&1} {(e>>1)&1}
|
||||||
|
fifos enable SA/EV/HK HI {(e>>7)&7:03b} {(e>>10)&7:03b} {(e>>6)&1}
|
||||||
|
empty {(ff[0]>>1)&7:03b} {(ff[0]>>4)&7:03b} {ff[0]&1} {(df[3]>>9)&7:03b}
|
||||||
|
packet {(ff[1]>>1)&7:03b} {(ff[1]>>4)&7:03b} {ff[1]&1} {(df[3]>>13)&7:03b}
|
||||||
|
full {(ff[2]>>1)&7:03b} {(ff[2]>>4)&7:03b} {ff[2]&1} {(df[3]>>5)&7:03b}
|
||||||
|
dig fifo status {df[2]&0x3ff} {df[1]&0x3ff} {df[0]&0x3ff}
|
||||||
|
""", file=sys.stderr)
|
||||||
|
return tri
|
||||||
|
|
||||||
|
def read_event(sl=None, ev=None):
|
||||||
|
if ev is None:
|
||||||
|
fifo_read(sl=sl, ev=True)
|
||||||
|
ev = read_fifo(2)
|
||||||
|
if (ev[0] & 0xfffc) != 0x5718:
|
||||||
|
raise ValueError(f"EV packet magic mismatch {ev[0]:04x}")
|
||||||
|
Ba = ev[5]
|
||||||
|
Ph = ev[6]
|
||||||
|
A = ev[7]<<8 | ev[9]>>8
|
||||||
|
B = ev[8]<<8 | ev[9]&0xff
|
||||||
|
E = ev[10] | ev[11]<<16
|
||||||
|
if Ba & 0x8000:
|
||||||
|
Ba -= 0x10000
|
||||||
|
if Ph & 0x8000:
|
||||||
|
Ph -= 0x10000
|
||||||
|
if A & 0x800000:
|
||||||
|
A -= 0x1000000
|
||||||
|
if B & 0x800000:
|
||||||
|
B -= 0x1000000
|
||||||
|
if E & 0x80000000:
|
||||||
|
E -= 0x100000000
|
||||||
|
print(f"""PHA Event slice {ev[0]&3} ch {ev[4]&15}
|
||||||
|
time: {ev[1] | ev[2]<<16}
|
||||||
|
Δtime: {ev[3]}
|
||||||
|
lost: {ev[4]>>4}
|
||||||
|
A: {A/1024:.2f}
|
||||||
|
B: {B/1024:.2f}
|
||||||
|
banana: {Ba/0x4000:.4f}
|
||||||
|
φ: {Ph/0x4000:.4f}
|
||||||
|
E: {E/0x20000:.2f}
|
||||||
|
""", file=sys.stderr)
|
||||||
|
return ev
|
||||||
|
|
||||||
|
def read_samples(sl=0, n=None, sa=None):
|
||||||
|
if not sa:
|
||||||
|
if not n:
|
||||||
|
n = nsamples(sl)
|
||||||
|
sa = []
|
||||||
|
while n:
|
||||||
|
ff = dorn_config(0x085)
|
||||||
|
if not (ff & (8 << (3*sl))):
|
||||||
|
break;
|
||||||
|
fifo_read(sl=sl, sa=True)
|
||||||
|
sa.append(read_fifo(3))
|
||||||
|
n -= 1
|
||||||
|
for s in sa:
|
||||||
|
if (s[0] & 0xfffc) != 0x5714:
|
||||||
|
raise ValueError(f"SA magic mismatch {s[0]:04x}")
|
||||||
|
t = s[1] | s[2]<<16
|
||||||
|
print(f"{t} ", " ".join([f"{ss&0xfff:5d}" for ss in s[3:]]), file=sys.stderr)
|
||||||
|
return sa
|
||||||
|
|
||||||
|
def make_pulser():
|
||||||
|
global pu
|
||||||
|
try:
|
||||||
|
pu.ID
|
||||||
|
except:
|
||||||
|
import agilent3322A
|
||||||
|
pu = agilent3322A.pulser()
|
||||||
|
return pu
|
||||||
|
|
||||||
|
from usbterm import DataJob
|
||||||
|
|
||||||
|
class pulser_test(DataJob):
|
||||||
|
|
||||||
|
cadence = 600
|
||||||
|
coffset = None
|
||||||
|
nsamples = 16
|
||||||
|
thres = 16
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
amplitudes=(0.25, 0.5, 1., 2., 4., 5.),
|
||||||
|
fn = None):
|
||||||
|
self.filename = fn
|
||||||
|
self.pu = make_pulser()
|
||||||
|
super().__init__(amplitudes)
|
||||||
|
self.connect(ifc)
|
||||||
|
|
||||||
|
def iniz(self):
|
||||||
|
disable()
|
||||||
|
self.pu.cmd("OUTPUT ON")
|
||||||
|
self.info("agilent pulser on")
|
||||||
|
self.next_time(10)
|
||||||
|
if self.filename:
|
||||||
|
ifc._data.Open()
|
||||||
|
enable()
|
||||||
|
|
||||||
|
def fini(self):
|
||||||
|
self.pu.cmd("OUTPUT OFF")
|
||||||
|
self.info("agilent pulser off")
|
||||||
|
if self.filename:
|
||||||
|
ifc._data.Open()
|
||||||
|
disable()
|
||||||
|
|
||||||
|
def Start(self, fn=None):
|
||||||
|
if fn is not None:
|
||||||
|
self.filename = fn
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
def func(self, a):
|
||||||
|
if self.filename:
|
||||||
|
ifc._data.Open()
|
||||||
|
disable()
|
||||||
|
pu.set_highlevel(a)
|
||||||
|
self.info("agilent pa %.3f" % a)
|
||||||
|
if self.filename:
|
||||||
|
ifc._data.Open(self.filename % a)
|
||||||
|
enable()
|
||||||
|
Status()
|
||||||
|
|
||||||
|
def mem_op(addr=None, hist=None, bank=None, data=None, read=None, clear=None, base=0x88c, WH=7):
|
||||||
|
|
||||||
|
a = 0
|
||||||
|
if read:
|
||||||
|
a |= 0x8000
|
||||||
|
if clear:
|
||||||
|
a |= 0x4000
|
||||||
|
|
||||||
|
if hist is True and addr is None:
|
||||||
|
dorn_config(base+2, False, "mem addr next histogram")
|
||||||
|
hist = None
|
||||||
|
|
||||||
|
if hist is not None:
|
||||||
|
a |= 0x2000
|
||||||
|
if addr is not None:
|
||||||
|
a |= addr >> WH
|
||||||
|
else:
|
||||||
|
a |= hist
|
||||||
|
elif bank is not None:
|
||||||
|
a |= 0x1000
|
||||||
|
if addr is not None:
|
||||||
|
a |= addr >> (WH+6)
|
||||||
|
else:
|
||||||
|
a |= bank
|
||||||
|
|
||||||
|
if a:
|
||||||
|
dorn_config(base+3, a, "mem address and command")
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
dd = data.__iter__()
|
||||||
|
except:
|
||||||
|
dd = (data,)
|
||||||
|
dh = 0x10000
|
||||||
|
for d in dd:
|
||||||
|
h = d >> 16
|
||||||
|
if h != dh:
|
||||||
|
dorn_config(base+1, h, "mem data high")
|
||||||
|
dh = h
|
||||||
|
dorn_config(base, d & 0xffff, "mem data write")
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ while True:
|
||||||
logger("connection from %s\n" % repr(s[1]))
|
logger("connection from %s\n" % repr(s[1]))
|
||||||
if len(sockets)>=10:
|
if len(sockets)>=10:
|
||||||
logger("too many connections %s\n" % repr(sockets))
|
logger("too many connections %s\n" % repr(sockets))
|
||||||
s[0].send(b"too many connections, good bye\n")
|
s[0].send("too many connections, good bye\n")
|
||||||
s[0].close()
|
s[0].close()
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue