otsdaq  v1_01_04
 All Classes Namespaces Functions
ARTDAQBoardReaderConfiguration_configuration.cc
1 #include "otsdaq-core/ConfigurationPluginDataFormats/ARTDAQBoardReaderConfiguration.h"
2 #include "otsdaq-core/Macros/ConfigurationPluginMacros.h"
3 #include "otsdaq-core/ConfigurationInterface/ConfigurationManager.h"
4 #include "otsdaq-core/ConfigurationPluginDataFormats/XDAQContextConfiguration.h"
5 
6 #include <iostream>
7 #include <fstream> // std::fstream
8 #include <stdio.h>
9 #include <sys/stat.h> //for mkdir
10 
11 using namespace ots;
12 
13 
14 #define ARTDAQ_FCL_PATH std::string(getenv("USER_DATA")) + "/"+ "ARTDAQConfigurations/"
15 #define ARTDAQ_FILE_PREAMBLE "boardReader"
16 
17 //helpers
18 #define OUT out << tabStr << commentStr
19 #define PUSHTAB tabStr += "\t"
20 #define POPTAB tabStr.resize(tabStr.size()-1)
21 #define PUSHCOMMENT commentStr += "# "
22 #define POPCOMMENT commentStr.resize(commentStr.size()-2)
23 
24 
25 //========================================================================================================================
26 ARTDAQBoardReaderConfiguration::ARTDAQBoardReaderConfiguration(void)
27 : ConfigurationBase("ARTDAQBoardReaderConfiguration")
28 {
30  //WARNING: the names used in C++ MUST match the Configuration INFO //
32 
33 }
34 
35 //========================================================================================================================
36 ARTDAQBoardReaderConfiguration::~ARTDAQBoardReaderConfiguration(void)
37 {}
38 
39 //========================================================================================================================
40 void ARTDAQBoardReaderConfiguration::init(ConfigurationManager* configManager)
41 {
42  //make directory just in case
43  mkdir((ARTDAQ_FCL_PATH).c_str(), 0755);
44 
45  __COUT__ << "*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*" << std::endl;
46  __COUT__ << configManager->__SELF_NODE__ << std::endl;
47 
48  const XDAQContextConfiguration *contextConfig = configManager->__GET_CONFIG__(XDAQContextConfiguration);
49 
50 // //ConfigurationTree contextNode = configManager->getNode(contextConfig->getConfigurationName());
51 //
52 // auto childrenMap = configManager->__SELF_NODE__.getChildren();
53 //
54 // //std::string appUID, buffUID, consumerUID;
55 // for(auto &child:childrenMap)
56 // if(child.second.getNode(ViewColumnInfo::COL_NAME_STATUS).getValue<bool>())
57 // {
60 // outputFHICL(child.second, contextConfig);
61 // }
62 
63  std::vector<const XDAQContextConfiguration::XDAQContext *> readerContexts =
64  contextConfig->getBoardReaderContexts();
65 
66 
67 
68 
69  //for each reader context
70  // do NOT output associated fcl config file
71  // but do check the link is to a DataManager-esque thing
72  for(auto &readerContext: readerContexts)
73  {
74  try
75  {
76  ConfigurationTree readerConfigNode = contextConfig->getSupervisorConfigNode(configManager,
77  readerContext->contextUID_, readerContext->applications_[0].applicationUID_);
78 
79  __COUT__ << "Path for this reader config is " <<
80  readerContext->contextUID_ << "/" <<
81  readerContext->applications_[0].applicationUID_ << "/" <<
82  readerConfigNode.getValueAsString() <<
83  std::endl;
84 
85  __COUT__ << "Checking that this reader supervisor node is DataManager-like." << std::endl;
86 
87  readerConfigNode.getNode("LinkToDataManagerConfiguration").getChildren();
88  }
89  catch(const std::runtime_error& e)
90  {
91  __SS__ << "artdaq Board Readers must be instantiated as a Consumer within a DataManager configuration. Error found while checking for LinkToDataManagerConfiguration: " <<
92  e.what() << std::endl;
93  __COUT_ERR__ << ss.str();
94  __COUT__ << "Path for this reader config is " <<
95  readerContext->contextUID_ << "/" <<
96  readerContext->applications_[0].applicationUID_ << "/X" << std::endl;
97  __COUT_ERR__ << "This board reader will likely not get instantiated properly! Proceeding anyway with fcl generation." << std::endl;
98 
99  //proceed anyway, because it was really annoying to not be able to activate the configuration group when the context is being developed also.
100  //throw std::runtime_error(ss.str());
101  }
102 
103  //artdaq Reader is not at Supervisor level like other apps
104  // it is at Consumer level!
105  //outputFHICL(readerConfigNode,
106  // contextConfig);
107  }
108 
109  //handle fcl file generation, wherever the level of this configuration
110 
111  auto childrenMap = configManager->__SELF_NODE__.getChildren();
112  std::string appUID, buffUID, consumerUID;
113 
114  for(auto &child:childrenMap)
115  if(child.second.getNode(ViewColumnInfo::COL_NAME_STATUS).getValue<bool>())
116  {
117  outputFHICL(child.second, contextConfig);
118  }
119 }
120 
122 //void ARTDAQBoardReaderConfiguration::getBoardReaderParents(const ConfigurationTree &readerNode,
123 // const ConfigurationTree &contextNode, std::string &applicationUID,
124 // std::string &bufferUID, std::string &consumerUID)
125 //{
126 // //search through all board reader contexts
127 // contextNode.getNode()
128 //}
129 
130 //========================================================================================================================
131 std::string ARTDAQBoardReaderConfiguration::getFHICLFilename(const ConfigurationTree &boardReaderNode)
132 {
133  __COUT__ << "ARTDAQ BoardReader UID: " << boardReaderNode.getValue() << std::endl;
134  std::string filename = ARTDAQ_FCL_PATH + ARTDAQ_FILE_PREAMBLE + "-";
135  std::string uid = boardReaderNode.getValue();
136  for(unsigned int i=0;i<uid.size();++i)
137  if((uid[i] >= 'a' && uid[i] <= 'z') ||
138  (uid[i] >= 'A' && uid[i] <= 'Z') ||
139  (uid[i] >= '0' && uid[i] <= '9')) //only allow alpha numeric in file name
140  filename += uid[i];
141 
142  filename += ".fcl";
143 
144  __COUT__ << "fcl: " << filename << std::endl;
145 
146  return filename;
147 }
148 
149 //========================================================================================================================
150 void ARTDAQBoardReaderConfiguration::outputFHICL(const ConfigurationTree &boardReaderNode,
151  const XDAQContextConfiguration *contextConfig)
152 {
153  /*
154  the file will look something like this:
155 
156  daq: {
157  fragment_receiver: {
158  mpi_sync_interval: 50
159 
160  # CommandableFragmentGenerator Configuration:
161  fragment_ids: []
162  fragment_id: -99 # Please define only one of these
163 
164  sleep_on_stop_us: 0
165 
166  requests_enabled: false # Whether to set up the socket for listening for trigger messages
167  request_mode: "Ignored" # Possible values are: Ignored, Single, Buffer, Window
168 
169  data_buffer_depth_fragments: 1000
170  data_buffer_depth_mb: 1000
171 
172  request_port: 3001
173  request_address: "227.128.12.26" # Multicast request address
174 
175  request_window_offset: 0 # Request message contains tzero. Window will be from tzero - offset to tzero + width
176  request_window_width: 0
177  stale_request_timeout: "0xFFFFFFFF" # How long to wait before discarding request messages that are outside the available data
178  request_windows_are_unique: true # If request windows are unique, avoids a copy operation, but the same data point cannot be used for two requests. If this is not anticipated, leave set to "true"
179 
180  separate_data_thread: false # MUST be true for triggers to be applied! If triggering is not desired, but a separate readout thread is, set this to true, triggers_enabled to false and trigger_mode to ignored.
181  separate_monitoring_thread: false # Whether a thread should be started which periodically calls checkHWStatus_, a user-defined function which should be used to check hardware status registers and report to MetricMan.
182  poll_hardware_status: false # Whether checkHWStatus_ will be called, either through the thread or at the start of getNext
183  hardware_poll_interval_us: 1000000 # If hardware monitoring thread is enabled, how often should it call checkHWStatus_
184 
185 
186  # Generated Parameters:
187  generator: ToySimulator
188  fragment_type: TOY1
189  fragment_id: 0
190  board_id: 0
191  starting_fragment_id: 0
192  random_seed: 5780
193  sleep_on_stop_us: 500000
194 
195  # Generator-Specific Configuration:
196 
197  nADCcounts: 40
198 
199  throttle_usecs: 100000
200 
201  distribution_type: 1
202 
203  timestamp_scale_factor: 1
204 
205 
206  destinations: {
207  d2: { transferPluginType: MPI destination_rank: 2 max_fragment_size_words: 2097152}
208  d3: { transferPluginType: MPI destination_rank: 3 max_fragment_size_words: 2097152}
209 
210  }
211  }
212 
213  metrics: {
214  brFile: {
215  metricPluginType: "file"
216  level: 3
217  fileName: "/tmp/boardreader/br_%UID%_metrics.log"
218  uniquify: true
219  }
220  # ganglia: {
221  # metricPluginType: "ganglia"
222  # level: %{ganglia_level}
223  # reporting_interval: 15.0
224  #
225  # configFile: "/etc/ganglia/gmond.conf"
226  # group: "ARTDAQ"
227  # }
228  # msgfac: {
229  # level: %{mf_level}
230  # metricPluginType: "msgFacility"
231  # output_message_application_name: "ARTDAQ Metric"
232  # output_message_severity: 0
233  # }
234  # graphite: {
235  # level: %{graphite_level}
236  # metricPluginType: "graphite"
237  # host: "localhost"
238  # port: 20030
239  # namespace: "artdaq."
240  # }
241  }
242  }
243 
244  */
245 
246  std::string filename = getFHICLFilename(boardReaderNode);
247 
249  //generate xdaq run parameter file
250  std::fstream out;
251 
252  std::string tabStr = "";
253  std::string commentStr = "";
254 
255  out.open(filename, std::fstream::out | std::fstream::trunc);
256  if(out.fail())
257  {
258  __SS__ << "Failed to open ARTDAQ Builder fcl file: " << filename << std::endl;
259  throw std::runtime_error(ss.str());
260  }
261 
262  //no primary link to configuration tree for reader node!
263  try
264  {
265  if(boardReaderNode.isDisconnected())
266  {
267  //create empty fcl
268  OUT << "{}\n\n";
269  out.close();
270  return;
271  }
272  }
273  catch(const std::runtime_error)
274  {
275  __COUT__ << "Ignoring error, assume this a valid UID node." << std::endl;
276  //error is expected here for UIDs.. so just ignore
277  // this check is valuable if source node is a unique-Link node, rather than UID
278  }
279 
280  //--------------------------------------
281  //handle daq
282  OUT << "daq: {\n";
283 
284  //fragment_receiver
285  PUSHTAB;
286  OUT << "fragment_receiver: {\n";
287 
288  PUSHTAB;
289  {
290  //plugin type and fragment data-type
291  OUT << "generator" <<
292  ": " <<
293  boardReaderNode.getNode("daqGeneratorPluginType").getValue()<<
294  ("\t #daq generator plug-in type") <<
295  "\n";
296  OUT << "fragment_type" <<
297  ": " <<
298  boardReaderNode.getNode("daqGeneratorFragmentType").getValue() <<
299  ("\t #generator data fragment type") <<
300  "\n\n";
301 
302  //shared and unique parameters
303  auto parametersLink = boardReaderNode.getNode("daqParametersLink");
304  if(!parametersLink.isDisconnected())
305  {
306 
307  auto parameters = parametersLink.getChildren();
308  for(auto &parameter:parameters)
309  {
310  if(!parameter.second.getNode(ViewColumnInfo::COL_NAME_STATUS).getValue<bool>())
311  PUSHCOMMENT;
312 
313  // __COUT__ << parameter.second.getNode("daqParameterKey").getValue() <<
314  // ": " <<
315  // parameter.second.getNode("daqParameterValue").getValue()
316  // <<
317  // "\n";
318 
319  auto comment = parameter.second.getNode("CommentDescription");
320  OUT << parameter.second.getNode("daqParameterKey").getValue() <<
321  ": " <<
322  parameter.second.getNode("daqParameterValue").getValue()
323  <<
324  (comment.isDefaultValue()?"":("\t # " + comment.getValue())) <<
325  "\n";
326 
327  if(!parameter.second.getNode(ViewColumnInfo::COL_NAME_STATUS).getValue<bool>())
328  POPCOMMENT;
329  }
330  }
331  OUT << "\n"; //end daq board reader parameters
332  }
333 // { //unique parameters
334 // auto parametersLink = boardReaderNode.getNode("daqUniqueParametersLink");
335 // if(!parametersLink.isDisconnected())
336 // {
337 //
338 // auto parameters = parametersLink.getChildren();
339 // for(auto &parameter:parameters)
340 // {
341 // if(!parameter.second.getNode(ViewColumnInfo::COL_NAME_STATUS).getValue<bool>())
342 // PUSHCOMMENT;
343 //
344 // auto comment = parameter.second.getNode("CommentDescription");
345 // OUT << parameter.second.getNode("daqParameterKey").getValue() <<
346 // ": " <<
347 // parameter.second.getNode("daqParameterValue").getValue()
348 // <<
349 // (comment.isDefaultValue()?"":("\t # " + comment.getValue())) <<
350 // "\n";
351 //
352 // if(!parameter.second.getNode(ViewColumnInfo::COL_NAME_STATUS).getValue<bool>())
353 // POPCOMMENT;
354 // }
355 // }
356 // OUT << "\n"; //end shared daq board reader parameters
357 // }
358 
359  OUT << "destinations: {\n";
360 
361  PUSHTAB;
362  auto destinationsGroup = boardReaderNode.getNode("daqDestinationsLink");
363  if(!destinationsGroup.isDisconnected())
364  {
365  try
366  {
367  auto destinations = destinationsGroup.getChildren();
368  for(auto &destination:destinations)
369  {
370  unsigned int destinationRank =
371  contextConfig->getARTDAQAppRank(
372  destination.second.getNode("destinationARTDAQContextLink").getValue());
373  OUT << destination.second.getNode("destinationKey").getValue() <<
374  ": {" <<
375  " transferPluginType: " <<
376  destination.second.getNode("transferPluginType").getValue() <<
377  " destination_rank: " <<
378  destinationRank <<
379  " max_fragment_size_words: " <<
380  destination.second.getNode("ARTDAQGlobalConfigurationLink/maxFragmentSizeWords").getValue<unsigned int>() <<
381  "}\n";
382  }
383  }
384  catch(const std::runtime_error& e)
385  {
386  __SS__ << "Are the DAQ destinations valid? Error occurred looking for Board Reader DAQ sources for UID '" <<
387  boardReaderNode.getValue() << "': " << e.what() << std::endl;
388  __COUT_ERR__ << ss.str() << std::endl;
389  throw std::runtime_error(ss.str());
390  }
391  }
392  POPTAB;
393  OUT << "}\n\n"; //end destinations
394 
395  POPTAB;
396  OUT << "}\n\n"; //end fragment_receiver
397 
398 
399  OUT << "metrics: {\n";
400 
401  PUSHTAB;
402  auto metricsGroup = boardReaderNode.getNode("daqMetricsLink");
403  if(!metricsGroup.isDisconnected())
404  {
405  auto metrics = metricsGroup.getChildren();
406 
407  for(auto &metric:metrics)
408  {
409  if(!metric.second.getNode(ViewColumnInfo::COL_NAME_STATUS).getValue<bool>())
410  PUSHCOMMENT;
411 
412  OUT << metric.second.getNode("metricKey").getValue() <<
413  ": {\n";
414  PUSHTAB;
415 
416  OUT << "metricPluginType: " <<
417  metric.second.getNode("metricPluginType").getValue()
418  << "\n";
419  OUT << "level: " <<
420  metric.second.getNode("metricLevel").getValue()
421  << "\n";
422 
423  auto metricParametersGroup = metric.second.getNode("metricParametersLink");
424  if(!metricParametersGroup.isDisconnected())
425  {
426  auto metricParameters = metricParametersGroup.getChildren();
427  for(auto &metricParameter:metricParameters)
428  {
429  if(!metricParameter.second.getNode(ViewColumnInfo::COL_NAME_STATUS).getValue<bool>())
430  PUSHCOMMENT;
431 
432  OUT << metricParameter.second.getNode("metricParameterKey").getValue() <<
433  ": " <<
434  metricParameter.second.getNode("metricParameterValue").getValue()
435  << "\n";
436 
437  if(!metricParameter.second.getNode(ViewColumnInfo::COL_NAME_STATUS).getValue<bool>())
438  POPCOMMENT;
439 
440  }
441  }
442  POPTAB;
443  OUT << "}\n\n"; //end metric
444 
445  if(!metric.second.getNode(ViewColumnInfo::COL_NAME_STATUS).getValue<bool>())
446  POPCOMMENT;
447  }
448  }
449  POPTAB;
450  OUT << "}\n\n"; //end metrics
451 
452  POPTAB;
453  OUT << "}\n\n"; //end daq
454 
455 
456  out.close();
457 }
458 
459 DEFINE_OTS_CONFIGURATION(ARTDAQBoardReaderConfiguration)