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