otsdaq  v2_04_02
ARTDAQTableBase.cc
1 #include <fhiclcpp/ParameterSet.h>
2 #include <fhiclcpp/detail/print_mode.h>
3 #include <fhiclcpp/intermediate_table.h>
4 #include <fhiclcpp/make_ParameterSet.h>
5 #include <fhiclcpp/parse.h>
6 
7 #include "otsdaq/TablePlugins/ARTDAQTableBase/ARTDAQTableBase.h"
8 
9 #include <fstream> // for std::ofstream
10 #include <iostream> // std::cout
11 #include <typeinfo>
12 
13 #include "otsdaq/ProgressBar/ProgressBar.h"
14 
15 //#include "otsdaq/TableCore/TableInfoReader.h"
16 
17 using namespace ots;
18 
19 #define ARTDAQ_FCL_PATH std::string(__ENV__("USER_DATA")) + "/" + "ARTDAQConfigurations/"
20 
21 ARTDAQTableBase::ProcessTypes ARTDAQTableBase::processTypes_ =
23 
24 const std::string ARTDAQTableBase::ARTDAQ_SUPERVISOR_TABLE = "ARTDAQSupervisorTable";
25 const int ARTDAQTableBase::NULL_SUBSYSTEM_DESTINATION = 0;
26 
27 //==============================================================================
28 // TableBase
29 // If a valid string pointer is passed in accumulatedExceptions
30 // then allowIllegalColumns is set for InfoReader
31 // If accumulatedExceptions pointer = 0, then illegal columns throw std::runtime_error
32 // exception
33 ARTDAQTableBase::ARTDAQTableBase(std::string tableName,
34  std::string* accumulatedExceptions /* =0 */)
35  : TableBase(tableName, accumulatedExceptions)
36 {
37  // make directory just in case
38  mkdir((ARTDAQ_FCL_PATH).c_str(), 0755);
39 } // end constuctor()
40 
41 //==============================================================================
42 // ARTDAQTableBase
43 // Default constructor should never be used because table type is lost
44 ARTDAQTableBase::ARTDAQTableBase(void) : TableBase("ARTDAQTableBase")
45 {
46  __SS__ << "Should not call void constructor, table type is lost!" << __E__;
47  __SS_THROW__;
48 } // end illegal default constructor()
49 
50 //==============================================================================
51 ARTDAQTableBase::~ARTDAQTableBase(void) {} // end destructor()
52 
53 //========================================================================================================================
54 const std::string& ARTDAQTableBase::getTypeString(ARTDAQTableBase::ARTDAQAppType type)
55 {
56  switch(type)
57  {
58  case ARTDAQTableBase::ARTDAQAppType::EventBuilder:
59  return processTypes_.BUILDER;
60  case ARTDAQTableBase::ARTDAQAppType::DataLogger:
61  return processTypes_.LOGGER;
62  case ARTDAQTableBase::ARTDAQAppType::Dispatcher:
63  return processTypes_.DISPATCHER;
64  case ARTDAQTableBase::ARTDAQAppType::BoardReader:
65  return processTypes_.READER;
66  }
67  // return "UNKNOWN";
68  __SS__ << "Illegal translation attempt for type '" << (unsigned int)type << "'"
69  << __E__;
70  __SS_THROW__;
71 } // end getTypeString()
72 
73 //========================================================================================================================
74 std::string ARTDAQTableBase::getFHICLFilename(ARTDAQTableBase::ARTDAQAppType type,
75  const std::string& name)
76 {
77  __COUT__ << "Type: " << ARTDAQTableBase::getTypeString(type) << " Name: " << name
78  << __E__;
79  std::string filename = ARTDAQ_FCL_PATH + ARTDAQTableBase::getTypeString(type) + "-";
80  std::string uid = name;
81  for(unsigned int i = 0; i < uid.size(); ++i)
82  if((uid[i] >= 'a' && uid[i] <= 'z') || (uid[i] >= 'A' && uid[i] <= 'Z') ||
83  (uid[i] >= '0' && uid[i] <= '9')) // only allow alpha numeric in file name
84  filename += uid[i];
85 
86  filename += ".fcl";
87 
88  __COUT__ << "fcl: " << filename << __E__;
89 
90  return filename;
91 } // end getFHICLFilename()
92 
93 //========================================================================================================================
94 std::string ARTDAQTableBase::getFlatFHICLFilename(ARTDAQTableBase::ARTDAQAppType type,
95  const std::string& name)
96 {
97  __COUT__ << "Type: " << ARTDAQTableBase::getTypeString(type) << " Name: " << name
98  << __E__;
99  std::string filename = ARTDAQ_FCL_PATH + ARTDAQTableBase::getTypeString(type) + "-";
100  std::string uid = name;
101  for(unsigned int i = 0; i < uid.size(); ++i)
102  if((uid[i] >= 'a' && uid[i] <= 'z') || (uid[i] >= 'A' && uid[i] <= 'Z') ||
103  (uid[i] >= '0' && uid[i] <= '9')) // only allow alpha numeric in file name
104  filename += uid[i];
105 
106  filename += "_flattened.fcl";
107 
108  __COUT__ << "fcl: " << filename << __E__;
109 
110  return filename;
111 } // end getFlatFHICLFilename()
112 
113 //========================================================================================================================
114 void ARTDAQTableBase::flattenFHICL(ARTDAQTableBase::ARTDAQAppType type,
115  const std::string& name)
116 {
117  __COUT__ << "flattenFHICL()" << __E__;
118  std::string inFile = getFHICLFilename(type, name);
119  std::string outFile = getFlatFHICLFilename(type, name);
120 
121  __COUTV__(__ENV__("FHICL_FILE_PATH"));
122 
123  cet::filepath_lookup_nonabsolute policy("FHICL_FILE_PATH");
124 
125  fhicl::ParameterSet pset;
126 
127  try
128  {
129  fhicl::intermediate_table tbl;
130  fhicl::parse_document(inFile, policy, tbl);
131  fhicl::ParameterSet pset;
132  fhicl::make_ParameterSet(tbl, pset);
133 
134  std::ofstream ofs{outFile};
135  ofs << pset.to_indented_string(0, fhicl::detail::print_mode::annotated);
136  }
137  catch(cet::exception const& e)
138  {
139  __SS__ << "Failed to parse fhicl: " << e.what() << __E__;
140  __SS_THROW__;
141  }
142 } // end flattenFHICL()
143 
144 //========================================================================================================================
145 // insertParameters
146 // Inserts parameters in FHiCL outputs stream.
147 //
148 // onlyInsertAtTableParameters allows @table:: parameters only,
149 // so that calling code can do two passes (i.e. top of fcl block, @table:: only,
150 // and bottom of fcl block, ignore/skip @table:: as default behavior).
151 void ARTDAQTableBase::insertParameters(std::ostream& out,
152  std::string& tabStr,
153  std::string& commentStr,
154  ConfigurationTree parameterGroupLink,
155  const std::string& parameterPreamble,
156  bool onlyInsertAtTableParameters /*=false*/,
157  bool includeAtTableParameters /*=false*/)
158 {
159  // skip if link is disconnected
160  if(!parameterGroupLink.isDisconnected())
161  {
163  auto otherParameters = parameterGroupLink.getChildren();
164 
165  std::string key;
166  //__COUTV__(otherParameters.size());
167  for(auto& parameter : otherParameters)
168  {
169  key = parameter.second.getNode(parameterPreamble + "Key").getValue();
170 
171  // handle special keyword @table:: (which imports full tables, usually as
172  // defaults)
173  if(key.find("@table::") != std::string::npos)
174  {
175  // include @table::
176  if(onlyInsertAtTableParameters || includeAtTableParameters)
177  {
178  if(!parameter.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
179  .getValue<bool>())
180  PUSHCOMMENT;
181 
182  OUT << key;
183 
184  // skip connecting : if special keywords found
185  OUT << parameter.second.getNode(parameterPreamble + "Value")
186  .getValue()
187  << "\n";
188 
189  if(!parameter.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
190  .getValue<bool>())
191  POPCOMMENT;
192  }
193  // else skip it
194 
195  continue;
196  }
197  // else NOT @table:: keyword parameter
198 
199  if(onlyInsertAtTableParameters)
200  continue; // skip all other types
201 
202  if(!parameter.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
203  .getValue<bool>())
204  PUSHCOMMENT;
205 
206  OUT << key;
207 
208  // skip connecting : if special keywords found
209  if(key.find("#include") == std::string::npos)
210  OUT << ":";
211  OUT << parameter.second.getNode(parameterPreamble + "Value").getValue()
212  << "\n";
213 
214  if(!parameter.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
215  .getValue<bool>())
216  POPCOMMENT;
217  }
218  }
219  // else
220  // __COUT__ << "No parameters found" << __E__;
221 
222 } // end insertParameters()
223 
224 //========================================================================================================================
225 // insertModuleType
226 // Inserts module type field, with consideration for @table::
227 std::string ARTDAQTableBase::insertModuleType(std::ostream& out,
228  std::string& tabStr,
229  std::string& commentStr,
230  ConfigurationTree moduleTypeNode)
231 {
232  std::string value = moduleTypeNode.getValue();
233 
234  OUT;
235  if(value.find("@table::") == std::string::npos)
236  out << "module_type: ";
237  out << value << "\n";
238 
239  return value;
240 } // end insertModuleType()
241 
242 //========================================================================================================================
243 void ARTDAQTableBase::outputReaderFHICL( // const ConfigurationManager* configManager,
244  const ConfigurationTree& boardReaderNode,
245  // unsigned int selfRank,
246  const std::string& selfHost,
247  // unsigned int selfPort,
248  // const XDAQContextTable* contextConfig,
249  size_t maxFragmentSizeBytes)
250 {
251  /*
252  the file will look something like this:
253 
254  daq: {
255  fragment_receiver: {
256  mpi_sync_interval: 50
257 
258  # CommandableFragmentGenerator Table:
259  fragment_ids: []
260  fragment_id: -99 # Please define only one of these
261 
262  sleep_on_stop_us: 0
263 
264  requests_enabled: false # Whether to set up the socket for listening for
265  trigger messages request_mode: "Ignored" # Possible values are: Ignored, Single,
266  Buffer, Window
267 
268  data_buffer_depth_fragments: 1000
269  data_buffer_depth_mb: 1000
270 
271  request_port: 3001
272  request_address: "227.128.12.26" # Multicast request address
273 
274  request_window_offset: 0 # Request message contains tzero. Window will be from
275  tzero - offset to tzero + width request_window_width: 0 stale_request_timeout:
276  "0xFFFFFFFF" # How long to wait before discarding request messages that are outside
277  the available data request_windows_are_unique: true # If request windows are
278  unique, avoids a copy operation, but the same data point cannot be used for two
279  requests. If this is not anticipated, leave set to "true"
280 
281  separate_data_thread: false # MUST be true for triggers to be applied! If
282  triggering is not desired, but a separate readout thread is, set this to true,
283  triggers_enabled to false and trigger_mode to ignored. separate_monitoring_thread:
284  false # Whether a thread should be started which periodically calls checkHWStatus_,
285  a user-defined function which should be used to check hardware status registers and
286  report to MetricMan. poll_hardware_status: false # Whether checkHWStatus_ will be
287  called, either through the thread or at the start of getNext
288  hardware_poll_interval_us: 1000000 # If hardware monitoring thread is enabled,
289  how often should it call checkHWStatus_
290 
291 
292  # Generated Parameters:
293  generator: ToySimulator
294  fragment_type: TOY1
295  fragment_id: 0
296  board_id: 0
297  starting_fragment_id: 0
298  random_seed: 5780
299  sleep_on_stop_us: 500000
300 
301  # Generator-Specific Table:
302 
303  nADCcounts: 40
304 
305  throttle_usecs: 100000
306 
307  distribution_type: 1
308 
309  timestamp_scale_factor: 1
310 
311 
312  destinations: {
313  d2: { transferPluginType: MPI
314  destination_rank: 2
315  max_fragment_size_bytes: 2097152
316  host_map: [
317  {
318  host: "mu2edaq01.fnal.gov"
319  rank: 0
320  },
321  {
322  host: "mu2edaq01.fnal.gov"
323  rank: 1
324  }]
325  }
326  d3: { transferPluginType: MPI
327  destination_rank: 3
328  max_fragment_size_bytes: 2097152
329  host_map: [
330  {
331  host: "mu2edaq01.fnal.gov"
332  rank: 0
333  },
334  {
335  host: "mu2edaq01.fnal.gov"
336  rank: 1
337  }]
338  }
339 
340  }
341  }
342 
343  metrics: {
344  brFile: {
345  metricPluginType: "file"
346  level: 3
347  fileName: "/tmp/boardreader/br_%UID%_metrics.log"
348  uniquify: true
349  }
350  # ganglia: {
351  # metricPluginType: "ganglia"
352  # level: %{ganglia_level}
353  # reporting_interval: 15.0
354  #
355  # configFile: "/etc/ganglia/gmond.conf"
356  # group: "ARTDAQ"
357  # }
358  # msgfac: {
359  # level: %{mf_level}
360  # metricPluginType: "msgFacility"
361  # output_message_application_name: "ARTDAQ Metric"
362  # output_message_severity: 0
363  # }
364  # graphite: {
365  # level: %{graphite_level}
366  # metricPluginType: "graphite"
367  # host: "localhost"
368  # port: 20030
369  # namespace: "artdaq."
370  # }
371  }
372  }
373 
374  */
375 
376  std::string filename = ARTDAQTableBase::getFHICLFilename(
377  ARTDAQTableBase::ARTDAQAppType::BoardReader, boardReaderNode.getValue());
378 
380  // generate xdaq run parameter file
381  std::fstream out;
382 
383  std::string tabStr = "";
384  std::string commentStr = "";
385 
386  out.open(filename, std::fstream::out | std::fstream::trunc);
387  if(out.fail())
388  {
389  __SS__ << "Failed to open ARTDAQ Builder fcl file: " << filename << __E__;
390  __SS_THROW__;
391  }
392 
393  //--------------------------------------
394  // header
395  OUT << "###########################################################" << __E__;
396  OUT << "#" << __E__;
397  OUT << "# artdaq reader fcl configuration file produced by otsdaq." << __E__;
398  OUT << "# Creation timestamp: " << StringMacros::getTimestampString() << __E__;
399  OUT << "# Original filename: " << filename << __E__;
400  OUT << "# otsdaq-ARTDAQ Reader UID: " << boardReaderNode.getValue() << __E__;
401  OUT << "#" << __E__;
402  OUT << "###########################################################" << __E__;
403  OUT << "\n\n";
404 
405  // no primary link to table tree for reader node!
406  try
407  {
408  if(boardReaderNode.isDisconnected())
409  {
410  // create empty fcl
411  OUT << "{}\n\n";
412  out.close();
413  return;
414  }
415  }
416  catch(const std::runtime_error&)
417  {
418  __COUT__ << "Ignoring error, assume this a valid UID node." << __E__;
419  // error is expected here for UIDs.. so just ignore
420  // this check is valuable if source node is a unique-Link node, rather than UID
421  }
422 
423  //--------------------------------------
424  // handle daq
425  OUT << "daq: {\n";
426 
427  // fragment_receiver
428  PUSHTAB;
429  OUT << "fragment_receiver: {\n";
430 
431  PUSHTAB;
432  OUT << "max_fragment_size_bytes: " << maxFragmentSizeBytes << "\n";
433  {
434  // plugin type and fragment data-type
435  OUT << "generator"
436  << ": " << boardReaderNode.getNode("daqGeneratorPluginType").getValue()
437  << ("\t #daq generator plug-in type") << "\n";
438  OUT << "fragment_type"
439  << ": " << boardReaderNode.getNode("daqGeneratorFragmentType").getValue()
440  << ("\t #generator data fragment type") << "\n\n";
441 
442  // shared and unique parameters
443  auto parametersLink = boardReaderNode.getNode("daqParametersLink");
444  if(!parametersLink.isDisconnected())
445  {
446  auto parameters = parametersLink.getChildren();
447  for(auto& parameter : parameters)
448  {
449  if(!parameter.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
450  .getValue<bool>())
451  PUSHCOMMENT;
452 
453  // __COUT__ <<
454  // parameter.second.getNode("daqParameterKey").getValue() <<
455  // ": " <<
456  // parameter.second.getNode("daqParameterValue").getValue()
457  // <<
458  // "\n";
459 
460  auto comment =
461  parameter.second.getNode(TableViewColumnInfo::COL_NAME_COMMENT);
462  OUT << parameter.second.getNode("daqParameterKey").getValue() << ": "
463  << parameter.second.getNode("daqParameterValue").getValue()
464  << (comment.isDefaultValue() ? "" : ("\t # " + comment.getValue()))
465  << "\n";
466 
467  if(!parameter.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
468  .getValue<bool>())
469  POPCOMMENT;
470  }
471  }
472  OUT << "\n"; // end daq board reader parameters
473  }
474 
475  OUT << "destinations: {\n";
476 
477  OUT << "}\n\n"; // end destinations
478 
479  POPTAB;
480  OUT << "}\n\n"; // end fragment_receiver
481 
482  OUT << "metrics: {\n";
483 
484  PUSHTAB;
485  auto metricsGroup = boardReaderNode.getNode("daqMetricsLink");
486  if(!metricsGroup.isDisconnected())
487  {
488  auto metrics = metricsGroup.getChildren();
489 
490  for(auto& metric : metrics)
491  {
492  if(!metric.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
493  .getValue<bool>())
494  PUSHCOMMENT;
495 
496  OUT << metric.second.getNode("metricKey").getValue() << ": {\n";
497  PUSHTAB;
498 
499  OUT << "metricPluginType: "
500  << metric.second.getNode("metricPluginType").getValue() << "\n";
501  OUT << "level: " << metric.second.getNode("metricLevel").getValue() << "\n";
502 
503  auto metricParametersGroup = metric.second.getNode("metricParametersLink");
504  if(!metricParametersGroup.isDisconnected())
505  {
506  auto metricParameters = metricParametersGroup.getChildren();
507  for(auto& metricParameter : metricParameters)
508  {
509  if(!metricParameter.second
510  .getNode(TableViewColumnInfo::COL_NAME_STATUS)
511  .getValue<bool>())
512  PUSHCOMMENT;
513 
514  OUT << metricParameter.second.getNode("metricParameterKey").getValue()
515  << ": "
516  << metricParameter.second.getNode("metricParameterValue")
517  .getValue()
518  << "\n";
519 
520  if(!metricParameter.second
521  .getNode(TableViewColumnInfo::COL_NAME_STATUS)
522  .getValue<bool>())
523  POPCOMMENT;
524  }
525  }
526  POPTAB;
527  OUT << "}\n\n"; // end metric
528 
529  if(!metric.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
530  .getValue<bool>())
531  POPCOMMENT;
532  }
533  }
534  POPTAB;
535  OUT << "}\n\n"; // end metrics
536 
537  POPTAB;
538  OUT << "}\n\n"; // end daq
539 
540  out.close();
541 } // end outputReaderFHICL()
542 
543 //========================================================================================================================
544 // outputDataReceiverFHICL
545 // Note: currently selfRank and selfPort are unused by artdaq fcl
546 void ARTDAQTableBase::outputDataReceiverFHICL(const ConfigurationTree& receiverNode,
547  // unsigned int selfRank,
548  const std::string& selfHost,
549  // unsigned int selfPort,
550  ARTDAQTableBase::ARTDAQAppType appType,
551  size_t maxFragmentSizeBytes)
552 {
553  std::string filename = getFHICLFilename(appType, receiverNode.getValue());
554 
556  // generate xdaq run parameter file
557  std::fstream out;
558 
559  std::string tabStr = "";
560  std::string commentStr = "";
561 
562  out.open(filename, std::fstream::out | std::fstream::trunc);
563  if(out.fail())
564  {
565  __SS__ << "Failed to open ARTDAQ fcl file: " << filename << __E__;
566  __SS_THROW__;
567  }
568 
569  //--------------------------------------
570  // header
571  OUT << "###########################################################" << __E__;
572  OUT << "#" << __E__;
573  OUT << "# artdaq " << getTypeString(appType)
574  << " fcl configuration file produced by otsdaq." << __E__;
575  OUT << "# Creation timestamp: " << StringMacros::getTimestampString() << __E__;
576  OUT << "# Original filename: " << filename << __E__;
577  OUT << "# otsdaq-ARTDAQ " << getTypeString(appType)
578  << " UID: " << receiverNode.getValue() << __E__;
579  OUT << "#" << __E__;
580  OUT << "###########################################################" << __E__;
581  OUT << "\n\n";
582 
583  // no primary link to table tree for data receiver node!
584  try
585  {
586  if(receiverNode.isDisconnected())
587  {
588  // create empty fcl
589  OUT << "{}\n\n";
590  out.close();
591  return;
592  }
593  }
594  catch(const std::runtime_error&)
595  {
596  __COUT__ << "Ignoring error, assume this a valid UID node." << __E__;
597  // error is expected here for UIDs.. so just ignore
598  // this check is valuable if source node is a unique-Link node, rather than UID
599  }
600 
601  //--------------------------------------
602  // handle preamble parameters
603  __COUT__ << "Inserting preamble parameters..." << __E__;
604  ARTDAQTableBase::insertParameters(out,
605  tabStr,
606  commentStr,
607  receiverNode.getNode("preambleParametersLink"),
608  "daqParameter" /*parameterType*/,
609  false /*onlyInsertAtTableParameters*/,
610  true /*includeAtTableParameters*/);
611 
612  //--------------------------------------
613  // handle daq
614  __COUT__ << "Generating daq block..." << __E__;
615  auto daq = receiverNode.getNode("daqLink");
616  if(!daq.isDisconnected())
617  {
619  OUT << "daq: {\n";
620 
621  PUSHTAB;
622  if(appType == ARTDAQAppType::EventBuilder)
623  {
624  // event_builder
625  OUT << "event_builder: {\n";
626  }
627  else
628  {
629  // both datalogger and dispatcher use aggregator for now
630  OUT << "aggregator: {\n";
631  }
632 
633  PUSHTAB;
634 
635  OUT << "max_fragment_size_bytes: " << maxFragmentSizeBytes << "\n";
636  if(appType == ARTDAQAppType::DataLogger)
637  {
638  OUT << "is_datalogger: true\n";
639  }
640  else if(appType == ARTDAQAppType::Dispatcher)
641  {
642  OUT << "is_dispatcher: true\n";
643  }
644 
645  //--------------------------------------
646  // handle ALL daq parameters
647  __COUT__ << "Inserting DAQ Parameters..." << __E__;
648  ARTDAQTableBase::insertParameters(out,
649  tabStr,
650  commentStr,
651  daq.getNode("daqParametersLink"),
652  "daqParameter" /*parameterType*/,
653  false /*onlyInsertAtTableParameters*/,
654  true /*includeAtTableParameters*/);
655 
656  __COUT__ << "Adding sources placeholder" << __E__;
657  OUT << "sources: {\n"
658  << "}\n\n"; // end sources
659 
660  POPTAB;
661  OUT << "}\n\n"; // end event builder
662 
663  __COUT__ << "Filling in metrics" << __E__;
664  OUT << "metrics: {\n";
665 
666  PUSHTAB;
667  auto metricsGroup = daq.getNode("daqMetricsLink");
668  if(!metricsGroup.isDisconnected())
669  {
670  auto metrics = metricsGroup.getChildren();
671 
672  for(auto& metric : metrics)
673  {
674  if(!metric.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
675  .getValue<bool>())
676  PUSHCOMMENT;
677 
678  OUT << metric.second.getNode("metricKey").getValue() << ": {\n";
679  PUSHTAB;
680 
681  OUT << "metricPluginType: "
682  << metric.second.getNode("metricPluginType").getValue() << "\n";
683  OUT << "level: " << metric.second.getNode("metricLevel").getValue()
684  << "\n";
685 
686  //--------------------------------------
687  // handle ALL metric parameters
688  ARTDAQTableBase::insertParameters(
689  out,
690  tabStr,
691  commentStr,
692  metric.second.getNode("metricParametersLink"),
693  "metricParameter" /*parameterType*/,
694  false /*onlyInsertAtTableParameters*/,
695  true /*includeAtTableParameters*/);
696 
697  POPTAB;
698  OUT << "}\n\n"; // end metric
699 
700  if(!metric.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
701  .getValue<bool>())
702  POPCOMMENT;
703  }
704  }
705  POPTAB;
706  OUT << "}\n\n"; // end metrics
707 
708  POPTAB;
709  OUT << "}\n\n"; // end daq
710  }
711 
712  //--------------------------------------
713  // handle art
714  __COUT__ << "Filling art block..." << __E__;
715  auto art = receiverNode.getNode("artLink");
716  if(!art.isDisconnected())
717  {
718  OUT << "art: {\n";
719 
720  PUSHTAB;
721 
722  //--------------------------------------
723  // handle services
724  __COUT__ << "Filling art.services" << __E__;
725  auto services = art.getNode("servicesLink");
726  if(!services.isDisconnected())
727  {
728  OUT << "services: {\n";
729 
730  PUSHTAB;
731 
732  //--------------------------------------
733  // handle services @table:: parameters
734  ARTDAQTableBase::insertParameters(out,
735  tabStr,
736  commentStr,
737  services.getNode("ServicesParametersLink"),
738  "daqParameter" /*parameterType*/,
739  true /*onlyInsertAtTableParameters*/,
740  false /*includeAtTableParameters*/);
741 
742  // scheduler
743  OUT << "scheduler: {\n";
744 
745 #if ART_HEX_VERSION < 0x30200
746  PUSHTAB;
747  // OUT << "fileMode: " <<
748  // services.getNode("schedulerFileMode").getValue()
749  //<<
750  //"\n";
751  OUT << "errorOnFailureToPut: "
752  << (services.getNode("schedulerErrorOnFailtureToPut").getValue<bool>()
753  ? "true"
754  : "false")
755  << "\n";
756  POPTAB;
757 #endif
758  OUT << "}\n\n";
759 
760  // NetMonTransportServiceInterface
761  OUT << "NetMonTransportServiceInterface: {\n";
762 
763  PUSHTAB;
764  OUT << "service_provider: " <<
765  // services.getNode("NetMonTrasportServiceInterfaceServiceProvider").getEscapedValue()
766  services.getNode("NetMonTrasportServiceInterfaceServiceProvider")
767  .getValue()
768  << "\n";
769 
770  OUT << "destinations: {\n"
771  << "}\n\n"; // end destinations
772 
773  POPTAB;
774  OUT << "}\n\n"; // end NetMonTransportServiceInterface
775 
776  //--------------------------------------
777  // handle services NOT @table:: parameters
778  ARTDAQTableBase::insertParameters(out,
779  tabStr,
780  commentStr,
781  services.getNode("ServicesParametersLink"),
782  "daqParameter" /*parameterType*/,
783  false /*onlyInsertAtTableParameters*/,
784  false /*includeAtTableParameters*/);
785 
786  POPTAB;
787  OUT << "}\n\n"; // end services
788  }
789 
790  //--------------------------------------
791  // handle outputs
792  __COUT__ << "Filling art.outputs" << __E__;
793  auto outputs = art.getNode("outputsLink");
794  if(!outputs.isDisconnected())
795  {
796  OUT << "outputs: {\n";
797 
798  PUSHTAB;
799 
800  auto outputPlugins = outputs.getChildren();
801  for(auto& outputPlugin : outputPlugins)
802  {
803  if(!outputPlugin.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
804  .getValue<bool>())
805  PUSHCOMMENT;
806 
807  OUT << outputPlugin.second.getNode("outputKey").getValue() << ": {\n";
808  PUSHTAB;
809 
810  std::string moduleType = ARTDAQTableBase::insertModuleType(
811  out,
812  tabStr,
813  commentStr,
814  outputPlugin.second.getNode("outputModuleType"));
815 
816  //--------------------------------------
817  // handle ALL output parameters
818  ARTDAQTableBase::insertParameters(
819  out,
820  tabStr,
821  commentStr,
822  outputPlugin.second.getNode("outputModuleParameterLink"),
823  "outputParameter" /*parameterType*/,
824  false /*onlyInsertAtTableParameters*/,
825  true /*includeAtTableParameters*/);
826 
827  if(outputPlugin.second.getNode("outputModuleType").getValue() ==
828  "BinaryNetOutput")
829  {
830  OUT << "destinations: {\n"
831  << "}\n\n"; // end destinations
832  }
833 
834  POPTAB;
835  OUT << "}\n\n"; // end output module
836 
837  if(!outputPlugin.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
838  .getValue<bool>())
839  POPCOMMENT;
840  }
841 
842  POPTAB;
843  OUT << "}\n\n"; // end outputs
844  }
845 
846  //--------------------------------------
847  // handle physics
848  __COUT__ << "Filling art.physics" << __E__;
849  auto physics = art.getNode("physicsLink");
850  if(!physics.isDisconnected())
851  {
853  OUT << "physics: {\n";
854 
855  PUSHTAB;
856 
857  //--------------------------------------
858  // handle only @table:: physics parameters
859  ARTDAQTableBase::insertParameters(
860  out,
861  tabStr,
862  commentStr,
863  physics.getNode("physicsOtherParametersLink"),
864  "physicsParameter" /*parameterType*/,
865  true /*onlyInsertAtTableParameters*/,
866  false /*includeAtTableParameters*/);
867 
868  auto analyzers = physics.getNode("analyzersLink");
869  if(!analyzers.isDisconnected())
870  {
872  OUT << "analyzers: {\n";
873 
874  PUSHTAB;
875 
876  auto modules = analyzers.getChildren();
877  for(auto& module : modules)
878  {
879  if(!module.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
880  .getValue<bool>())
881  PUSHCOMMENT;
882 
883  //--------------------------------------
884  // handle only @table:: analyzer parameters
885  ARTDAQTableBase::insertParameters(
886  out,
887  tabStr,
888  commentStr,
889  module.second.getNode("analyzerModuleParameterLink"),
890  "analyzerParameter" /*parameterType*/,
891  true /*onlyInsertAtTableParameters*/,
892  false /*includeAtTableParameters*/);
893 
894  OUT << module.second.getNode("analyzerKey").getValue() << ": {\n";
895  PUSHTAB;
896  ARTDAQTableBase::insertModuleType(
897  out,
898  tabStr,
899  commentStr,
900  module.second.getNode("analyzerModuleType"));
901 
902  //--------------------------------------
903  // handle NOT @table:: producer parameters
904  ARTDAQTableBase::insertParameters(
905  out,
906  tabStr,
907  commentStr,
908  module.second.getNode("analyzerModuleParameterLink"),
909  "analyzerParameter" /*parameterType*/,
910  false /*onlyInsertAtTableParameters*/,
911  false /*includeAtTableParameters*/);
912 
913  POPTAB;
914  OUT << "}\n\n"; // end analyzer module
915 
916  if(!module.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
917  .getValue<bool>())
918  POPCOMMENT;
919  }
920  POPTAB;
921  OUT << "}\n\n"; // end analyzer
922  }
923 
924  auto producers = physics.getNode("producersLink");
925  if(!producers.isDisconnected())
926  {
928  OUT << "producers: {\n";
929 
930  PUSHTAB;
931 
932  auto modules = producers.getChildren();
933  for(auto& module : modules)
934  {
935  if(!module.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
936  .getValue<bool>())
937  PUSHCOMMENT;
938 
939  //--------------------------------------
940  // handle only @table:: producer parameters
941  ARTDAQTableBase::insertParameters(
942  out,
943  tabStr,
944  commentStr,
945  module.second.getNode("producerModuleParameterLink"),
946  "producerParameter" /*parameterType*/,
947  true /*onlyInsertAtTableParameters*/,
948  false /*includeAtTableParameters*/);
949 
950  OUT << module.second.getNode("producerKey").getValue() << ": {\n";
951  PUSHTAB;
952 
953  ARTDAQTableBase::insertModuleType(
954  out,
955  tabStr,
956  commentStr,
957  module.second.getNode("producerModuleType"));
958 
959  //--------------------------------------
960  // handle NOT @table:: producer parameters
961  ARTDAQTableBase::insertParameters(
962  out,
963  tabStr,
964  commentStr,
965  module.second.getNode("producerModuleParameterLink"),
966  "producerParameter" /*parameterType*/,
967  false /*onlyInsertAtTableParameters*/,
968  false /*includeAtTableParameters*/);
969 
970  POPTAB;
971  OUT << "}\n\n"; // end producer module
972 
973  if(!module.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
974  .getValue<bool>())
975  POPCOMMENT;
976  }
977  POPTAB;
978  OUT << "}\n\n"; // end producer
979  }
980 
981  auto filters = physics.getNode("filtersLink");
982  if(!filters.isDisconnected())
983  {
985  OUT << "filters: {\n";
986 
987  PUSHTAB;
988 
989  auto modules = filters.getChildren();
990  for(auto& module : modules)
991  {
992  if(!module.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
993  .getValue<bool>())
994  PUSHCOMMENT;
995 
996  //--------------------------------------
997  // handle only @table:: filter parameters
998  ARTDAQTableBase::insertParameters(
999  out,
1000  tabStr,
1001  commentStr,
1002  module.second.getNode("filterModuleParameterLink"),
1003  "filterParameter" /*parameterType*/,
1004  true /*onlyInsertAtTableParameters*/,
1005  false /*includeAtTableParameters*/);
1006 
1007  OUT << module.second.getNode("filterKey").getValue() << ": {\n";
1008  PUSHTAB;
1009 
1010  ARTDAQTableBase::insertModuleType(
1011  out,
1012  tabStr,
1013  commentStr,
1014  module.second.getNode("filterModuleType"));
1015 
1016  //--------------------------------------
1017  // handle NOT @table:: filter parameters
1018  ARTDAQTableBase::insertParameters(
1019  out,
1020  tabStr,
1021  commentStr,
1022  module.second.getNode("filterModuleParameterLink"),
1023  "filterParameter" /*parameterType*/,
1024  false /*onlyInsertAtTableParameters*/,
1025  false /*includeAtTableParameters*/);
1026 
1027  POPTAB;
1028  OUT << "}\n\n"; // end filter module
1029 
1030  if(!module.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
1031  .getValue<bool>())
1032  POPCOMMENT;
1033  }
1034  POPTAB;
1035  OUT << "}\n\n"; // end filter
1036  }
1037 
1038  //--------------------------------------
1039  // handle NOT @table:: physics parameters
1040  ARTDAQTableBase::insertParameters(
1041  out,
1042  tabStr,
1043  commentStr,
1044  physics.getNode("physicsOtherParametersLink"),
1045  "physicsParameter" /*parameterType*/,
1046  false /*onlyInsertAtTableParameters*/,
1047  false /*includeAtTableParameters*/);
1048 
1049  POPTAB;
1050  OUT << "}\n\n"; // end physics
1051  }
1052 
1053  //--------------------------------------
1054  // handle source
1055  __COUT__ << "Filling art.source" << __E__;
1056  auto source = art.getNode("sourceLink");
1057  if(!source.isDisconnected())
1058  {
1059  OUT << "source: {\n";
1060 
1061  PUSHTAB;
1062 
1063  ARTDAQTableBase::insertModuleType(
1064  out, tabStr, commentStr, source.getNode("sourceModuleType"));
1065 
1066  OUT << "waiting_time: " << source.getNode("sourceWaitingTime").getValue()
1067  << "\n";
1068  OUT << "resume_after_timeout: "
1069  << (source.getNode("sourceResumeAfterTimeout").getValue<bool>() ? "true"
1070  : "false")
1071  << "\n";
1072  POPTAB;
1073  OUT << "}\n\n"; // end source
1074  }
1075 
1076  //--------------------------------------
1077  // handle process_name
1078  __COUT__ << "Writing art.process_name" << __E__;
1079  OUT << "process_name: " << art.getNode("ProcessName") << "\n";
1080 
1081  POPTAB;
1082  OUT << "}\n\n"; // end art
1083  }
1084 
1085  //--------------------------------------
1086  // handle ALL add-on parameters
1087  __COUT__ << "Inserting add-on parameters" << __E__;
1088  ARTDAQTableBase::insertParameters(out,
1089  tabStr,
1090  commentStr,
1091  receiverNode.getNode("addOnParametersLink"),
1092  "daqParameter" /*parameterType*/,
1093  false /*onlyInsertAtTableParameters*/,
1094  true /*includeAtTableParameters*/);
1095 
1096  __COUT__ << "outputDataReceiverFHICL DONE" << __E__;
1097  out.close();
1098 } // end outputDataReceiverFHICL()
1099 
1100 //========================================================================================================================
1101 void ARTDAQTableBase::extractArtdaqInfo(
1102  ConfigurationTree artdaqSupervisorNode,
1103  std::map<int /*subsystem ID*/, ARTDAQTableBase::SubsystemInfo>& subsystems,
1104  std::map<ARTDAQTableBase::ARTDAQAppType, std::list<ARTDAQTableBase::ProcessInfo>>& processes,
1105  bool doWriteFHiCL /* = false */,
1106  size_t maxFragmentSizeBytes /* = ARTDAQTableBase::DEFAULT_MAX_FRAGMENT_SIZE*/,
1107  ProgressBar* progressBar /* =0 */)
1108 {
1109  if(progressBar)
1110  progressBar->step();
1111 
1112  subsystems[ARTDAQTableBase::NULL_SUBSYSTEM_DESTINATION].id = ARTDAQTableBase::NULL_SUBSYSTEM_DESTINATION;
1113  subsystems[ARTDAQTableBase::NULL_SUBSYSTEM_DESTINATION].label = "nullDestinationSubsystem";
1114 
1115  std::list<ARTDAQTableBase::ProcessInfo>& readerInfo =
1116  processes[ARTDAQTableBase::ARTDAQAppType::BoardReader];
1117  {
1118  __COUT__ << "Checking for BoardReaders" << __E__;
1119  auto readersLink = artdaqSupervisorNode.getNode("boardreadersLink");
1120  if(!readersLink.isDisconnected() && readersLink.getChildren().size() > 0)
1121  {
1122  auto readers = readersLink.getChildren();
1123  __COUT__ << "There are " << readers.size() << " configured BoardReaders"
1124  << __E__;
1125 
1126  for(auto& reader : readers)
1127  {
1128  if(reader.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
1129  .getValue<bool>())
1130  {
1131  auto readerUID = reader.second.getNode("SupervisorUID").getValue();
1132  auto readerHost =
1133  reader.second.getNode("DAQInterfaceHostname").getValue();
1134 
1135  auto readerSubsystemID = 1;
1136  auto readerSubsystemLink = reader.second.getNode("SubsystemLink");
1137  if(!readerSubsystemLink.isDisconnected())
1138  {
1139  readerSubsystemID = ARTDAQTableBase::getSubsytemId(readerSubsystemLink);
1140  __COUTV__(readerSubsystemID);
1141  subsystems[readerSubsystemID].id = readerSubsystemID;
1142 
1143  const std::string& readerSubsystemName =
1144  readerSubsystemLink.getUIDAsString();
1145  __COUTV__(readerSubsystemName);
1146 
1147  subsystems[readerSubsystemID].label = readerSubsystemName;
1148 
1149  auto readerSubsystemDestinationLink =
1150  readerSubsystemLink.getNode("SubsystemDestinationLink");
1151  if(readerSubsystemDestinationLink.isDisconnected())
1152  {
1153  //default to no destination when no link
1154  subsystems[readerSubsystemID].destination = 0;
1155  }
1156  else
1157  {
1158  //get destination subsystem id
1159  subsystems[readerSubsystemID].destination =
1160  ARTDAQTableBase::getSubsytemId(readerSubsystemDestinationLink);
1161  }
1162  __COUTV__(subsystems[readerSubsystemID].destination);
1163 
1164  //add this subsystem to destination subsystem's sources, if not there
1165  if(!subsystems.count(subsystems[readerSubsystemID].destination) ||
1166  !subsystems[subsystems[readerSubsystemID].destination]
1167  .sources.count(readerSubsystemID))
1168  {
1169  subsystems[subsystems[readerSubsystemID].destination]
1170  .sources.insert(readerSubsystemID);
1171  }
1172 
1173  } //end subsystem instantiation
1174 
1175  __COUT__ << "Found BoardReader with UID " << readerUID
1176  << ", DAQInterface Hostname " << readerHost
1177  << ", and Subsystem " << readerSubsystemID << __E__;
1178  readerInfo.emplace_back(readerUID, readerHost, readerSubsystemID);
1179 
1180  if(doWriteFHiCL)
1181  ARTDAQTableBase::outputReaderFHICL(
1182  reader.second,
1183  readerHost,
1184  maxFragmentSizeBytes);
1185  }
1186  else
1187  {
1188  __COUT__ << "BoardReader "
1189  << reader.second.getNode("SupervisorUID").getValue()
1190  << " is disabled." << __E__;
1191  }
1192  }
1193  }
1194  else
1195  {
1196  __SS__ << "Error: There should be at least one BoardReader!";
1197  __SS_THROW__;
1198  return;
1199  }
1200  }
1201 
1202  if(progressBar)
1203  progressBar->step();
1204 
1205  std::list<ARTDAQTableBase::ProcessInfo>& builderInfo =
1206  processes[ARTDAQTableBase::ARTDAQAppType::EventBuilder];
1207  {
1208  auto buildersLink = artdaqSupervisorNode.getNode("eventbuildersLink");
1209  if(!buildersLink.isDisconnected() && buildersLink.getChildren().size() > 0)
1210  {
1211  auto builders = buildersLink.getChildren();
1212 
1213  for(auto& builder : builders)
1214  {
1215  if(builder.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
1216  .getValue<bool>())
1217  {
1218  auto builderUID = builder.second.getNode("SupervisorUID").getValue();
1219  auto builderHost =
1220  builder.second.getNode("DAQInterfaceHostname").getValue();
1221 
1222  auto builderSubsystemID = 1;
1223  auto builderSubsystemLink = builder.second.getNode("SubsystemLink");
1224  if(!builderSubsystemLink.isDisconnected())
1225  {
1226  builderSubsystemID = ARTDAQTableBase::getSubsytemId(builderSubsystemLink);
1227  __COUTV__(builderSubsystemID);
1228 
1229  subsystems[builderSubsystemID].id = builderSubsystemID;
1230 
1231  const std::string& builderSubsystemName =
1232  builderSubsystemLink.getUIDAsString();
1233  __COUTV__(builderSubsystemName);
1234 
1235  subsystems[builderSubsystemID].label = builderSubsystemName;
1236 
1237  auto builderSubsystemDestinationLink =
1238  builderSubsystemLink.getNode("SubsystemDestinationLink");
1239  if(builderSubsystemDestinationLink.isDisconnected())
1240  {
1241  //default to no destination when no link
1242  subsystems[builderSubsystemID].destination = 0;
1243  }
1244  else
1245  {
1246  //get destination subsystem id
1247  subsystems[builderSubsystemID].destination =
1248  ARTDAQTableBase::getSubsytemId(builderSubsystemDestinationLink);
1249  }
1250  __COUTV__(subsystems[builderSubsystemID].destination);
1251 
1252  //add this subsystem to destination subsystem's sources, if not there
1253  if(!subsystems.count(subsystems[builderSubsystemID].destination) ||
1254  !subsystems[subsystems[builderSubsystemID].destination]
1255  .sources.count(builderSubsystemID))
1256  {
1257  subsystems[subsystems[builderSubsystemID].destination]
1258  .sources.insert(builderSubsystemID);
1259  }
1260 
1261  } //end subsystem instantiation
1262 
1263  __COUT__ << "Found EventBuilder with UID " << builderUID
1264  << ", DAQInterface Hostname " << builderHost
1265  << ", and Subsystem " << builderSubsystemID << __E__;
1266  builderInfo.emplace_back(builderUID, builderHost, builderSubsystemID);
1267 
1268  if(doWriteFHiCL)
1269  ARTDAQTableBase::outputDataReceiverFHICL(
1270  builder.second,
1271  builderHost,
1272  ARTDAQTableBase::ARTDAQAppType::EventBuilder,
1273  maxFragmentSizeBytes);
1274  }
1275  else
1276  {
1277  __COUT__ << "EventBuilder "
1278  << builder.second.getNode("SupervisorUID").getValue()
1279  << " is disabled." << __E__;
1280  }
1281  }
1282  }
1283  else
1284  {
1285  __SS__ << "Error: There should be at least one EventBuilder!";
1286  __SS_THROW__;
1287  return;
1288  }
1289  }
1290 
1291  if(progressBar)
1292  progressBar->step();
1293 
1294  std::list<ARTDAQTableBase::ProcessInfo>& loggerInfo =
1295  processes[ARTDAQTableBase::ARTDAQAppType::DataLogger];
1296  {
1297  auto dataloggersLink = artdaqSupervisorNode.getNode("dataloggersLink");
1298  if(!dataloggersLink.isDisconnected())
1299  {
1300  auto dataloggers = dataloggersLink.getChildren();
1301 
1302  for(auto& datalogger : dataloggers)
1303  {
1304  if(datalogger.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
1305  .getValue<bool>())
1306  {
1307  auto loggerHost =
1308  datalogger.second.getNode("DAQInterfaceHostname").getValue();
1309  auto loggerUID =
1310  datalogger.second.getNode("SupervisorUID").getValue();
1311 
1312  auto loggerSubsystemID = 1;
1313  auto loggerSubsystemLink = datalogger.second.getNode("SubsystemLink");
1314  if(!loggerSubsystemLink.isDisconnected())
1315  {
1316  loggerSubsystemID = ARTDAQTableBase::getSubsytemId(loggerSubsystemLink);
1317  __COUTV__(loggerSubsystemID);
1318  subsystems[loggerSubsystemID].id = loggerSubsystemID;
1319 
1320  const std::string& loggerSubsystemName =
1321  loggerSubsystemLink.getUIDAsString();
1322  __COUTV__(loggerSubsystemName);
1323 
1324  subsystems[loggerSubsystemID].label = loggerSubsystemName;
1325 
1326  auto loggerSubsystemDestinationLink =
1327  loggerSubsystemLink.getNode("SubsystemDestinationLink");
1328  if(loggerSubsystemDestinationLink.isDisconnected())
1329  {
1330  //default to no destination when no link
1331  subsystems[loggerSubsystemID].destination = 0;
1332  }
1333  else
1334  {
1335  //get destination subsystem id
1336  subsystems[loggerSubsystemID].destination =
1337  ARTDAQTableBase::getSubsytemId(loggerSubsystemDestinationLink);
1338  }
1339  __COUTV__(subsystems[loggerSubsystemID].destination);
1340 
1341  //add this subsystem to destination subsystem's sources, if not there
1342  if(!subsystems.count(subsystems[loggerSubsystemID].destination) ||
1343  !subsystems[subsystems[loggerSubsystemID].destination]
1344  .sources.count(loggerSubsystemID))
1345  {
1346  subsystems[subsystems[loggerSubsystemID].destination]
1347  .sources.insert(loggerSubsystemID);
1348  }
1349 
1350  } //end subsystem instantiation
1351 
1352  __COUT__ << "Found DataLogger with UID " << loggerUID
1353  << ", DAQInterface Hostname " << loggerHost
1354  << ", and Subsystem " << loggerSubsystemID << __E__;
1355  loggerInfo.emplace_back(loggerUID, loggerHost, loggerSubsystemID);
1356 
1357  if(doWriteFHiCL)
1358  ARTDAQTableBase::outputDataReceiverFHICL(
1359  datalogger.second,
1360  loggerHost,
1361  ARTDAQTableBase::ARTDAQAppType::DataLogger,
1362  maxFragmentSizeBytes);
1363  }
1364  else
1365  {
1366  __COUT__ << "DataLogger "
1367  << datalogger.second.getNode("SupervisorUID").getValue()
1368  << " is disabled." << __E__;
1369  }
1370  }
1371  }
1372  }
1373 
1374  std::list<ARTDAQTableBase::ProcessInfo>& dispatcherInfo =
1375  processes[ARTDAQTableBase::ARTDAQAppType::Dispatcher];
1376  {
1377  auto dispatchersLink = artdaqSupervisorNode.getNode("dispatchersLink");
1378  if(!dispatchersLink.isDisconnected())
1379  {
1380  auto dispatchers = dispatchersLink.getChildren();
1381 
1382  for(auto& dispatcher : dispatchers)
1383  {
1384  if(dispatcher.second.getNode(TableViewColumnInfo::COL_NAME_STATUS)
1385  .getValue<bool>())
1386  {
1387  auto dispatcherHost =
1388  dispatcher.second.getNode("DAQInterfaceHostname").getValue();
1389  auto dispatcherUID = dispatcher.second.getNode("SupervisorUID").getValue();
1390 
1391  auto dispatcherSubsystemID = 1;
1392  auto dispatcherSubsystemLink = dispatcher.second.getNode("SubsystemLink");
1393  if(!dispatcherSubsystemLink.isDisconnected())
1394  {
1395  dispatcherSubsystemID = ARTDAQTableBase::getSubsytemId(dispatcherSubsystemLink);
1396  __COUTV__(dispatcherSubsystemID);
1397  subsystems[dispatcherSubsystemID].id = dispatcherSubsystemID;
1398 
1399  const std::string& dispatcherSubsystemName =
1400  dispatcherSubsystemLink.getUIDAsString();
1401  __COUTV__(dispatcherSubsystemName);
1402 
1403  subsystems[dispatcherSubsystemID].label = dispatcherSubsystemName;
1404 
1405  auto dispatcherSubsystemDestinationLink =
1406  dispatcherSubsystemLink.getNode("SubsystemDestinationLink");
1407  if(dispatcherSubsystemDestinationLink.isDisconnected())
1408  {
1409  //default to no destination when no link
1410  subsystems[dispatcherSubsystemID].destination = 0;
1411  }
1412  else
1413  {
1414  //get destination subsystem id
1415  subsystems[dispatcherSubsystemID].destination =
1416  ARTDAQTableBase::getSubsytemId(dispatcherSubsystemDestinationLink);
1417  }
1418  __COUTV__(subsystems[dispatcherSubsystemID].destination);
1419 
1420  //add this subsystem to destination subsystem's sources, if not there
1421  if(!subsystems.count(subsystems[dispatcherSubsystemID].destination) ||
1422  !subsystems[subsystems[dispatcherSubsystemID].destination]
1423  .sources.count(dispatcherSubsystemID))
1424  {
1425  subsystems[subsystems[dispatcherSubsystemID].destination]
1426  .sources.insert(dispatcherSubsystemID);
1427  }
1428  }
1429 
1430  __COUT__ << "Found Dispatcher with UID " << dispatcherUID
1431  << ", DAQInterface Hostname " << dispatcherHost
1432  << ", and Subsystem " << dispatcherSubsystemID << __E__;
1433  dispatcherInfo.emplace_back(dispatcherUID, dispatcherHost, dispatcherSubsystemID);
1434 
1435  if(doWriteFHiCL)
1436  ARTDAQTableBase::outputDataReceiverFHICL(
1437  dispatcher.second,
1438  dispatcherHost,
1439  ARTDAQTableBase::ARTDAQAppType::Dispatcher,
1440  maxFragmentSizeBytes);
1441  }
1442  else
1443  {
1444  __COUT__ << "Dispatcher "
1445  << dispatcher.second.getNode("SupervisorUID").getValue()
1446  << " is disabled." << __E__;
1447  }
1448  }
1449  }
1450  }
1451 
1452 } // end extractArtdaqInfo()
1453 
1454 //==============================================================================
1455 int ARTDAQTableBase::getSubsytemId(ConfigurationTree subsystemNode)
1456 {
1457  //using row forces a unique ID from 0 to rows-1
1458  // note: default no defined subsystem link to id=1; so add 2
1459 
1460  return subsystemNode.getNodeRow() + 2;
1461 } //end getSubsytemId()
1462 
1463 
1464 
1465 
1466