artdaq_demo  v3_11_02
AsciiSimulator_generator.cc
1 #include "artdaq-demo/Generators/AsciiSimulator.hh"
2 
3 #include "canvas/Utilities/Exception.h"
4 
5 #include "artdaq-core-demo/Overlays/AsciiFragment.hh"
6 #include "artdaq-core-demo/Overlays/AsciiFragmentWriter.hh"
7 #include "artdaq-core-demo/Overlays/FragmentType.hh"
8 #include "artdaq-core/Utilities/SimpleLookupPolicy.hh"
9 #include "artdaq/Generators/GeneratorMacros.hh"
10 #include "cetlib_except/exception.h"
11 #include "fhiclcpp/ParameterSet.h"
12 
13 #include <fstream>
14 #include <iomanip>
15 #include <iostream>
16 #include <iterator>
17 
18 #include <unistd.h>
19 
20 namespace {
27 template<typename T>
28 T convertToASCII(std::string input)
29 {
30  if (input.size() < sizeof(T) / sizeof(char))
31  {
32  input.insert(0, sizeof(T) / sizeof(char) - input.size(), ' ');
33  }
34  else if (input.size() > sizeof(T) / sizeof(char))
35  {
36  input.erase(0, input.size() - sizeof(T) / sizeof(char));
37  }
38 
39  uint64_t bigOutput = 0ull;
40  // std::ofstream outputStr ("/tmp/ASCIIConverter.bin", std::ios::out | std::ios::app | std::ios::binary );
41  for (uint i = 0; i < input.length(); ++i)
42  {
43  // outputStr.write((char*)&input[i],sizeof(char));
44  bigOutput *= 0x100;
45  bigOutput += input[input.length() - i - 1];
46  }
47 
48  // outputStr.close();
49  return static_cast<T>(bigOutput);
50 }
51 } // namespace
52 
53 demo::AsciiSimulator::AsciiSimulator(fhicl::ParameterSet const& ps)
54  : CommandableFragmentGenerator(ps)
55  , throttle_usecs_(ps.get<size_t>("throttle_usecs", 100000))
56  , string1_(ps.get<std::string>("string1", "All work and no play makes ARTDAQ a dull library"))
57  , string2_(ps.get<std::string>("string2", "Hey, look at what ARTDAQ can do!"))
58  , timestamp_(0)
59  , timestampScale_(ps.get<int>("timestamp_scale_factor", 1))
60 {}
61 
62 bool demo::AsciiSimulator::getNext_(artdaq::FragmentPtrs& frags)
63 {
64  // JCF, 9/23/14
65 
66  // If throttle_usecs_ is greater than zero (i.e., user requests a
67  // sleep interval before generating the pseudodata) then during that
68  // interval perform a periodic check to see whether a stop request
69  // has been received
70 
71  // Values for throttle_usecs_ and throttle_usecs_check_ will have
72  // been tested for validity in constructor
73 
74  std::unique_lock<std::mutex> throttle_lock(throttle_mutex_);
75  throttle_cv_.wait_for(throttle_lock, std::chrono::microseconds(throttle_usecs_), [&]() { return should_stop(); });
76 
77  if (should_stop())
78  {
79  return false;
80  }
81 
82  // Set fragment's metadata
83  size_t data_size = (ev_counter() % 2) != 0u ? string1_.length() + 2 : string2_.length() + 2;
84  AsciiFragment::Metadata metadata;
85  std::string size_string = "S:" + std::to_string(data_size) + ",";
86  metadata.charsInLine = convertToASCII<AsciiFragment::Metadata::chars_in_line_t>(size_string);
87 
88  // And use it, along with the artdaq::Fragment header information
89  // (fragment id, sequence id, and user type) to create a fragment
90 
91  // We'll use the static factory function
92 
93  // artdaq::Fragment::FragmentBytes(std::size_t payload_size_in_bytes, sequence_id_t sequence_id,
94  // fragment_id_t fragment_id, type_t type, const T & metadata)
95 
96  // which will then return a unique_ptr to an artdaq::Fragment
97  // object. The advantage of this approach over using the
98  // artdaq::Fragment constructor is that, if we were to want to
99  // initialize the artdaq::Fragment with a nonzero-size payload (data
100  // after the artdaq::Fragment header and metadata), we could provide
101  // the size of the payload in bytes, rather than in units of the
102  // artdaq::Fragment's RawDataType (8 bytes, as of 3/26/14). The
103  // artdaq::Fragment constructor itself was not altered so as to
104  // maintain backward compatibility.
105 
106  std::size_t initial_payload_size = 0;
107 
108  std::unique_ptr<artdaq::Fragment> fragptr(artdaq::Fragment::FragmentBytes(
109  initial_payload_size, ev_counter(), fragment_id(), FragmentType::ASCII, metadata, timestamp_));
110  frags.emplace_back(std::move(fragptr));
111 
112  // Then any overlay-specific quantities next; will need the
113  // AsciiFragmentWriter class's setter-functions for this
114 
115  AsciiFragmentWriter newfrag(*frags.back());
116 
117  newfrag.set_hdr_line_number(
118  convertToASCII<AsciiFragment::Header::line_number_t>("LN:" + std::to_string(ev_counter()) + ","));
119 
120  newfrag.resize(data_size);
121 
122  // Now, generate the payload, based on the string to use
123  std::string string_to_use = (ev_counter() % 2) != 0u ? string1_ : string2_;
124  string_to_use += "\r\n";
125 
126  // std::ofstream output ("/tmp/ASCIIGenerator.bin", std::ios::out | std::ios::app | std::ios::binary );
127  for (uint i = 0; i < string_to_use.length(); ++i)
128  {
129  // output.write((char*)&string_to_use[i],sizeof(char));
130  *(newfrag.dataBegin() + i) = string_to_use[i]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
131  }
132  // output.close();
133 
134  ev_counter_inc();
135  timestamp_ += timestampScale_;
136 
137  return true;
138 }
139 
140 // The following macro is defined in artdaq's GeneratorMacros.hh header
141 DEFINE_ARTDAQ_COMMANDABLE_GENERATOR(demo::AsciiSimulator)
Generates ASCIIFragments filled with user-specified ASCII strings.
AsciiSimulator(fhicl::ParameterSet const &ps)
AsciiSimulator Constructor.
T convertToASCII(std::string input)
Convert sizeof(T) characters of a string to a number containing the ASCII representation of that stri...