artdaq_demo  v3_06_01
demo_driver.cc
1 //
2 // Based off of "ds50driver", a program for testing DarkSide-50 input
3 // sources, "driver" is an executable designed to make it simple to
4 // test a fragment generator under development
5 
6 // Run 'driver --help' to get a description of the
7 // expected command-line parameters.
8 //
9 //
10 // The current version generates data fragments and passes them
11 // to an EventStore instance and then to art, if desired.
12 //
13 
14 #include "art/Framework/Art/artapp.h"
15 #include "artdaq-core/Core/SimpleMemoryReader.hh"
16 #include "artdaq-core/Data/Fragment.hh"
17 #include "artdaq-core/Utilities/SimpleLookupPolicy.hh"
18 #include "artdaq/Application/CommandableFragmentGenerator.hh"
19 #include "artdaq/Application/makeCommandableFragmentGenerator.hh"
20 #include "artdaq/DAQrate/EventStore.hh"
21 #include "cetlib/container_algorithms.h"
22 #include "cetlib/filepath_maker.h"
23 #include "fhiclcpp/ParameterSet.h"
24 #include "fhiclcpp/make_ParameterSet.h"
25 
26 #include <boost/program_options.hpp>
27 
28 #include <signal.h>
29 #include <iostream>
30 #include <limits>
31 #include <memory>
32 #include <utility>
33 
34 using namespace fhicl;
35 namespace bpo = boost::program_options;
36 
37 int main( int argc, char* argv[] ) try
38 {
39  // 15-Dec-2016, KAB: by consensus, we want people to use the "artdaqDriver"
40  // program (which corresponds to "artdaq/proto/driver.cc").
41  if ( true )
42  {
43  std::cout << "****************************************" << std::endl;
44  std::cout << "*** \"demo_driver\" has been deprecated (15-Dec-2016)." << std::endl;
45  std::cout << "*** Please use the \"artdaqDriver\" application that is available from" << std::endl
46  << "*** the artdaq software package instead of \"demo_driver\"." << std::endl;
47  exit( 1 );
48  }
49 
50  // Get the input parameters via the boost::program_options library,
51  // designed to make it relatively simple to define arguments and
52  // issue errors if argument list is supplied incorrectly
53 
54  std::ostringstream descstr;
55  descstr << argv[ 0 ] << " <-c <config-file>> <other-options>";
56 
57  bpo::options_description desc = descstr.str();
58 
59  desc.add_options()( "config,c", bpo::value<std::string>(), "Configuration file." )( "help,h",
60  "produce help message" );
61 
62  bpo::variables_map vm;
63 
64  try
65  {
66  bpo::store( bpo::command_line_parser( argc, argv ).options( desc ).run(), vm );
67  bpo::notify( vm );
68  }
69  catch ( bpo::error const& e )
70  {
71  std::cerr << "Exception from command line processing in " << argv[ 0 ] << ": " << e.what() << "\n";
72  return -1;
73  }
74 
75  if ( vm.count( "help" ) )
76  {
77  std::cout << desc << std::endl;
78  return 1;
79  }
80  if ( !vm.count( "config" ) )
81  {
82  std::cerr << "Exception from command line processing in " << argv[ 0 ] << ": no configuration file given.\n"
83  << "For usage and an options list, please do '" << argv[ 0 ] << " --help"
84  << "'.\n";
85  return 2;
86  }
87 
88  // Check the directories defined by the FHICL_FILE_PATH
89  // environmental variable for the *.fcl file whose name was passed to
90  // the command line. If not defined, look in the current directory.
91 
92  ParameterSet complete_pset;
93 
94  if ( getenv( "FHICL_FILE_PATH" ) == nullptr )
95  {
96  std::cerr << "INFO: environment variable FHICL_FILE_PATH was not set. Using \".\"\n";
97  setenv( "FHICL_FILE_PATH", ".", 0 );
98  }
99 
100  artdaq::SimpleLookupPolicy lookup_policy( "FHICL_FILE_PATH" );
101 
102  make_ParameterSet( vm[ "config" ].as<std::string>(), lookup_policy, complete_pset );
103 
104  ParameterSet fragment_receiver_pset = complete_pset.get<ParameterSet>( "fragment_receiver" );
105  ParameterSet event_builder_pset = complete_pset.get<ParameterSet>( "event_builder" );
106 
107  // Use the "generator" parameter from the user-supplied *.fcl
108  // configuration file to define our fragment generator
109 
110  std::unique_ptr<artdaq::CommandableFragmentGenerator> const gen( artdaq::makeCommandableFragmentGenerator(
111  fragment_receiver_pset.get<std::string>( "generator" ), fragment_receiver_pset ) );
112 
113  // The instance of the artdaq::EventStore object can either pass
114  // events to a thread running Art, or to a small executable called
115  // "SimpleMemoryReader"
116 
117  bool const want_artapp = event_builder_pset.get<bool>( "use_art", false );
118 
119  std::ostringstream os;
120  if ( !want_artapp ) { os << event_builder_pset.get<int>( "events_expected_in_SimpleMemoryReader" ); }
121  std::string oss = os.str();
122 
123  const char* args[ 2 ]{"SimpleMemoryReader", const_cast<char*>( oss.c_str() )};
124 
125  int es_argc( want_artapp ? argc : 2 );
126  char** es_argv( want_artapp ? argv : const_cast<char**>( args ) );
127 
128  artdaq::EventStore::ART_CMDLINE_FCN* es_fcn( want_artapp ? &artapp : &artdaq::SimpleMemoryReaderApp );
129 
130  artdaq::EventStore store( event_builder_pset, event_builder_pset.get<size_t>( "expected_fragments_per_event" ),
131  complete_pset.get<artdaq::EventStore::run_id_t>( "run_number" ), es_argc, es_argv,
132  es_fcn );
133 
134  int events_to_generate = complete_pset.get<int>( "events_to_generate", 0 );
135  int event_count = 0;
136  artdaq::Fragment::sequence_id_t previous_sequence_id = 0;
137 
138  uint64_t timeout = 45;
139  uint64_t timestamp = std::numeric_limits<uint64_t>::max();
140 
141  gen.get()->StartCmd( complete_pset.get<artdaq::EventStore::run_id_t>( "run_number" ), timeout, timestamp );
142 
143  artdaq::FragmentPtrs frags;
144 
145  while ( events_to_generate >= 0 && gen->getNext( frags ) )
146  {
147  for ( auto& val : frags )
148  {
149  std::cout << "Fragment: Seq ID: " << val->sequenceID() << ", Frag ID: " << val->fragmentID()
150  << ", total size in bytes: " << val->size() * sizeof( artdaq::RawDataType ) << std::endl;
151 
152  if ( val->sequenceID() != previous_sequence_id )
153  {
154  ++event_count;
155  previous_sequence_id = val->sequenceID();
156  }
157  if ( events_to_generate != 0 && event_count > events_to_generate ) gen.get()->StopCmd( timeout, timestamp );
158 
159  store.insert( std::move( val ) );
160  }
161  frags.clear();
162 
163  if ( events_to_generate != 0 && event_count >= events_to_generate ) gen.get()->StopCmd( timeout, timestamp );
164  }
165 
166  int readerReturnValue;
167  bool endSucceeded = false;
168  int attemptsToEnd = 1;
169  endSucceeded = store.endOfData( readerReturnValue );
170  while ( !endSucceeded && attemptsToEnd < 3 )
171  {
172  ++attemptsToEnd;
173  endSucceeded = store.endOfData( readerReturnValue );
174  }
175  if ( !endSucceeded )
176  {
177  std::cerr << "Failed to shut down the reader and the event store "
178  << "because the endOfData marker could not be pushed "
179  << "onto the queue." << std::endl;
180  }
181  return readerReturnValue;
182 }
183 
184 catch ( std::string& x )
185 {
186  std::cerr << "Exception (type string) caught in driver: " << x << "\n";
187  return 1;
188 }
189 
190 catch ( char const* m )
191 {
192  std::cerr << "Exception (type char const*) caught in driver: " << std::endl;
193  if ( m ) { std::cerr << m; }
194  else
195  {
196  std::cerr << "[the value was a null pointer, so no message is available]";
197  }
198  std::cerr << '\n';
199 }