mu2e_artdaq_core  v1_03_01
 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 
20 namespace mu2e {
21 class ArtFragmentReader;
22 
23 std::ostream &operator<<(std::ostream &, ArtFragmentReader const &);
24 } // namespace mu2e
25 
27 {
28 public:
29  ArtFragmentReader(artdaq::Fragment const &f)
30  : ArtFragment(f){};
31 
32  enum class PacketType : uint8_t
33  {
34  DCSRequest = 0,
35  Heartbeat = 1,
36  DataRequest = 2,
37  DCSReply = 3,
38  Dataheader = 5
39  };
40 
41  const int format_version = 6;
42  /**************************************************************************
43  *************** DATA STRUCTURES ***************
44  **************************************************************************/
46  {
47  // Word 0
48  uint16_t ByteCount;
49  // Word 1
50  uint8_t Hopcount : 4;
51  uint8_t PacketType : 4;
52  uint8_t ROCID : 3;
53  uint8_t unused1 : 1;
54  uint8_t SubsystemID : 3;
55  uint8_t Valid : 1;
56  // Word 2
57  uint16_t PacketCount : 11;
58  uint16_t unused2 : 5;
59  // Word 3
60  uint16_t TimestampLow;
61  // Word 4
62  uint16_t TimestampMed;
63  // Word 5
64  uint16_t TimestampHigh;
65  // Word 6
66  uint8_t Status;
67  uint8_t FormatVersion;
68  // Word 7
69  uint8_t DTCID;
70  uint8_t EVBMode;
71 
72  uint64_t GetTimestamp() const { return static_cast<uint64_t>(TimestampLow) + (static_cast<uint64_t>(TimestampMed) << 16) + (static_cast<uint64_t>(TimestampHigh) << 32); }
73  };
74 
76  {
77  uint16_t StrawIndex;
78  uint16_t TDC0;
79  uint16_t TDC1;
80  uint8_t TOT0;
81  uint8_t TOT1;
82  uint64_t ADC00 : 12; // 12b
83  uint64_t ADC01 : 12; // 24b
84  uint64_t ADC02 : 12; // 36b
85  uint64_t ADC03 : 12; // 48b
86  uint64_t ADC04 : 12; // 60b
87  uint64_t ADC05A : 4; // 64b
88  uint64_t ADC05B : 8; // 8b
89  uint16_t ADC05() const { return static_cast<uint16_t>(ADC05A) + static_cast<uint16_t>(ADC05B << 4); }
90  uint64_t ADC06 : 12; // 20b
91  uint64_t ADC07 : 12; // 32b
92  uint64_t ADC08 : 12; // 44b
93  uint64_t ADC09 : 12; // 56b
94  uint64_t ADC10A : 8; // 64b
95  uint64_t ADC10B : 4; // 4b
96  uint16_t ADC10() const { return static_cast<uint16_t>(ADC10A) + static_cast<uint16_t>(ADC10B << 8); }
97  uint64_t ADC11 : 12; // 16b
98  uint64_t ADC12 : 12; // 28b
99  uint64_t ADC13 : 12; // 40b
100  uint64_t ADC14 : 12; // 52b
101  uint64_t unused1 : 4;
102  uint64_t PreprocessingFlags : 8;
103 
104  std::array<adc_t, 15> Waveform() const
105  {
106  std::array<adc_t, 15> output;
107  output[0] = ADC00;
108  output[1] = ADC01;
109  output[2] = ADC02;
110  output[3] = ADC03;
111  output[4] = ADC04;
112  output[5] = ADC05();
113  output[6] = ADC06;
114  output[7] = ADC07;
115  output[8] = ADC08;
116  output[9] = ADC09;
117  output[10] = ADC10();
118  output[11] = ADC11;
119  output[12] = ADC12;
120  output[13] = ADC13;
121  output[14] = ADC14;
122  return output;
123  }
124  };
125 
127  {
128  uint16_t NumberOfHits;
129  };
130 
132  {
133  uint16_t BoardID : 10;
134  uint16_t ChannelStatusFlagsA : 6;
135  uint16_t ChannelStatusFlagsB : 14;
136  uint16_t unused : 2;
137  };
138 
140  {
141  uint16_t ChannelNumber : 6;
142  uint16_t DIRACA : 10;
143  uint16_t DIRACB;
144  uint16_t ErrorFlags;
145  uint16_t Time;
146  uint8_t NumberOfSamples;
147  uint8_t IndexOfMaxDigitizerSample;
148  };
149 
151  {
152  uint8_t unused1 : 4;
153  uint8_t PacketType : 4; // == 0x06
154  uint8_t ControllerID;
155  uint16_t ControllerEventWordCount;
156  uint8_t ActiveFEBFlags2;
157  uint8_t unused2;
158  uint8_t ActiveFEBFlags0;
159  uint8_t ActiveFEBFlags1;
160  uint8_t unused3;
161  uint8_t unused4;
162  uint16_t TriggerCount;
163  uint8_t unused5;
164  uint8_t unused6;
165  uint8_t Errors;
166  uint8_t EventType;
167  };
168 
170  {
171  uint16_t SiPMID;
172  uint16_t HitTime : 10;
173  uint16_t NumSamples : 6;
174  uint8_t WaveformSample0;
175  uint8_t WaveformSample1;
176  uint8_t WaveformSample2;
177  uint8_t WaveformSample3;
178  uint8_t WaveformSample4;
179  uint8_t WaveformSample5;
180  uint8_t WaveformSample6;
181  uint8_t WaveformSample7;
182 
183  std::array<unsigned int, 8> Waveform() const {
184  std::array<unsigned int, 8> output;
185  output[0] = WaveformSample0;
186  output[1] = WaveformSample1;
187  output[2] = WaveformSample2;
188  output[3] = WaveformSample3;
189  output[4] = WaveformSample4;
190  output[5] = WaveformSample5;
191  output[6] = WaveformSample6;
192  output[7] = WaveformSample7;
193  return output;
194  }
195  };
196 
197  /**************************************************************************
198  *************** RETRIEVAL METHODS ***************
199  **************************************************************************/
200 
201  const DataBlockHeader *GetHeader(size_t block_num)
202  {
203  if (block_num >= block_count())
204  {
205  TLOG(TLVL_ERROR) << "Requested block " << block_num << " is outside the allowed range! (" << block_count() << ")";
206  return nullptr;
207  }
208  if (blockSizeBytes(block_num) < sizeof(DataBlockHeader))
209  {
210  TLOG(TLVL_ERROR) << "Data block size indicates that it does not contain a complete DataBlockHeader! This data is probably corrupt!";
211  return nullptr;
212  }
213  return reinterpret_cast<const DataBlockHeader *>(dataAtBlockIndex(block_num));
214  }
215 
216  const TrackerDataPacket *GetTrackerData(size_t block_num)
217  {
218  auto hdr = GetHeader(block_num);
219  if (hdr == nullptr) return nullptr;
220  if (hdr->SubsystemID != 0)
221  {
222  TLOG(TLVL_ERROR) << "Trying to get Tracker data packet from non-Tracker DataBlock!";
223  return nullptr;
224  }
225  if (blockSizeBytes(block_num) < sizeof(DataBlockHeader) + sizeof(TrackerDataPacket))
226  {
227  TLOG(TLVL_ERROR) << "Data Block size indicates that Tracker Data is not present! This event is probably corrupt!";
228  return nullptr;
229  }
230  return reinterpret_cast<const TrackerDataPacket *>(hdr + 1);
231  }
232 
233  const CalorimeterDataPacket *GetCalorimeterData(size_t block_num)
234  {
235  auto hdr = GetHeader(block_num);
236  if (hdr == nullptr) return nullptr;
237  if (hdr->SubsystemID != 1)
238  {
239  TLOG(TLVL_ERROR) << "Trying to get Calorimeter data packet from non-Calorimeter DataBlock!";
240  return nullptr;
241  }
242  auto pkt = reinterpret_cast<const CalorimeterDataPacket *>(hdr + 1);
243 
244  if (blockSizeBytes(block_num) < sizeof(DataBlockHeader) + sizeof(CalorimeterDataPacket) + sizeof(CalorimeterBoardID) + sizeof(uint16_t) * (pkt->NumberOfHits + sizeof(CalorimeterHitReadoutPacket)))
245  {
246  TLOG(TLVL_ERROR) << "DataBlock size and Calorimeter header indicate that this DataBlock does not contain a complete Calorimeter event! This data is probably corrupt!";
247  return nullptr;
248  }
249 
250  return pkt;
251  }
252 
253  const uint16_t *GetCalorimeterHitIndex(size_t block_num, size_t hit_num)
254  {
255  auto data_pkt = GetCalorimeterData(block_num);
256  if (data_pkt == nullptr) return nullptr;
257  if (hit_num >= data_pkt->NumberOfHits)
258  {
259  TLOG(TLVL_ERROR) << "Requested hit index " << hit_num << " is greater than the maximum (" << (data_pkt->NumberOfHits - 1) << ")!";
260  return nullptr;
261  }
262 
263  return reinterpret_cast<const uint16_t *>(data_pkt + 1) + hit_num;
264  }
265 
266  const CalorimeterBoardID *GetCalorimeterBoardID(size_t block_num)
267  {
268  auto data_pkt = GetCalorimeterData(block_num);
269  if (data_pkt == nullptr) return nullptr;
270 
271  return reinterpret_cast<const CalorimeterBoardID *>(reinterpret_cast<const uint16_t *>(data_pkt + 1) + data_pkt->NumberOfHits);
272  }
273 
274  const CalorimeterHitReadoutPacket *GetCalorimeterReadoutPacket(size_t block_num, size_t hit_num)
275  {
276  auto end_ptr = reinterpret_cast<const uint8_t *>(dataAtBlockIndex(block_num)) + blockSizeBytes(block_num);
277 
278  auto data_pkt = GetCalorimeterData(block_num);
279  if (data_pkt == nullptr) return nullptr;
280  if (hit_num >= data_pkt->NumberOfHits)
281  {
282  TLOG(TLVL_ERROR) << "Requested Hit Readout Packet at index " << hit_num << ", but maximum index is " << (data_pkt->NumberOfHits - 1) << "!";
283  return nullptr;
284  }
285 
286  if (ReadoutPacketPointerCache[block_num].size() == 0)
287  {
288  auto ptr = reinterpret_cast<const CalorimeterHitReadoutPacket *>(GetCalorimeterBoardID(block_num) + 1);
289  if (ptr == nullptr) return nullptr;
290  if (reinterpret_cast<const uint8_t *>(ptr) > end_ptr)
291  {
292  TLOG(TLVL_ERROR) << "Fell off the end of the DataBlock while processing CalorimeterHitReadoutPackets!";
293  return nullptr;
294  }
295  ReadoutPacketPointerCache[block_num].push_back(ptr);
296  }
297 
298  while (ReadoutPacketPointerCache[block_num].size() < hit_num + 1)
299  {
300  auto last_ptr = ReadoutPacketPointerCache[block_num].back();
301  auto ptr = reinterpret_cast<const CalorimeterHitReadoutPacket *>(reinterpret_cast<const uint16_t *>(last_ptr + 1) + last_ptr->NumberOfSamples);
302  if (reinterpret_cast<const uint8_t *>(ptr) > end_ptr)
303  {
304  TLOG(TLVL_ERROR) << "Fell off the end of the DataBlock while processing CalorimeterHitReadoutPackets!";
305  return nullptr;
306  }
307  ReadoutPacketPointerCache[block_num].push_back(ptr);
308  }
309  return ReadoutPacketPointerCache[block_num][hit_num + 1];
310  }
311 
312  const uint16_t *GetCalorimeterReadoutSample(size_t block_num, size_t hit_num, size_t sample_num)
313  {
314  auto pkt = GetCalorimeterReadoutPacket(block_num, hit_num);
315  if (pkt == nullptr) return nullptr;
316  if (sample_num >= pkt->NumberOfSamples)
317  {
318  TLOG(TLVL_ERROR) << "Requested sample index " << sample_num << " is greater than the maximum allowed (" << (pkt->NumberOfSamples - 1) << ")!";
319  return nullptr;
320  }
321  return reinterpret_cast<const uint16_t *>(pkt + 1) + sample_num;
322  }
323 
324  const CRVROCStatusPacket *GetCRVROCStatusPacket(size_t block_num)
325  {
326  auto hdr = GetHeader(block_num);
327  if (hdr == nullptr) return nullptr;
328  if (hdr->SubsystemID != 2)
329  {
330  TLOG(TLVL_ERROR) << "Trying to get CRV data packet from non-CRV DataBlock!";
331  return nullptr;
332  }
333 
334  if (blockSizeBytes(block_num) < sizeof(DataBlockHeader) + sizeof(CRVROCStatusPacket))
335  {
336  TLOG(TLVL_ERROR) << "Data Block size indicates that CRV ROC Status Packet is not present! This event is probably corrupt!";
337  return nullptr;
338  }
339 
340  auto crv_hdr = reinterpret_cast<const CRVROCStatusPacket *>(hdr + 1);
341  if (blockSizeBytes(block_num) < sizeof(DataBlockHeader) + crv_hdr->ControllerEventWordCount)
342  {
343  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!";
344  return nullptr;
345  }
346 
347  return crv_hdr;
348  }
349 
350  size_t GetCRVHitCount(size_t block_num)
351  {
352  auto hdr = GetCRVROCStatusPacket(block_num);
353  if (hdr == nullptr) return 0;
354 
355  size_t hit_bytes = hdr->ControllerEventWordCount - sizeof(CRVROCStatusPacket);
356 
357  size_t packet_count = hit_bytes / sizeof(CRVHitReadoutPacket);
358 
359  auto hit_packet = reinterpret_cast<const CRVHitReadoutPacket *>(hdr + 1);
360  if (*reinterpret_cast<const uint8_t *>(hit_packet + (packet_count - 1)) == 0)
361  {
362  packet_count--;
363  }
364 
365  return packet_count;
366  }
367 
368  const CRVHitReadoutPacket *GetCRVHitReadoutPacket(size_t block_num, size_t hit_idx)
369  {
370  auto hdr = GetCRVROCStatusPacket(block_num);
371  if (hdr == nullptr) return nullptr;
372 
373  auto hit_count = GetCRVHitCount(block_num);
374  if (hit_idx >= hit_count) {
375  TLOG(TLVL_ERROR) << "Requested hit index " << hit_idx << " is greater than the last hit index in this DataBlock (" << (hit_count - 1) << ")!";
376  return nullptr;
377  }
378 
379  return reinterpret_cast<const CRVHitReadoutPacket *>(hdr + 1) + hit_idx;
380  }
381 
382 private:
383  std::unordered_map<size_t, std::deque<const CalorimeterHitReadoutPacket *>> ReadoutPacketPointerCache;
384 };
385 
386 #endif /* mu2e_artdaq_Overlays_ArtFragmentReader_hh */