1 #include "artdaq-demo/Generators/ToyHardwareInterface/ToyHardwareInterface.hh"
2 #define TRACE_NAME "ToyHardwareInterface"
3 #include "artdaq-core-demo/Overlays/FragmentType.hh"
4 #include "artdaq-core-demo/Overlays/ToyFragment.hh"
5 #include "artdaq/DAQdata/Globals.hh"
7 #include "cetlib_except/exception.h"
8 #include "fhiclcpp/ParameterSet.h"
24 , nADCcounts_(ps.get<size_t>(
"nADCcounts", 40))
25 , maxADCcounts_(ps.get<size_t>(
"maxADCcounts", 50000000))
26 , change_after_N_seconds_(ps.get<size_t>(
"change_after_N_seconds", std::numeric_limits<size_t>::max()))
27 , nADCcounts_after_N_seconds_(ps.get<int>(
"nADCcounts_after_N_seconds", nADCcounts_))
28 , exception_after_N_seconds_(ps.get<bool>(
"exception_after_N_seconds", false))
29 , exit_after_N_seconds_(ps.get<bool>(
"exit_after_N_seconds", false))
30 , abort_after_N_seconds_(ps.get<bool>(
"abort_after_N_seconds", false))
31 , fragment_type_(demo::toFragmentType(ps.get<std::string>(
"fragment_type")))
32 , maxADCvalue_(pow(2, NumADCBits()) - 1)
34 throttle_usecs_(ps.get<size_t>(
"throttle_usecs", 100000))
35 , usecs_between_sends_(ps.get<size_t>(
"usecs_between_sends", 0))
36 , distribution_type_(static_cast<
DistributionType>(ps.get<int>(
"distribution_type")))
37 , engine_(ps.get<int64_t>(
"random_seed", 314159))
38 , uniform_distn_(new std::uniform_int_distribution<
data_t>(0, maxADCvalue_))
39 , gaussian_distn_(new std::normal_distribution<double>(0.5 * maxADCvalue_, 0.1 * maxADCvalue_))
40 , start_time_(fake_time_)
42 , serial_number_((*uniform_distn_)(engine_))
44 #pragma GCC diagnostic push
45 #pragma GCC diagnostic ignored "-Wsign-compare"
53 if (nADCcounts_ > maxADCcounts_ ||
54 (nADCcounts_after_N_seconds_ >= 0 && nADCcounts_after_N_seconds_ > maxADCcounts_))
56 throw cet::exception(
"HardwareInterface")
57 <<
"Either (or both) of \"nADCcounts\" and \"nADCcounts_after_N_seconds\""
58 <<
" is larger than the \"maxADCcounts\" setting (currently at " << maxADCcounts_ <<
")";
61 bool planned_disruption = nADCcounts_after_N_seconds_ != nADCcounts_ || exception_after_N_seconds_ ||
62 exit_after_N_seconds_ || abort_after_N_seconds_;
64 if (planned_disruption && change_after_N_seconds_ == std::numeric_limits<size_t>::max())
66 throw cet::exception(
"HardwareInterface") <<
"A FHiCL parameter designed to create a disruption has been "
67 "set, so \"change_after_N_seconds\" should be set as well";
68 #pragma GCC diagnostic pop
87 start_time_ = fake_time_;
94 usleep(throttle_usecs_);
96 auto elapsed_secs_since_datataking_start = artdaq::TimeUtils::GetElapsedTime(start_time_);
98 #pragma GCC diagnostic push
99 #pragma GCC diagnostic ignored "-Wsign-compare"
100 if (elapsed_secs_since_datataking_start < change_after_N_seconds_ || send_calls_ == 0)
102 #pragma GCC diagnostic pop
104 *bytes_read =
sizeof(demo::ToyFragment::Header) + nADCcounts_ *
sizeof(
data_t);
108 if (abort_after_N_seconds_)
112 else if (exit_after_N_seconds_)
116 else if (exception_after_N_seconds_)
118 throw cet::exception(
"HardwareInterface")
119 <<
"This is an engineered exception designed for testing purposes";
121 else if (nADCcounts_after_N_seconds_ >= 0)
123 *bytes_read =
sizeof(demo::ToyFragment::Header) + nADCcounts_after_N_seconds_ *
sizeof(
data_t);
140 assert(*bytes_read %
sizeof(demo::ToyFragment::Header::data_t) == 0);
142 demo::ToyFragment::Header* header =
reinterpret_cast<demo::ToyFragment::Header*
>(buffer);
144 header->event_size = *bytes_read /
sizeof(demo::ToyFragment::Header::data_t);
145 header->trigger_number = 99;
146 header->distribution_type =
static_cast<uint8_t
>(distribution_type_);
151 std::function<data_t()> generator;
154 switch (distribution_type_)
157 generator = [&]() {
return static_cast<data_t>((*uniform_distn_)(engine_)); };
164 gen_seed =
static_cast<data_t>(std::round((*gaussian_distn_)(engine_)));
165 }
while (gen_seed > maxADCvalue_);
173 if (++gen_seed > maxADCvalue_) gen_seed = 0;
180 case DistributionType::uninit2:
184 throw cet::exception(
"HardwareInterface") <<
"Unknown distribution type specified";
189 std::generate_n(reinterpret_cast<data_t*>(reinterpret_cast<demo::ToyFragment::Header*>(buffer) + 1),
190 nADCcounts_, generator);
195 throw cet::exception(
"ToyHardwareInterface") <<
"Attempt to call FillBuffer when not sending data";
198 if (send_calls_ == 0)
200 start_time_ = std::chrono::steady_clock::now();
201 TLOG(50) <<
"FillBuffer has set the start_time_";
204 if (usecs_between_sends_ != 0)
206 if (send_calls_ != 0)
208 #pragma GCC diagnostic push
209 #pragma GCC diagnostic ignored "-Wsign-compare"
211 auto usecs_since_start = artdaq::TimeUtils::GetElapsedTimeMicroseconds(start_time_);
212 long delta = (long)(usecs_between_sends_ * send_calls_) - usecs_since_start;
213 if (delta > 0) usleep(delta);
215 TLOG(15) <<
"FillBuffer send_calls=" << send_calls_ <<
" usecs_since_start=" << usecs_since_start
216 <<
" delta=" << delta;
218 #pragma GCC diagnostic pop
226 *buffer =
reinterpret_cast<char*
>(
227 new uint8_t[
sizeof(demo::ToyFragment::Header) + maxADCcounts_ *
sizeof(
data_t)]);
237 return static_cast<int>(fragment_type_) + 1000;
242 switch (fragment_type_)
244 case demo::FragmentType::TOY1:
247 case demo::FragmentType::TOY2:
251 throw cet::exception(
"ToyHardwareInterface") <<
"Unknown board type " << fragment_type_ <<
" ("
252 << demo::fragmentTypeToString(fragment_type_) <<
").\n";
259 return serial_number_;
int NumADCBits() const
Get the number of ADC bits used in generating data.
void StartDatataking()
"StartDatataking" is meant to mimic actions one would take when telling the hardware to start sending...
uint16_t data_t
The type used to represent ADC counts (which are 12 or 14 bits, for TOY1 or TOY2) ...
void StopDatataking()
Performs shutdown actions.
void FillBuffer(char *buffer, size_t *bytes_read)
Use configured generator to fill a buffer with data.
DistributionType
Allow for the selection of output distribution.
void FreeReadoutBuffer(char *buffer)
Release the given buffer to the hardware.
A monotonically-increasing distribution.
ToyHardwareInterface(fhicl::ParameterSet const &ps)
Construct and configure ToyHardwareInterface.
A use-after-free expliot distribution.
void AllocateReadoutBuffer(char **buffer)
Request a buffer from the hardware.
int SerialNumber() const
Gets the serial number of the simulated hardware.
int BoardType() const
Return the "board type" of the simulated hardware.