DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
amc_butler.py
Go to the documentation of this file.
1#!/usr/bin/env python
2"""
3Created on: 05/06/2025 11:16
4
5Author: Shyam Bhuller, Alessandro Thea
6
7Description: Check the status of an AMC or multiple AMCs to ensure they can be reached.
8"""
9
10import subprocess
11import time
12import sh
13import re
14import click
15from rich import print
16
17import tdemodules
18
19def ping(host):
20 return subprocess.call(['ping', "-c", '1', host]) == 0
21
22class Commands():
23 def __init__(self, controllers : dict):
24 self.controllerscontrollers = controllers
25
26 def stop(self):
27 for k, v in self.controllerscontrollers.items():
28 print(f"starting: {k}")
29 v.card_stop()
30 return
31
32 def start(self):
33 for k, v in self.controllerscontrollers.items():
34 print(f"starting: {k}")
35 v.card_start()
36 return
37
38 def status(self):
39 # Constantly get the status of the AMCs to check whether they can be accessed.
41 print("[yellow]Press ctrl-C to exit.[/yellow]")
42 ti = 10
43 t = time.time()
44 while True:
45 for k, v in self.controllerscontrollers.items():
46 print(f"Reading status of AMC with IP: {k})")
47 v.card_status()
48 print(f"[cyan]Sleeping {ti}s[/cyan]")
49 time.sleep(ti)
50 print(f"-- {time.time() - t:.2g} s elapsed")
51 return
52
53
54
55
56
57
58@click.command()
59@click.argument('crate_ip', type=str)
60@click.option('-a', '--amcs', type=int, multiple=True, default=[i for i in range(10)])
61@click.option('-c', 'cmd', type=click.Choice(['arping', 'status', 'start', 'stop']), default=None)
62def main(crate_ip, amcs, cmd):
63
64 # get list of amcs from the command arguments
65 try:
66 sh.ping(["-c", '1', crate_ip])
67 print(f"[green]uTCA crate {crate_ip} is active[/green]")
68 except sh.ErrorReturnCode as e:
69 print(f"[red]Could not ping uTCA Crate at IP: {crate_ip}[/red]")
70 exit(1)
71
72 crate_subnet = crate_ip.rsplit(".", 1)[0]
73 nic_ip = crate_subnet+'.129'
74
75 amc_ips = { i: crate_subnet + f".{i + 1}" for i in amcs}
76
77 if cmd=='arping':
78
79
80 devices = {
81 'crate': crate_ip,
82 'nic': nic_ip
83 }
84
85 devices.update({f'AMC {amc}': amc_ip for amc, amc_ip in amc_ips.items()})
86
87
88
89 from concurrent.futures import ThreadPoolExecutor, as_completed
90 import subprocess as sp
91 import sys
92
93 failures = []
94 MAX_WORKERS=10
95 def arping(amc_ip):
96 return sh.arping(["-c", '1', amc_ip])
97 try:
98
99 with ThreadPoolExecutor(max_workers=MAX_WORKERS) as pool:
100 futures = {pool.submit(arping, amc_ip):(amc, amc_ip) for amc, amc_ip in devices.items()}
101 for fut in as_completed(futures):
102 amc, amc_ip = futures[fut]
103 try:
104 rc = fut.result()
105 except sp.TimeoutExpired:
106 print(f"[TIMEOUT] {amc}", file=sys.stderr)
107 failures.append((amc, "timeout"))
108 continue
109 except sh.ErrorReturnCode as e:
110 print(f"- [red]Could not arping device at IP: {amc_ip}[/red]")
111 continue
112 except Exception as ex:
113 print(f"[EXCEPTION] {amc}: {ex}", file=sys.stderr)
114 failures.append((amc, "exception"))
115 continue
116
117 match = re.search(r"Unicast reply from\s+([\d.]+)\s+\[([0-9A-Fa-f:]{17})\]", rc)
118 if match:
119 ipaddr, mac = match.group(1), match.group(2)
120 print(f"- [green]{amc} ({amc_ip}) responded to arping : mac {mac}[/green]")
121
122
123 except KeyboardInterrupt:
124 print("\nInterrupted. Shutting down workers…", file=sys.stderr)
125 # ProcessPool will terminate on context exit
126 else:
127 controllers = { amc_ip:tdemodules.AMCController(amc_ip, 54321 + (i + 1)) for i,amc_ip in amc_ips.items() }
128 print(controllers)
129 cmds = Commands(controllers)
130 getattr(cmds, cmd)()
131
132 return
133
134 return
135
136if __name__ == "__main__":
137
138 main()
__init__(self, dict controllers)
Definition amc_butler.py:23
main(crate_ip, amcs, cmd)
Definition amc_butler.py:62
ping(host)
Definition amc_butler.py:19