mu2e_artdaq_core  v1_04_07
 All Classes Functions
ArtFragmentReader.hh
1 #ifndef mu2e_artdaq_core_Overlays_ArtFragmentReader_hh
2 #define mu2e_artdaq_core_Overlays_ArtFragmentReader_hh
3 
5 // ArtFragmentReader
6 //
7 // Class derived from mu2eFragment which provides additional methods
8 // for accessing data stored in a mu2eFragment
9 //
11 
12 #include "artdaq-core/Data/Fragment.hh"
13 #include "mu2e-artdaq-core/Overlays/ArtFragment.hh"
14 //#include "RecoDataProducts/CrvDigi.hh"
15 
16 #include <iostream>
17 #include <deque>
18 #include <unordered_map>
19 #include <array>
20 
21 namespace mu2e {
22 class ArtFragmentReader;
23 
24 std::ostream &operator<<(std::ostream &, ArtFragmentReader const &);
25 } // namespace mu2e
26 
28 {
29 public:
30  ArtFragmentReader(artdaq::Fragment const &f)
31  : ArtFragment(f){};
32 
33  enum class PacketType : uint8_t
34  {
35  DCSRequest = 0,
36  Heartbeat = 1,
37  DataRequest = 2,
38  DCSReply = 3,
39  Dataheader = 5
40  };
41 
42  const int format_version = 6;
43  /**************************************************************************
44  *************** DATA STRUCTURES ***************
45  **************************************************************************/
47  {
48  // Word 0
49  uint16_t ByteCount;
50  // Word 1
51  uint8_t Hopcount : 4;
52  uint8_t PacketType : 4;
53  uint8_t ROCID : 3;
54  uint8_t unused1 : 1;
55  uint8_t SubsystemID : 3;
56  uint8_t Valid : 1;
57  // Word 2
58  uint16_t PacketCount : 11;
59  uint16_t unused2 : 5;
60  // Word 3
61  uint16_t TimestampLow;
62  // Word 4
63  uint16_t TimestampMed;
64  // Word 5
65  uint16_t TimestampHigh;
66  // Word 6
67  uint8_t Status;
68  uint8_t FormatVersion;
69  // Word 7
70  uint8_t DTCID;
71  uint8_t EVBMode;
72 
74  : ByteCount(0)
75  , Hopcount(0)
76  , PacketType(0)
77  , ROCID(0)
78  , unused1(0)
79  , SubsystemID(0)
80  , Valid(0)
81  , PacketCount(0)
82  , unused2(0)
83  , TimestampLow(0)
84  , TimestampMed(0)
85  , TimestampHigh(0)
86  , Status(0)
87  , FormatVersion(0)
88  , DTCID(0)
89  , EVBMode(0)
90  {}
91  uint64_t GetTimestamp() const { return static_cast<uint64_t>(TimestampLow) + (static_cast<uint64_t>(TimestampMed) << 16) + (static_cast<uint64_t>(TimestampHigh) << 32); }
92  };
93 
95  {
96  uint16_t StrawIndex;
97  uint16_t TDC0;
98  uint16_t TDC1;
99  uint8_t TOT0;
100  uint8_t TOT1;
101  uint16_t ADC00 : 12;
102  uint16_t ADC01A : 4;
103  uint16_t ADC01B : 8;
104  uint16_t ADC01() const { return ADC01A + (ADC01B << 4); }
105  uint16_t ADC02A : 8;
106  uint16_t ADC02B : 4;
107  uint16_t ADC02() const { return ADC02A + (ADC02B << 8); }
108  uint16_t ADC03 : 12;
109 
110  uint16_t ADC04 : 12;
111  uint16_t ADC05A : 4;
112  uint16_t ADC05B : 8;
113  uint16_t ADC05() const { return ADC05A + (ADC05B << 4); }
114  uint16_t ADC06A : 8;
115  uint16_t ADC06B : 4;
116  uint16_t ADC06() const { return ADC06A + (ADC06B << 8); }
117  uint16_t ADC07 : 12;
118 
119  uint16_t ADC08 : 12;
120  uint16_t ADC09A : 4;
121  uint16_t ADC09B : 8;
122  uint16_t ADC09() const { return ADC09A + (ADC09B << 4); }
123  uint16_t ADC10A : 8;
124  uint16_t ADC10B : 4;
125  uint16_t ADC10() const { return ADC10A + (ADC10B << 8); }
126  uint16_t ADC11 : 12;
127 
128  uint16_t ADC12 : 12;
129  uint16_t ADC13A : 4;
130  uint16_t ADC13B : 8;
131  uint16_t ADC13() const { return ADC13A + (ADC13B << 4); }
132  uint16_t ADC14A : 8;
133  uint16_t ADC14B : 4;
134  uint16_t ADC14() const { return ADC14A + (ADC14B << 8); }
135 
136  uint16_t unused1 : 4;
137  uint16_t PreprocessingFlags : 8;
138 
140  : StrawIndex(0)
141  , TDC0(0)
142  , TDC1(0)
143  , TOT0(0)
144  , TOT1(0)
145  , ADC00(0)
146  , ADC01A(0)
147  , ADC01B(0)
148  , ADC02A(0)
149  , ADC02B(0)
150  , ADC03(0)
151  , ADC04(0)
152  , ADC05A(0)
153  , ADC05B(0)
154  , ADC06A(0)
155  , ADC06B(0)
156  , ADC07(0)
157  , ADC08(0)
158  , ADC09A(0)
159  , ADC09B(0)
160  , ADC10A(0)
161  , ADC10B(0)
162  , ADC11(0)
163  , ADC12(0)
164  , ADC13A(0)
165  , ADC13B(0)
166  , ADC14A(0)
167  , ADC14B(0)
168  , unused1(0)
169  , PreprocessingFlags(0)
170  {}
171 
172  std::array<adc_t, 15> Waveform() const
173  {
174  std::array<adc_t, 15> output;
175  output[0] = ADC00;
176  output[1] = ADC01();
177  output[2] = ADC02();
178  output[3] = ADC03;
179  output[4] = ADC04;
180  output[5] = ADC05();
181  output[6] = ADC06();
182  output[7] = ADC07;
183  output[8] = ADC08;
184  output[9] = ADC09();
185  output[10] = ADC10();
186  output[11] = ADC11;
187  output[12] = ADC12;
188  output[13] = ADC13();
189  output[14] = ADC14();
190  return output;
191  }
192 
193  void SetWaveform(size_t index, adc_t waveform)
194  {
195  switch (index)
196  {
197  case 0:
198  ADC00 = waveform & 0xFFF;
199  break;
200  case 1:
201  ADC01A = waveform & 0xF;
202  ADC01B = (waveform >> 4) & 0xFF;
203  break;
204  case 2:
205  ADC02A = waveform & 0xFF;
206  ADC02B = (waveform >> 8) & 0xF;
207  break;
208  case 3:
209  ADC03 = waveform & 0xFFF;
210  break;
211  case 4:
212  ADC04 = waveform & 0xFFF;
213  break;
214  case 5:
215  ADC05A = waveform & 0xF;
216  ADC05B = (waveform >> 4) & 0xFF;
217  break;
218  case 6:
219  ADC06A = waveform & 0xFF;
220  ADC06B = (waveform >> 8) & 0xF;
221  break;
222  case 7:
223  ADC07 = waveform & 0xFFF;
224  break;
225  case 8:
226  ADC08 = waveform & 0xFFF;
227  break;
228  case 9:
229  ADC09A = waveform & 0xF;
230  ADC09B = (waveform >> 4) & 0xFF;
231  break;
232  case 10:
233  ADC10A = waveform & 0xFF;
234  ADC10B = (waveform >> 8) & 0xF;
235  break;
236  case 11:
237  ADC11 = waveform & 0xFFF;
238  break;
239  case 12:
240  ADC12 = waveform & 0xFFF;
241  break;
242  case 13:
243  ADC13A = waveform & 0xF;
244  ADC13B = (waveform >> 4) & 0xFF;
245  break;
246  case 14:
247  ADC14A = waveform & 0xFF;
248  ADC14B = (waveform >> 8) & 0xF;
249  break;
250  }
251  }
252  };
253 
255  {
256  uint16_t NumberOfHits;
257 
259  : NumberOfHits(0) {}
260  };
261 
263  {
264  uint16_t BoardID : 10;
265  uint16_t ChannelStatusFlagsA : 6;
266  uint16_t ChannelStatusFlagsB : 14;
267  uint16_t unused : 2;
268 
270  : BoardID(0), ChannelStatusFlagsA(0), ChannelStatusFlagsB(0), unused(0) {}
271  };
272 
274  {
275  uint16_t ChannelNumber : 6;
276  uint16_t DIRACA : 10;
277  uint16_t DIRACB;
278  uint16_t ErrorFlags;
279  uint16_t Time;
280  uint8_t NumberOfSamples;
281  uint8_t IndexOfMaxDigitizerSample;
282 
284  : ChannelNumber(0), DIRACA(0), DIRACB(0), ErrorFlags(0), Time(0), NumberOfSamples(0), IndexOfMaxDigitizerSample(0) {}
285  };
286 
288  {
289  uint8_t unused1 : 4;
290  uint8_t PacketType : 4; // == 0x06
291  uint8_t ControllerID;
292  uint16_t ControllerEventWordCount;
293  uint8_t ActiveFEBFlags2;
294  uint8_t unused2;
295  uint8_t ActiveFEBFlags0;
296  uint8_t ActiveFEBFlags1;
297  uint8_t unused3;
298  uint8_t unused4;
299  uint16_t TriggerCount;
300  uint8_t unused5;
301  uint8_t unused6;
302  uint8_t Errors;
303  uint8_t EventType;
304 
306  : unused1(0)
307  , PacketType(0)
308  , ControllerID(0)
309  , ControllerEventWordCount(0)
310  , ActiveFEBFlags2(0)
311  , unused2(0)
312  , ActiveFEBFlags0(0)
313  , ActiveFEBFlags1(0)
314  , unused3(0)
315  , unused4(0)
316  , TriggerCount(0)
317  , unused5(0)
318  , unused6(0)
319  , Errors(0)
320  , EventType(0)
321  {}
322  };
323 
325  {
326  uint16_t SiPMID;
327  uint16_t HitTime : 10;
328  uint16_t NumSamples : 6;
329  uint8_t WaveformSample0;
330  uint8_t WaveformSample1;
331  uint8_t WaveformSample2;
332  uint8_t WaveformSample3;
333  uint8_t WaveformSample4;
334  uint8_t WaveformSample5;
335  uint8_t WaveformSample6;
336  uint8_t WaveformSample7;
337 
339  : SiPMID(0)
340  , HitTime(0)
341  , NumSamples(0)
342  , WaveformSample0(0)
343  , WaveformSample1(0)
344  , WaveformSample2(0)
345  , WaveformSample3(0)
346  , WaveformSample4(0)
347  , WaveformSample5(0)
348  , WaveformSample6(0)
349  , WaveformSample7(0) {}
350  std::array<unsigned int, 8> Waveform() const
351  {
352  std::array<unsigned int, 8> output;
353  output[0] = WaveformSample0;
354  output[1] = WaveformSample1;
355  output[2] = WaveformSample2;
356  output[3] = WaveformSample3;
357  output[4] = WaveformSample4;
358  output[5] = WaveformSample5;
359  output[6] = WaveformSample6;
360  output[7] = WaveformSample7;
361  return output;
362  }
363  };
364 
365  /**************************************************************************
366  *************** RETRIEVAL METHODS ***************
367  **************************************************************************/
368 
369  const DataBlockHeader *GetHeader(size_t block_num)
370  {
371  if (block_num >= block_count())
372  {
373  TLOG(TLVL_ERROR) << "Requested block " << block_num << " is outside the allowed range! (" << block_count() << ")";
374  return nullptr;
375  }
376  if (blockSizeBytes(block_num) < sizeof(DataBlockHeader))
377  {
378  TLOG(TLVL_ERROR) << "Data block size indicates that it does not contain a complete DataBlockHeader! This data is probably corrupt!";
379  return nullptr;
380  }
381  return reinterpret_cast<const DataBlockHeader *>(dataAtBlockIndex(block_num));
382  }
383 
384  const TrackerDataPacket *GetTrackerData(size_t block_num)
385  {
386  auto hdr = GetHeader(block_num);
387  if (hdr == nullptr) return nullptr;
388  if (hdr->SubsystemID != 0)
389  {
390  TLOG(TLVL_ERROR) << "Trying to get Tracker data packet from non-Tracker DataBlock!";
391  return nullptr;
392  }
393  if (blockSizeBytes(block_num) < sizeof(DataBlockHeader) + sizeof(TrackerDataPacket))
394  {
395  TLOG(TLVL_ERROR) << "Data Block size indicates that Tracker Data is not present! This event is probably corrupt!";
396  return nullptr;
397  }
398  return reinterpret_cast<const TrackerDataPacket *>(hdr + 1);
399  }
400 
401  const CalorimeterDataPacket *GetCalorimeterData(size_t block_num)
402  {
403  auto hdr = GetHeader(block_num);
404  if (hdr == nullptr) return nullptr;
405  if (hdr->SubsystemID != 1)
406  {
407  TLOG(TLVL_ERROR) << "Trying to get Calorimeter data packet from non-Calorimeter DataBlock!";
408  return nullptr;
409  }
410  auto pkt = reinterpret_cast<const CalorimeterDataPacket *>(hdr + 1);
411 
412  if (blockSizeBytes(block_num) < sizeof(DataBlockHeader) + sizeof(CalorimeterDataPacket) + sizeof(CalorimeterBoardID) + sizeof(uint16_t) * (pkt->NumberOfHits + sizeof(CalorimeterHitReadoutPacket)))
413  {
414  TLOG(TLVL_ERROR) << "DataBlock size and Calorimeter header indicate that this DataBlock does not contain a complete Calorimeter event! This data is probably corrupt!";
415  return nullptr;
416  }
417 
418  return pkt;
419  }
420 
421  const uint16_t *GetCalorimeterHitIndex(size_t block_num, size_t hit_num)
422  {
423  auto data_pkt = GetCalorimeterData(block_num);
424  if (data_pkt == nullptr) return nullptr;
425  if (hit_num >= data_pkt->NumberOfHits)
426  {
427  TLOG(TLVL_ERROR) << "Requested hit index " << hit_num << " is greater than the maximum (" << (data_pkt->NumberOfHits - 1) << ")!";
428  return nullptr;
429  }
430 
431  return reinterpret_cast<const uint16_t *>(data_pkt + 1) + hit_num;
432  }
433 
434  const CalorimeterBoardID *GetCalorimeterBoardID(size_t block_num)
435  {
436  auto data_pkt = GetCalorimeterData(block_num);
437  if (data_pkt == nullptr) return nullptr;
438 
439  return reinterpret_cast<const CalorimeterBoardID *>(reinterpret_cast<const uint16_t *>(data_pkt + 1) + data_pkt->NumberOfHits);
440  }
441 
442  const CalorimeterHitReadoutPacket *GetCalorimeterReadoutPacket(size_t block_num, size_t hit_num)
443  {
444  auto end_ptr = reinterpret_cast<const uint8_t *>(dataAtBlockIndex(block_num)) + blockSizeBytes(block_num);
445 
446  auto data_pkt = GetCalorimeterData(block_num);
447  if (data_pkt == nullptr) return nullptr;
448  if (hit_num >= data_pkt->NumberOfHits)
449  {
450  TLOG(TLVL_ERROR) << "Requested Hit Readout Packet at index " << hit_num << ", but maximum index is " << (data_pkt->NumberOfHits - 1) << "!";
451  return nullptr;
452  }
453 
454  if (ReadoutPacketPointerCache[block_num].size() == 0)
455  {
456  auto ptr = reinterpret_cast<const CalorimeterHitReadoutPacket *>(GetCalorimeterBoardID(block_num) + 1);
457  if (ptr == nullptr) return nullptr;
458  if (reinterpret_cast<const uint8_t *>(ptr) > end_ptr)
459  {
460  TLOG(TLVL_ERROR) << "Fell off the end of the DataBlock while processing CalorimeterHitReadoutPackets!";
461  return nullptr;
462  }
463  ReadoutPacketPointerCache[block_num].push_back(ptr);
464  }
465 
466  while (ReadoutPacketPointerCache[block_num].size() <= hit_num)
467  {
468  auto last_ptr = ReadoutPacketPointerCache[block_num].back();
469  auto ptr = reinterpret_cast<const CalorimeterHitReadoutPacket *>(reinterpret_cast<const uint16_t *>(last_ptr + 1) + last_ptr->NumberOfSamples);
470  if (reinterpret_cast<const uint8_t *>(ptr) > end_ptr)
471  {
472  TLOG(TLVL_ERROR) << "Fell off the end of the DataBlock while processing CalorimeterHitReadoutPackets!";
473  return nullptr;
474  }
475  ReadoutPacketPointerCache[block_num].push_back(ptr);
476  }
477  return ReadoutPacketPointerCache[block_num][hit_num];
478  }
479 
480  const uint16_t *GetCalorimeterReadoutSample(size_t block_num, size_t hit_num, size_t sample_num)
481  {
482  auto pkt = GetCalorimeterReadoutPacket(block_num, hit_num);
483  if (pkt == nullptr) return nullptr;
484  if (sample_num >= pkt->NumberOfSamples)
485  {
486  TLOG(TLVL_ERROR) << "Requested sample index " << sample_num << " is greater than the maximum allowed (" << (pkt->NumberOfSamples - 1) << ")!";
487  return nullptr;
488  }
489  return reinterpret_cast<const uint16_t *>(pkt + 1) + sample_num;
490  }
491 
492  const CRVROCStatusPacket *GetCRVROCStatusPacket(size_t block_num)
493  {
494  auto hdr = GetHeader(block_num);
495  if (hdr == nullptr) return nullptr;
496  if (hdr->SubsystemID != 2)
497  {
498  TLOG(TLVL_ERROR) << "Trying to get CRV data packet from non-CRV DataBlock!";
499  return nullptr;
500  }
501 
502  if (blockSizeBytes(block_num) < sizeof(DataBlockHeader) + sizeof(CRVROCStatusPacket))
503  {
504  TLOG(TLVL_ERROR) << "Data Block size indicates that CRV ROC Status Packet is not present! This event is probably corrupt!";
505  return nullptr;
506  }
507 
508  auto crv_hdr = reinterpret_cast<const CRVROCStatusPacket *>(hdr + 1);
509  if (blockSizeBytes(block_num) < sizeof(DataBlockHeader) + crv_hdr->ControllerEventWordCount)
510  {
511  TLOG(TLVL_ERROR) << "Inconsistency detected between Data Block Size (" << blockSizeBytes(block_num) << ") and CRV header's declared size (" << (sizeof(DataBlockHeader) + crv_hdr->ControllerEventWordCount) << ")! This event is probably corrupt!";
512  return nullptr;
513  }
514 
515  return crv_hdr;
516  }
517 
518  size_t GetCRVHitCount(size_t block_num)
519  {
520  auto hdr = GetCRVROCStatusPacket(block_num);
521  if (hdr == nullptr) return 0;
522 
523  size_t hit_bytes = hdr->ControllerEventWordCount - sizeof(CRVROCStatusPacket);
524 
525  size_t packet_count = hit_bytes / sizeof(CRVHitReadoutPacket);
526 
527  auto hit_packet = reinterpret_cast<const CRVHitReadoutPacket *>(hdr + 1);
528  if (*reinterpret_cast<const uint8_t *>(hit_packet + (packet_count - 1)) == 0)
529  {
530  packet_count--;
531  }
532 
533  return packet_count;
534  }
535 
536  const CRVHitReadoutPacket *GetCRVHitReadoutPacket(size_t block_num, size_t hit_idx)
537  {
538  auto hdr = GetCRVROCStatusPacket(block_num);
539  if (hdr == nullptr) return nullptr;
540 
541  auto hit_count = GetCRVHitCount(block_num);
542  if (hit_idx >= hit_count)
543  {
544  TLOG(TLVL_ERROR) << "Requested hit index " << hit_idx << " is greater than the last hit index in this DataBlock (" << (hit_count - 1) << ")!";
545  return nullptr;
546  }
547 
548  return reinterpret_cast<const CRVHitReadoutPacket *>(hdr + 1) + hit_idx;
549  }
550 
551 private:
552  std::unordered_map<size_t, std::deque<const CalorimeterHitReadoutPacket *>> ReadoutPacketPointerCache;
553 };
554 
555 #endif /* mu2e_artdaq_Overlays_ArtFragmentReader_hh */