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