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"
23 : taking_data_( false )
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_ ) { std::abort(); }
109 else if ( exit_after_N_seconds_ )
113 else if ( exception_after_N_seconds_ )
115 throw cet::exception(
"HardwareInterface" )
116 <<
"This is an engineered exception designed for testing purposes";
118 else if ( nADCcounts_after_N_seconds_ >= 0 )
120 *bytes_read =
sizeof( demo::ToyFragment::Header ) + nADCcounts_after_N_seconds_ *
sizeof(
data_t );
135 assert( *bytes_read %
sizeof( demo::ToyFragment::Header::data_t ) == 0 );
137 demo::ToyFragment::Header* header =
reinterpret_cast<demo::ToyFragment::Header*
>( buffer );
139 header->event_size = *bytes_read /
sizeof( demo::ToyFragment::Header::data_t );
140 header->trigger_number = 99;
141 header->distribution_type =
static_cast<uint8_t
>( distribution_type_ );
146 std::function<data_t()> generator;
149 switch ( distribution_type_ )
152 generator = [&]() {
return static_cast<data_t>( ( *uniform_distn_ )( engine_ ) ); };
159 gen_seed =
static_cast<data_t>( std::round( ( *gaussian_distn_ )( engine_ ) ) );
160 }
while ( gen_seed > maxADCvalue_ );
168 if ( ++gen_seed > maxADCvalue_ ) gen_seed = 0;
175 case DistributionType::uninit2:
179 throw cet::exception(
"HardwareInterface" ) <<
"Unknown distribution type specified";
184 std::generate_n( reinterpret_cast<data_t*>( reinterpret_cast<demo::ToyFragment::Header*>( buffer ) + 1 ),
185 nADCcounts_, generator );
190 throw cet::exception(
"ToyHardwareInterface" ) <<
"Attempt to call FillBuffer when not sending data";
193 if ( send_calls_ == 0 )
195 start_time_ = std::chrono::steady_clock::now();
196 TLOG( 50 ) <<
"FillBuffer has set the start_time_";
199 if ( usecs_between_sends_ != 0 )
201 if ( send_calls_ != 0 )
203 #pragma GCC diagnostic push
204 #pragma GCC diagnostic ignored "-Wsign-compare"
206 auto usecs_since_start = artdaq::TimeUtils::GetElapsedTimeMicroseconds( start_time_ );
207 long delta = (long)( usecs_between_sends_ * send_calls_ ) - usecs_since_start;
208 if ( delta > 0 ) usleep( delta );
210 TLOG( 15 ) <<
"FillBuffer send_calls=" << send_calls_ <<
" usecs_since_start=" << usecs_since_start
211 <<
" delta=" << delta;
213 #pragma GCC diagnostic pop
221 *buffer =
reinterpret_cast<char*
>(
222 new uint8_t[
sizeof( demo::ToyFragment::Header ) + maxADCcounts_ *
sizeof(
data_t ) ] );
232 return static_cast<int>( fragment_type_ ) + 1000;
237 switch ( fragment_type_ )
239 case demo::FragmentType::TOY1:
242 case demo::FragmentType::TOY2:
246 throw cet::exception(
"ToyHardwareInterface" ) <<
"Unknown board type " << fragment_type_ <<
" ("
247 << demo::fragmentTypeToString( fragment_type_ ) <<
").\n";
254 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.