artdaq_demo  v3_06_01
ToySimulator_generator.cc
1 // For an explanation of this class, look at its header,
2 // ToySimulator.hh, as well as
3 // https://cdcvs.fnal.gov/redmine/projects/artdaq-demo/wiki/Fragments_and_FragmentGenerators_w_Toy_Fragments_as_Examples
4 
5 #include "artdaq-demo/Generators/ToySimulator.hh"
6 
7 #include "canvas/Utilities/Exception.h"
8 
9 #include "artdaq-core/Utilities/SimpleLookupPolicy.hh"
10 #include "artdaq/Generators/GeneratorMacros.hh"
11 
12 #include "artdaq-core-demo/Overlays/FragmentType.hh"
13 #include "artdaq-core-demo/Overlays/ToyFragment.hh"
14 
15 #include "fhiclcpp/ParameterSet.h"
16 
17 #include <fstream>
18 #include <iomanip>
19 #include <iostream>
20 #include <iterator>
21 
22 #include <unistd.h>
23 #define TRACE_NAME "ToySimulator"
24 #include "cetlib_except/exception.h"
25 #include "tracemf.h" // TRACE, TLOG*
26 
27 demo::ToySimulator::ToySimulator( fhicl::ParameterSet const& ps )
28  : CommandableFragmentGenerator( ps )
29  , hardware_interface_( new ToyHardwareInterface( ps ) )
30  , timestamp_( 0 )
31  , timestampScale_( ps.get<int>( "timestamp_scale_factor", 1 ) )
32  , rollover_subrun_interval_( ps.get<int>( "rollover_subrun_interval", 0 ) )
33  , metadata_( {0, 0, 0} )
34  , readout_buffer_( nullptr )
35  , fragment_type_( static_cast<decltype( fragment_type_ )>( artdaq::Fragment::InvalidFragmentType ) )
36  , distribution_type_( static_cast<ToyHardwareInterface::DistributionType>( ps.get<int>( "distribution_type" ) ) )
37  , generated_fragments_per_event_( ps.get<int>( "generated_fragments_per_event", 1 ) )
38  , exception_on_config_( ps.get<bool>( "exception_on_config", false ) )
39  , dies_on_config_( ps.get<bool>( "dies_on_config", false ) )
40 
41 {
42  hardware_interface_->AllocateReadoutBuffer( &readout_buffer_ );
43 
44  if ( exception_on_config_ )
45  {
46  throw cet::exception( "ToySimulator" ) << "This is an engineered exception designed for testing purposes, set "
47  "by the exception_on_config FHiCL variable";
48  }
49  else if ( dies_on_config_ )
50  {
51  TLOG( TLVL_ERROR ) << "This is an engineered process death, set by the dies_on_config FHiCL variable";
52  std::exit( 1 );
53  }
54 
55  metadata_.board_serial_number = hardware_interface_->SerialNumber() & 0xFFFF;
56  metadata_.num_adc_bits = hardware_interface_->NumADCBits();
57  TLOG( TLVL_INFO ) << "Constructor: metadata_.unused = 0x" << std::hex << metadata_.unused
58  << " sizeof(metadata_) = " << std::dec << sizeof( metadata_ );
59 
60  switch ( hardware_interface_->BoardType() )
61  {
62  case 1002:
63  fragment_type_ = toFragmentType( "TOY1" );
64  break;
65  case 1003:
66  fragment_type_ = toFragmentType( "TOY2" );
67  break;
68  default:
69  throw cet::exception( "ToySimulator" ) << "Unable to determine board type supplied by hardware";
70  }
71 }
72 
73 demo::ToySimulator::~ToySimulator() { hardware_interface_->FreeReadoutBuffer( readout_buffer_ ); }
74 
75 bool demo::ToySimulator::getNext_( artdaq::FragmentPtrs& frags )
76 {
77  if ( should_stop() ) { return false; }
78 
79  // ToyHardwareInterface (an instance to which "hardware_interface_"
80  // is a unique_ptr object) is just one example of the sort of
81  // interface a hardware library might offer. For example, other
82  // interfaces might require you to allocate and free the memory used
83  // to store hardware data in your generator using standard C++ tools
84  // (rather than via the "AllocateReadoutBuffer" and
85  // "FreeReadoutBuffer" functions provided here), or could have a
86  // function which directly returns a pointer to the data buffer
87  // rather than sticking the data in the location pointed to by your
88  // pointer (which is what happens here with readout_buffer_)
89 
90  std::size_t bytes_read = 0;
91  hardware_interface_->FillBuffer( readout_buffer_, &bytes_read );
92 
93  // We'll use the static factory function
94 
95  // artdaq::Fragment::FragmentBytes(std::size_t payload_size_in_bytes, sequence_id_t sequence_id,
96  // fragment_id_t fragment_id, type_t type, const T & metadata)
97 
98  // which will then return a unique_ptr to an artdaq::Fragment
99  // object.
100 
101  for ( auto& id : fragmentIDs() )
102  {
103  // The offset logic below is designed to both ensure
104  // backwards compatibility and to (help) avoid collisions
105  // with fragment_ids from other boardreaders if more than
106  // one fragment is generated per event
107 
108  std::unique_ptr<artdaq::Fragment> fragptr(
109  artdaq::Fragment::FragmentBytes( bytes_read, ev_counter(), id, fragment_type_, metadata_, timestamp_ ) );
110  frags.emplace_back( std::move( fragptr ) );
111 
112  if ( distribution_type_ != ToyHardwareInterface::DistributionType::uninitialized )
113  memcpy( frags.back()->dataBeginBytes(), readout_buffer_, bytes_read );
114  else
115  {
116  // Must preserve the Header!
117  memcpy( frags.back()->dataBeginBytes(), readout_buffer_, sizeof( ToyFragment::Header ) );
118  }
119 
120  TLOG( 50 ) << "getNext_ after memcpy " << bytes_read
121  << " bytes and std::move dataSizeBytes()=" << frags.back()->sizeBytes()
122  << " metabytes=" << sizeof( metadata_ );
123  }
124 
125  if ( metricMan != nullptr )
126  { metricMan->sendMetric( "Fragments Sent", ev_counter(), "Events", 3, artdaq::MetricMode::LastPoint ); }
127 
128  if ( rollover_subrun_interval_ > 0 && ev_counter() % rollover_subrun_interval_ == 0 && fragment_id() == 0 )
129  {
130  bool fragmentIdZero = false;
131  for ( auto& id : fragmentIDs() )
132  {
133  if ( id == 0 ) fragmentIdZero = true;
134  }
135  if ( fragmentIdZero )
136  {
137  artdaq::FragmentPtr endOfSubrunFrag( new artdaq::Fragment( static_cast<size_t>(
138  ceil( sizeof( my_rank ) / static_cast<double>( sizeof( artdaq::Fragment::value_type ) ) ) ) ) );
139  endOfSubrunFrag->setSystemType( artdaq::Fragment::EndOfSubrunFragmentType );
140 
141  endOfSubrunFrag->setSequenceID( ev_counter() + 1 );
142  endOfSubrunFrag->setTimestamp( 1 + ( ev_counter() / rollover_subrun_interval_ ) );
143 
144  *endOfSubrunFrag->dataBegin() = my_rank;
145  frags.emplace_back( std::move( endOfSubrunFrag ) );
146  }
147  }
148 
149  ev_counter_inc();
150  timestamp_ += timestampScale_;
151 
152  return true;
153 }
154 
155 void demo::ToySimulator::start()
156 {
157  hardware_interface_->StartDatataking();
158  timestamp_ = 0;
159 }
160 
161 void demo::ToySimulator::stop() { hardware_interface_->StopDatataking(); }
162 
163 // The following macro is defined in artdaq's GeneratorMacros.hh header
164 DEFINE_ARTDAQ_COMMANDABLE_GENERATOR( demo::ToySimulator )
A use-after-free expliot distribution.
ToySimulator(fhicl::ParameterSet const &ps)
ToySimulator Constructor.
JCF, Mar-17-2016: ToyHardwareInterface is meant to mimic a vendor-provided hardware API...
virtual ~ToySimulator()
Shutdown the ToySimulator.
ToySimulator is a simple type of fragment generator intended to be studied by new users of artdaq as ...
Definition: ToySimulator.hh:35