DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
timing_app_confgen.py
Go to the documentation of this file.
1from rich.console import Console
2console = Console()
3
4# Set moo schema search path
5from dunedaq.env import get_moo_model_path
6import moo.io
7moo.io.default_load_path = get_moo_model_path()
8
9# Load configuration types
10import moo.otypes
11moo.otypes.load_types('rcif/cmd.jsonnet')
12moo.otypes.load_types('timinglibs/timingcmd.jsonnet')
13moo.otypes.load_types('timinglibs/timinghardwaremanagerpdi.jsonnet')
14moo.otypes.load_types('timinglibs/timingmastercontroller.jsonnet')
15moo.otypes.load_types('timinglibs/timingfanoutcontroller.jsonnet')
16moo.otypes.load_types('timinglibs/timingpartitioncontroller.jsonnet')
17moo.otypes.load_types('timinglibs/timingendpointcontroller.jsonnet')
18moo.otypes.load_types('hsilibs/hsicontroller.jsonnet')
19
20# Import new types
21import dunedaq.rcif.cmd as rccmd # AddressedCmd,
23import dunedaq.timinglibs.timinghardwaremanagerpdi as thi
24import dunedaq.timinglibs.timingmastercontroller as tmc
25import dunedaq.timinglibs.timingpartitioncontroller as tpc
26import dunedaq.timinglibs.timingendpointcontroller as tec
27import dunedaq.hsilibs.hsicontroller as hsi
28import dunedaq.timinglibs.timingfanoutcontroller as tfc
29
30from appfwk.utils import acmd
31from daqconf.core.app import App, ModuleGraph
32from daqconf.core.daqmodule import DAQModule
33from daqconf.core.conf_utils import Direction
34from daqconf.core.system import System
35from daqconf.core.metadata import write_metadata_file
36from daqconf.core.config_file import generate_cli_from_schema
37
38from timing.cli import toolbox
39
40import json
41import math
42
43from os.path import exists, join
44
45CLOCK_SPEED_HZ=62500000
46
48 CONFIG,
49 RUN_NUMBER = 333,
50 PARTITION_IDS=[],
51 FANOUT_DEVICES_NAMES=[],
52 FANOUT_CLOCK_FILE="",
53 ENDPOINT_CLOCK_FILE="",
54 HSI_CLOCK_FILE="",
55 HSI_RANDOM_RATE=1.0,
56 PART_TRIGGER_MASK=0xff,
57 PART_SPILL_GATE_ENABLED=True,
58 PART_RATE_CONTROL_ENABLED=True,
59 UHAL_LOG_LEVEL="notice",
60 OUTPUT_PATH="./timing_app",
61 DEBUG=False,
62 ):
63
64 if exists(OUTPUT_PATH):
65 raise RuntimeError(f"Directory {OUTPUT_PATH} already exists")
66
67 config_data = CONFIG[0]
68 config_file = CONFIG[1]
69
70 # Get our config objects
71 # Loading this one another time... (first time in config_file.generate_cli_from_schema)
72 moo.otypes.load_types('timinglibs/timing_app_confgen.jsonnet')
73 import dunedaq.timinglibs.timing_app_confgen as timing_app_confgen
74
75 moo.otypes.load_types('daqconf/bootgen.jsonnet')
76 import dunedaq.daqconf.bootgen as daqconf_bootgen
77
78 moo.otypes.load_types('daqconf/hsigen.jsonnet')
79 import dunedaq.daqconf.hsigen as daqconf_hsigen
80
81 moo.otypes.load_types('timinglibs/confgen.jsonnet')
82 import dunedaq.timinglibs.confgen as daqconf_timing_confgen
83
84
85 boot = daqconf_bootgen.boot(**config_data.boot)
86 if DEBUG: console.log(f"boot configuration object: {boot.pod()}")
87
88
89 thi_conf_gen = daqconf_timing_confgen.timing_hardware_interface(**config_data.timing_hardware_interface)
90 if DEBUG: console.log(f"timing_hardware_interface configuration object: {thi_conf_gen.pod()}")
91
92 tmc_conf_gen = daqconf_timing_confgen.timing_master_controller(**config_data.timing_master_controller)
93 if DEBUG: console.log(f"tmc configuration object: {tmc_conf_gen.pod()}")
94
95 tfc_conf_gen = daqconf_timing_confgen.timing_fanout_controller(**config_data.timing_fanout_controller)
96 if DEBUG: console.log(f"timing_fanout_controller configuration object: {tfc_conf_gen.pod()}")
97
98 hsi_conf_gen = daqconf_hsigen.hsi(**config_data.hsi)
99 if DEBUG: console.log(f"hsi configuration object: {hsi_conf_gen.pod()}")
100
101 tec_conf_gen = timing_app_confgen.timing_endpoint_controller(**config_data.timing_endpoint_controller)
102 if DEBUG: console.log(f"timing_endpoint_controller configuration object: {tec_conf_gen.pod()}")
103
104 FIRMWARE_STYLE = thi_conf_gen.firmware_type
105 HSI_DEVICE_NAME = hsi_conf_gen.hsi_device_name
106 ENDPOINT_DEVICE_NAME = tec_conf_gen.endpoint_device_name
107
108 if FIRMWARE_STYLE == "pdi":
109 thi_class="TimingHardwareManagerPDI"
110 elif FIRMWARE_STYLE == "pdii":
111 thi_class="TimingHardwareManagerPDII"
112 else:
113 console.log('!!! ERROR !!! Unknown firmware style. Exiting...', style="bold red")
114 exit()
115
116 # Define modules and queues
117 thi_modules = [
118 DAQModule( name="thi",
119 plugin=thi_class,
120 conf= thi.ConfParams(connections_file=thi_conf_gen.timing_hw_connections_file,
121 gather_interval=thi_conf_gen.gather_interval,
122 gather_interval_debug=thi_conf_gen.gather_interval_debug,
123 monitored_device_name_master=tmc_conf_gen.master_device_name,
124 monitored_device_names_fanout=FANOUT_DEVICES_NAMES,
125 monitored_device_name_endpoint=ENDPOINT_DEVICE_NAME,
126 monitored_device_name_hsi=HSI_DEVICE_NAME,
127 uhal_log_level=UHAL_LOG_LEVEL)),
128 ]
129
130 controller_modules = []
131 custom_cmds=[]
132
133
134 master_controller_mod_name="tmc"
135
136 if FIRMWARE_STYLE == "pdi":
137 tmc_class="TimingMasterControllerPDI"
138 elif FIRMWARE_STYLE == "pdii":
139 tmc_class="TimingMasterControllerPDII"
140 else:
141 console.log('!!! ERROR !!! Unknown firmware style. Exiting...', style="bold red")
142 exit()
143
144 if tmc_conf_gen.master_device_name != "":
145 controller_modules.extend( [DAQModule(name = master_controller_mod_name,
146 plugin = tmc_class,
147 conf = tmc.ConfParams(
148 device=tmc_conf_gen.master_device_name,
149 endpoint_scan_period=tmc_conf_gen.master_endpoint_scan_period,
150 clock_config=tmc_conf_gen.master_clock_file,
151 clock_source=tmc_conf_gen.master_clock_source,
152 monitored_endpoints=tmc_conf_gen.monitored_endpoints,
153 ))])
154
155
156 custom_cmds.extend( [
157 ("master_configure", acmd([("tmc", tmc.ConfParams(
158 device=tmc_conf_gen.master_device_name,
159 endpoint_scan_period=tmc_conf_gen.master_endpoint_scan_period,
160 clock_config=tmc_conf_gen.master_clock_file,
161 fanout_mode=tmc_conf_gen.master_clock_mode,
162 monitored_endpoints=tmc_conf_gen.monitored_endpoints,
163 ))])),
164 ("master_io_reset", acmd([("tmc", tcmd.IOResetCmdPayload(
165 clock_config=tmc_conf_gen.master_clock_file,
166 fanout_mode=tmc_conf_gen.master_clock_mode,
167 soft=False
168 ))])),
169 ("master_set_timestamp", acmd([("tmc",None)])),
170 ("master_print_status", acmd([("tmc",None)])),
171 ] )
172 if FIRMWARE_STYLE == 'pdii':
173 custom_cmds.extend( [
174 ("master_endpoint_scan", acmd([("tmc", tcmd.TimingMasterEndpointScanPayload(
175 endpoints=tmc_conf_gen.monitored_endpoints,
176 ))])),
177 ])
178
179
180 if FIRMWARE_STYLE == "pdi":
181 tpc_mods=[]
182 for partition_id in PARTITION_IDS:
183
184 tpc_mods.append( DAQModule(name = f"tpc{partition_id}",
185 plugin = "TimingPartitionController",
186 conf = tpc.PartitionConfParams(
187 device=tmc_conf_gen.master_device_name,
188 partition_id=partition_id,
189 trigger_mask=PART_TRIGGER_MASK,
190 spill_gate_enabled=PART_SPILL_GATE_ENABLED,
191 rate_control_enabled=PART_RATE_CONTROL_ENABLED,
192 )))
193 custom_cmds.extend( [
194 ("partition_configure", acmd([("tpc*", tpc.PartitionConfParams(
195 device=tmc_conf_gen.master_device_name,
196 partition_id=partition_id,
197 trigger_mask=PART_TRIGGER_MASK,
198 spill_gate_enabled=PART_SPILL_GATE_ENABLED,
199 rate_control_enabled=PART_RATE_CONTROL_ENABLED,
200 ))])),
201 ("partition_enable", acmd([("tpc.*", None)])),
202 ("partition_disable", acmd([("tpc.*", None)])),
203 ("partition_start", acmd([("tpc.*", None)])),
204 ("partition_stop", acmd([("tpc.*", None)])),
205 ("partition_enable_triggers", acmd([("tpc.*", None)])),
206 ("partition_disable_triggers", acmd([("tpc.*", None)])),
207 ("partition_print_status", acmd([("tpc.*", None)])),
208 ] )
209 controller_modules.extend( tpc_mods )
210
211
212
213 for i,fanout_device_name in enumerate(FANOUT_DEVICES_NAMES):
214 controller_modules.extend( [DAQModule(name = "tfc{}".format(i),
215 plugin = "TimingFanoutController",
216 conf = tfc.ConfParams(
217 device=fanout_device_name,
218 clock_config=FANOUT_CLOCK_FILE,
219 ))]
220 )
221 custom_cmds.extend( [
222 ("fanout_configure", acmd([("tfc*", tfc.ConfParams(
223 device=fanout_device_name,
224 ))])),
225
226 ("fanout_io_reset", acmd([("tfc.*", tcmd.IOResetCmdPayload(
227 clock_config=FANOUT_CLOCK_FILE,
228 soft=False
229 ))])),
230 ("fanout_print_status", acmd([("tfc.*", None)])),
231 ] )
232
233
234 ENDPOINT_ADDRESS = tec_conf_gen.endpoint_address
235 ENDPOINT_PARTITION = tec_conf_gen.endpoint_partition
236
237 if ENDPOINT_DEVICE_NAME != "":
238 controller_modules.extend( [DAQModule(name = "tec0",
239 plugin = "TimingEndpointController",
240 conf = tec.ConfParams(
241 device=ENDPOINT_DEVICE_NAME,
242 endpoint_id=0,
243 address=ENDPOINT_ADDRESS,
244 partition=ENDPOINT_PARTITION
245 ))] )
246 custom_cmds.extend( [
247
248 ("endpoint_io_reset", acmd([("tec.*", tcmd.IOResetCmdPayload(
249 clock_config=tec_conf_gen.endpoint_clock_file,
250 soft=False
251 ))])),
252
253
254 ("endpoint_enable", acmd([("tec.*", tcmd.TimingEndpointConfigureCmdPayload(
255 address=ENDPOINT_ADDRESS,
256 partition=ENDPOINT_PARTITION
257 ))])),
258 ("endpoint_disable", acmd([("tec.*", None)])),
259
260 ("endpoint_reset", acmd([("tec.*", tcmd.TimingEndpointConfigureCmdPayload(
261 address=ENDPOINT_ADDRESS,
262 partition=ENDPOINT_PARTITION
263 ))])),
264 ("endpoint_print_status", acmd([("tec.*", None)])),
265
266 ])
267
268 trigger_interval_ticks=0
269
270 if HSI_DEVICE_NAME != "":
271 if HSI_RANDOM_RATE > 0:
272 trigger_interval_ticks=math.floor((1/HSI_RANDOM_RATE) * CLOCK_SPEED_HZ)
273 else:
274 console.log('WARNING! Emulated trigger rate of 0 will not disable signal emulation in real HSI hardware! To disable emulated HSI triggers, use option: "--hsi-source 0" or mask all signal bits', style="bold red")
275
276 startpars = rccmd.StartParams(run=RUN_NUMBER, trigger_rate = HSI_RANDOM_RATE)
277 #resumepars = rccmd.ResumeParams(trigger_interval_ticks = trigger_interval_ticks)
278
279 HSI_ENDPOINT_ADDRESS = hsi_conf_gen.hsi_endpoint_address
280 HSI_ENDPOINT_PARTITION = hsi_conf_gen.hsi_endpoint_address
281 HSI_RE_MASK = hsi_conf_gen.hsi_re_mask
282 HSI_FE_MASK = hsi_conf_gen.hsi_fe_mask
283 HSI_INV_MASK = hsi_conf_gen.hsi_inv_mask
284 HSI_SOURCE = hsi_conf_gen.hsi_source
285
286
287 controller_modules.extend( [ DAQModule(name="hsic",
288 plugin = "HSIController",
289 conf = hsi.ConfParams( device=HSI_DEVICE_NAME,
290 clock_frequency=CLOCK_SPEED_HZ,
291 trigger_rate=HSI_RANDOM_RATE,
292 address=HSI_ENDPOINT_ADDRESS,
293 partition=HSI_ENDPOINT_PARTITION,
294 rising_edge_mask=HSI_RE_MASK,
295 falling_edge_mask=HSI_FE_MASK,
296 invert_edge_mask=HSI_INV_MASK,
297 data_source=HSI_SOURCE),
298 extra_commands = {"start": startpars,
299 #"resume": resumepars
300 }), ] )
301 custom_cmds.extend( [
302
303 ("hsi_io_reset", acmd([("hsi.*", tcmd.IOResetCmdPayload(
304 clock_config=HSI_CLOCK_FILE,
305 soft=False
306 ))])),
307 ("hsi_endpoint_enable", acmd([("hsi.*", tcmd.TimingEndpointConfigureCmdPayload(
308 address=HSI_ENDPOINT_ADDRESS,
309 partition=HSI_ENDPOINT_PARTITION
310 ))])),
311
312 ("hsi_endpoint_disable", acmd([("hsi.*", None)])),
313
314 ("hsi_endpoint_reset", acmd([("hsi.*", tcmd.TimingEndpointConfigureCmdPayload(
315 address=hsi_conf_gen.hsi_endpoint_address,
316 partition=HSI_ENDPOINT_PARTITION
317 ))])),
318 ("hsi_reset", acmd([("hsi.*", None)])),
319
320 ("hsi_configure", acmd([("hsi.*", tcmd.HSIConfigureCmdPayload(
321 rising_edge_mask=HSI_RE_MASK,
322 falling_edge_mask=HSI_FE_MASK,
323 invert_edge_mask=HSI_INV_MASK,
324 data_source=HSI_SOURCE,
325 random_rate=HSI_RANDOM_RATE
326 ))])),
327 ("hsi_start", acmd([("hsi.*", None)])),
328 ("hsi_stop", acmd([("hsi.*", None)])),
329 ("hsi_print_status", acmd([("hsi.*", None)])),
330 ])
331
332 thi_graph = ModuleGraph(thi_modules)
333
334 controllers_graph = ModuleGraph(controller_modules)
335 if ENDPOINT_DEVICE_NAME:
336 controllers_graph.add_endpoint("timing_cmds", "tec0.timing_cmds", "TimingHwCmd", Direction.OUT)
337
338 controllers_graph.add_endpoint(ENDPOINT_DEVICE_NAME+"_info", f"tec0.{ENDPOINT_DEVICE_NAME}_info", "JSON", Direction.IN, is_pubsub=True)
339 thi_graph.add_endpoint( ENDPOINT_DEVICE_NAME+"_info", "thi."+ENDPOINT_DEVICE_NAME+"_info", "JSON", Direction.OUT, is_pubsub=True)
340 if tmc_conf_gen.master_device_name:
341 controllers_graph.add_endpoint("timing_cmds", f"{master_controller_mod_name}.timing_cmds", "TimingHwCmd", Direction.OUT)
342
343 controllers_graph.add_endpoint(tmc_conf_gen.master_device_name+"_info", f"{master_controller_mod_name}.{tmc_conf_gen.master_device_name}_info", "JSON", Direction.IN, is_pubsub=True)
344 thi_graph.add_endpoint( tmc_conf_gen.master_device_name+"_info", "thi."+tmc_conf_gen.master_device_name+"_info", "JSON", Direction.OUT, is_pubsub=True)
345
346 if FIRMWARE_STYLE == 'pdi':
347 for partition_id in PARTITION_IDS:
348 controllers_graph.add_endpoint("timing_cmds", f"tpc{partition_id}.timing_cmds", "TimingHwCmd", Direction.OUT)
349 controllers_graph.add_endpoint(tmc_conf_gen.master_device_name+"_info", f"tpc{partition_id}.{tmc_conf_gen.master_device_name}_info", "JSON", Direction.IN, is_pubsub=True)
350
351 for i,fanout_device_name in enumerate(FANOUT_DEVICES_NAMES):
352 controllers_graph.add_endpoint("timing_cmds", f"tfc{i}.timing_cmds", "TimingHwCmd", Direction.OUT)
353
354 controllers_graph.add_endpoint(fanout_device_name+"_info", f"tfc{i}.{fanout_device_name}_info", "JSON", Direction.IN, is_pubsub=True)
355 thi_graph.add_endpoint( fanout_device_name+"_info", "thi."+fanout_device_name+"_info", "JSON", Direction.OUT, is_pubsub=True)
356
357 if HSI_DEVICE_NAME:
358 controllers_graph.add_endpoint("timing_cmds", f"hsic.timing_cmds", "TimingHwCmd", Direction.OUT)
359
360 controllers_graph.add_endpoint(HSI_DEVICE_NAME+"_info", f"hsic.{HSI_DEVICE_NAME}_info", "JSON", Direction.IN, is_pubsub=True)
361 thi_graph.add_endpoint( HSI_DEVICE_NAME+"_info", "thi."+HSI_DEVICE_NAME+"_info", "JSON", Direction.OUT, is_pubsub=True)
362
363
364 thi_graph.add_endpoint("timing_cmds", "thi.timing_cmds", "TimingHwCmd", Direction.IN)
365 #thi_graph.add_endpoint("timing_device_info", "thi.timing_device_info", "JSON", Direction.OUT, set(devices))
366
367 thi_app = App(modulegraph=thi_graph, host=thi_conf_gen.host_thi)
368 controllers_app = App(modulegraph=controllers_graph, host=tmc_conf_gen.host_tmc)
369
370 controllers_app_name="ctrls"
371
372 the_system = System()
373 the_system.apps["thi"]=thi_app
374 the_system.apps[controllers_app_name]=controllers_app
375
376
379 from daqconf.core.conf_utils import make_app_command_data
380 # Arrange per-app command data into the format used by util.write_json_files()
381 app_command_datas = {
382 name : make_app_command_data(the_system, app, name, verbose=DEBUG, use_k8s=(boot.process_manager=='k8s'), use_connectivity_service=boot.use_connectivity_service)
383 for name,app in the_system.apps.items()
384 }
385
386 # Make boot.json config
387 from daqconf.core.conf_utils import make_system_command_datas, write_json_files
388 system_command_datas = make_system_command_datas(
389 boot,
390 the_system,
391 verbose=DEBUG
392 )
393
394 write_json_files(app_command_datas, system_command_datas, OUTPUT_PATH, verbose=DEBUG)
395
396 console.log(f"Timing app config generated in {OUTPUT_PATH}")
397
398 write_metadata_file(OUTPUT_PATH, "timing_app_confgen", config_file)
399
400 console.log("Generating custom timing RC commands")
401
402 data_dir = f"{OUTPUT_PATH}/data"
403
404 for c,d in custom_cmds:
405 cfg = {
406 "apps": {controllers_app_name: f'data/{controllers_app_name}_{c}'}
407 }
408 with open(f"{OUTPUT_PATH}/{c}.json", 'w') as f:
409 json.dump(cfg, f, indent=4, sort_keys=True)
410
411 with open(f'{data_dir}/{controllers_app_name}_{c}.json', 'w') as f:
412 json.dump(d.pod(), f, indent=4, sort_keys=True)
413
414def split_string(ctx, param, value):
415 if value is None:
416 return []
417
418 return value.split(',')
419
420if __name__ == '__main__':
421 # Add -h as default help option
422 CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
423
424 import click
425
426 @click.command(context_settings=CONTEXT_SETTINGS)
427 @generate_cli_from_schema('timinglibs/timing_app_confgen.jsonnet', 'app_confgen')
428 @click.option('-r', '--run-number', default=333)
429
430 @click.option('-p', '--partition-ids', default="0", callback=split_string)
431 @click.option('--part-trig-mask', default=0xff)
432 @click.option('--part-spill-gate', type=bool, default=True)
433 @click.option('--part-rate-control', type=bool, default=True)
434
435 @click.option('-f', '--fanout-devices-names', callback=split_string)
436 @click.option('--fanout-clock-file', default="")
437
438 @click.option('--hsi-clock-file', default="")
439 @click.option('--hsi-random-rate', default=1.0)
440
441 @click.option('-u', '--uhal-log-level', default="notice")
442 @click.option('--debug', default=False, is_flag=True, help="Switch to get a lot of printout and dot files")
443 @click.argument('json_dir', type=click.Path(), default='timing_app')
444 def cli(config, run_number, partition_ids, part_trig_mask, part_spill_gate, part_rate_control,
445
446 fanout_devices_names, fanout_clock_file,
447 hsi_clock_file, hsi_random_rate,
448 uhal_log_level, debug, json_dir):
449 """
450 JSON_FILE: Input raw data file.
451 JSON_FILE: Output json configuration file.
452 """
453
454 generate(
455 CONFIG = config,
456 RUN_NUMBER = run_number,
457 PARTITION_IDS = partition_ids,
458 FANOUT_DEVICES_NAMES = fanout_devices_names,
459 FANOUT_CLOCK_FILE = fanout_clock_file,
460 HSI_CLOCK_FILE = hsi_clock_file,
461 HSI_RANDOM_RATE=hsi_random_rate,
462 PART_TRIGGER_MASK=part_trig_mask,
463 PART_SPILL_GATE_ENABLED=part_spill_gate,
464 PART_RATE_CONTROL_ENABLED=part_rate_control,
465 UHAL_LOG_LEVEL = uhal_log_level,
466 OUTPUT_PATH = json_dir,
467 DEBUG = debug,
468 )
469 cli()
470
cli(config, run_number, partition_ids, part_trig_mask, part_spill_gate, part_rate_control, fanout_devices_names, fanout_clock_file, hsi_clock_file, hsi_random_rate, uhal_log_level, debug, json_dir)