mu2e_artdaq_core  v1_02_31
 All Classes Functions
DetectorFragment.hh
1 #ifndef mu2e_artdaq_Overlays_DetectorFragment_hh
2 #define mu2e_artdaq_Overlays_DetectorFragment_hh
3 
4 #include "artdaq-core/Data/Fragment.hh"
5 #include "cetlib_except/exception.h"
6 
7 #include <iostream>
8 
9 #include <ostream>
10 #include <vector>
11 
12 #include <bitset>
13 
14 //#include "dtcInterfaceLib/DTC.h"
15 
16 // Implementation of "DetectorFragment", an artdaq::Fragment overlay class
17 // used for processing data from the detector. This class provides helper
18 // functions for parsing bits in DTC packets, as well as functions for
19 // accessing specific variables stored in DTC header packets.
20 
21 namespace mu2e {
22 class DetectorFragment;
23 
24 // Let the "<<" operator dump the DetectorFragment's data to stdout
25 std::ostream &operator<<(std::ostream &, DetectorFragment const &);
26 } // namespace mu2e
27 
29 {
30 public:
31  // The DetectorFragment represents its data through the adc_t type, which
32  // is a typedef of an unsigned 16-bit integer.
33 
34  typedef uint16_t adc_t;
35 
36  // The "Metadata" struct is used to store info primarily related to
37  // the upstream hardware environment from where the fragment came
38 
39  // "data_t" is a typedef of the fundamental unit of data the
40  // metadata structure thinks of itself as consisting of; it can give
41  // its size via the static "size_words" variable (
42  // DetectorFragment::Metadata::size_words )
43 
44  struct Metadata
45  {
46  typedef uint32_t data_t;
47  // typedef __uint128_t data_t;
48 
49  data_t board_serial_number : 16;
50  data_t num_adc_bits : 8;
51  data_t unused : 8; // 16 + 8 + 8 == 32 bits
52 
53  static size_t const size_words = 1ul; // Units of Metadata::data_t
54  };
55 
56  static_assert(sizeof(Metadata) == Metadata::size_words * sizeof(Metadata::data_t),
57  "DetectorFragment::Metadata size changed");
58 
59  // The "Header" struct contains "metadata" specific to the fragment
60  // which is not hardware-related
61 
62  // Header::data_t -- not to be confused with Metadata::data_t ! --
63  // describes the standard size of a data type not just for the
64  // header data, but ALSO the physics data beyond it; the size of the
65  // header in units of Header::data_t is given by "size_words", and
66  // the size of the fragment beyond the header in units of
67  // Header::data_t is given by "event_size"
68 
69  // Notice only the first 28 bits of the first 32-bit unsigned
70  // integer in the Header is used to hold the event_size ; this means
71  // that you can't represent a fragment larger than 2**28 units of
72  // data_t, or 1,073,741,824 bytes
73 
74  struct Header
75  {
76  typedef uint32_t data_t;
77 
78  typedef uint32_t event_size_t;
79  typedef uint32_t run_number_t;
80 
81  event_size_t event_size : 28;
82  event_size_t unused_1 : 4;
83 
84  run_number_t run_number : 32;
85 
86  static size_t const size_words = 2ul; // Units of Header::data_t
87  };
88 
89  static_assert(sizeof(Header) == Header::size_words * sizeof(Header::data_t), "DetectorFragment::Header size changed");
90 
91  // The constructor simply sets its const private member "artdaq_Fragment_"
92  // to refer to the artdaq::Fragment object
93 
94  DetectorFragment(artdaq::Fragment const &f)
95  : current_offset_(0), current_offset_index_(0), artdaq_Fragment_(f) {}
96 
97  virtual ~DetectorFragment() {}
98 
99  // const getter functions for the data in the header
100 
101  Header::event_size_t hdr_event_size() const { return header_()->event_size; }
102  Header::run_number_t hdr_run_number() const { return header_()->run_number; }
103  static constexpr size_t hdr_size_words() { return Header::size_words; }
104 
105  // The number of ADC values describing data beyond the header
106  size_t total_adc_values() const { return (hdr_event_size() - hdr_size_words()) * adcs_per_word_(); }
107 
108  size_t total_adc_values_in_data_block() const
109  {
110  mu2e::DetectorFragment::adc_t packetCount = convertFromBinary(bitArray(dataBlockBegin()), 127 - 43, 127 - 32);
111  return 8 * (size_t(packetCount) + 1);
112  }
113 
114  // Start of the ADC values returned as a pointer to the ADC type
115  adc_t const *dataBegin() const { return (reinterpret_cast<mu2e::DetectorFragment::adc_t const *>(header_() + 1)); }
116  // End of the ADC values, returned as a pointer to the ADC type
117  adc_t const *dataEnd() const { return dataBegin() + total_adc_values(); }
118 
119  // Start of the ADC values for the current block, returned as a
120  // pointer to the 16-bit ADC type
121  adc_t const *dataBlockBegin() const
122  {
123  return (reinterpret_cast<mu2e::DetectorFragment::adc_t const *>(header_() + 1)) + current_offset_;
124  }
125  // End of the ADC values for the current data block, returned as
126  // a pointer to the 16-bit ADC type
127  adc_t const *dataBlockEnd() const { return dataBlockBegin() + total_adc_values_in_data_block(); }
128 
129  // Functions to check if any ADC values are corrupt
130 
131  // findBadADC() checks to make sure that the ADC type (adc_t) variable
132  // holding the ADC value doesn't contain bits beyond the expected
133  // range, i.e., can't be evaluated to a larger value than the max
134  // permitted ADC value
135 
136  adc_t const *findBadADC(int daq_adc_bits) const
137  {
138  return std::find_if(dataBegin(), dataEnd(),
139  [&](mu2e::DetectorFragment::adc_t const adc) -> bool { return (adc >> daq_adc_bits); });
140  }
141 
142  bool fastVerify(int daq_adc_bits) const { return (findBadADC(daq_adc_bits) == dataEnd()); };
143 
144  // Defined in DetectorFragment.cc, this throws if any ADC appears corrupt
145  void checkADCData(int daq_adc_bits) const;
146 
147  // Largest ADC value possible
148  size_t adc_range(int daq_adc_bits) { return (1ul << daq_adc_bits); }
149 
150  size_t numDataBlocks()
151  {
152  size_t data_counter = 0;
153  size_t numDataBlocks = 0;
154  size_t totalPacketsRead = 0;
155  for (mu2e::DetectorFragment::adc_t const *curPos = dataBegin(); curPos != dataEnd(); curPos += 8) {
156  if (data_counter == 0) {
157  // std::cout << "ERR: data_counter==0" << std::endl << std::flush;
158 
159  // Verify that this is a header block
160  mu2e::DetectorFragment::adc_t packetType = convertFromBinary(bitArray(curPos), 127 - 24, 127 - 20);
161  mu2e::DetectorFragment::adc_t packetCount = convertFromBinary(bitArray(curPos), 127 - 43, 127 - 32);
162  // mu2e::DetectorFragment::adc_t status = convertFromBinary(bitArray(curPos),127-104,127-96);
163  data_counter = packetCount;
164  // Increment number of data blocks
165  if (packetType == 5 || packetType == 0x1 ||
166  packetType == 0x2) { // Type 0x1 and 0x2 correspond to debug header packets
167  numDataBlocks++;
168  }
169  else
170  {
171  // DTCLib::DTC_DataPacket errPacket((char*)curPos);
172  // std::cout << "ERR: Packet Type: " << packetType << std::endl << std::flush;
173  // std::cout << "ERR: Packet Conut: " << packetCount << std::endl << std::flush;
174  // std::cout << "ERR: totalPacketsRead: " << totalPacketsRead << std::endl << std::flush;
175  // std::cout << "ERR: BitArray: " << std::endl << std::flush;
176  // printBitArray(bitArray(curPos));
177  // std::cout << std::flush;
178  throw cet::exception("Error in DetectorFragment: Non-dataheader packet found in dataheader packet location");
179  }
180  }
181  else
182  {
183  data_counter--;
184  }
185  totalPacketsRead++;
186  }
187 
188  return numDataBlocks;
189  }
190 
191  size_t offset() { return current_offset_; }
192 
193  size_t offsetIndex() { return current_offset_index_; }
194 
195  bool setDataBlockIndex(size_t theIndex)
196  {
197  size_t numDB = numDataBlocks();
198  if (theIndex < numDB) {
199  current_offset_index_ = theIndex;
200  current_offset_ = 0;
201 
202  size_t blockNum = 0;
203  mu2e::DetectorFragment::adc_t const *curPos = dataBegin();
204  bool foundBlock = false;
205  while (!foundBlock) {
206  mu2e::DetectorFragment::adc_t packetCount = convertFromBinary(bitArray(curPos), 127 - 43, 127 - 32);
207  if (blockNum == theIndex) {
208  foundBlock = true;
209  // current_block_length_ = 8*(size_t(packetCount) + 1)
210  }
211  else
212  {
213  // Jump to the next header packet:
214  // (add 1 for the DTC header packet which is not included in the packet count)
215  curPos += 8 * (size_t(packetCount) + 1);
216 
217  current_offset_ += 8 * (size_t(packetCount) + 1);
218 
219  blockNum++;
220  }
221  }
222  }
223  else
224  {
225  return false;
226  }
227  return true;
228  }
229 
230  // DTC Header Packet Methods
231  adc_t byteCount();
232  adc_t rocID();
233  adc_t packetType();
234  adc_t valid();
235  adc_t packetCount();
236  adc_t status();
237  std::vector<adc_t> timestampVector();
238  std::vector<adc_t> dataVector();
239  void printDTCHeader();
240  virtual void printAll();
241 
242 protected:
243  // Functions to translate between size (in bytes) of an ADC, size of
244  // this fragment overlay's concept of a unit of data (i.e.,
245  // Header::data_t) and size of an artdaq::Fragment's concept of a
246  // unit of data (the artdaq::Fragment::value_type).
247 
248  static constexpr size_t adcs_per_word_() { return sizeof(Header::data_t) / sizeof(adc_t); }
249 
250  static constexpr size_t words_per_frag_word_()
251  {
252  return sizeof(artdaq::Fragment::value_type) / sizeof(Header::data_t);
253  }
254 
255  // header_() simply takes the address of the start of this overlay's
256  // data (i.e., where the DetectorFragment::Header object begins) and
257  // casts it as a pointer to DetectorFragment::Header
258 
259  Header const *header_() const
260  {
261  return reinterpret_cast<DetectorFragment::Header const *>(&*artdaq_Fragment_.dataBegin());
262  }
263 
264  // Bit processing helper methods
265  // For now, the focus is on clarity and ease of use, but eventually
266  // these sorts of functions will need to be optimized for efficiency
267 
268  // bitArray populates a 128-bit bitset using the 128 bits beginning
269  // at the position indicated by the provided pointer
270  // std::bitset<128> bitArray(adc_t const * beginning);
271  std::bitset<128> bitArray(mu2e::DetectorFragment::adc_t const *beginning) const;
272 
273  // Populates the provided bitset using the 128 bits beginning at the
274  // position indicated by the provided pointer
275  void fillBitArray(std::bitset<128> &theArray, adc_t const *beginning);
276 
277  void printBitArray(std::bitset<128> theArray);
278 
279  // Accepts a 128 bit biteset and converts the bits from minIdx to maxIdx
280  // into a 16-bit adc_t (minIdx and maxIdx should be within 16 bits of
281  // each other as no error-checking is performed at the moment).
282  mu2e::DetectorFragment::adc_t convertFromBinary(std::bitset<128> theArray, int minIdx, int maxIdx) const;
283 
284  // current_offset_ stores the offset of the DataBlock currently being accessed
285  size_t current_offset_;
286  size_t current_offset_index_;
287 
288  // // Length of the current datablock in units of 16-bit adc_t values
289  // size_t current_block_length_;
290 
291 private:
292  artdaq::Fragment const &artdaq_Fragment_;
293 };
294 
295 #endif /* mu2e_artdaq_Overlays_DetectorFragment_hh */