$treeview $search $mathjax $extrastylesheet
artdaq_demo
v3_04_01
$projectbrief
|
$projectbrief
|
$searchbox |
00001 // For an explanation of this class, look at its header, 00002 // ToySimulator.hh, as well as 00003 // https://cdcvs.fnal.gov/redmine/projects/artdaq-demo/wiki/Fragments_and_FragmentGenerators_w_Toy_Fragments_as_Examples 00004 00005 #include "artdaq-demo/Generators/ToySimulator.hh" 00006 00007 #include "canvas/Utilities/Exception.h" 00008 00009 #include "artdaq/Application/GeneratorMacros.hh" 00010 #include "artdaq-core/Utilities/SimpleLookupPolicy.hh" 00011 00012 #include "artdaq-core-demo/Overlays/ToyFragment.hh" 00013 #include "artdaq-core-demo/Overlays/FragmentType.hh" 00014 00015 #include "fhiclcpp/ParameterSet.h" 00016 00017 #include <fstream> 00018 #include <iomanip> 00019 #include <iterator> 00020 #include <iostream> 00021 00022 #include <unistd.h> 00023 #define TRACE_NAME "ToySimulator" 00024 #include "tracemf.h" // TRACE, TLOG* 00025 #include "cetlib_except/exception.h" 00026 00027 demo::ToySimulator::ToySimulator(fhicl::ParameterSet const& ps) 00028 : 00029 CommandableFragmentGenerator(ps) 00030 , hardware_interface_(new ToyHardwareInterface(ps)) 00031 , timestamp_(0) 00032 , timestampScale_(ps.get<int>("timestamp_scale_factor", 1)) 00033 , rollover_subrun_interval_(ps.get<int>("rollover_subrun_interval", 0)) 00034 , metadata_({ 0,0,0 }) 00035 , readout_buffer_(nullptr) 00036 , fragment_type_(static_cast<decltype(fragment_type_)>(artdaq::Fragment::InvalidFragmentType)) 00037 , distribution_type_(static_cast<ToyHardwareInterface::DistributionType>(ps.get<int>("distribution_type"))) 00038 , generated_fragments_per_event_(ps.get<int>("generated_fragments_per_event", 1)) 00039 , exception_on_config_(ps.get<bool>("exception_on_config", false)) , dies_on_config_(ps.get<bool>("dies_on_config", false)) 00040 00041 { 00042 hardware_interface_->AllocateReadoutBuffer(&readout_buffer_); 00043 00044 if (exception_on_config_) { 00045 throw cet::exception("ToySimulator") << "This is an engineered exception designed for testing purposes, set by the exception_on_config FHiCL variable"; 00046 } else if (dies_on_config_) { 00047 TLOG(TLVL_ERROR) << "This is an engineered process death, set by the dies_on_config FHiCL variable"; 00048 std::exit(1); 00049 } 00050 00051 metadata_.board_serial_number = hardware_interface_->SerialNumber() & 0xFFFF; 00052 metadata_.num_adc_bits = hardware_interface_->NumADCBits(); 00053 TLOG(TLVL_INFO) << "Constructor: metadata_.unused = 0x" << std::hex << metadata_.unused << " sizeof(metadata_) = " << std::dec << sizeof(metadata_); 00054 00055 switch (hardware_interface_->BoardType()) 00056 { 00057 case 1002: 00058 fragment_type_ = toFragmentType("TOY1"); 00059 break; 00060 case 1003: 00061 fragment_type_ = toFragmentType("TOY2"); 00062 break; 00063 default: 00064 throw cet::exception("ToySimulator") << "Unable to determine board type supplied by hardware"; 00065 } 00066 } 00067 00068 demo::ToySimulator::~ToySimulator() 00069 { 00070 hardware_interface_->FreeReadoutBuffer(readout_buffer_); 00071 } 00072 00073 bool demo::ToySimulator::getNext_(artdaq::FragmentPtrs& frags) 00074 { 00075 if (should_stop()) 00076 { 00077 return false; 00078 } 00079 00080 // ToyHardwareInterface (an instance to which "hardware_interface_" 00081 // is a unique_ptr object) is just one example of the sort of 00082 // interface a hardware library might offer. For example, other 00083 // interfaces might require you to allocate and free the memory used 00084 // to store hardware data in your generator using standard C++ tools 00085 // (rather than via the "AllocateReadoutBuffer" and 00086 // "FreeReadoutBuffer" functions provided here), or could have a 00087 // function which directly returns a pointer to the data buffer 00088 // rather than sticking the data in the location pointed to by your 00089 // pointer (which is what happens here with readout_buffer_) 00090 00091 std::size_t bytes_read = 0; 00092 hardware_interface_->FillBuffer(readout_buffer_, &bytes_read); 00093 00094 // We'll use the static factory function 00095 00096 // artdaq::Fragment::FragmentBytes(std::size_t payload_size_in_bytes, sequence_id_t sequence_id, 00097 // fragment_id_t fragment_id, type_t type, const T & metadata) 00098 00099 // which will then return a unique_ptr to an artdaq::Fragment 00100 // object. 00101 00102 #if 1 00103 for (auto i_f = 0; i_f < generated_fragments_per_event_; ++i_f) { 00104 00105 // The offset logic below is designed to both ensure 00106 // backwards compatibility and to (help) avoid collisions 00107 // with fragment_ids from other boardreaders if more than 00108 // one fragment is generated per event 00109 00110 auto offset = i_f == 0 ? 0 : i_f + 10000; 00111 std::unique_ptr<artdaq::Fragment> fragptr( 00112 artdaq::Fragment::FragmentBytes(bytes_read, 00113 ev_counter(), 00114 fragment_id() + offset, 00115 fragment_type_, 00116 metadata_, timestamp_)); 00117 frags.emplace_back(std::move(fragptr)); 00118 } 00119 #else 00120 std::unique_ptr<artdaq::Fragment> fragptr( 00121 artdaq::Fragment::FragmentBytes(/*bytes_read*/ 1024 - 40, 00122 ev_counter(), fragment_id(), 00123 fragment_type_, 00124 metadata_, timestamp_)); 00125 frags.emplace_back(std::move(fragptr)); 00126 artdaq::detail::RawFragmentHeader *hdr = (artdaq::detail::RawFragmentHeader*)(frags.back()->headerBeginBytes()); 00127 // Need a way to fake frag->sizeBytes() (which calls frag->size() which calls fragmentHeader()->word_count 00128 hdr->word_count = ceil((bytes_read + 32) / static_cast<double>(sizeof(artdaq::RawDataType))); 00129 #endif 00130 00131 if ( !frags.empty() ) { 00132 00133 if (distribution_type_ != ToyHardwareInterface::DistributionType::uninitialized) 00134 memcpy(frags.back()->dataBeginBytes(), readout_buffer_, bytes_read); 00135 else 00136 { 00137 // Must preserve the Header! 00138 memcpy(frags.back()->dataBeginBytes(), readout_buffer_, sizeof(ToyFragment::Header)); 00139 } 00140 00141 TLOG(50) << "getNext_ after memcpy " << bytes_read 00142 << " bytes and std::move dataSizeBytes()=" << frags.back()->sizeBytes() << " metabytes=" << sizeof(metadata_); 00143 } 00144 00145 if (metricMan != nullptr) 00146 { 00147 metricMan->sendMetric("Fragments Sent", ev_counter(), "Events", 3, artdaq::MetricMode::LastPoint); 00148 } 00149 00150 if (rollover_subrun_interval_ > 0 && ev_counter() % rollover_subrun_interval_ == 0 && fragment_id() == 0) 00151 { 00152 artdaq::FragmentPtr endOfSubrunFrag(new artdaq::Fragment(static_cast<size_t>(ceil(sizeof(my_rank) / static_cast<double>(sizeof(artdaq::Fragment::value_type)))))); 00153 endOfSubrunFrag->setSystemType(artdaq::Fragment::EndOfSubrunFragmentType); 00154 00155 endOfSubrunFrag->setSequenceID(ev_counter() + 1); 00156 endOfSubrunFrag->setTimestamp(1 + (ev_counter() / rollover_subrun_interval_)); 00157 00158 *endOfSubrunFrag->dataBegin() = my_rank; 00159 frags.emplace_back(std::move(endOfSubrunFrag)); 00160 } 00161 00162 ev_counter_inc(); 00163 timestamp_ += timestampScale_; 00164 00165 return true; 00166 } 00167 00168 void demo::ToySimulator::start() 00169 { 00170 hardware_interface_->StartDatataking(); 00171 timestamp_ = 0; 00172 } 00173 00174 void demo::ToySimulator::stop() 00175 { 00176 hardware_interface_->StopDatataking(); 00177 } 00178 00179 // The following macro is defined in artdaq's GeneratorMacros.hh header 00180 DEFINE_ARTDAQ_COMMANDABLE_GENERATOR(demo::ToySimulator)