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 , pause_after_N_seconds_(ps.get<size_t>(
"pause_after_N_seconds", 0))
28 , nADCcounts_after_N_seconds_(ps.get<size_t>(
"nADCcounts_after_N_seconds", nADCcounts_))
29 , exception_after_N_seconds_(ps.get<bool>(
"exception_after_N_seconds", false))
30 , exit_after_N_seconds_(ps.get<bool>(
"exit_after_N_seconds", false))
31 , abort_after_N_seconds_(ps.get<bool>(
"abort_after_N_seconds", false))
32 , hang_after_N_seconds_(ps.get<bool>(
"hang_after_N_seconds",false))
33 , fragment_type_(demo::toFragmentType(ps.get<std::string>(
"fragment_type")))
34 , maxADCvalue_(static_cast<size_t>(pow(2, NumADCBits()) - 1))
36 throttle_usecs_(ps.get<size_t>(
"throttle_usecs", 100000))
37 , usecs_between_sends_(ps.get<size_t>(
"usecs_between_sends", 0))
38 , distribution_type_(static_cast<
DistributionType>(ps.get<int>(
"distribution_type")))
39 , engine_(ps.get<int64_t>(
"random_seed", 314159))
40 , uniform_distn_(new std::uniform_int_distribution<
data_t>(0, maxADCvalue_))
41 , gaussian_distn_(new std::normal_distribution<double>(0.5 * maxADCvalue_, 0.1 * maxADCvalue_))
42 , start_time_(fake_time_)
44 , serial_number_((*uniform_distn_)(engine_))
47 if (nADCcounts_ > maxADCcounts_ ||
48 nADCcounts_after_N_seconds_ > maxADCcounts_)
50 throw cet::exception(
"HardwareInterface")
51 << R
"(Either (or both) of "nADCcounts" and "nADCcounts_after_N_seconds")"
52 << " is larger than the \"maxADCcounts\" setting (currently at " << maxADCcounts_ <<
")";
55 bool planned_disruption = nADCcounts_after_N_seconds_ != nADCcounts_ || exception_after_N_seconds_ ||
56 exit_after_N_seconds_ || abort_after_N_seconds_;
58 if (planned_disruption && change_after_N_seconds_ == std::numeric_limits<size_t>::max())
60 throw cet::exception(
"HardwareInterface") <<
"A FHiCL parameter designed to create a disruption has been "
61 "set, so \"change_after_N_seconds\" should be set as well";
80 start_time_ = fake_time_;
85 TLOG(TLVL_TRACE) <<
"FillBuffer BEGIN";
88 TLOG(6) <<
"FillBuffer: Sleeping for " << throttle_usecs_ <<
" microseconds";
89 usleep(throttle_usecs_);
91 auto elapsed_secs_since_datataking_start = artdaq::TimeUtils::GetElapsedTime(start_time_);
92 if (elapsed_secs_since_datataking_start < 0) elapsed_secs_since_datataking_start = 0;
94 if (static_cast<size_t>(elapsed_secs_since_datataking_start) < change_after_N_seconds_ || send_calls_ == 0)
96 TLOG(6) <<
"FillBuffer: Setting bytes_read to " <<
sizeof(demo::ToyFragment::Header) + nADCcounts_ *
sizeof(
data_t);
97 *bytes_read =
sizeof(demo::ToyFragment::Header) + nADCcounts_ *
sizeof(
data_t);
101 if (abort_after_N_seconds_)
103 TLOG(TLVL_ERROR) <<
"Engineered Abort!";
106 else if (exit_after_N_seconds_)
108 TLOG(TLVL_ERROR) <<
"Engineered Exit!";
111 else if (exception_after_N_seconds_)
113 TLOG(TLVL_ERROR) <<
"Engineered Exception!";
114 throw cet::exception(
"HardwareInterface")
115 <<
"This is an engineered exception designed for testing purposes";
117 else if (hang_after_N_seconds_)
119 TLOG(TLVL_ERROR) <<
"Pretending that the hardware has hung! Variable name for gdb: hardwareIsHung";
120 volatile bool hardwareIsHung =
true;
122 while (hardwareIsHung)
129 if ((pause_after_N_seconds_ != 0u) && (static_cast<size_t>(elapsed_secs_since_datataking_start) % change_after_N_seconds_ == 0))
131 TLOG(6) <<
"pausing " << pause_after_N_seconds_ <<
" seconds";
132 sleep(pause_after_N_seconds_);
133 TLOG(6) <<
"resuming after pause of " << pause_after_N_seconds_ <<
" seconds";
135 TLOG(6) <<
"FillBuffer: Setting bytes_read to " <<
sizeof(demo::ToyFragment::Header) + nADCcounts_after_N_seconds_ *
sizeof(
data_t);
136 *bytes_read =
sizeof(demo::ToyFragment::Header) + nADCcounts_after_N_seconds_ *
sizeof(
data_t);
140 TLOG(6) <<
"FillBuffer: Making the fake data, starting with the header";
146 assert(*bytes_read %
sizeof(demo::ToyFragment::Header::data_t) == 0);
148 auto* header =
reinterpret_cast<demo::ToyFragment::Header*
>(buffer);
150 header->event_size = *bytes_read /
sizeof(demo::ToyFragment::Header::data_t);
151 header->trigger_number = 99;
152 header->distribution_type =
static_cast<uint8_t
>(distribution_type_);
154 TLOG(6) <<
"FillBuffer: Generating nADCcounts ADC values ranging from 0 to max based on the desired distribution";
156 std::function<data_t()> generator;
159 switch (distribution_type_)
162 generator = [&]() {
return static_cast<data_t>((*uniform_distn_)(engine_)); };
169 gen_seed =
static_cast<data_t>(std::round((*gaussian_distn_)(engine_)));
170 }
while (gen_seed > maxADCvalue_);
178 if (++gen_seed > maxADCvalue_)
188 case DistributionType::uninit2:
192 throw cet::exception(
"HardwareInterface") <<
"Unknown distribution type specified";
197 TLOG(6) <<
"FillBuffer: Calling generate_n";
198 std::generate_n(reinterpret_cast<data_t*>(reinterpret_cast<demo::ToyFragment::Header*>(buffer) + 1),
199 nADCcounts_, generator);
204 throw cet::exception(
"ToyHardwareInterface") <<
"Attempt to call FillBuffer when not sending data";
207 if (send_calls_ == 0)
209 TLOG(6) <<
"FillBuffer has set the start_time_";
210 start_time_ = std::chrono::steady_clock::now();
213 if (usecs_between_sends_ != 0)
218 auto usecs_since_start = artdaq::TimeUtils::GetElapsedTimeMicroseconds(start_time_);
219 double delta =
static_cast<double>(usecs_between_sends_ * send_calls_) - usecs_since_start;
220 TLOG(6) <<
"FillBuffer send_calls=" << send_calls_ <<
" usecs_since_start=" << usecs_since_start
221 <<
" delta=" << delta;
224 TLOG(6) <<
"FillBuffer: Sleeping for " << delta <<
" microseconds";
232 TLOG(TLVL_TRACE) <<
"FillBuffer END";
237 *buffer =
reinterpret_cast<char*
>(
238 new uint8_t[
sizeof(demo::ToyFragment::Header) + maxADCcounts_ *
sizeof(
data_t)]);
248 return static_cast<int>(fragment_type_) + 1000;
253 switch (fragment_type_)
255 case demo::FragmentType::TOY1:
258 case demo::FragmentType::TOY2:
262 throw cet::exception(
"ToyHardwareInterface") <<
"Unknown board type " << fragment_type_ <<
" ("
263 << demo::fragmentTypeToString(fragment_type_) <<
").\n";
270 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(const 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.