This repository was archived by the owner on Jan 31, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathultraLatency.py
More file actions
executable file
·477 lines (387 loc) · 20.7 KB
/
ultraLatency.py
File metadata and controls
executable file
·477 lines (387 loc) · 20.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
#!/bin/env python
r"""
Latency
=======
WIP
``UltraLatency.py``
===================
Synopsis
--------
**run_scans.py** **lat** [-**h**] [--**amc13local**] [-**c** *CHAN*] [-**chMax** *CHMAX*] [-**chMin** *CHHMIN*] [-**i**] [-**m** *MSPL*] [-**n** *NEVTS*] [-**randoms** *RANDOMS*] [-**scanmin** *SCANMIN*] [-**scanmax** *SCANMAX*] [-**stepSize** *STEPSIZE*] [-**t3trig**] [-**throttle** *THROTTLE*] [-**v** *VCAL*] [-**vfatmask** *VFATMASK*] shelf slot ohMask
Mandatory arguments
-------------------
.. program:: run_Scans.py lat
Positional arguments
--------------------
.. option:: shelf
uTCA crate shelf number
.. option:: slot
AMC slot number in the uTCA crate
.. option:: ohMask
optohybrid mask to apply, a 1 in the n^{th} bit indicates the n^{th} OH should be considered
Optional arguments
------------------
.. option:: -h, --help
show the help message and exit
.. option:: --amc13local
use AMC13 local trigger generator
.. option:: -c CHAN, --chan <CHAN>
Channel on VFATs to run the latency scan. Only applies when calling with --internal; otherwise OR of all channels is used.
.. option:: --chMax <CHMAX>
Specify maximum channel number to scan
.. option:: --chMin <CHMIN>
Specify minimum channel number to scan
.. option:: -i, --internal
Run scan using calibration module
.. option:: -m, --mspl <MSPL>
Setting of ``CFG_PULSE_STRETCH`` register
.. option:: -n, --nevts <NEVTS>
Number of events for each scan position
.. option:: --randoms <RANDOMS>
Generate random triggers using AMC13 local trigger generator at specified rate
.. option:: --scanmin <SCANMIN>
Minimum ``CFG_LATENCY``
.. option:: --scanmax <SCANMAX>
Maximum ``CFG_LATENCY``
.. option:: -stepSize <STEPSIZE>
Step size to use when scanning ``CFG_LATENCY``
.. option:: --t3trig
take L1As from AMC13 T3 trigger input
.. option:: --throttle <THROTTLE>
factor by which to throttle the input L1A rate, e.g.
new trig rate = L1A rate / throttle
.. option:: -v, --vcal <VCAL>
Height of CalPulse in DAC units for all VFATs
.. option:: --vfatmask <VFATMASK>
If specified, this will use this VFAT mask for all unmasked OptoHybrids in ohMask.
Here this is a 24 bit number, where a 1 in the N^{th} bit means ignore the N^{th} VFAT.
If this argument is not specified, VFAT masks are determined at runtime automatically.
Environment
-----------
The following `$SHELL` variables should be defined beforehand:
.. glossary::
:envvar: `BUILD_HOME`
the location of your ``vfatqc-python-scripts`` directory
:envvar: `DATA_PATH`
the location of input data
Then execute:
`source $BUILD_HOME/vfatqc-python-scripts/setup/paths.sh`
"""
if __name__ == '__main__':
"""
Script to take latency data using OH ultra scans
By: Jared Sturdy (sturdy@cern.ch)
Cameron Bravo (c.bravo@cern.ch)
Brian Dorney (brian.l.dorney@cern.ch)
"""
import sys, os, random, time
from array import array
from ctypes import *
from gempython.tools.vfat_user_functions_xhal import *
from gempython.tools.vfat_user_functions_uhal import * #remove this later after making it so amc13 communication doesn't spit bullshit messages
from gempython.tools.optohybrid_user_functions_uhal import scanmode
from gempython.tools.hw_constants import vfatsPerGemVariant
from gempython.vfatqc.utils.qcoptions import parser
parser.add_option("--amc13local", action="store_true", dest="amc13local",
help="Set up for using AMC13 local trigger generator", metavar="amc13local")
parser.add_option("--chan", type="int", dest="chan",
help="Channel on the VFATs on which to run the latency scan. This only applies when calling the --internal option; otherwise the OR of all channels is used.", metavar="chan", default=0)
parser.add_option("--fakeTTC", action="store_true", dest="fakeTTC",
help="Set up for using AMC13 local TTC generator", metavar="fakeTTC")
parser.add_option("--filename", type="string", dest="filename", default="LatencyScanData.root",
help="Specify Output Filename", metavar="filename")
parser.add_option("--internal", action="store_true", dest="internal",
help="Run a latency scan using the internal calibration pulse", metavar="internal")
parser.add_option("--L1Atime", type="int", dest = "L1Atime", default = 250,
help="Specify time between L1As in bx", metavar="L1Atime")
parser.add_option("--mspl", type="int", dest = "MSPL", default = 3,
help="Specify MSPL. Must be in the range 0-7 (default is 3)", metavar="MSPL")
parser.add_option("--pulseDelay", type="int", dest = "pDel", default = 40,
help="Specify time of pulse before L1A in bx", metavar="pDel")
parser.add_option("--randoms", type="int", default=0, dest="randoms",
help="Set up for using AMC13 local trigger generator to generate random triggers with rate specified",
metavar="randoms")
parser.add_option("--t3trig", action="store_true", dest="t3trig",
help="Set up for using AMC13 T3 trigger input", metavar="t3trig")
parser.add_option("--throttle", type="int", default=0, dest="throttle",
help="factor by which to throttle the input L1A rate, e.g. new trig rate = L1A rate / throttle", metavar="throttle")
parser.add_option("--vcal", type="int", dest="vcal",
help="Height of CalPulse in DAC units for all VFATs", metavar="vcal", default=250)
parser.add_option("--voltageStepPulse", action="store_true",dest="voltageStepPulse",
help="Calibration Module is set to use voltage step pulsing instead of default current pulse injection",
metavar="voltageStepPulse")
parser.add_option("--vt2", type="int", dest="vt2",
help="VThreshold2 DAC value for all VFATs (v2b electronics only)", metavar="vt2", default=0)
parser.add_option("--gemType",type=str,help="String that defines the GEM variant, available from the list: {0}".format(gemVariants.keys()),default="ge11")
parser.add_option("--detType",type=str,
help="Detector type within gemType. If gemType is 'ge11' then this should be from list {0}; if gemType is 'ge21' then this should be from list {1}; and if type is 'me0' then this should be from the list {2}".format(gemVariants['ge11'],gemVariants['ge21'],gemVariants['me0']),default="short")
parser.set_defaults(scanmin=153,scanmax=172,nevts=500)
(options, args) = parser.parse_args()
remainder = (options.scanmax-options.scanmin+1) % options.stepSize
if remainder != 0:
options.scanmax = options.scanmax + remainder
print "extending scanmax to: ", options.scanmax
if options.debug:
uhal.setLogLevelTo(uhal.LogLevel.INFO)
else:
uhal.setLogLevelTo(uhal.LogLevel.ERROR)
from ROOT import TFile,TTree
filename = options.filename
myF = TFile(filename,'recreate')
import subprocess,datetime,time
startTime = datetime.datetime.now().strftime("%Y.%m.%d.%H.%M")
print(startTime)
Date = startTime
# Track the current pulse
isCurrentPulse = (not options.voltageStepPulse)
# Setup the output TTree
from gempython.vfatqc.utils.treeStructure import gemTreeStructure
gemData = gemTreeStructure('latTree','Tree Holding CMS GEM Latency Data',scanmode.LATENCY)
gemData.setDefaults(options, int(time.time()))
import amc13
connection_file = "%s/connections.xml"%(os.getenv("GEM_ADDRESS_TABLE_PATH"))
amc13base = "gem.shelf%02d.amc13"%(options.shelf)
amc13board = amc13.AMC13(connection_file,"%s.T1"%(amc13base),"%s.T2"%(amc13base))
from gempython.vfatqc.utils.qcutilities import getCardName, inputOptionsValid
cardName = getCardName(options.shelf,options.slot)
vfatBoard = HwVFAT(cardName, options.gtx, options.debug, options.gemType, options.detType)
print 'opened connection'
# Check options
if not inputOptionsValid(options, vfatBoard.parentOH.parentAMC.fwVersion):
exit(os.EX_USAGE)
pass
if vfatBoard.parentOH.parentAMC.fwVersion < 3:
if options.scanmin not in range(256) or options.scanmax not in range(256) or not (options.scanmax > options.scanmin):
print("Invalid scan parameters specified [min,max] = [%d,%d]"%(options.scanmin,options.scanmax))
print("Scan parameters must be in range [0,255] and min < max")
exit(1)
pass
else:
if options.scanmin not in range(1025) or options.scanmax not in range(1025) or not (options.scanmax > options.scanmin):
print("Invalid scan parameters specified [min,max] = [%d,%d]"%(options.scanmin,options.scanmax))
print("Scan parameters must be in range [0,1024] and min < max")
exit(1)
pass
mask = options.vfatmask
try:
vfatBoard.setRunModeAll(mask, True, options.debug)
vfatBoard.setVFATMSPLAll(mask, options.MSPL, options.debug)
if vfatBoard.parentOH.parentAMC.fwVersion < 3:
vfatBoard.writeAllVFATs("VThreshold2", options.vt2, mask)
vals = vfatBoard.readAllVFATs("CalPhase", 0x0)
calPhasevals = dict(map(lambda slotID: (slotID, bin(vals[slotID]).count("1")),
range(0,vfatsPerGemVariant[options.gemType])))
vals = vfatBoard.readAllVFATs("ContReg2", 0x0)
msplvals = dict(map(lambda slotID: (slotID, (1+(vals[slotID]>>4)&0x7)),
range(0,vfatsPerGemVariant[options.gemType])))
vals = vfatBoard.readAllVFATs("ContReg3", 0x0)
trimRangevals = dict(map(lambda slotID: (slotID, (0x07 & vals[slotID])),
range(0,vfatsPerGemVariant[options.gemType])))
#vfatIDvals = getAllChipIDs(ohboard, options.gtx, 0x0)
vals = vfatBoard.readAllVFATs("VThreshold1", 0x0)
vt1vals = dict(map(lambda slotID: (slotID, vals[slotID]&0xff),
range(0,vfatsPerGemVariant[options.gemType])))
vals = vfatBoard.readAllVFATs("VThreshold2", 0x0)
vt2vals = dict(map(lambda slotID: (slotID, vals[slotID]&0xff),
range(0,vfatsPerGemVariant[options.gemType])))
vthvals = dict(map(lambda slotID: (slotID, vt2vals[slotID]-vt1vals[slotID]),
range(0,vfatsPerGemVariant[options.gemType])))
else:
vals = vfatBoard.readAllVFATs("CFG_THR_ARM_DAC", mask)
vt1vals = dict(map(lambda slotID: (slotID, vals[slotID]&0xff),
range(0,vfatsPerGemVariant[options.gemType])))
vals = vfatBoard.readAllVFATs("CFG_PULSE_STRETCH", mask)
msplvals = dict(map(lambda slotID: (slotID, vals[slotID]),
range(0,vfatsPerGemVariant[options.gemType])))
vfatIDvals = vfatBoard.getAllChipIDs(mask)
# Stop triggers
vfatBoard.parentOH.parentAMC.blockL1A()
amc13board.enableLocalL1A(False)
amc13board.resetCounters()
# Check to see if an ultra scan is already running
if vfatBoard.parentOH.parentAMC.fwVersion < 3:
scanBase = "GEM_AMC.OH.OH%d.ScanController.ULTRA"%(options.gtx)
if (vfatBoard.parentOH.parentAMC.readRegister("%s.MONITOR.STATUS"%(scanBase)) > 0):
print("Scan was already running, resetting module")
vfatBoard.parentOH.parentAMC.writeRegister("%s.RESET"%(scanBase),0x1)
time.sleep(0.1)
pass
amc13nL1A = (amc13board.read(amc13board.Board.T1, "STATUS.GENERAL.L1A_COUNT_HI") << 32) | (amc13board.read(amc13board.Board.T1, "STATUS.GENERAL.L1A_COUNT_LO"))
amcnL1A = vfatBoard.parentOH.parentAMC.getL1ACount()
if vfatBoard.parentOH.parentAMC.fwVersion < 3:
ohnL1A = vfatBoard.parentOH.getL1ACount()
print "Initial L1A counts:"
print "AMC13: %s"%(amc13nL1A)
print "AMC: %s"%(amcnL1A)
if vfatBoard.parentOH.parentAMC.fwVersion < 3:
print "OH%s: %s"%(options.gtx,ohnL1A)
sys.stdout.flush()
scanChan=128
enableCalPulse=False
if options.internal:
enableCalPulse=True
scanChan=options.chan
if vfatBoard.parentOH.parentAMC.fwVersion < 3:
vfatBoard.parentOH.setTriggerSource(0x1)
print "stopping cal pulse to all channels"
vfatBoard.stopCalPulses(mask, 0, 128)
print "Setting channel %i to calpulse"%(scanChan)
vfatBoard.setSpecificChannelAllRegisters(chan=scanChan, chMask=0, pulse=1, trimARM=0, vfatMask=mask)
vfatBoard.setVFATCalHeightAll(mask, options.vcal, currentPulse=isCurrentPulse)
# Configure TTC
print "attempting to configure TTC"
if 0 == vfatBoard.parentOH.parentAMC.configureTTC(options.pDel,options.L1Atime,options.gtx,1,0,0,True):
print "TTC configured successfully"
vfatBoard.parentOH.parentAMC.getTTCStatus(options.gtx,True)
else:
raise Exception('RPC response was non-zero, TTC configuration failed')
else:
if options.amc13local:
amcMask = amc13board.parseInputEnableList("%s"%(options.slot), True)
amc13board.reset(amc13board.Board.T1)
amc13board.resetCounters()
amc13board.resetDAQ()
if options.fakeTTC:
amc13board.localTtcSignalEnable(options.fakeTTC)
pass
amc13board.AMCInputEnable(amcMask)
amc13board.startRun()
# rate should be desired rate * 16
# mode may be: 0(per-orbit), 1(per-BX), 2(random)
# configureLocalL1A(ena, mode, burst, rate, rules)
if options.randoms > 0:
amc13board.configureLocalL1A(True, 0, 1, 1, 0) # per-orbit
pass
if options.t3trig:
amc13board.write(amc13board.Board.T1, 'CONF.TTC.T3_TRIG', 0x1)
pass
# to prevent trigger blocking
amc13board.fakeDataEnable(True)
# disable the event builder?
# amc13board.write(amc13board.Board.T1, 'CONF.DIAG.DISABLE_EVB', 0x1)
#amc13board.enableLocalL1A(True)
if options.randoms > 0:
amc13board.startContinuousL1A()
pass
pass
print "attempting to configure TTC"
if vfatBoard.parentOH.parentAMC.fwVersion < 3:
vfatBoard.parentOH.setTriggerSource(0x5) # GBT, 0x0 for GTX
print "TTC configured successfully"
pass
# Throttle the trigger if requested
if vfatBoard.parentOH.parentAMC.fwVersion < 3:
vfatBoard.parentOH.setTriggerThrottle(options.throttle)
sys.stdout.flush()
scanDataSizeVFAT = (options.scanmax-options.scanmin+1)/options.stepSize
scanDataSizeNet = scanDataSizeVFAT * vfatsPerGemVariant[options.gemType]
scanData = (c_uint32 * scanDataSizeNet)()
# Determine the scanReg
scanReg = "LATENCY"
if vfatBoard.parentOH.parentAMC.fwVersion < 3:
scanReg = "Latency"
# Perform the scan
if options.internal:
print("Starting scan for channel %i; pulseDelay: %i; L1Atime: %i"%(scanChan, options.pDel, options.L1Atime))
else:
print("Starting scan")
# Not sure I understand why it has to be scanChan+1 below...
amc13board.enableLocalL1A(True)
vfatBoard.parentOH.parentAMC.enableL1A()
rpcResp = vfatBoard.parentOH.performCalibrationScan(
chan=scanChan,
currentPulse=isCurrentPulse,
dacMax=options.scanmax,
dacMin=options.scanmin,
enableCal=enableCalPulse,
outData=scanData,
mask=options.vfatmask,
nevts=options.nevts,
scanReg=scanReg,
stepSize=options.stepSize,
useExtTrig=(not options.internal))
if rpcResp != 0:
raise Exception('RPC response was non-zero, this inidcates an RPC exception occurred')
print("Done scanning, processing output")
print "Final L1A counts:"
amc13board.enableLocalL1A(False)
vfatBoard.parentOH.parentAMC.blockL1A()
amc13nL1Af = (amc13board.read(amc13board.Board.T1, "STATUS.GENERAL.L1A_COUNT_HI") << 32) | (amc13board.read(amc13board.Board.T1, "STATUS.GENERAL.L1A_COUNT_LO"))
amcnL1Af = vfatBoard.parentOH.parentAMC.getL1ACount()
if vfatBoard.parentOH.parentAMC.fwVersion < 3:
ohnL1Af = vfatBoard.parentOH.getL1ACount()
print "AMC13: %s, difference %s"%(amc13nL1Af,amc13nL1Af-amc13nL1A)
print "AMC: %s, difference %s"%(amcnL1Af,amcnL1Af-amcnL1A)
if vfatBoard.parentOH.parentAMC.fwVersion < 3:
print "OH%s: %s, difference %s"%(options.gtx,ohnL1Af,ohnL1Af-ohnL1A)
print("Information on CRC packets")
print("\tActually still needs to be implemented (oops) - Brian")
# this is the way to do this for v2b
#for i in range(24):
# print "Total number of CRC packets for VFAT%s on link %s is %s"%(i, options.gtx, readRegister(ohboard,"GEM_AMC.OH.OH%d.COUNTERS.CRC.INCORRECT.VFAT%d"%(options.gtx,i)) + readRegister(ohboard,"GEM_AMC.OH.OH%d.COUNTERS.CRC.VALID.VFAT%d"%(options.gtx,i)))
#for i in range(24):
# print "Number of CRC errors for VFAT%s on link %s is %s"%(i, options.gtx, readRegister(ohboard,"GEM_AMC.OH.OH%d.COUNTERS.CRC.INCORRECT.VFAT%d"%(options.gtx,i)))
# for v3 evaldas says I can count number of good & bad CRC eventss w/DAQ_MONITPR as well as number of L1As received by the CTP7 and forwarded to the VFATs with GEM_AMC.TTC.CMD_COUNTERS.L1A
#amc13board.enableLocalL1A(True)
sys.stdout.flush()
print("parsing scan data")
for vfat in range(0,vfatsPerGemVariant[options.gemType]):
if (mask >> vfat) & 0x1: continue
if options.debug:
sys.stdout.flush()
pass
for latReg in range(vfat*scanDataSizeVFAT,(vfat+1)*scanDataSizeVFAT):
try:
if vfatBoard.parentOH.parentAMC.fwVersion < 3:
gemData.fill(
calPhase = calPhasevals[vfat],
latency = int((scanData[latReg] & 0xff000000) >> 24),
mspl = msplvals[vfat],
Nhits = int(scanData[latReg] & 0xffffff),
trimRange = trimRangevals[vfat],
#vfatID = vfatIDvals[vfat],
vfatN = vfat,
vth = vthvals[vfat],
vth1 = vt1vals[vfat],
vth2 = vt2vals[vfat]
)
else:
gemData.fill(
isCurrentPulse = isCurrentPulse,
latency = (options.scanmin + (latReg - vfat*scanDataSizeVFAT) * options.stepSize),
mspl = msplvals[vfat],
Nev = (scanData[latReg] & 0xffff),
Nhits = ((scanData[latReg]>>16) & 0xffff),
vfatID = vfatIDvals[vfat],
vfatN = vfat,
vth1 = vt1vals[vfat]
)
pass
except IndexError:
print 'Unable to index data for channel %i'%chan
print scanData[latReg]
finally:
if options.debug:
print "vfat%i; lat %i; Nev %i; Nhits %i"%(
gemData.vfatN[0],
gemData.latency[0],
gemData.Nev[0],
gemData.Nhits[0])
pass
pass
gemData.autoSave("SaveSelf")
vfatBoard.setRunModeAll(mask, False, options.debug)
if options.internal:
vfatBoard.parentOH.parentAMC.toggleTTCGen(options.gtx, False)
pass
elif options.amc13local:
amc13board.stopContinuousL1A()
amc13board.fakeDataEnable(False)
pass
except Exception as e:
gemData.autoSave()
print("An exception occurred", e)
finally:
myF.cd()
gemData.write()
myF.Close()