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