CMS 3D CMS Logo

HGCalUnpacker.cc
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * This is a part of HGCAL offline software.
4  * Authors:
5  * Yulun Miao, Northwestern University
6  * Huilin Qu, CERN
7  * Laurent Forthomme, CERN
8  *
9  ****************************************************************************/
10 
12 
15 
16 template <class D>
18  : config_(config),
19  channelData_(config_.channelMax),
20  commonModeIndex_(config_.channelMax),
21  commonModeData_(config_.commonModeMax) {}
22 
23 template <class D>
25  const std::vector<uint32_t>& inputArray,
26  const std::function<uint16_t(uint16_t sLink, uint8_t captureBlock, uint8_t econd)>& enabledERXMapping,
27  const std::function<D(HGCalElectronicsId elecID)>& logicalMapping) {
28  uint16_t sLink = 0;
29 
30  channelDataSize_ = 0;
31  commonModeDataSize_ = 0;
32  badECOND_.clear();
33 
34  for (uint32_t iword = 0; iword < inputArray.size();) { // loop through the S-Link
35  //----- parse the S-Link header
36  if (((inputArray[iword] >> kSLinkBOEShift) & kSLinkBOEMask) != config_.sLinkBOE) // sanity check
37  throw cms::Exception("CorruptData")
38  << "Expected a S-Link header at word " << std::dec << iword << "/0x" << std::hex << iword << " (BOE: 0x"
39  << config_.sLinkBOE << "), got 0x" << inputArray[iword] << ".";
40 
41  iword += 4; // length of the S-Link header (128 bits)
42 
43  LogDebug("HGCalUnpack") << "SLink=" << sLink;
44 
45  //----- parse the S-Link body
46  for (uint8_t captureBlock = 0; captureBlock < config_.sLinkCaptureBlockMax;
47  captureBlock++) { // loop through all capture blocks
48  //----- parse the capture block header
49  if (((inputArray[iword] >> kCaptureBlockReservedShift) & kCaptureBlockReservedMask) !=
50  config_.captureBlockReserved) // sanity check
51  throw cms::Exception("CorruptData")
52  << "Expected a capture block header at word " << std::dec << iword << "/0x" << std::hex << iword
53  << " (reserved word: 0x" << config_.captureBlockReserved << "), got 0x" << inputArray[iword] << ".";
54 
55  const uint64_t captureBlockHeader = ((uint64_t)inputArray[iword] << 32) | ((uint64_t)inputArray[iword + 1]);
56  iword += 2; // length of capture block header (64 bits)
57 
58  LogDebug("HGCalUnpack") << "Capture block=" << (int)captureBlock << ", capture block header=0x" << std::hex
59  << captureBlockHeader;
60 
61  //----- parse the capture block body
62  for (uint8_t econd = 0; econd < config_.captureBlockECONDMax; econd++) { // loop through all ECON-Ds
63  if (((captureBlockHeader >> (3 * econd)) & kCaptureBlockECONDStatusMask) >= 0b100)
64  continue; // only pick active ECON-Ds
65 
66  //----- parse the ECON-D header
67  // (the second word of ECON-D header contains no information for unpacking, use only the first one)
68  if (((inputArray[iword] >> kHeaderShift) & kHeaderMask) != config_.econdHeaderMarker) // sanity check
69  throw cms::Exception("CorruptData")
70  << "Expected a ECON-D header at word " << std::dec << iword << "/0x" << std::hex << iword
71  << " (marker: 0x" << config_.econdHeaderMarker << "), got 0x" << inputArray[iword] << ".";
72 
73  const auto& econdHeader = inputArray[iword];
74  iword += 2; // length of ECON-D header (2 * 32 bits)
75 
76  LogDebug("HGCalUnpack") << "ECON-D #" << (int)econd << ", first word of ECON-D header=0x" << std::hex
77  << econdHeader;
78 
79  //----- extract the payload length
80  const uint32_t payloadLength = (econdHeader >> kPayloadLengthShift) & kPayloadLengthMask;
81  if (payloadLength > config_.payloadLengthMax) // if payload length too big
82  throw cms::Exception("CorruptData") << "Unpacked payload length=" << payloadLength
83  << " exceeds the maximal length=" << config_.payloadLengthMax;
84 
85  LogDebug("HGCalUnpack") << "ECON-D #" << (int)econd << ", payload length=" << payloadLength;
86  //Quality check
87  if ((((captureBlockHeader >> (3 * econd)) & kCaptureBlockECONDStatusMask) != 0b000) ||
88  (((econdHeader >> kHTShift) & kHTMask) >= 0b10) || (((econdHeader >> kEBOShift) & kEBOMask) >= 0b10) ||
89  (((econdHeader >> kMatchShift) & kMatchMask) == 0) ||
90  (((econdHeader >> kTruncatedShift) & kTruncatedMask) == 1)) { // bad ECOND
91  LogDebug("HGCalUnpack") << "ECON-D failed quality check, HT=" << (econdHeader >> kHTShift & kHTMask)
92  << ", EBO=" << (econdHeader >> kEBOShift & kEBOMask)
93  << ", M=" << (econdHeader >> kMatchShift & kMatchMask)
94  << ", T=" << (econdHeader >> kTruncatedShift & kTruncatedMask);
95  badECOND_.emplace_back(iword - 2);
96  iword += payloadLength; // skip the current ECON-D (using the payload length parsed above)
97 
98  if (iword % 2 != 0) { //TODO: check this
99  LogDebug("HGCalUnpacker") << "Padding ECON-D payload to 2 32-bit words (remainder: " << (iword % 2) << ").";
100  iword += 1;
101  }
102  continue; // go to the next ECON-D
103  }
104  const uint32_t econdBodyStart = iword; // for the ECON-D length check
105  //----- parse the ECON-D body
106  if (((econdHeader >> kPassThroughShift) & kPassThroughMask) == 0) {
107  // standard ECON-D
108  LogDebug("HGCalUnpack") << "Standard ECON-D";
109  const auto enabledERX = enabledERXMapping(sLink, captureBlock, econd);
110  for (uint8_t erx = 0; erx < config_.econdERXMax; erx++) {
111  //loop through eRx
112  //pick active eRx
113  if ((enabledERX >> erx & 1) == 0)
114  continue;
115 
116  //----- parse the eRX subpacket header
117  //common mode
118  LogDebug("HGCalUnpack") << "ECON-D:eRx=" << (int)econd << ":" << (int)erx
119  << ", first word of the eRx header=0x" << std::hex << inputArray[iword] << "\n"
120  << " extracted common mode 0=0x" << std::hex
121  << ((inputArray[iword] >> kCommonmode0Shift) & kCommonmode0Mask) << std::dec
122  << ", saved at " << commonModeDataSize_ << "\n"
123  << " extracted common mode 1=0x" << std::hex
124  << ((inputArray[iword] >> kCommonmode1Shift) & kCommonmode1Mask) << std::dec
125  << ", saved at " << (commonModeDataSize_ + 1);
126  commonModeData_[commonModeDataSize_] = (inputArray[iword] >> kCommonmode0Shift) & kCommonmode0Mask;
127  commonModeData_[commonModeDataSize_ + 1] = (inputArray[iword] >> kCommonmode1Shift) & kCommonmode1Mask;
128  if ((erx % 2 == 0 && (enabledERX >> (erx + 1) & 1) == 0) ||
129  (erx % 2 == 1 && (enabledERX >> (erx - 1) & 1) == 0)) {
130  commonModeDataSize_ += 2;
131  commonModeData_[commonModeDataSize_] = commonModeData_[commonModeDataSize_ - 2];
132  commonModeData_[commonModeDataSize_ + 1] = commonModeData_[commonModeDataSize_ - 1];
133  LogDebug("HGCalUnpack") << "half ROC turned on, padding to 4 common modes\n"
134  << "0x" << std::hex << commonModeData_[commonModeDataSize_ - 2] << std::dec
135  << " saved at " << commonModeDataSize_ << "\n"
136  << "0x" << std::hex << commonModeData_[commonModeDataSize_ - 1] << std::dec
137  << " saved at " << commonModeDataSize_ + 1;
138  }
139  // empty check
140  if (((inputArray[iword] >> kFormatShift) & kFormatMask) == 1) { // empty
141  LogDebug("HGCalUnpack") << "eRx empty";
142  iword += 1; // length of an empty eRx header (32 bits)
143  continue; // go to the next eRx
144  }
145  // regular mode
146  const uint64_t erxHeader = ((uint64_t)inputArray[iword] << 32) | ((uint64_t)inputArray[iword + 1]);
147  iword += 2; // length of a standard eRx header (2 * 32 bits)
148  LogDebug("HGCalUnpack") << "whole eRx header=0x" << std::hex << erxHeader;
149 
150  //----- parse the eRx subpacket body
151  uint32_t bitCounter = 0;
152  for (uint8_t channel = 0; channel < config_.erxChannelMax; channel++) { // loop through all channels in eRx
153  if (((erxHeader >> channel) & 1) == 0)
154  continue; // only pick active channels
155  const HGCalElectronicsId id(sLink, captureBlock, econd, erx, channel);
156  commonModeIndex_[channelDataSize_] = commonModeDataSize_ / 4 * 4;
157  const uint32_t tempIndex = bitCounter / 32 + iword;
158  const uint8_t tempBit = bitCounter % 32;
159  const uint32_t temp =
160  (tempBit == 0) ? inputArray[tempIndex]
161  : (inputArray[tempIndex] << tempBit) | (inputArray[tempIndex + 1] >> (32 - tempBit));
162  const uint8_t code = temp >> 28;
163  // use if and else here
164  channelData_[channelDataSize_] = HGCROCChannelDataFrame<D>(
165  logicalMapping(id),
166  ((temp << erxBodyLeftShift_[code]) >> erxBodyRightShift_[code]) & erxBodyMask_[code]);
167  bitCounter += erxBodyBits_[code];
168  if (code == 0b0010)
169  channelData_[channelDataSize_].fillFlag1(1);
170  LogDebug("HGCalUnpack") << "Word " << channelDataSize_ << ", ECON-D:eRx:channel=" << (int)econd << ":"
171  << (int)erx << ":" << (int)channel << "\n"
172  << " assigned common mode index=" << commonModeIndex_.at(channelDataSize_)
173  << "\n"
174  << " full word readout=0x" << std::hex << temp << std::dec << ", code=0x"
175  << std::hex << (int)code << std::dec << "\n"
176  << " extracted channel data=0x" << std::hex
177  << channelData_[channelDataSize_].raw();
178  channelDataSize_++;
179  }
180  // pad to the whole word
181  iword += bitCounter / 32;
182  if (bitCounter % 32 != 0)
183  iword += 1;
184 
185  if (commonModeDataSize_ + 1 > config_.commonModeMax)
186  throw cms::Exception("HGCalUnpack") << "Too many common mode data unpacked: " << (commonModeDataSize_ + 1)
187  << " >= " << config_.commonModeMax << ".";
188  commonModeDataSize_ += 2;
189  // eRx subpacket has no trailer
190  }
191  } else {
192  // passthrough ECON-D
193  LogDebug("HGCalUnpack") << "Passthrough ECON-D";
194  const auto enabledERX = enabledERXMapping(sLink, captureBlock, econd);
195  for (uint8_t erx = 0; erx < config_.econdERXMax; erx++) { // loop through all eRxs
196  if ((enabledERX >> erx & 1) == 0)
197  continue; // only pick active eRxs
198 
199  //----- eRX subpacket header
200  // common mode
201  uint32_t temp = inputArray[iword];
202  LogDebug("HGCalUnpack") << "ECON-D:eRx=" << (int)econd << ":" << (int)erx
203  << ", first word of the eRx header=0x" << std::hex << temp << std::dec << "\n"
204  << " extracted common mode 0=0x" << std::hex
205  << ((temp >> kCommonmode0Shift) & kCommonmode0Mask) << std::dec << ", saved at "
206  << commonModeDataSize_ << "\n"
207  << " extracted common mode 1=0x" << std::hex
208  << ((temp >> kCommonmode1Shift) & kCommonmode1Mask) << std::dec << ", saved at "
209  << (commonModeDataSize_ + 1);
210  commonModeData_[commonModeDataSize_] = (temp >> kCommonmode0Shift) & kCommonmode0Mask;
211  commonModeData_[commonModeDataSize_ + 1] = (temp >> kCommonmode1Shift) & kCommonmode1Mask;
212  if ((erx % 2 == 0 && (enabledERX >> (erx + 1) & 1) == 0) ||
213  (erx % 2 == 1 && (enabledERX >> (erx - 1) & 1) == 0)) {
214  commonModeDataSize_ += 2;
215  commonModeData_[commonModeDataSize_] = commonModeData_[commonModeDataSize_ - 2];
216  commonModeData_[commonModeDataSize_ + 1] = commonModeData_[commonModeDataSize_ - 1];
217  LogDebug("HGCalUnpack") << "half ROC turned on, padding to 4 common modes\n"
218  << "0x" << std::hex << commonModeData_[commonModeDataSize_ - 2] << std::dec
219  << " saved at " << commonModeDataSize_ << "\n"
220  << "0x" << std::hex << commonModeData_[commonModeDataSize_ - 1] << std::dec
221  << " saved at " << commonModeDataSize_ + 1;
222  }
223  iword += 2; // length of the standard eRx header (2 * 32 bits)
224  for (uint8_t channel = 0; channel < config_.erxChannelMax; channel++) { // loop through all channels in eRx
225  const HGCalElectronicsId id(sLink, captureBlock, econd, erx, channel);
226  commonModeIndex_[channelDataSize_] = commonModeDataSize_ / 4 * 4;
227  channelData_[channelDataSize_] =
228  HGCROCChannelDataFrame<HGCalElectronicsId>(logicalMapping(id), inputArray[iword]);
229  LogDebug("HGCalUnpack") << "Word " << channelDataSize_ << ", ECON-D:eRx:channel=" << (int)econd << ":"
230  << (int)erx << ":" << (int)channel << ", HGCalElectronicsId=" << id.raw()
231  << ", assigned common mode index=" << commonModeIndex_.at(channelDataSize_)
232  << "\n"
233  << "extracted channel data=0x" << std::hex
234  << channelData_.at(channelDataSize_).raw();
235  channelDataSize_++;
236  iword++;
237  }
238  if (commonModeDataSize_ + 1 > config_.commonModeMax)
239  throw cms::Exception("HGCalUnpack") << "Too many common mode data unpacked: " << (commonModeDataSize_ + 1)
240  << " >= " << config_.commonModeMax << ".";
241  commonModeDataSize_ += 2;
242  }
243  }
244  //----- parse the ECON-D trailer
245  // (no information needed from ECON-D trailer in unpacker, skip it)
246  iword += 1; // length of the ECON-D trailer (32 bits CRC)
247 
248  if (iword - econdBodyStart != payloadLength)
249  throw cms::Exception("CorruptData")
250  << "Mismatch between unpacked and expected ECON-D #" << (int)econd << " payload length\n"
251  << " unpacked payload length=" << iword - econdBodyStart << "\n"
252  << " expected payload length=" << payloadLength;
253  // pad to 2 words
254  if (iword % 2 != 0) { //TODO: check this
255  LogDebug("HGCalUnpacker") << "Padding ECON-D payload to 2 32-bit words (remainder: " << (iword % 2) << ").";
256  iword += 1;
257  }
258  }
259  //----- capture block has no trailer
260  // pad to 4 words
261  if (iword % 4 != 0) { //TODO: check this
262  LogDebug("HGCalUnpacker") << "Padding capture block to 4 32-bit words (remainder: " << (iword % 4) << ").";
263  iword += 4 - (iword % 4);
264  }
265  }
266  //----- parse the S-Link trailer
267  // (no information is needed in unpacker)
268 
269  iword += 4; // length of the S-Link trailer (128 bits)
270  sLink++;
271  }
272  channelData_.resize(channelDataSize_);
273  commonModeIndex_.resize(channelDataSize_);
274  commonModeData_.resize(commonModeDataSize_);
275  return;
276 }
277 
278 template <class D>
280  const std::vector<uint32_t>& inputArray,
281  const std::function<uint16_t(uint16_t sLink, uint8_t captureBlock, uint8_t econd)>& enabledERXMapping,
282  const std::function<D(HGCalElectronicsId elecID)>& logicalMapping) {
283  uint16_t sLink = 0;
284  uint8_t captureBlock = 0;
285 
286  channelDataSize_ = 0;
287  commonModeDataSize_ = 0;
288  badECOND_.clear();
289 
290  for (uint32_t iword = 0; iword < inputArray.size();) { // loop through all capture blocks
291 
292  //----- parse the capture block header
293  if (((inputArray[iword] >> kCaptureBlockReservedShift) & kCaptureBlockReservedMask) != config_.captureBlockReserved)
294  throw cms::Exception("CorruptData")
295  << "Expected a capture block header at word " << std::dec << iword << "/0x" << std::hex << iword
296  << " (reserved word: 0x" << config_.captureBlockReserved << "), got 0x" << inputArray[iword] << ".";
297 
298  const uint64_t captureBlockHeader = ((uint64_t)inputArray[iword] << 32) | ((uint64_t)inputArray[iword + 1]);
299  LogDebug("HGCalUnpack") << "Capture block=" << (int)captureBlock << ", capture block header=0x" << std::hex
300  << captureBlockHeader;
301  iword += 2; // length of capture block header (64 bits)
302 
303  //----- parse the capture block body
304  for (uint8_t econd = 0; econd < config_.captureBlockECONDMax; econd++) { // loop through all ECON-Ds
305  if ((captureBlockHeader >> (3 * econd) & kCaptureBlockECONDStatusMask) >= 0b100)
306  continue; // only pick the active ECON-Ds
307 
308  //----- parse the ECON-D header
309  // (the second word of ECON-D header contains no information useful for unpacking, use only the first one)
310  if (((inputArray[iword] >> kHeaderShift) & kHeaderMask) != config_.econdHeaderMarker) // sanity check
311  throw cms::Exception("CorruptData")
312  << "Expected a ECON-D header at word " << std::dec << iword << "/0x" << std::hex << iword << " (marker: 0x"
313  << config_.econdHeaderMarker << "), got 0x" << inputArray[iword] << ".";
314 
315  const uint32_t econdHeader = inputArray[iword];
316  iword += 2; // length of ECON-D header (2 * 32 bits)
317 
318  LogDebug("HGCalUnpack") << "ECON-D #" << (int)econd << ", first word of ECON-D header=0x" << std::hex
319  << econdHeader;
320 
321  //----- extract the payload length
322  const uint32_t payloadLength = ((econdHeader >> kPayloadLengthShift)) & kPayloadLengthMask;
323  if (payloadLength > config_.payloadLengthMax) // payload length is too large
324  throw cms::Exception("CorruptData") << "Unpacked payload length=" << payloadLength
325  << " exceeds the maximal length=" << config_.payloadLengthMax;
326  LogDebug("HGCalUnpack") << "ECON-D #" << (int)econd << ", payload length = " << payloadLength;
327 
328  if ((((captureBlockHeader >> (3 * econd)) & kCaptureBlockECONDStatusMask) != 0b000) ||
329  (((econdHeader >> kHTShift) & kHTMask) >= 0b10) || (((econdHeader >> kEBOShift) & kEBOMask) >= 0b10) ||
330  (((econdHeader >> kMatchShift) & kMatchMask) == 0) ||
331  (((econdHeader >> kTruncatedShift) & kTruncatedMask) == 1)) { // quality check failed: bad ECON-D
332  LogDebug("HGCalUnpack") << "ECON-D failed quality check, HT=" << (econdHeader >> kHTShift & kHTMask)
333  << ", EBO=" << (econdHeader >> kEBOShift & kEBOMask)
334  << ", M=" << (econdHeader >> kMatchShift & kMatchMask)
335  << ", T=" << (econdHeader >> kTruncatedShift & kTruncatedMask);
336  badECOND_.emplace_back(iword - 2);
337  iword += payloadLength; // skip the current ECON-D (using the payload length parsed above)
338 
339  if (iword % 2 != 0) { //TODO: check this
340  LogDebug("HGCalUnpacker") << "Padding ECON-D payload to 2 32-bit words (remainder: " << (iword % 2) << ").";
341  iword += 1;
342  }
343  continue; // go to the next ECON-D
344  }
345 
346  //----- parse the ECON-D body
347  const uint32_t econdBodyStart = iword; // for the ECON-D length check
348  if (((econdHeader >> kPassThroughShift) & kPassThroughMask) == 0) {
349  // standard ECON-D
350  LogDebug("HGCalUnpack") << "Standard ECON-D";
351  const auto enabledERX = enabledERXMapping(sLink, captureBlock, econd);
352  for (uint8_t erx = 0; erx < config_.econdERXMax; erx++) { // loop through all eRxs
353  if ((enabledERX >> erx & 1) == 0)
354  continue; // only pick active eRx
355 
356  //----- parse the eRX subpacket header
357  // common mode
358  LogDebug("HGCalUnpack") << "ECON-D:eRx=" << (int)econd << ":" << (int)erx
359  << ", first word of the eRx header=0x" << std::hex << inputArray[iword] << std::dec
360  << "\n"
361  << " extracted common mode 0=0x" << std::hex
362  << ((inputArray[iword] >> kCommonmode0Shift) & kCommonmode0Mask) << std::dec
363  << ", saved at " << commonModeDataSize_ << "\n"
364  << " extracted common mode 1=0x" << std::hex
365  << ((inputArray[iword] >> kCommonmode1Shift) & kCommonmode1Mask) << std::dec
366  << ", saved at " << (commonModeDataSize_ + 1);
367 
368  commonModeData_[commonModeDataSize_] = (inputArray[iword] >> kCommonmode0Shift) & kCommonmode0Mask;
369  commonModeData_[commonModeDataSize_ + 1] = (inputArray[iword] >> kCommonmode1Shift) & kCommonmode1Mask;
370  if ((erx % 2 == 0 && (enabledERX >> (erx + 1) & 1) == 0) ||
371  (erx % 2 == 1 && (enabledERX >> (erx - 1) & 1) == 0)) {
372  commonModeDataSize_ += 2;
373  commonModeData_[commonModeDataSize_] = commonModeData_[commonModeDataSize_ - 2];
374  commonModeData_[commonModeDataSize_ + 1] = commonModeData_[commonModeDataSize_ - 1];
375  LogDebug("HGCalUnpack") << "half ROC turned on, padding to 4 common modes\n"
376  << "0x" << std::hex << commonModeData_[commonModeDataSize_ - 2] << std::dec
377  << " saved at " << commonModeDataSize_ << "\n"
378  << "0x" << std::hex << commonModeData_[commonModeDataSize_ - 1] << std::dec
379  << " saved at " << commonModeDataSize_ + 1;
380  }
381 
382  // empty check
383  if (((inputArray[iword] >> kFormatShift) & kFormatMask) == 1) {
384  iword += 1; // length of an empty eRx header (32 bits)
385  LogDebug("HGCalUnpack") << "eRx #" << (int)erx << " is empty.";
386  continue; // go to next eRx
387  }
388 
389  // regular mode
390  const uint64_t erxHeader = ((uint64_t)inputArray[iword] << 32) | (uint64_t)inputArray[iword + 1];
391  LogDebug("HGCalUnpack") << "whole eRx header=0x" << std::hex << erxHeader;
392  iword += 2; // length of a standard eRx header (2 * 32 bits)
393 
394  uint32_t bitCounter = 0;
395  //----- parse the eRx subpacket body
396  for (uint8_t channel = 0; channel < config_.erxChannelMax; channel++) { // loop through channels in eRx
397  if (((erxHeader >> channel) & 1) == 0)
398  continue; // only pick active channels
399  const HGCalElectronicsId id(sLink, captureBlock, econd, erx, channel);
400  commonModeIndex_[channelDataSize_] = commonModeDataSize_ / 4 * 4;
401  const uint32_t tempIndex = bitCounter / 32 + iword;
402  const uint8_t tempBit = bitCounter % 32;
403  const uint32_t temp =
404  (tempBit == 0) ? inputArray[tempIndex]
405  : (inputArray[tempIndex] << tempBit) | (inputArray[tempIndex + 1] >> (32 - tempBit));
406  const uint8_t code = temp >> 28;
407  // use if and else here
408  channelData_[channelDataSize_] = HGCROCChannelDataFrame<D>(
409  logicalMapping(id),
410  ((temp << erxBodyLeftShift_[code]) >> erxBodyRightShift_[code]) & erxBodyMask_[code]);
411  bitCounter += erxBodyBits_[code];
412  if (code == 0b0010)
413  channelData_[channelDataSize_].fillFlag1(1);
414  LogDebug("HGCalUnpack") << "Word " << channelDataSize_ << ", ECON-D:eRx:channel=" << (int)econd << ":"
415  << (int)erx << ":" << (int)channel
416  << ", assigned common mode index=" << commonModeIndex_[channelDataSize_] << "\n"
417  << " full word readout=0x" << std::hex << temp << std::dec << ", code=0x"
418  << std::hex << (int)code << std::dec << "\n"
419  << " extracted channel data=0x" << std::hex
420  << channelData_[channelDataSize_].raw();
421  channelDataSize_++;
422  }
423  // pad to the whole word
424  iword += bitCounter / 32;
425  if (bitCounter % 32 != 0)
426  iword += 1;
427 
428  if (commonModeDataSize_ + 1 > config_.commonModeMax)
429  throw cms::Exception("HGCalUnpack") << "Too many common mode data unpacked: " << (commonModeDataSize_ + 1)
430  << " >= " << config_.commonModeMax << ".";
431  commonModeDataSize_ += 2;
432  // eRx subpacket has no trailer
433  }
434  } else { // passthrough ECON-D
435  LogDebug("HGCalUnpack") << "Passthrough ECON-D";
436  const auto enabledERX = enabledERXMapping(sLink, captureBlock, econd);
437  for (uint8_t erx = 0; erx < config_.econdERXMax; erx++) { // loop through all eRx
438  if ((enabledERX >> erx & 1) == 0)
439  continue; // only pick active eRx
440 
441  //----- parse the eRX subpacket header
442  // common mode
443  uint32_t temp = inputArray[iword];
444  LogDebug("HGCalUnpack") << "ECON-D:eRx=" << (int)econd << ":" << (int)erx
445  << ", first word of the eRx header=0x" << std::hex << temp << std::dec << "\n"
446  << " extracted common mode 0=0x" << std::hex
447  << ((temp >> kCommonmode0Shift) & kCommonmode0Mask) << std::dec << ", saved at "
448  << commonModeDataSize_ << "\n"
449  << " extracted common mode 1=0x" << std::hex
450  << ((temp >> kCommonmode1Shift) & kCommonmode1Mask) << std::dec << ", saved at "
451  << (commonModeDataSize_ + 1);
452  commonModeData_[commonModeDataSize_] = (temp >> kCommonmode0Shift) & kCommonmode0Mask;
453  commonModeData_[commonModeDataSize_ + 1] = (temp >> kCommonmode1Shift) & kCommonmode1Mask;
454  if ((erx % 2 == 0 && (enabledERX >> (erx + 1) & 1) == 0) ||
455  (erx % 2 == 1 && (enabledERX >> (erx - 1) & 1) == 0)) {
456  commonModeDataSize_ += 2;
457  commonModeData_[commonModeDataSize_] = commonModeData_[commonModeDataSize_ - 2];
458  commonModeData_[commonModeDataSize_ + 1] = commonModeData_[commonModeDataSize_ - 1];
459  LogDebug("HGCalUnpack") << "half ROC turned on, padding to 4 common modes\n"
460  << "0x" << std::hex << commonModeData_[commonModeDataSize_ - 2] << std::dec
461  << " saved at " << commonModeDataSize_ << "\n"
462  << "0x" << std::hex << commonModeData_[commonModeDataSize_ - 1] << std::dec
463  << " saved at " << commonModeDataSize_ + 1;
464  }
465  iword += 2; // length of a standard eRx header (2 * 32 bits)
466 
467  for (uint8_t channel = 0; channel < config_.erxChannelMax; channel++) { // loop through all channels in eRx
468  const HGCalElectronicsId id(sLink, captureBlock, econd, erx, channel);
469  commonModeIndex_[channelDataSize_] = commonModeDataSize_ / 4 * 4;
470  channelData_[channelDataSize_] =
471  HGCROCChannelDataFrame<HGCalElectronicsId>(logicalMapping(id), inputArray[iword]);
472  LogDebug("HGCalUnpack") << "Word" << channelDataSize_ << ", ECON-D:eRx:channel=" << (int)econd << ":"
473  << (int)erx << ":" << (int)channel << ", HGCalElectronicsId=" << id.raw()
474  << ", assigned common mode index=" << commonModeIndex_[channelDataSize_] << "\n"
475  << "extracted channel data=0x" << std::hex << channelData_[channelDataSize_].raw();
476  channelDataSize_++;
477  iword++;
478  }
479  if (commonModeDataSize_ + 1 > config_.commonModeMax)
480  throw cms::Exception("HGCalUnpack") << "Too many common mode data unpacked: " << (commonModeDataSize_ + 1)
481  << " >= " << config_.commonModeMax << ".";
482  commonModeDataSize_ += 2;
483  }
484  }
485 
486  //----- parse the ECON-D trailer
487  // (no information unpacked from ECON-D trailer, just skip it)
488  iword += 1; // length of an ECON-D trailer (32 bits CRC)
489 
490  if (iword - econdBodyStart != payloadLength)
491  throw cms::Exception("CorruptData")
492  << "Mismatch between unpacked and expected ECON-D #" << (int)econd << " payload length\n"
493  << " unpacked payload length=" << iword - econdBodyStart << "\n"
494  << " expected payload length=" << payloadLength;
495  // pad to 2 words
496  if (iword % 2 != 0) {
497  LogDebug("HGCalUnpacker") << "Padding ECON-D payload to 2 32-bit words (remainder: " << (iword % 2) << ").";
498  iword += 1;
499  }
500  }
501  captureBlock++; // the capture block has no trailer to parse
502  }
503  channelData_.resize(channelDataSize_);
504  commonModeIndex_.resize(channelDataSize_);
505  commonModeData_.resize(commonModeDataSize_);
506  return;
507 }
508 
509 template <class D>
511  const std::vector<uint32_t>& inputArray,
512  const std::function<uint16_t(uint16_t sLink, uint8_t captureBlock, uint8_t econd)>& enabledERXMapping,
513  const std::function<D(HGCalElectronicsId elecID)>& logicalMapping) {
514  uint16_t sLink = 0;
515  uint8_t captureBlock = 0;
516  uint8_t econd = 0;
517 
518  channelDataSize_ = 0;
519  commonModeDataSize_ = 0;
520  badECOND_.clear();
521 
522  for (uint32_t iword = 0; iword < inputArray.size();) { // loop through all ECON-Ds
523  //----- parse the ECON-D header
524  // (the second word of ECON-D header contains no information for unpacking, use only the first one)
525  if (((inputArray[iword] >> kHeaderShift) & kHeaderMask) != config_.econdHeaderMarker) // sanity check
526  throw cms::Exception("CorruptData")
527  << "Expected a ECON-D header at word " << std::dec << iword << "/0x" << std::hex << iword << " (marker: 0x"
528  << config_.econdHeaderMarker << "), got 0x" << inputArray[iword] << ".";
529 
530  const uint32_t econdHeader = inputArray[iword];
531  iword += 2; // length of ECON-D header (2 * 32 bits)
532 
533  LogDebug("HGCalUnpack") << "ECON-D #" << (int)econd << ", first word of ECON-D header=0x" << std::hex
534  << econdHeader;
535 
536  //----- extract the payload length
537  const uint32_t payloadLength = (econdHeader >> kPayloadLengthShift) & kPayloadLengthMask;
538  if (payloadLength > config_.payloadLengthMax) // payload length too big
539  throw cms::Exception("CorruptData")
540  << "Unpacked payload length=" << payloadLength << " exceeds the maximal length=" << config_.payloadLengthMax;
541 
542  LogDebug("HGCalUnpack") << "ECON-D #" << (int)econd << ", payload length = " << payloadLength;
543  //Quality check
544  if (((econdHeader >> kHTShift & kHTMask) >= 0b10) || ((econdHeader >> kEBOShift & kEBOMask) >= 0b10) ||
545  ((econdHeader >> kMatchShift & kMatchMask) == 0) ||
546  ((econdHeader >> kTruncatedShift & kTruncatedMask) == 1)) { // bad ECOND
547  LogDebug("HGCalUnpack") << "ECON-D failed quality check, HT=" << (econdHeader >> kHTShift & kHTMask)
548  << ", EBO=" << (econdHeader >> kEBOShift & kEBOMask)
549  << ", M=" << (econdHeader >> kMatchShift & kMatchMask)
550  << ", T=" << (econdHeader >> kTruncatedShift & kTruncatedMask);
551  badECOND_.emplace_back(iword - 2);
552  iword += payloadLength; // skip the current ECON-D (using the payload length parsed above)
553 
554  continue; // go to the next ECON-D
555  }
556 
557  //----- perse the ECON-D body
558  const uint32_t econdBodyStart = iword; // for the ECON-D length check
559  if (((econdHeader >> kPassThroughShift) & kPassThroughMask) == 0) {
560  // standard ECON-D
561  LogDebug("HGCalUnpack") << "Standard ECON-D";
562  const auto enabledERX = enabledERXMapping(sLink, captureBlock, econd);
563  for (uint8_t erx = 0; erx < config_.econdERXMax; erx++) { // loop through all eRxs
564  if ((enabledERX >> erx & 1) == 0)
565  continue; // only pick active eRxs
566 
567  //----- parse the eRX subpacket header
568  // common mode
569  LogDebug("HGCalUnpack") << "ECON-D:eRx=" << (int)econd << ":" << (int)erx << ", first word of the eRx header=0x"
570  << std::hex << inputArray[iword] << std::dec << "\n"
571  << " extracted common mode 0=0x" << std::hex
572  << ((inputArray[iword] >> kCommonmode0Shift) & kCommonmode0Mask) << std::dec
573  << ", saved at " << commonModeDataSize_ << "\n"
574  << " extracted common mode 1=0x" << std::hex
575  << ((inputArray[iword] >> kCommonmode1Shift) & kCommonmode1Mask) << std::dec
576  << ", saved at " << (commonModeDataSize_ + 1);
577  commonModeData_[commonModeDataSize_] = (inputArray[iword] >> kCommonmode0Shift) & kCommonmode0Mask;
578  commonModeData_[commonModeDataSize_ + 1] = (inputArray[iword] >> kCommonmode1Shift) & kCommonmode1Mask;
579  if ((erx % 2 == 0 && (enabledERX >> (erx + 1) & 1) == 0) ||
580  (erx % 2 == 1 && (enabledERX >> (erx - 1) & 1) == 0)) {
581  commonModeDataSize_ += 2;
582  commonModeData_[commonModeDataSize_] = commonModeData_[commonModeDataSize_ - 2];
583  commonModeData_[commonModeDataSize_ + 1] = commonModeData_[commonModeDataSize_ - 1];
584  LogDebug("HGCalUnpack") << "half ROC turned on, padding to 4 common modes\n"
585  << "0x" << std::hex << commonModeData_[commonModeDataSize_ - 2] << std::dec
586  << " saved at " << commonModeDataSize_ << "\n"
587  << "0x" << std::hex << commonModeData_[commonModeDataSize_ - 1] << std::dec
588  << " saved at " << commonModeDataSize_ + 1;
589  }
590  if (((inputArray[iword] >> kFormatShift) & kFormatMask) == 1) { // empty eRx
591  LogDebug("HGCalUnpack") << "eRx empty";
592  iword += 1; // length of an empty eRx header (32 bits)
593 
594  continue; // skip to the next eRx
595  }
596 
597  // regular mode
598  const uint64_t erxHeader = ((uint64_t)inputArray[iword] << 32) | ((uint64_t)inputArray[iword + 1]);
599  iword += 2; // length of a standard eRx header (2 * 32 bits)
600  LogDebug("HGCalUnpack") << "whole eRx header=0x" << std::hex << erxHeader;
601 
602  //----- parse eRx subpacket body
603  uint32_t bitCounter = 0;
604  for (uint8_t channel = 0; channel < config_.erxChannelMax; channel++) { // loop through all channels in eRx
605  if (((erxHeader >> channel) & 1) == 0)
606  continue; // only pick active channels
607  const HGCalElectronicsId id(sLink, captureBlock, econd, erx, channel);
608  commonModeIndex_[channelDataSize_] = commonModeDataSize_ / 4 * 4;
609  const uint32_t tempIndex = bitCounter / 32 + iword;
610  const uint8_t tempBit = bitCounter % 32;
611  const uint32_t temp =
612  (tempBit == 0) ? inputArray[tempIndex]
613  : (inputArray[tempIndex] << tempBit) | (inputArray[tempIndex + 1] >> (32 - tempBit));
614  const uint8_t code = temp >> 28;
615  // use if and else here
616  channelData_[channelDataSize_] = HGCROCChannelDataFrame<D>(
617  logicalMapping(id), ((temp << erxBodyLeftShift_[code]) >> erxBodyRightShift_[code]) & erxBodyMask_[code]);
618  bitCounter += erxBodyBits_[code];
619  if (code == 0b0010)
620  channelData_[channelDataSize_].fillFlag1(1);
621  LogDebug("HGCalUnpack") << "Word " << channelDataSize_ << ", ECON-D:eRx:channel=" << (int)econd << ":"
622  << (int)erx << ":" << (int)channel << "\n"
623  << " assigned common mode index=" << commonModeIndex_.at(channelDataSize_) << "\n"
624  << " full word readout=0x" << std::hex << temp << std::dec << ", code=0x" << std::hex
625  << (int)code << std::dec << "\n"
626  << " extracted channel data=0x" << std::hex << channelData_[channelDataSize_].raw();
627  channelDataSize_++;
628  }
629  // pad to the whole word
630  iword += bitCounter / 32;
631  if (bitCounter % 32 != 0)
632  iword += 1;
633 
634  if (commonModeDataSize_ + 1 > config_.commonModeMax)
635  throw cms::Exception("HGCalUnpack") << "Too many common mode data unpacked: " << (commonModeDataSize_ + 1)
636  << " >= " << config_.commonModeMax << ".";
637  commonModeDataSize_ += 2;
638  // eRx subpacket has no trailer
639  }
640  } else {
641  // passthrough ECON-D
642  LogDebug("HGCalUnpack") << "Passthrough ECON-D";
643  const auto enabledERX = enabledERXMapping(sLink, captureBlock, econd);
644  for (uint8_t erx = 0; erx < config_.econdERXMax; erx++) { // loop through all eRxs
645  if ((enabledERX >> erx & 1) == 0)
646  continue; // only pick active eRx
647  //----- parse the eRX subpacket header
648  // common mode
649  uint32_t temp = inputArray[iword];
650  LogDebug("HGCalUnpack") << "ECON-D:eRx=" << (int)econd << ":" << (int)erx << ", first word of the eRx header=0x"
651  << std::hex << temp << std::dec << "\n"
652  << " extracted common mode 0=0x" << std::hex
653  << ((temp >> kCommonmode0Shift) & kCommonmode0Mask) << std::dec << ", saved at "
654  << commonModeDataSize_ << "\n"
655  << " extracted common mode 1=0x" << std::hex
656  << ((temp >> kCommonmode1Shift) & kCommonmode1Mask) << std::dec << ", saved at "
657  << (commonModeDataSize_ + 1);
658  commonModeData_[commonModeDataSize_] = (temp >> kCommonmode0Shift) & kCommonmode0Mask;
659  commonModeData_[commonModeDataSize_ + 1] = (temp >> kCommonmode1Shift) & kCommonmode1Mask;
660  if ((erx % 2 == 0 && (enabledERX >> (erx + 1) & 1) == 0) ||
661  (erx % 2 == 1 && (enabledERX >> (erx - 1) & 1) == 0)) {
662  commonModeDataSize_ += 2;
663  commonModeData_[commonModeDataSize_] = commonModeData_[commonModeDataSize_ - 2];
664  commonModeData_[commonModeDataSize_ + 1] = commonModeData_[commonModeDataSize_ - 1];
665  LogDebug("HGCalUnpack") << "half ROC turned on, padding to 4 common modes\n"
666  << "0x" << std::hex << commonModeData_[commonModeDataSize_ - 2] << std::dec
667  << " saved at " << commonModeDataSize_ << "\n"
668  << "0x" << std::hex << commonModeData_[commonModeDataSize_ - 1] << std::dec
669  << " saved at " << commonModeDataSize_ + 1;
670  }
671  iword += 2; // length of the standard eRx header (2 * 32 bits)
672 
673  for (uint8_t channel = 0; channel < config_.erxChannelMax; channel++) { // loop through all channels in eRx
674  const HGCalElectronicsId id(sLink, captureBlock, econd, erx, channel);
675  commonModeIndex_[channelDataSize_] = commonModeDataSize_ / 4 * 4;
676  channelData_[channelDataSize_] =
677  HGCROCChannelDataFrame<HGCalElectronicsId>(logicalMapping(id), inputArray[iword]);
678  LogDebug("HGCalUnpack") << "Word " << channelDataSize_ << ", ECON-D:eRx:channel=" << (int)econd << ":"
679  << (int)erx << ":" << (int)channel << ", HGCalElectronicsId=" << id.raw() << "\n"
680  << " assigned common mode index=" << commonModeIndex_.at(channelDataSize_) << "\n"
681  << "extracted channel data=0x" << std::hex << channelData_.at(channelDataSize_).raw();
682  channelDataSize_++;
683  iword++;
684  }
685  if (commonModeDataSize_ + 1 > config_.commonModeMax)
686  throw cms::Exception("HGCalUnpack") << "Too many common mode data unpacked: " << (commonModeDataSize_ + 1)
687  << " >= " << config_.commonModeMax << ".";
688  commonModeDataSize_ += 2;
689  }
690  }
691  //----- fill the ECON-D trailer
692  // (no information is needed from ECON-D trailer in unpacker, skip it)
693  iword += 1; // length of the ECON-D trailer (32 bits CRC)
694 
695  if (iword - econdBodyStart != payloadLength)
696  throw cms::Exception("CorruptData")
697  << "Mismatch between unpacked and expected ECON-D #" << (int)econd << " payload length\n"
698  << " unpacked payload length=" << iword - econdBodyStart << "\n"
699  << " expected payload length=" << payloadLength;
700  }
701  channelData_.resize(channelDataSize_);
702  commonModeIndex_.resize(channelDataSize_);
703  commonModeData_.resize(commonModeDataSize_);
704  return;
705 }
706 
707 // class specialisation for the electronics ID indexing
708 template class HGCalUnpacker<HGCalElectronicsId>;
void parseSLink(const std::vector< uint32_t > &inputArray, const std::function< uint16_t(uint16_t sLink, uint8_t captureBlock, uint8_t econd)> &enabledERXMapping, const std::function< D(HGCalElectronicsId elecID)> &logicalMapping)
Definition: config.py:1
This class is designed to unpack raw data from HGCal, formatted as S-Links, capture blocks...
Definition: HGCalUnpacker.h:36
void parseECOND(const std::vector< uint32_t > &inputArray, const std::function< uint16_t(uint16_t sLink, uint8_t captureBlock, uint8_t econd)> &enabledERXMapping, const std::function< D(HGCalElectronicsId elecID)> &logicalMapping)
wrapper for a 32b data word identifying a readout channel in the raw data The format is the following...
DecomposeProduct< arg, typename Div::arg > D
Definition: Factorize.h:141
unsigned long long uint64_t
Definition: Time.h:13
HGCalUnpacker(HGCalUnpackerConfig config)
void parseCaptureBlock(const std::vector< uint32_t > &inputArray, const std::function< uint16_t(uint16_t sLink, uint8_t captureBlock, uint8_t econd)> &enabledERXMapping, const std::function< D(HGCalElectronicsId elecID)> &logicalMapping)
static const int elecID
Definition: TopGenEvent.h:18
wrapper for a 32b data word from a single channel and its detid The format is always the same: |1b|1b...
#define LogDebug(id)