artdaq  v3_06_00
BoardReaderCore.cc
1 
2 #include "artdaq/DAQdata/Globals.hh" // include these 2 first -
3 #define TRACE_NAME (app_name + "_BoardReaderCore").c_str()
4 #include "artdaq/Application/TaskType.hh"
5 #include "artdaq/Application/BoardReaderCore.hh"
6 #include "artdaq-core/Data/Fragment.hh"
7 #include "artdaq-core/Utilities/ExceptionHandler.hh"
8 #include "artdaq/Generators/makeCommandableFragmentGenerator.hh"
9 #include "canvas/Utilities/Exception.h"
10 #include "cetlib_except/exception.h"
11 #include <pthread.h>
12 #include <sched.h>
13 #include <algorithm>
14 
15 const std::string artdaq::BoardReaderCore::
16 FRAGMENTS_PROCESSED_STAT_KEY("BoardReaderCoreFragmentsProcessed");
17 const std::string artdaq::BoardReaderCore::
18 INPUT_WAIT_STAT_KEY("BoardReaderCoreInputWaitTime");
19 const std::string artdaq::BoardReaderCore::
20 BRSYNC_WAIT_STAT_KEY("BoardReaderCoreBRSyncWaitTime");
21 const std::string artdaq::BoardReaderCore::
22 OUTPUT_WAIT_STAT_KEY("BoardReaderCoreOutputWaitTime");
23 const std::string artdaq::BoardReaderCore::
24 FRAGMENTS_PER_READ_STAT_KEY("BoardReaderCoreFragmentsPerRead");
25 
26 std::unique_ptr<artdaq::DataSenderManager> artdaq::BoardReaderCore::sender_ptr_ = nullptr;
27 
29  parent_application_(parent_application)
30  /*, local_group_comm_(local_group_comm)*/
31  , generator_ptr_(nullptr)
32  , stop_requested_(false)
33  , pause_requested_(false)
34 {
35  TLOG(TLVL_DEBUG) << "Constructor";
41 }
42 
44 {
45  TLOG(TLVL_DEBUG) << "Destructor";
46 }
47 
48 bool artdaq::BoardReaderCore::initialize(fhicl::ParameterSet const& pset, uint64_t, uint64_t)
49 {
50  TLOG(TLVL_DEBUG) << "initialize method called with " << "ParameterSet = \"" << pset.to_string() << "\".";
51 
52  // pull out the relevant parts of the ParameterSet
53  fhicl::ParameterSet daq_pset;
54  try
55  {
56  daq_pset = pset.get<fhicl::ParameterSet>("daq");
57  }
58  catch (...)
59  {
60  TLOG(TLVL_ERROR)
61  << "Unable to find the DAQ parameters in the initialization "
62  << "ParameterSet: \"" + pset.to_string() + "\".";
63  return false;
64  }
65  fhicl::ParameterSet fr_pset;
66  try
67  {
68  fr_pset = daq_pset.get<fhicl::ParameterSet>("fragment_receiver");
69  data_pset_ = fr_pset;
70  }
71  catch (...)
72  {
73  TLOG(TLVL_ERROR)
74  << "Unable to find the fragment_receiver parameters in the DAQ "
75  << "initialization ParameterSet: \"" + daq_pset.to_string() + "\".";
76  return false;
77  }
78 
79  // pull out the Metric part of the ParameterSet
80  fhicl::ParameterSet metric_pset;
81  try
82  {
83  metric_pset = daq_pset.get<fhicl::ParameterSet>("metrics");
84  }
85  catch (...) {} // OK if there's no metrics table defined in the FHiCL
86 
87  if (metric_pset.is_empty())
88  {
89  TLOG(TLVL_INFO) << "No metric plugins appear to be defined";
90  }
91  try
92  {
93  metricMan->initialize(metric_pset, app_name);
94  }
95  catch (...)
96  {
97  ExceptionHandler(ExceptionHandlerRethrow::no,
98  "Error loading metrics in BoardReaderCore::initialize()");
99  }
100 
101  if (daq_pset.has_key("rank"))
102  {
103  if (my_rank >= 0 && daq_pset.get<int>("rank") != my_rank) {
104  TLOG(TLVL_WARNING) << "BoardReader rank specified at startup is different than rank specified at configure! Using rank received at configure!";
105  }
106  my_rank = daq_pset.get<int>("rank");
107  }
108  if (my_rank == -1)
109  {
110  TLOG(TLVL_ERROR) << "BoardReader rank not specified at startup or in configuration! Aborting";
111  exit(1);
112  }
113 
114 
115  // create the requested CommandableFragmentGenerator
116  std::string frag_gen_name = fr_pset.get<std::string>("generator", "");
117  if (frag_gen_name.length() == 0)
118  {
119  TLOG(TLVL_ERROR)
120  << "No fragment generator (parameter name = \"generator\") was "
121  << "specified in the fragment_receiver ParameterSet. The "
122  << "DAQ initialization PSet was \"" << daq_pset.to_string() << "\".";
123  return false;
124  }
125 
126  try
127  {
128  generator_ptr_ = artdaq::makeCommandableFragmentGenerator(frag_gen_name, fr_pset);
129  }
130  catch (...)
131  {
132  std::stringstream exception_string;
133  exception_string << "Exception thrown during initialization of fragment generator of type \""
134  << frag_gen_name << "\"";
135 
136  ExceptionHandler(ExceptionHandlerRethrow::no, exception_string.str());
137 
138  TLOG(TLVL_DEBUG) << "FHiCL parameter set used to initialize the fragment generator which threw an exception: " << fr_pset.to_string();
139 
140  return false;
141  }
142  metricMan->setPrefix(generator_ptr_->metricsReportingInstanceName());
143 
144  rt_priority_ = fr_pset.get<int>("rt_priority", 0);
145 
146  // fetch the monitoring parameters and create the MonitoredQuantity instances
147  statsHelper_.createCollectors(fr_pset, 100, 30.0, 60.0, FRAGMENTS_PROCESSED_STAT_KEY);
148 
149  // check if we should skip the sequence ID test...
150  skip_seqId_test_ = (generator_ptr_->fragmentIDs().size() > 1 || generator_ptr_->request_mode() != RequestMode::Ignored);
151 
152  verbose_ = fr_pset.get<bool>("verbose", true);
153 
154  return true;
155 }
156 
157 bool artdaq::BoardReaderCore::start(art::RunID id, uint64_t timeout, uint64_t timestamp)
158 {
159  logMessage_("Starting run " + boost::lexical_cast<std::string>(id.run()));
160  stop_requested_.store(false);
161  pause_requested_.store(false);
162 
163  fragment_count_ = 0;
164  prev_seq_id_ = 0;
165  statsHelper_.resetStatistics();
166 
167  metricMan->do_start();
168  generator_ptr_->StartCmd(id.run(), timeout, timestamp);
169  run_id_ = id;
170 
171  logMessage_("Completed the Start transition (Started run) for run " +
172  boost::lexical_cast<std::string>(run_id_.run()) +
173  ", timeout = " + boost::lexical_cast<std::string>(timeout) +
174  ", timestamp = " + boost::lexical_cast<std::string>(timestamp));
175  return true;
176 }
177 
178 bool artdaq::BoardReaderCore::stop(uint64_t timeout, uint64_t timestamp)
179 {
180  logMessage_("Stopping run " + boost::lexical_cast<std::string>(run_id_.run()) +
181  " after " + boost::lexical_cast<std::string>(fragment_count_) + " fragments.");
182  stop_requested_.store(true);
183 
184  TLOG(TLVL_DEBUG) << "Stopping CommandableFragmentGenerator BEGIN";
185  generator_ptr_->StopCmd(timeout, timestamp);
186  TLOG(TLVL_DEBUG) << "Stopping CommandableFragmentGenerator END";
187 
188  TLOG(TLVL_DEBUG) << "Stopping DataSenderManager";
189  if(sender_ptr_) sender_ptr_->StopSender();
190 
191  logMessage_("Completed the Stop transition for run " + boost::lexical_cast<std::string>(run_id_.run()));
192  return true;
193 }
194 
195 bool artdaq::BoardReaderCore::pause(uint64_t timeout, uint64_t timestamp)
196 {
197  logMessage_("Pausing run " + boost::lexical_cast<std::string>(run_id_.run()) +
198  " after " + boost::lexical_cast<std::string>(fragment_count_) + " fragments.");
199  pause_requested_.store(true);
200  generator_ptr_->PauseCmd(timeout, timestamp);
201  logMessage_("Completed the Pause transition for run " + boost::lexical_cast<std::string>(run_id_.run()));
202  return true;
203 }
204 
205 bool artdaq::BoardReaderCore::resume(uint64_t timeout, uint64_t timestamp)
206 {
207  logMessage_("Resuming run " + boost::lexical_cast<std::string>(run_id_.run()));
208  pause_requested_.store(false);
209  metricMan->do_start();
210  generator_ptr_->ResumeCmd(timeout, timestamp);
211  logMessage_("Completed the Resume transition for run " + boost::lexical_cast<std::string>(run_id_.run()));
212  return true;
213 }
214 
216 {
217  logMessage_("Starting Shutdown transition");
218  generator_ptr_->joinThreads(); // Cleanly shut down the CommandableFragmentGenerator
219  generator_ptr_.reset(nullptr);
220  metricMan->shutdown();
221  logMessage_("Completed Shutdown transition");
222  return true;
223 }
224 
225 bool artdaq::BoardReaderCore::soft_initialize(fhicl::ParameterSet const& pset, uint64_t, uint64_t)
226 {
227  TLOG(TLVL_DEBUG) << "soft_initialize method called with "
228  << "ParameterSet = \"" << pset.to_string()
229  << "\".";
230  return true;
231 }
232 
233 bool artdaq::BoardReaderCore::reinitialize(fhicl::ParameterSet const& pset, uint64_t, uint64_t)
234 {
235  TLOG(TLVL_DEBUG) << "reinitialize method called with "
236  << "ParameterSet = \"" << pset.to_string()
237  << "\".";
238  return true;
239 }
240 
242 {
243  if (rt_priority_ > 0)
244  {
245 #pragma GCC diagnostic push
246 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
247  sched_param s_param = {};
248  s_param.sched_priority = rt_priority_;
249  if (pthread_setschedparam(pthread_self(), SCHED_RR, &s_param))
250  TLOG(TLVL_WARNING) << "setting realtime priority failed";
251 #pragma GCC diagnostic pop
252  }
253 
254  // try-catch block here?
255 
256  // how to turn RT PRI off?
257  if (rt_priority_ > 0)
258  {
259 #pragma GCC diagnostic push
260 #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
261  sched_param s_param = {};
262  s_param.sched_priority = rt_priority_;
263  int status = pthread_setschedparam(pthread_self(), SCHED_RR, &s_param);
264  if (status != 0)
265  {
266  TLOG(TLVL_ERROR)
267  << "Failed to set realtime priority to " << rt_priority_
268  << ", return code = " << status;
269  }
270 #pragma GCC diagnostic pop
271  }
272 
273  TLOG(TLVL_DEBUG) << "Initializing DataSenderManager. my_rank=" << my_rank;
274  sender_ptr_.reset(new artdaq::DataSenderManager(data_pset_));
275 
276  TLOG(TLVL_DEBUG) << "Waiting for first fragment.";
277  artdaq::MonitoredQuantityStats::TIME_POINT_T startTime;
278  double delta_time;
279  artdaq::FragmentPtrs frags;
280  auto targetFragCount = generator_ptr_->fragmentIDs().size();
281 
282  bool active = true;
283 
284  while (active)
285  {
286  startTime = artdaq::MonitoredQuantity::getCurrentTime();
287 
288  TLOG(18) << "process_fragments getNext start";
289  active = generator_ptr_->getNext(frags);
290  TLOG(18) << "process_fragments getNext done (active=" << active << ")";
291  // 08-May-2015, KAB & JCF: if the generator getNext() method returns false
292  // (which indicates that the data flow has stopped) *and* the reason that
293  // it has stopped is because there was an exception that wasn't handled by
294  // the experiment-specific FragmentGenerator class, we move to the
295  // InRunError state so that external observers (e.g. RunControl or
296  // DAQInterface) can see that there was a problem.
297  if (!active && generator_ptr_ && generator_ptr_->exception())
298  {
299  parent_application_.in_run_failure();
300  }
301 
302  delta_time = artdaq::MonitoredQuantity::getCurrentTime() - startTime;
303  statsHelper_.addSample(INPUT_WAIT_STAT_KEY, delta_time);
304 
305  TLOG(16) << "process_fragments INPUT_WAIT=" << delta_time;
306 
307  if (!active) { break; }
308  statsHelper_.addSample(FRAGMENTS_PER_READ_STAT_KEY, frags.size());
309 
310  for (auto& fragPtr : frags)
311  {
312  if (!fragPtr.get())
313  {
314  TLOG(TLVL_WARNING) << "Encountered a bad fragment pointer in fragment " << fragment_count_ << ". "
315  << "This is most likely caused by a problem with the Fragment Generator!";
316  continue;
317  }
318  artdaq::Fragment::sequence_id_t sequence_id = fragPtr->sequenceID();
319  SetMFIteration("Sequence ID " + std::to_string(sequence_id));
320  statsHelper_.addSample(FRAGMENTS_PROCESSED_STAT_KEY, fragPtr->size());
321 
322  /*if ((fragment_count_ % 250) == 0)
323  {
324  TLOG(TLVL_DEBUG)
325  << "Sending fragment " << fragment_count_
326  << " with sequence id " << sequence_id << ".";
327  }*/
328 
329  // check for continous sequence IDs
330  if (!skip_seqId_test_ && abs(static_cast<int64_t>(sequence_id) - static_cast<int64_t>(prev_seq_id_)) > 1)
331  {
332  TLOG(TLVL_WARNING)
333  << "Missing sequence IDs: current sequence ID = "
334  << sequence_id << ", previous sequence ID = "
335  << prev_seq_id_ << ".";
336  }
337  prev_seq_id_ = sequence_id;
338 
339  startTime = artdaq::MonitoredQuantity::getCurrentTime();
340  TLOG(17) << "process_fragments seq=" << sequence_id << " sendFragment start";
341  auto res = sender_ptr_->sendFragment(std::move(*fragPtr));
342  if (sender_ptr_->GetSentSequenceIDCount(sequence_id) == targetFragCount)
343  {
344  sender_ptr_->RemoveRoutingTableEntry(sequence_id);
345  }
346  TLOG(17) << "process_fragments seq=" << sequence_id << " sendFragment done (dest=" << res.first << ", sts=" << TransferInterface::CopyStatusToString(res.second) << ")";
347  ++fragment_count_;
348  statsHelper_.addSample(OUTPUT_WAIT_STAT_KEY,
349  artdaq::MonitoredQuantity::getCurrentTime() - startTime);
350 
351  bool readyToReport = statsHelper_.readyToReport();
352  if (readyToReport)
353  {
354  std::string statString = buildStatisticsString_();
355  TLOG(TLVL_INFO) << statString;
356  }
357  if (fragment_count_ % 250 == 1 || readyToReport)
358  {
359  TLOG(TLVL_DEBUG)
360  << "Sending fragment " << fragment_count_
361  << " with SeqID " << sequence_id << ".";
362  }
363  }
364  if (statsHelper_.statsRollingWindowHasMoved()) { sendMetrics_(); }
365  frags.clear();
366  }
367 
368  sender_ptr_.reset(nullptr);
369 
370  // 11-May-2015, KAB: call MetricManager::do_stop whenever we exit the
371  // processing fragments loop so that metrics correctly go to zero when
372  // there is no data flowing
373  metricMan->do_stop();
374 
375  TLOG(TLVL_DEBUG) << "process_fragments loop end";
376 }
377 
378 std::string artdaq::BoardReaderCore::report(std::string const& which) const
379 {
380  std::string resultString;
381 
382  // pass the request to the FragmentGenerator instance, if it's available
383  if (generator_ptr_.get() != 0)
384  {
385  resultString = generator_ptr_->ReportCmd(which);
386  if (resultString.length() > 0) { return resultString; }
387  }
388 
389  // handle the request at this level, if we can
390  // --> nothing here yet
391 
392  // if we haven't been able to come up with any report so far, say so
393  std::string tmpString = app_name + " run number = ";
394  tmpString.append(boost::lexical_cast<std::string>(run_id_.run()));
395  tmpString.append(". Command=\"" + which + "\" is not currently supported.");
396  return tmpString;
397 }
398 
399 bool artdaq::BoardReaderCore::metaCommand(std::string const& command, std::string const& arg)
400 {
401  TLOG(TLVL_DEBUG) << "metaCommand method called with "
402  << "command = \"" << command << "\""
403  << ", arg = \"" << arg << "\""
404  << ".";
405 
406  if (generator_ptr_) return generator_ptr_->metaCommand(command, arg);
407 
408  return true;
409 }
410 
411 std::string artdaq::BoardReaderCore::buildStatisticsString_()
412 {
413  std::ostringstream oss;
414  oss << app_name << " statistics:" << std::endl;
415 
416  double fragmentCount = 1.0;
417  artdaq::MonitoredQuantityPtr mqPtr = artdaq::StatisticsCollection::getInstance().
418  getMonitoredQuantity(FRAGMENTS_PROCESSED_STAT_KEY);
419  if (mqPtr.get() != 0)
420  {
421  artdaq::MonitoredQuantityStats stats;
422  mqPtr->getStats(stats);
423  oss << " Fragment statistics: "
424  << stats.recentSampleCount << " fragments received at "
425  << stats.recentSampleRate << " fragments/sec, effective data rate = "
426  << (stats.recentValueRate * sizeof(artdaq::RawDataType)
427  / 1024.0 / 1024.0) << " MB/sec, monitor window = "
428  << stats.recentDuration << " sec, min::max event size = "
429  << (stats.recentValueMin * sizeof(artdaq::RawDataType)
430  / 1024.0 / 1024.0)
431  << "::"
432  << (stats.recentValueMax * sizeof(artdaq::RawDataType)
433  / 1024.0 / 1024.0)
434  << " MB" << std::endl;
435  fragmentCount = std::max(double(stats.recentSampleCount), 1.0);
436  oss << " Average times per fragment: ";
437  if (stats.recentSampleRate > 0.0)
438  {
439  oss << " elapsed time = "
440  << (1.0 / stats.recentSampleRate) << " sec";
441  }
442  }
443 
444  // 31-Dec-2014, KAB - Just a reminder that using "fragmentCount" in the
445  // denominator of the calculations below is important because the way that
446  // the accumulation of these statistics is done is not fragment-by-fragment
447  // but read-by-read (where each read can contain multiple fragments).
448  // 29-Aug-2016, KAB - BRSYNC_WAIT and OUTPUT_WAIT are now done fragment-by-
449  // fragment, but we'll leave the calculation the same. (The alternative
450  // would be to use recentValueAverage().)
451 
452  mqPtr = artdaq::StatisticsCollection::getInstance().
453  getMonitoredQuantity(INPUT_WAIT_STAT_KEY);
454  if (mqPtr.get() != 0)
455  {
456  oss << ", input wait time = "
457  << (mqPtr->getRecentValueSum() / fragmentCount) << " sec";
458  }
459 
460  mqPtr = artdaq::StatisticsCollection::getInstance().
461  getMonitoredQuantity(BRSYNC_WAIT_STAT_KEY);
462  if (mqPtr.get() != 0)
463  {
464  oss << ", BRsync wait time = "
465  << (mqPtr->getRecentValueSum() / fragmentCount) << " sec";
466  }
467 
468  mqPtr = artdaq::StatisticsCollection::getInstance().
469  getMonitoredQuantity(OUTPUT_WAIT_STAT_KEY);
470  if (mqPtr.get() != 0)
471  {
472  oss << ", output wait time = "
473  << (mqPtr->getRecentValueSum() / fragmentCount) << " sec";
474  }
475 
476  oss << std::endl << " Fragments per read: ";
477  mqPtr = artdaq::StatisticsCollection::getInstance().
478  getMonitoredQuantity(FRAGMENTS_PER_READ_STAT_KEY);
479  if (mqPtr.get() != 0)
480  {
481  artdaq::MonitoredQuantityStats stats;
482  mqPtr->getStats(stats);
483  oss << "average = "
484  << stats.recentValueAverage
485  << ", min::max = "
486  << stats.recentValueMin
487  << "::"
488  << stats.recentValueMax;
489  }
490 
491  return oss.str();
492 }
493 
494 void artdaq::BoardReaderCore::sendMetrics_()
495 {
496  //TLOG(TLVL_DEBUG) << "Sending metrics " << __LINE__ ;
497  double fragmentCount = 1.0;
498  artdaq::MonitoredQuantityPtr mqPtr = artdaq::StatisticsCollection::getInstance().
499  getMonitoredQuantity(FRAGMENTS_PROCESSED_STAT_KEY);
500  if (mqPtr.get() != 0)
501  {
502  artdaq::MonitoredQuantityStats stats;
503  mqPtr->getStats(stats);
504  fragmentCount = std::max(double(stats.recentSampleCount), 1.0);
505  metricMan->sendMetric("Fragment Count", static_cast<unsigned long>(stats.fullSampleCount), "fragments", 1, MetricMode::LastPoint);
506  metricMan->sendMetric("Fragment Rate", stats.recentSampleRate, "fragments/sec", 1, MetricMode::Average);
507  metricMan->sendMetric("Average Fragment Size", (stats.recentValueAverage * sizeof(artdaq::RawDataType)), "bytes/fragment", 2, MetricMode::Average);
508  metricMan->sendMetric("Data Rate", (stats.recentValueRate * sizeof(artdaq::RawDataType)), "bytes/sec", 2, MetricMode::Average);
509  }
510 
511  // 31-Dec-2014, KAB - Just a reminder that using "fragmentCount" in the
512  // denominator of the calculations below is important because the way that
513  // the accumulation of these statistics is done is not fragment-by-fragment
514  // but read-by-read (where each read can contain multiple fragments).
515  // 29-Aug-2016, KAB - BRSYNC_WAIT and OUTPUT_WAIT are now done fragment-by-
516  // fragment, but we'll leave the calculation the same. (The alternative
517  // would be to use recentValueAverage().)
518 
519  mqPtr = artdaq::StatisticsCollection::getInstance().
520  getMonitoredQuantity(INPUT_WAIT_STAT_KEY);
521  if (mqPtr.get() != 0)
522  {
523  metricMan->sendMetric("Avg Input Wait Time", (mqPtr->getRecentValueSum() / fragmentCount), "seconds/fragment", 3, MetricMode::Average);
524  }
525 
526  mqPtr = artdaq::StatisticsCollection::getInstance().
527  getMonitoredQuantity(BRSYNC_WAIT_STAT_KEY);
528  if (mqPtr.get() != 0)
529  {
530  metricMan->sendMetric("Avg BoardReader Sync Wait Time", (mqPtr->getRecentValueSum() / fragmentCount), "seconds/fragment", 3, MetricMode::Average);
531  }
532 
533  mqPtr = artdaq::StatisticsCollection::getInstance().
534  getMonitoredQuantity(OUTPUT_WAIT_STAT_KEY);
535  if (mqPtr.get() != 0)
536  {
537  metricMan->sendMetric("Avg Output Wait Time", (mqPtr->getRecentValueSum() / fragmentCount), "seconds/fragment", 3, MetricMode::Average);
538  }
539 
540  mqPtr = artdaq::StatisticsCollection::getInstance().
541  getMonitoredQuantity(FRAGMENTS_PER_READ_STAT_KEY);
542  if (mqPtr.get() != 0)
543  {
544  metricMan->sendMetric("Avg Frags Per Read", mqPtr->getRecentValueAverage(), "fragments/read", 4, MetricMode::Average);
545  }
546 }
547 
548 void artdaq::BoardReaderCore::logMessage_(std::string const& text)
549 {
550  if (verbose_)
551  {
552  TLOG(TLVL_INFO) << text;
553  }
554  else
555  {
556  TLOG(TLVL_DEBUG) << text;
557  }
558 }
void addMonitoredQuantityName(std::string const &statKey)
Add a MonitoredQuantity name to the list.
Commandable is the base class for all artdaq components which implement the artdaq state machine...
Definition: Commandable.hh:20
Sends Fragment objects using TransferInterface plugins. Uses Routing Tables if confgiured, otherwise will Round-Robin Fragments to the destinations.
static const std::string FRAGMENTS_PROCESSED_STAT_KEY
Key for the Fragments Processed MonitoredQuantity.
static const std::string INPUT_WAIT_STAT_KEY
Key for the Input Wait MonitoredQuantity.
bool stop(uint64_t timeout, uint64_t timestamp)
Stop the BoardReader, and the CommandableFragmentGenerator.
virtual ~BoardReaderCore()
BoardReaderCore Destructor.
static std::string CopyStatusToString(CopyStatus in)
Convert a CopyStatus variable to its string represenatation
BoardReaderCore(Commandable &parent_application)
BoardReaderCore Constructor.
std::unique_ptr< CommandableFragmentGenerator > makeCommandableFragmentGenerator(std::string const &generator_plugin_spec, fhicl::ParameterSet const &ps)
Load a CommandableFragmentGenerator plugin.
bool reinitialize(fhicl::ParameterSet const &pset, uint64_t, uint64_t)
Reinitialize the BoardReader. No-Op.
bool soft_initialize(fhicl::ParameterSet const &pset, uint64_t, uint64_t)
Soft-Initialize the BoardReader. No-Op.
static const std::string BRSYNC_WAIT_STAT_KEY
Key for the Sync Wait MonitoredQuantity.
static const std::string FRAGMENTS_PER_READ_STAT_KEY
Key for the Fragments Per Read MonitoredQuantity.
static const std::string OUTPUT_WAIT_STAT_KEY
Key for the Output Wait MonitoredQuantity.
bool initialize(fhicl::ParameterSet const &pset, uint64_t, uint64_t)
Initialize the BoardReaderCore.
std::string report(std::string const &which) const
Send a report on a given run-time quantity.
void process_fragments()
Main working loop of the BoardReaderCore.
bool start(art::RunID id, uint64_t timeout, uint64_t timestamp)
Start the BoardReader, and the CommandableFragmentGenerator.
bool resume(uint64_t timeout, uint64_t timestamp)
Resume the BoardReader, and the CommandableFragmentGenerator.
bool pause(uint64_t timeout, uint64_t timestamp)
Pause the BoardReader, and the CommandableFragmentGenerator.
bool shutdown(uint64_t)
Shutdown the BoardReader, and the CommandableFragmentGenerator.
bool metaCommand(std::string const &command, std::string const &arg)
Run a user-defined command on the CommandableFragmentGenerator.