artdaq  v3_09_04
CommandableFragmentGenerator.hh
1 #ifndef artdaq_Application_CommandableFragmentGenerator_hh
2 #define artdaq_Application_CommandableFragmentGenerator_hh
3 
4 // Socket Includes
5 #include <arpa/inet.h>
6 #include <netinet/in.h>
7 #include <sys/socket.h>
8 #include <sys/types.h>
9 #include <unistd.h>
10 
11 #include <array>
12 #include <atomic>
13 #include <chrono>
14 #include <condition_variable>
15 #include <list>
16 #include <mutex>
17 #include <queue>
18 
19 #include "fhiclcpp/ParameterSet.h"
20 #include "fhiclcpp/fwd.h"
21 
22 #include "artdaq-core/Data/Fragment.hh"
23 #include "artdaq-core/Generators/FragmentGenerator.hh"
24 #include "artdaq-utilities/Plugins/MetricManager.hh"
25 #include "artdaq/DAQdata/Globals.hh"
26 #include "artdaq/DAQrate/FragmentBuffer.hh"
27 
28 namespace artdaq {
29 
72 class CommandableFragmentGenerator : public FragmentGenerator
73 {
74 public:
78  struct Config
79  {
81  fhicl::Atom<std::string> generator_type{fhicl::Name{"generator"}, fhicl::Comment{"Name of the CommandableFragmentGenerator plugin to load"}};
83  fhicl::Atom<Fragment::type_t> expected_fragment_type{fhicl::Name{"expected_fragment_type"}, fhicl::Comment{"The type of Fragments this CFG will be generating. \"Empty\" will auto-detect type based on Fragments generated."}, Fragment::type_t(Fragment::EmptyFragmentType)};
85  fhicl::Atom<size_t> sleep_on_no_data_us{fhicl::Name{"sleep_on_no_data_us"}, fhicl::Comment{"How long to sleep after calling getNext_ if no data is returned"}, 0};
87  fhicl::Atom<bool> separate_monitoring_thread{fhicl::Name{"separate_monitoring_thread"}, fhicl::Comment{"Whether a thread that calls the checkHWStatus_ method should be created"}, false};
89  fhicl::Atom<int64_t> hardware_poll_interval_us{fhicl::Name{"hardware_poll_interval_us"}, fhicl::Comment{"If a separate monitoring thread is used, how often should it call checkHWStatus_"}, 0};
91  fhicl::Atom<int> board_id{fhicl::Name{"board_id"}, fhicl::Comment{"The identification number for this CommandableFragmentGenerator"}};
94  fhicl::Sequence<Fragment::fragment_id_t> fragment_ids{fhicl::Name("fragment_ids"), fhicl::Comment("A list of Fragment IDs created by this CommandableFragmentGenerator")};
97  fhicl::Atom<int> fragment_id{fhicl::Name{"fragment_id"}, fhicl::Comment{"The Fragment ID created by this CommandableFragmentGenerator"}, -99};
99  fhicl::Atom<int> sleep_on_stop_us{fhicl::Name{"sleep_on_stop_us"}, fhicl::Comment{"How long to sleep before returning when stop transition is called"}, 0};
100  };
102  using Parameters = fhicl::WrappedTable<Config>;
103 
108  explicit CommandableFragmentGenerator(const fhicl::ParameterSet& ps);
109 
116 
123  void joinThreads();
124 
130  bool getNext(FragmentPtrs& output) override final;
131 
135  void startMonitoringThread();
136 
140  void getMonitoringDataLoop();
141 
146  std::vector<Fragment::fragment_id_t> fragmentIDs() override
147  {
148  std::vector<Fragment::fragment_id_t> output;
149 
150  for (auto& id : expectedTypes_)
151  {
152  output.push_back(id.first);
153  }
154 
155  return output;
156  }
157 
162  size_t ev_counter() const { return ev_counter_.load(); }
163 
164  //
165  // State-machine related interface below.
166  //
167 
182  void StartCmd(int run, uint64_t timeout, uint64_t timestamp);
183 
193  void StopCmd(uint64_t timeout, uint64_t timestamp);
194 
204  void PauseCmd(uint64_t timeout, uint64_t timestamp);
205 
214  void ResumeCmd(uint64_t timeout, uint64_t timestamp);
215 
226  std::string ReportCmd(std::string const& which = "");
227 
232  virtual std::string metricsReportingInstanceName() const
233  {
234  return instance_name_for_metrics_;
235  }
236 
237  // The following functions are not yet implemented, and their
238  // signatures may be subject to change.
239 
240  // John F., 12/6/13 -- do we want Reset and Shutdown commands?
241  // Kurt B., 15-Feb-2014. For the moment, I suspect that we don't
242  // want a Shutdown command. FragmentGenerator instances are
243  // Constructed at Initialization time, and they are destructed
244  // at Shutdown time. So, any shutdown operations that need to be
245  // done should be put in the FragmentGenerator child class
246  // destructors. If we find that want shutdown (or initialization)
247  // operations that are different from destruction (construction),
248  // then we'll have to add InitCmd and ShutdownCmd methods.
249 
250  // virtual void ResetCmd() final {}
251  // virtual void ShutdownCmd() final {}
252 
257  bool exception() const { return exception_.load(); }
258 
265  virtual bool metaCommand(std::string const& command, std::string const& arg);
266 
271  void SetRequestBuffer(std::shared_ptr<RequestBuffer> buffer) { requestBuffer_ = buffer; }
272 
273 protected:
274  // John F., 12/6/13 -- need to figure out which of these getter
275  // functions should be promoted to "public"
276 
277  // John F., 1/21/15 -- after more than a year, there hasn't been a
278  // single complaint that a CommandableFragmentGenerator-derived
279  // class hasn't allowed its users to access these quantities, so
280  // they're probably fine as is
281 
286  int run_number() const { return run_number_; }
291  int subrun_number() const { return subrun_number_; }
296  uint64_t timeout() const { return timeout_; }
301  uint64_t timestamp() const { return timestamp_; }
302 
308  artdaq::Fragment::fragment_id_t fragment_id() const
309  {
310  if (expectedTypes_.size() > 1) throw cet::exception("FragmentID") << "fragment_id() was called, indicating that Fragment Generator was expecting one and only one Fragment ID, but " << expectedTypes_.size() << " were declared!"; // NOLINT(cert-err60-cpp)
311  return (*expectedTypes_.begin()).first;
312  }
313 
318  bool should_stop() const { return should_stop_.load(); }
319 
324  bool check_stop();
325 
330  int board_id() const { return board_id_; }
331 
337  size_t ev_counter_inc(size_t step = 1); // returns the prev value
338 
343  void set_exception(bool exception) { exception_.store(exception); }
344 
349  void metricsReportingInstanceName(std::string const& name)
350  {
351  instance_name_for_metrics_ = name;
352  }
353 
354  // John F., 12/10/13
355  // Is there a better way to handle mutex_ than leaving it a protected variable?
356 
357  // John F., 1/21/15
358  // Translation above is "should mutex_ be a private variable,
359  // accessible via a getter function". Probably, but at this point
360  // it's not worth breaking code by implementing this.
361 
362  std::mutex mutex_;
363 
368  std::shared_ptr<RequestBuffer> GetRequestBuffer() { return requestBuffer_; }
369 
370 private:
375 
376  // FHiCL-configurable variables. Note that the C++ variable names
377  // are the FHiCL variable names with a "_" appended
378 
379  //Socket parameters
380 
381  std::map<Fragment::fragment_id_t, Fragment::type_t> expectedTypes_;
382 
383  bool useMonitoringThread_;
384  boost::thread monitoringThread_;
385  int64_t monitoringInterval_; // Microseconds
386  std::chrono::steady_clock::time_point lastMonitoringCall_;
387  std::atomic<bool> isHardwareOK_;
388 
389  // In order to support the state-machine related behavior, all
390  // CommandableFragmentGenerators must be able to remember a run number and a
391  // subrun number.
392  int run_number_, subrun_number_;
393 
394  // JCF, 8/28/14
395 
396  // Provide a user-adjustable timeout for the start transition
397  uint64_t timeout_;
398 
399  // JCF, 8/21/14
400 
401  // In response to a need to synchronize various components using
402  // different fragment generators in an experiment, keep a record
403  // of a timestamp (see Redmine Issue #6783 for more)
404 
405  uint64_t timestamp_;
406 
407  std::atomic<bool> should_stop_, exception_;
408  std::string latest_exception_report_;
409  std::atomic<size_t> ev_counter_;
410 
411  int board_id_;
412  std::string instance_name_for_metrics_;
413 
414  // Depending on what sleep_on_stop_us_ is set to, this gives the
415  // stopping thread the chance to gather the required lock
416 
417  int sleep_on_stop_us_;
418 
419  // So that derived classes can access information about requests
420  std::shared_ptr<RequestBuffer> requestBuffer_;
421 
422 protected:
430  virtual bool getNext_(FragmentPtrs& output) = 0;
431 
438  virtual bool checkHWStatus_();
439 
440  //
441  // State-machine related implementor interface below.
442  //
443 
454  virtual void start() = 0;
455 
462  virtual void stopNoMutex() = 0;
463 
472  virtual void stop() = 0;
473 
478  virtual void pauseNoMutex();
479 
485  virtual void pause();
486 
490  virtual void resume();
491 
503  virtual std::string report();
504 
510  virtual std::string reportSpecific(std::string const& what);
511 };
512 } // namespace artdaq
513 
514 #endif /* artdaq_Application_CommandableFragmentGenerator_hh */
fhicl::Atom< Fragment::type_t > expected_fragment_type
&quot;expected_fragment_type&quot; (Default: 231, EmptyFragmentType) : The type of Fragments this CFG will be g...
fhicl::Atom< int > board_id
&quot;board_id&quot; (REQUIRED) : The identification number for this CommandableFragmentGenerator ...
CommandableFragmentGenerator(const fhicl::ParameterSet &ps)
CommandableFragmentGenerator Constructor.
int subrun_number() const
Get the current Subrun number.
virtual void start()=0
If a CommandableFragmentGenerator subclass is reading from a file, and start() is called...
fhicl::Atom< int64_t > hardware_poll_interval_us
&quot;hardware_poll_interval_us&quot; (Default: 0) : If a separate monitoring thread is used, how often should it call checkHWStatus_
virtual bool checkHWStatus_()
Check any relavent hardware status registers. Return false if an error condition exists that should h...
virtual ~CommandableFragmentGenerator()
CommandableFragmentGenerator Destructor.
bool exception() const
Get the current value of the exception flag.
void metricsReportingInstanceName(std::string const &name)
Sets the name for metrics reporting.
std::mutex mutex_
Mutex used to ensure that multiple transition commands do not run at the same time.
void getMonitoringDataLoop()
This function regularly calls checkHWStatus_(), and sets the isHardwareOK flag accordingly.
artdaq::Fragment::fragment_id_t fragment_id() const
Get the Fragment ID of this Fragment generator.
std::string ReportCmd(std::string const &which="")
Get a report about a user-specified run-time quantity.
virtual bool metaCommand(std::string const &command, std::string const &arg)
The meta-command is used for implementing user-specific commands in a CommandableFragmentGenerator.
void StopCmd(uint64_t timeout, uint64_t timestamp)
Stop the CommandableFragmentGenerator.
uint64_t timeout() const
Timeout of last command.
void StartCmd(int run, uint64_t timeout, uint64_t timestamp)
Start the CommandableFragmentGenerator.
virtual void pauseNoMutex()
On call to PauseCmd, pauseNoMutex() is called prior to PauseCmd acquiring the mutex ...
bool check_stop()
Routine used by applyRequests to make sure that all outstanding requests have been fulfilled before r...
void ResumeCmd(uint64_t timeout, uint64_t timestamp)
Resume the CommandableFragmentGenerator.
bool getNext(FragmentPtrs &output) overridefinal
getNext calls either applyRequests or getNext_ to get any data that is ready to be sent to the EventB...
std::vector< Fragment::fragment_id_t > fragmentIDs() override
Get the list of Fragment IDs handled by this CommandableFragmentGenerator.
fhicl::Atom< int > sleep_on_stop_us
&quot;sleep_on_stop_us&quot; (Default: 0) : How long to sleep before returning when stop transition is called ...
void PauseCmd(uint64_t timeout, uint64_t timestamp)
Pause the CommandableFragmentGenerator.
fhicl::Sequence< Fragment::fragment_id_t > fragment_ids
virtual std::string metricsReportingInstanceName() const
Get the name used when reporting metrics.
bool should_stop() const
Get the current value of the should_stop flag.
CommandableFragmentGenerator is a FragmentGenerator-derived abstract class that defines the interface...
fhicl::WrappedTable< Config > Parameters
Used for ParameterSet validation (if desired)
virtual bool getNext_(FragmentPtrs &output)=0
Obtain the next group of Fragments, if any are available. Return false if readout cannot continue...
void startMonitoringThread()
Function that launches the monitoring thread (getMonitoringDataLoop())
virtual void pause()
If a CommandableFragmentGenerator subclass is reading from hardware, the implementation of pause() sh...
virtual void resume()
The subrun number will be incremented before a call to resume.
size_t ev_counter() const
Get the current value of the event counter.
fhicl::Atom< size_t > sleep_on_no_data_us
&quot;sleep_on_no_data_us&quot; (Default: 0 (no sleep)) : How long to sleep after calling getNext_ if no data i...
virtual std::string report()
Let&#39;s say that the contract with the report() functions is that they return a non-empty string if the...
virtual void stopNoMutex()=0
On call to StopCmd, stopNoMutex() is called prior to StopCmd acquiring the mutex
int board_id() const
Gets the current board_id.
std::shared_ptr< RequestBuffer > GetRequestBuffer()
Get the shared_ptr to the RequestBuffer.
void SetRequestBuffer(std::shared_ptr< RequestBuffer > buffer)
Set the shared_ptr to the RequestBuffer.
void set_exception(bool exception)
Control the exception flag.
uint64_t timestamp() const
Timestamp of last command.
Configuration of the CommandableFragmentGenerator. May be used for parameter validation ...
fhicl::Atom< std::string > generator_type
&quot;generator&quot; (REQUIRED) Name of the CommandableFragmentGenerator plugin to load
size_t ev_counter_inc(size_t step=1)
Increment the event counter.
virtual void stop()=0
If a CommandableFragmentGenerator subclass is reading from a file, calling stop() should arrange that...
virtual std::string reportSpecific(std::string const &what)
Report the status of a specific quantity
int run_number() const
Get the current Run number.
fhicl::Atom< bool > separate_monitoring_thread
&quot;separate_monitoring_thread&quot; (Default: false) : Whether a thread that calls the checkHWStatus_ method...
void joinThreads()
Join any data-taking threads. Should be called when destructing CommandableFragmentGenerator.