DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
hermesbutler.py
Go to the documentation of this file.
1#!/usr/bin/env python
2
3import click
4import os
5import socket
6import time
7import uhal
8import logging
9from rich import print
10from rich.table import Table
11from rich.logging import RichHandler
12
13from hermesmodules.tx_endpoints import tx_endpoints
14from hermesmodules.rx_endpoints import rx_endpoints
15
16from pprint import pprint
17
18
19# from crappyhalclient import CrappyHardwareClient
20
21# -----------------------------------------------------------------------------
22# Utilities
23def dict_to_table( vals: dict, **kwargs):
24
25 t = Table(**kwargs)
26 t.add_column('name')
27 t.add_column('value', style='green')
28 for k,v in vals.items():
29 t.add_row(k,hex(v))
30 return t
31
32def read_regs(hw, reg_list):
33 d = {}
34 for r in reg_list:
35 v = hw.read(r)
36 d[r] = v
37 return d
38
39def read_and_print(hw, reg_list):
40 d = {}
41 for r in reg_list:
42 v = hw.read(r)
43 d[r] = v
44 print(dict_to_table(d))
45
46
47# -----------------------------------------------------------------------------
48def dump_sub_regs(node):
49 regs = {}
50 for i in sorted(node.getNodes()):
51 regs[i] = node.getNode(i).read()
52 node.getClient().dispatch()
53
54 return {k: v.value() for k, v in regs.items()}
55
56
57# -----------------------------------------------------------------------------
58def dump_reg(node):
59 v = node.read()
60 node.getClient().dispatch()
61 return {node.getId(): v.value()}
62
63
65 def __init__(self, node):
66 self.node = node
67
68 self._load_info()
69
70
71 def _load_info(self):
72 magic = self.node.getNode('info.magic').read()
73 self.node.getClient().dispatch()
74 self.magic = magic.value()
75 if self.magic != 0xdeadbeef:
76 raise ValueError(f"Magic number check failed. Expected '0xdeadbeef', found '{hex(self.magic)}'")
77
78
79
80 n_mgt = self.node.getNode('info.generics.n_mgts').read()
81 n_src = self.node.getNode('info.generics.n_srcs').read()
82 ref_freq = self.node.getNode('info.generics.ref_freq').read()
83 self.node.getClient().dispatch()
84
85 # Generics
86 self.n_mgt = n_mgt.value()
87 self.n_src = n_src.value()
88 self.ref_freq = ref_freq.value()
89 # Extra info
90 self.n_srcs_p_mgt = self.n_src
91
92 def get_node(self, id):
93 return self.node.getNode(id)
94
95 def get_nodes(self, regex):
96 return self.node.getNodes(regex)
97
98 def dispatch(self):
99 self.node.getClient().dispatch()
100
101 def sample_ctrs(self, seconds: int):
102 self.node.getNode('samp.ctrl.samp').write(True)
103 self.node.getNode('samp.ctrl.samp').write(False)
104 self.node.getClient().dispatch()
105 if seconds:
106 time.sleep(seconds)
107 self.node.getNode('samp.ctrl.samp').write(False)
108 self.node.getNode('samp.ctrl.samp').write(False)
109 self.node.getClient().dispatch()
110
111
112 def sel_tx_mux(self, i: int):
113
114 if i >= self.n_mgt:
115 raise ValueError(f"Link {i} does not exist ({self.n_mgt})")
116
117 self.get_node('tx_path.csr_tx_mux.ctrl.tx_mux_sel').write(i)
118 self.dispatch()
119 j = self.get_node('tx_path.csr_tx_mux.ctrl.tx_mux_sel').read()
120 self.dispatch()
121 print(f"Link {j} selected")
122
123
124 def sel_tx_mux_buf(self, i: int):
125
126 if i >= self.n_src:
127 raise ValueError(f"Input buffer {i} does not exist ({self.n_src})")
128
129 self.node.getNode('tx_path.tx_mux.csr.ctrl.sel_buf').write(i)
130 self.node.getClient().dispatch()
131
132 def sel_udp_core(self, i: int):
133
134 if i >= self.n_mgt:
135 raise ValueError(f"Link {i} does not exist ({self.n_mgt})")
136
137 self.node.getNode('tx_path.csr_udp_core.ctrl.udp_core_sel').write(i)
138 self.node.getClient().dispatch()
139
140
141# N_MGT=4
142# N_SRC=8
143# N_SRCS_P_MGT = N_SRC//N_MGT
144MAX_MGT=2
145MAX_SRCS_P_MGT =16
146mgts_all = tuple(str(i) for i in range(MAX_MGT))
147#
148CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
149
150# DEFAULT_MAP = {'connections': '${HERMESMODULES_SHARE}/config/etc/connections.xml'}
151# CONTEXT_SETTINGS = {
152# 'help_option_names': ['-h', '--help'],
153# 'default_map': DEFAULT_MAP,
154# }
155
156# -----------------
157def validate_device(ctx, param, value):
158 lDevices = ctx.obj.cm.getDevices()
159 if value and (value not in lDevices):
160 raise click.BadParameter(
161 'Device must be one of '+
162 ', '.join(["'"+lId+"'" for lId in lDevices])
163 )
164 return value
165# -----------------
166
168
169 def __init__(self):
170 uhal.setLogLevelTo(uhal.LogLevel.WARNING)
171 self._cm_cm = None
172 self.hw = None
173 self.device_id = None
174 self.connection_file_path = 'file://${HERMESMODULES_SHARE}/config/c.xml'
175 self._controller = None
176
177 @property
178 def hermes(self):
179 if self._controller is None:
180 hw = self.cm.getDevice(self.device_id)
181
182 # Identify board
183 is_zcu = hw.getNodes('tx.info')
184 is_wib = hw.getNodes('info')
185
186 if is_zcu:
187 print("zcu mode")
188 tx_mux = hw.getNode('tx')
189 elif is_wib:
190 print("wib mode")
191 tx_mux = hw.getNode()
192 else:
193 raise ValueError(f"{self.device_id} is neither a zcu nor a wib")
194
195 self.hw = hw
196 # pprint(vars(self))
197 self._controller = HermesModule(tx_mux)
198
199 return self._controller
200
201 @property
202 def cm(self):
203 if self._cm_cm is None:
204 self._cm_cm = uhal.ConnectionManager(self.connection_file_path)
205
206 return self._cm_cm
207
208
209@click.group(chain=True, context_settings=CONTEXT_SETTINGS)
210@click.option('-c', '--connection-file', default=None, help="IPBus connection file ")
211@click.option('-d', '--device', callback=validate_device, help="IPBus device")
212# @click.pass_context
213@click.pass_obj
214def cli(obj, connection_file, device):
215
216 obj.connection_file_path = connection_file
217 obj.device_id = device
218
219@cli.command()
220@click.pass_obj
221def addrbook(obj):
222
223 t = Table(title="Control hosts")
224 t.add_column('name')
225 # t.add_column('addrtable', style='green')
226 for h in obj.cm.getDevices():
227 t.add_row(h)
228 print(t)
229
230 t = Table(title="Receivers")
231 t.add_column('name')
232 t.add_column('mac', style='green')
233 t.add_column('ip', style='blue')
234 t.add_column('port', style='blue')
235 for h,d in rx_endpoints.items():
236 t.add_row(h, f"0x{d['mac']:012x}", f"{d['ip']}", str(d['port']))
237 print(t)
238
239 t = Table(title="Transmitters")
240 t.add_column('name')
241 t.add_column('mac', style='green')
242 t.add_column('ip', style='blue')
243 t.add_column('port', style='blue')
244 for h,d in tx_endpoints.items():
245 t.add_row(h, f"0x{d['mac']:012x}", f"{d['ip']}", str(d['port']))
246 print(t)
247
248
249@cli.command()
250@click.option('--nuke', is_flag=True, default=None)
251@click.pass_obj
252def reset(obj, nuke):
253
254 hrms = obj.hermes
255
256 if nuke is not None:
257 hrms.get_node('csr.ctrl.nuke').write(0x1)
258 hrms.dispatch()
259
260 time.sleep(0.1)
261
262 hrms.get_node('csr.ctrl.nuke').write(0x0)
263 hrms.dispatch()
264
265 hrms.get_node('csr.ctrl.soft_rst').write(0x1)
266 hrms.dispatch()
267
268 time.sleep(0.1)
269
270 hrms.get_node('csr.ctrl.soft_rst').write(0x0)
271 hrms.dispatch()
272
273
274@cli.command()
275@click.option('--en/--dis', 'enable', default=None)
276@click.option('--buf-en/--buf-dis', 'buf_en', default=None)
277@click.option('--tx-en/--tx-dis', 'tx_en', default=None)
278@click.option('-l', '--link', type=int, default=0)
279@click.pass_obj
280def enable(obj, enable, buf_en, tx_en, link):
281
282 hrms = obj.hermes
283
284 n_mgt = hrms.n_mgt
285
286 if link >= n_mgt:
287 raise ValueError(f"MGT {link} not instantiated")
288
289 hrms.sel_tx_mux(link)
290
291 print()
292
293 tx_en = tx_en if tx_en is not None else enable
294 buf_en = buf_en if buf_en is not None else enable
295
296 if tx_en is not None:
297 print(f"- {'Enabling' if tx_en else 'Disabling'} 'tx block'")
298 hrms.get_node('tx_path.tx_mux.csr.ctrl.tx_en').write(tx_en)
299 print()
300
301 if buf_en is not None:
302 print(f"- {'Enabling' if buf_en else 'Disabling'} 'input buffers'")
303 hrms.get_node('tx_path.tx_mux.csr.ctrl.en_buf').write(buf_en)
304
305 time.sleep(0.1)
306
307 if enable is not None:
308 print(f"- {'Enabling' if enable else 'Disabling'} 'mux'")
309 hrms.get_node('tx_path.tx_mux.csr.ctrl.en').write(enable)
310
311
312
313 hrms.dispatch()
314
315
316 top_ctrl = dump_sub_regs(hrms.get_node('tx_path.tx_mux.csr.ctrl'))
317
318 print(
319 dict_to_table(top_ctrl, title=f'Link {link} ctrls', show_header=False),
320 )
321
322
323@cli.command("mux-config")
324@click.argument('detid', type=int)
325@click.argument('crate', type=int)
326@click.argument('slot', type=int)
327@click.option('-l', '--link', type=int, default=0)
328@click.pass_obj
329def mux_config(obj, detid, crate, slot, link):
330 """Configure the UDP blocks """
331
332 hrms = obj.hermes
333
334 hrms.sel_tx_mux(link)
335
336 hrms.get_node('tx_path.tx_mux.mux.ctrl.detid').write(detid)
337 hrms.get_node('tx_path.tx_mux.mux.ctrl.crate').write(crate)
338 hrms.get_node('tx_path.tx_mux.mux.ctrl.slot').write(slot)
339
340 mux_ctrl = dump_sub_regs(hrms.get_node('tx_path.tx_mux.mux.ctrl'))
341
342 print(
343 dict_to_table(mux_ctrl, title=f'Link {link} mux cfg', show_header=False),
344 )
345
346
347@cli.command("udp-config")
348@click.argument('src_id', type=click.Choice(tx_endpoints.keys()))
349@click.argument('dst_id', type=click.Choice(rx_endpoints.keys()))
350@click.option('-l', '--link', type=int, default=0)
351@click.pass_obj
352def udp_config(obj, src_id, dst_id, link):
353 """Configure the UDP blocks """
354
355 filter_control = 0x07400307
356 hrms = obj.hermes
357
358 if link >= hrms.n_mgt:
359 raise ValueError(f"Link {link} not instantiated")
360
361
362 dst = rx_endpoints[dst_id]
363 src = tx_endpoints[src_id]
364
365 udp_core_ctrl = f'tx_path.udp_core.udp_core_control'
366
367 hrms.get_node(f'{udp_core_ctrl}.ctrl.filter_control').write(filter_control)
368
369 hrms.get_node(f'{udp_core_ctrl}.src_addr_ctrl.use_external').write(0);
370
371 # Our IP address = 10.73.139.23
372 # print(f"Our ip address: {socket.inet_ntoa(src['ip'].to_bytes(4, 'big'))}")
373 src_u32 = int.from_bytes(socket.inet_aton(src['ip']),"big")
374 print(f"Our ip address: {src['ip']} (0x{src_u32:08x})")
375
376 hrms.get_node(f'{udp_core_ctrl}.src_addr_ctrl.src_ip_addr').write(src_u32)
377
378 # Their IP address = 10.73.139.23
379 # print(f"Their ip address: {socket.inet_ntoa(dst['ip'].to_bytes(4, 'big'))}")
380 dst_u32 = int.from_bytes(socket.inet_aton(dst['ip']),"big")
381 print(f"Their ip address: {dst['ip']} (0x{dst_u32:08x})")
382 hrms.get_node(f'{udp_core_ctrl}.ctrl.dst_ip_addr').write(dst_u32)
383
384 # Our MAC address
385 # Dest MAC address
386 print(f"Our mac address: 0x{src['mac']:012x}")
387 hrms.get_node(f'{udp_core_ctrl}.src_addr_ctrl.src_mac_addr_lower').write(src['mac'] & 0xffffffff)
388 hrms.get_node(f'{udp_core_ctrl}.src_addr_ctrl.src_mac_addr_upper').write((src['mac'] >> 32) & 0xffff)
389
390 # Dest MAC address
391 print(f"Their mac address: 0x{dst['mac']:012x}")
392 hrms.get_node(f'{udp_core_ctrl}.ctrl.dst_mac_addr_lower').write(dst['mac'] & 0xffffffff)
393 hrms.get_node(f'{udp_core_ctrl}.ctrl.dst_mac_addr_upper').write((dst['mac'] >> 32) & 0xffff)
394
395 # Ports
396 hrms.get_node(f'{udp_core_ctrl}.src_addr_ctrl.src_port').write(src['port'])
397 hrms.get_node(f'{udp_core_ctrl}.ctrl.dst_port').write(dst['port'])
398
399 hrms.dispatch()
400
401
402@cli.command("zcu-src-config")
403@click.option('-l', '--link', type=int, default=0)
404@click.option('-n', '--en-n-src', type=click.IntRange(0, MAX_SRCS_P_MGT), default=1)
405@click.option('-d', '--dlen', type=click.IntRange(0, 0xfff), default=0x383)
406@click.option('-r', '--rate-rdx', type=click.IntRange(0, 0x3f), default=0xa)
407@click.pass_obj
408def zcu_src_config(obj, link, en_n_src, dlen, rate_rdx):
409 """Configure trivial data sources"""
410
411 hw = obj.cm.getDevice(obj.device_id)
412 #hw = obj.hw
413 hrms = obj.hermes
414
415 # n_mgt = obj.n_mgt
416 # n_src = obj.n_src
417 # n_srcs_p_mgt = n_src//n_mgt
418
419 #print(hw)
420 #pprint(vars(obj))
421 #pprint(vars(hrms))
422 #print(hw)
423
424 if link >= hrms.n_mgt:
425 raise ValueError(f"MGT {link} not instantiated")
426
427 if en_n_src > hrms.n_srcs_p_mgt:
428 raise ValueError(f"{en_n_src} must be lower than the number of generators per link ({hrms.n_srcs_p_mgt})")
429
430 for i in range(hrms.n_srcs_p_mgt):
431 src_id = hrms.n_srcs_p_mgt*link+i
432 hw.getNode('src.csr.ctrl.sel').write(src_id)
433 src_en = (i<en_n_src)
434 print(f'Configuring generator {src_id} : {src_en}')
435 #data_gen = hw.getNode("src.data_src.src.params.write")
436 #data_gen.getNode("gap").write(1)
437 #hw.getNode('src.data_src.src.csr.ctrl.start_stop').write(src_en)
438 #if not src_en:
439 # continue
440
444 hw.dispatch()
445
446
447 regs = {}
448 for i in range(hrms.n_srcs_p_mgt):
449 hw.getNode('src.csr.ctrl.sel').write(i)
450 src_regs = dump_sub_regs(hw.getNode('src.csr'))
451 data_src_regs = dump_sub_regs(hw.getNode('src.data_src'))
452
453 grid = Table.grid()
454 grid.add_column("ctrl")
455 grid.add_column("stat")
456 grid.add_row(
457 dict_to_table(src_regs, title='src_ctrl', show_header=False),
458 #dict_to_table(data_src_regs, title='data_src_ctrl', show_header=False)
459 )
460 for j in range(hrms.n_srcs_p_mgt):
461 grid.add_row(
462 dict_to_table(data_src_regs, title='data_src_ctrl', show_header=False)
463
464 )
465 print(f'Link {i}')
466 print(grid)
467
468 #regs[i] = dump_sub_regs(hw.getNode('src.csr.stat.no_of_src_blocks'))
469
470 # Create the summary table
471 t = Table()
472
473
474
475 # Add 1 column for the reg name, and as many as the number of sources
476 #t.add_column('name')
477 # for j in range(hrms.n_srcs_p_mgt):
478 # t.add_column(f'Src {j}', style='green')
479
480 # for n in hw.getNode('src').getNodes():
481 # t.add_row(n, *[hex(regs[i][n]) for i in range(hrms.n_srcs_p_mgt)])
482
483
484 #print(t)
485
486@cli.command("fakesrc-config")
487@click.option('-l', '--link', type=int, default=0)
488@click.option('-n', '--n-src', type=click.IntRange(0, MAX_SRCS_P_MGT), default=1)
489@click.option('-s', '--src', type=click.IntRange(0, MAX_SRCS_P_MGT), default=None, multiple=True)
490@click.option('-k', '--data-len', type=click.IntRange(0, 0xfff), default=0x383)
491@click.option('-r', '--rate-rdx', type=click.IntRange(0, 0x3f), default=0xa)
492@click.pass_obj
493def fakesrc_config(obj, link, n_src, src, data_len, rate_rdx):
494 """Configure trivial data sources"""
495
496 hrms = obj.hermes
497
498 all_srcs = set(range(hrms.n_srcs_p_mgt))
499 en_srcs = set(src)
500
501 if en_srcs != set.intersection(all_srcs, en_srcs):
502 raise ValueError("AAARGH")
503
504 # print(src)
505 # return
506
507 hrms.sel_tx_mux(link)
508
509 if n_src > hrms.n_srcs_p_mgt:
510 raise ValueError(f"{n_src} must be lower than the number of generators per link ({n_srcs_p_mgt})")
511
512 was_en = hrms.get_node('tx_path.tx_mux.csr.ctrl.en_buf').read()
513 # disable buffer before reconfiguring "or bad things will happen"
514 hrms.get_node('tx_path.tx_mux.csr.ctrl.en_buf').write(0x0)
515 hrms.dispatch()
516
517 for src_id in range(hrms.n_srcs_p_mgt):
518 hrms.sel_tx_mux_buf(src_id)
519
520 # src_en = (src_id<n_src)
521 src_en = (src_id in en_srcs)
522 print(f'Configuring generator {src_id} : {src_en}')
523 # hw.write(f'tx.buf.ctrl.fake_en', src_en)
524 hrms.get_node('tx_path.tx_mux.buf.ctrl.fake_en').write(src_en)
525 if not src_en:
526 continue
527
528 hrms.get_node('tx_path.tx_mux.buf.ctrl.dlen').write(data_len)
529
530 hrms.get_node('tx_path.tx_mux.buf.ctrl.rate_rdx').write(rate_rdx)
531 hrms.dispatch()
532
533 hrms.get_node('tx_path.tx_mux.csr.ctrl.en_buf').write(was_en.value())
534 hrms.dispatch()
535
536
537@cli.command()
538@click.pass_obj
539@click.option('-l', '--links', 'sel_links', type=click.Choice(mgts_all), multiple=True, default=None)
540@click.option('-s', '--seconds', type=int, default=0)
541@click.option('-u/-U', '--show-udp/--hide-udp', 'show_udp', default=True)
542@click.option('-b/-B', '--show-buf/--hide-buf', 'show_buf', default=True)
543
544def stats(obj, sel_links, seconds, show_udp, show_buf):
545 """Simple program that greets NAME for a total of COUNT times."""
546
547 hrms = obj.hermes
548
549 mgts = list(range(hrms.n_mgt))
550
551 # deal with defaults
552 if not sel_links:
553 sel_links = mgts
554 else:
555 sel_links = [int(s) for s in sel_links]
556
557
558 # Check for existance
559 if not set(sel_links).issubset(mgts):
560 print(sel_links, mgts)
561 raise ValueError(f"MGTs {set(sel_links)-set(mgts)} are not instantiated")
562
563 # mgts = [int(s) for s in (mgts if mgts else [0])]
564
565 print(f"Sampling hermes counters for {seconds}s")
566 hrms.sample_ctrs(seconds)
567
568 info_data = dump_sub_regs(hrms.get_node('info'))
569 print(dict_to_table(info_data, title='hermes info', show_header=False))
570
571 # n_srcs_p_mgt = n_src//n_mgt
572
573 for i in sel_links:
574 print(f'---Tx Mux {i} Status---')
575
576 hrms.sel_tx_mux(i)
577
578
579 # cli control registers
580 top_ctrl = dump_sub_regs(hrms.get_node('tx_path.tx_mux.csr.ctrl'))
581 top_stat = dump_sub_regs(hrms.get_node('tx_path.tx_mux.csr.stat'))
582 ctrl_mux = dump_sub_regs(hrms.get_node('tx_path.tx_mux.mux.ctrl'))
583 stat_mux = dump_sub_regs(hrms.get_node('tx_path.tx_mux.mux.stat'))
584
585 grid = Table.grid()
586 grid.add_column("ctrl")
587 grid.add_column("stat")
588 grid.add_row(
589 dict_to_table(top_ctrl, title='tx_mux ctrl', show_header=False),
590 dict_to_table(top_stat, title='tx mux stat', show_header=False),
591 dict_to_table(ctrl_mux, title="mux ctrl", show_header=False),
592 dict_to_table(stat_mux, title="mux stat", show_header=False),
593 )
594 print(grid)
595
596
597 if show_udp:
598 hrms.sel_udp_core(i)
599 ctrl_udp_src = dump_sub_regs(hrms.get_node(f'tx_path.udp_core.udp_core_control.src_addr_ctrl'))
600 ctrl_udp = dump_sub_regs(hrms.get_node(f'tx_path.udp_core.udp_core_control.ctrl'))
601 ctrl_flt_udp = dump_sub_regs(hrms.get_node(f'tx_path.udp_core.udp_core_control.ctrl.filter_control'))
602 if hrms.get_nodes(f'tx_path.udp_core.udp_core_control.rx_packet_counters'):
603 print("New tx counters found")
604 stat_rx_udp = dump_sub_regs(hrms.get_node(f'tx_path.udp_core.udp_core_control.rx_packet_counters'))
605 stat_tx_udp = dump_sub_regs(hrms.get_node(f'tx_path.udp_core.udp_core_control.tx_packet_counters'))
606 else:
607 print("No new tx counters found")
608 stat_rx_udp = dump_sub_regs(hrms.get_node(f'tx_path.udp_core.udp_core_control.tx_packet_counters'))
609 stat_tx_udp = {'-':0}
610
611
612 ctrl_srcdst = {}
613 ctrl_srcdst['src_ip'] = ctrl_udp_src['src_ip_addr']
614 ctrl_srcdst['dst_ip'] = ctrl_udp['dst_ip_addr']
615 ctrl_srcdst['src_mac'] = (ctrl_udp_src['src_mac_addr_upper'] << 32) + ctrl_udp_src['src_mac_addr_lower']
616 ctrl_srcdst['dst_mac'] = (ctrl_udp['dst_mac_addr_upper'] << 32) + ctrl_udp['dst_mac_addr_lower']
617 ctrl_srcdst['src_port'] = ctrl_udp_src['src_port']
618 ctrl_srcdst['dst_port'] = ctrl_udp['dst_port']
619
620 grid = Table.grid()
621 grid.add_column("ctrl")
622 grid.add_column("stat")
623 grid.add_row(
624 # dict_to_table(ctrl_udp, title="udp ctrl", show_header=False),
625 dict_to_table(ctrl_srcdst, title="udp src/dst", show_header=False),
626 dict_to_table(ctrl_flt_udp, title="udp filter", show_header=False),
627 dict_to_table(stat_rx_udp, title="udp rx stat", show_header=False),
628 dict_to_table(stat_tx_udp, title="udp tx stat", show_header=False),
629 )
630 print(grid)
631
632 if show_buf:
633 ibuf_stats = {}
634
635 src_ids = tuple(range(hrms.n_srcs_p_mgt))
636 for j in src_ids:
637 # hw.write('tx.mux.csr.ctrl.sel_buf',j)
638 hrms.sel_tx_mux_buf(j)
639 s = dump_sub_regs(hrms.get_node('tx_path.tx_mux.buf'))
640 s['blk_acc'] = (s['blk_acc_h']<<32)+s['blk_acc_l']
641 s['blk_oflow'] = (s['blk_oflow_h']<<32)+s['blk_oflow_l']
642 s['blk_rej'] = (s['blk_rej_h']<<32)+s['blk_rej_l']
643 s['ts'] = (s['ts_h']<<32)+s['ts_l']
644 s['vol'] = (s['vol_h']<<32)+s['vol_l']
645 s['blk_longlast'] = (s['blk_longlast_h']<<32)+s['blk_longlast_l']
646 s['blk_lastnotval'] = (s['blk_lastnotval_h']<<32)+s['blk_lastnotval_l']
647
648 for k in tuple(s.keys()):
649 for n in ('blk_acc_', 'blk_oflow_', 'blk_rej_', 'ts_', 'vol_', 'blk_longlast_', 'blk_lastnotval_'):
650 if k.startswith(n):
651 del s[k]
652
653 for k in ('ctrl', 'stat', 'buf_mon'):
654 del s[k]
655
656
657 ibuf_stats[j] = s
658
659 # Create the summary table
660 t = Table()
661
662 # Add 1 column for the reg name, and as many as the number of sources
663 t.add_column('name')
664 for j in src_ids:
665 t.add_column(f'Buf {j}', style='green')
666
667 # Unify the reg list (useless?)
668 reg_names = set()
669 for k,v in ibuf_stats.items():
670 reg_names = reg_names.union(v.keys())
671
672 for n in sorted(reg_names):
673 t.add_row(n,*(hex(ibuf_stats[j][n]) for j in src_ids))
674 print(t)
675
676
677@cli.command()
678@click.pass_obj
679@click.option('-r', '--phy-reset', is_flag=True, default=None, help="Reset the phy block")
680def tx_path(obj, phy_reset):
681
682 hrms = obj.hermes
683 pcs_pma_node = hrms.get_node('pcs_pma')
684
685 if phy_reset:
686 print("[cyan]Resetting pty[/cyan]")
687 pcs_pma_node.getNode('debug.csr.ctrl.phy_reset').write(0x1)
688 pcs_pma_node.getNode('debug.csr.ctrl.phy_reset').write(0x0)
689 pcs_pma_node.getClient().dispatch()
690
691
692 clk_ids = [
693 'ref_clk_out',
694 'tx_mii_clk_0',
695 'rx_clk_out_0',
696 ]
697
698 print(pcs_pma_node.getNode('debug.csr.stat').getNodes())
699 stats = { n: pcs_pma_node.getNode('debug.csr.stat.'+n).read() for n in pcs_pma_node.getNode('debug.csr.stat').getNodes() }
700 pcs_pma_node.getClient().dispatch()
701
702 for n,v in stats.items():
703 print(n,hex(v))
704
705
706 for idx, clk_id in enumerate(clk_ids):
707
708 fn = pcs_pma_node.getNode('freq')
709 fn.getNode('ctrl.chan_sel').write(idx)
710 fn.getNode('ctrl.en_crap_mode').write(0x0)
711 fn.getClient().dispatch()
712
713 time.sleep(1.1)
714 c = fn.getNode('freq.count').read()
715 v = fn.getNode('freq.valid').read()
716 fn.getClient().dispatch()
717
718 if v == 0:
719 print(f'[red]Failed to measure frequency of clock {clk_id}[/red]')
720
721 ipb_freq = 100000000
722 # ipb_freq = 125000000
723 denominator = 2**24
724 true_count = int(c)*64
725
726 clk_freq = true_count/denominator*ipb_freq
727 print(f"Measured {clk_id} clock freq {clk_freq/1000000:04} MHz")
728
729
730if __name__ == '__main__':
731 FORMAT = "%(message)s"
732 logging.basicConfig(
733 level="INFO", format=FORMAT, datefmt="[%X]", handlers=[RichHandler()]
734 )
735 cli(obj=HermesCliObj())
sample_ctrs(self, int seconds)
dict_to_table(dict vals, **kwargs)
dump_sub_regs(node)
stats(obj, sel_links, seconds, show_udp, show_buf)
cli(obj, connection_file, device)
tx_path(obj, phy_reset)
fakesrc_config(obj, link, n_src, src, data_len, rate_rdx)
udp_config(obj, src_id, dst_id, link)
mux_config(obj, detid, crate, slot, link)
read_and_print(hw, reg_list)
validate_device(ctx, param, value)
read_regs(hw, reg_list)
reset(obj, nuke)
zcu_src_config(obj, link, en_n_src, dlen, rate_rdx)