Belle II Software  release-06-00-14
TOPUnpackerModule.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 // Own include
10 #include <top/modules/TOPUnpacker/TOPUnpackerModule.h>
11 #include <top/RawDataTypes.h>
12 
13 // framework - DataStore
14 #include <framework/datastore/DataStore.h>
15 #include <framework/datastore/StoreArray.h>
16 #include <framework/datastore/StoreObjPtr.h>
17 
18 // framework aux
19 #include <framework/logging/Logger.h>
20 
21 // Dataobject classes
22 #include <framework/dataobjects/EventMetaData.h>
23 
24 #include <bitset>
25 #include <iomanip>
26 #include <fstream>
27 #include <algorithm>
28 
29 using namespace std;
30 
31 namespace Belle2 {
37  using namespace TOP;
38 
39  //-----------------------------------------------------------------
40  // Register module
41  //-----------------------------------------------------------------
42 
43  REG_MODULE(TOPUnpacker)
44 
45  //-----------------------------------------------------------------
46  // Implementation
47  //-----------------------------------------------------------------
48 
50  {
51  // set module description
52  setDescription("Raw data unpacker for TOP");
53  setPropertyFlags(c_ParallelProcessingCertified);
54 
55  // Add parameters
56  addParam("inputRawDataName", m_inputRawDataName,
57  "name of RawTOP store array", string(""));
58  addParam("outputDigitsName", m_outputDigitsName,
59  "name of TOPDigit store array", string(""));
60  addParam("outputWaveformsName", m_outputWaveformsName,
61  "name of TOP(Raw/Production)Waveform store array", string(""));
62  addParam("outputRawDigitsName", m_outputRawDigitsName,
63  "name of TOPRawDigit store array", string(""));
64  addParam("outputTemplateFitResultName", m_templateFitResultName,
65  "name of TOPTemplateFitResult", string(""));
66  addParam("swapBytes", m_swapBytes, "if true, swap bytes", false);
67  addParam("dataFormat", m_dataFormat,
68  "data format as defined in top/include/RawDataTypes.h, 0 = auto detect", 0);
69  addParam("addRelations", m_addRelations,
70  "if true, make relations to TOPProductionHitDebugs (production debug data format only)", true);
71  }
72 
73  TOPUnpackerModule::~TOPUnpackerModule()
74  {
75  }
76 
77  void TOPUnpackerModule::initialize()
78  {
79 
80  // input
81 
82  m_rawData.isRequired(m_inputRawDataName);
83 
84  // output
85 
86  m_digits.registerInDataStore(m_outputDigitsName);
87  m_rawDigits.registerInDataStore(m_outputRawDigitsName);
88  m_slowData.registerInDataStore();
89  m_interimFEInfos.registerInDataStore(DataStore::c_DontWriteOut);
90  m_waveforms.registerInDataStore(m_outputWaveformsName, DataStore::c_DontWriteOut);
91  m_productionEventDebugs.registerInDataStore(DataStore::c_DontWriteOut);
92  m_productionHitDebugs.registerInDataStore(DataStore::c_DontWriteOut);
93  m_templateFitResults.registerInDataStore(m_templateFitResultName, DataStore::c_DontWriteOut);
94 
95  m_rawDigits.registerRelationTo(m_waveforms, DataStore::c_Event, DataStore::c_DontWriteOut);
96  m_rawDigits.registerRelationTo(m_templateFitResults, DataStore::c_Event, DataStore::c_DontWriteOut);
97  m_rawDigits.registerRelationTo(m_interimFEInfos, DataStore::c_Event, DataStore::c_DontWriteOut);
98  m_rawDigits.registerRelationTo(m_productionHitDebugs, DataStore::c_Event, DataStore::c_DontWriteOut);
99  m_waveforms.registerRelationTo(m_interimFEInfos, DataStore::c_Event, DataStore::c_DontWriteOut);
100 
101  // check if front end mappings are available
102  const auto& mapper = m_topgp->getFrontEndMapper();
103  int mapSize = mapper.getMapSize();
104  if (mapSize == 0) B2ERROR("TOPUnpacker: No front-end mapping available for TOP");
105 
106  }
107 
108  void TOPUnpackerModule::beginRun()
109  {
110  m_channelStatistics.clear();
111  }
112 
113  void TOPUnpackerModule::event()
114  {
115  // clear output store arrays
116  m_digits.clear();
117  m_rawDigits.clear();
118  m_waveforms.clear();
119  m_productionEventDebugs.clear();
120  m_productionHitDebugs.clear();
121  m_templateFitResults.clear();
122  m_slowData.clear();
123  m_interimFEInfos.clear();
124 
125  StoreObjPtr<EventMetaData> evtMetaData;
126  for (auto& raw : m_rawData) {
127  for (int finesse = 0; finesse < raw.GetMaxNumOfCh(0); finesse++) {
128  const int* buffer = raw.GetDetectorBuffer(0, finesse);
129  int bufferSize = raw.GetDetectorNwords(0, finesse);
130  if (bufferSize < 1) continue;
131 
132  int err = 0;
133 
134  int dataFormat = m_dataFormat;
135  if (dataFormat == 0) { // auto detect data format
136  DataArray array(buffer, bufferSize, m_swapBytes);
137  unsigned word = array.getWord();
138  dataFormat = (word >> 16);
139  bool isKnownDataFormat = false;
140  for (auto& t : TOP::membersRawDataType) {
141  if (static_cast<int>(t) == dataFormat) {
142  isKnownDataFormat = true;
143  break;
144  }
145  }
146 
147  if (!isKnownDataFormat) { //dataformat word is not recognised, might be interim format.
148  if (evtMetaData->getExperiment() == 1) { // all exp.1 data was taken with interim format
149  dataFormat = 0x0301;
150  m_swapBytes = true;
151  } else {
152  if (unpackHeadersInterimFEVer01(buffer, bufferSize, true)) { //if buffer unpacks without errors assuming it's interim format
153  B2DEBUG(22, "Assuming interim FW data format");
154  dataFormat = 0x0301; //assume it's interim format
155  m_swapBytes = true;
156  } else {
157  B2WARNING("TOPUnpacker: Could not establish data format.");
158  err = bufferSize;
159  }
160  }
161  }
162  }
163 
164  switch (dataFormat) {
165  case static_cast<int>(TOP::RawDataType::c_Type0Ver16):
166  unpackType0Ver16(buffer, bufferSize);
167  break;
168  case static_cast<int>(TOP::RawDataType::c_Type2Ver1):
169  err = unpackInterimFEVer01(buffer, bufferSize, false);
170  break;
171  case static_cast<int>(TOP::RawDataType::c_Type3Ver1):
172  err = unpackInterimFEVer01(buffer, bufferSize, true);
173  break;
174  case static_cast<int>(TOP::RawDataType::c_Draft):
175  unpackProductionDraft(buffer, bufferSize);
176  break;
177  case static_cast<int>(TOP::RawDataType::c_ProductionDebug01):
178  err = unpackProdDebug(buffer, bufferSize, TOP::RawDataType::c_ProductionDebug01, true);
179  break;
180  case static_cast<int>(TOP::RawDataType::c_ProductionDebug02):
181  err = unpackProdDebug(buffer, bufferSize, TOP::RawDataType::c_ProductionDebug02, true);
182  break;
183 
184  default:
185  B2ERROR("TOPUnpacker: unknown data format."
186  << LogVar("Type", (dataFormat >> 8))
187  << LogVar("Version", (dataFormat & 0xFF)));
188  err = bufferSize;
189 
190  }
191 
192 
193  if (err != 0) {
194  if (raw.GetMaxNumOfCh(0) <= 4) { // COPPER
195  stringstream copperName;
196  //nodeid format is described on page7 of: https://confluence.desy.de/display/BI/DAQ+WebHome?preview=%2F34029242%2F37487394%2FSetupPocketDAQ_4p1_RawCOPPERDataFormat.pdf
197  copperName << "cpr" << ((raw.GetNodeID(0) >> 24) * 1000 + (raw.GetNodeID(0) & 0x3FF)) << char('a' + finesse);
198  B2ERROR("TOPUnpacker: error in unpacking data from frontend " << copperName.str()
199  << LogVar("words unused", err)
200  << LogVar("copper", copperName.str()));
201  } else { // PCIe40
202  int slot = (raw.GetNodeID(0) & 0xF) * 8 - 7 + finesse / 4;
203  std::string name = (slot < 10) ? "s0" : "s";
204  name += std::to_string(slot) + char('a' + finesse % 4);
205  B2ERROR("TOPUnpacker: error in unpacking data from boardstack " << name << " "
206  << LogVar("words unused", err));
207  }
208  }
209 
210  } // finesse loop
211  } // m_rawData loop
212 
213  }
214 
215 
216  void TOPUnpackerModule::unpackProductionDraft(const int* buffer, int bufferSize)
217  {
218 
219  B2DEBUG(22, "Unpacking ProductionDraft to TOPDigits, dataSize = " << bufferSize);
220 
221  unsigned short scrodID = buffer[0] & 0xFFFF;
222  const auto* feemap = m_topgp->getFrontEndMapper().getMap(scrodID);
223  if (!feemap) {
224  B2ERROR("TOPUnpacker: no front-end map available."
225  << LogVar("SCROD ID", scrodID));
226  return;
227  }
228  int moduleID = feemap->getModuleID();
229  int boardstack = feemap->getBoardstackNumber();
230  const auto& mapper = m_topgp->getChannelMapper();
231 
232  const auto* geo = m_topgp->getGeometry();
233  auto subBits = geo->getNominalTDC().getSubBits();
234  int sampleDivisions = 0x1 << subBits;
235 
236  for (int i = 1; i < bufferSize; i++) {
237  int word = buffer[i];
238  int tdc = word & 0xFFFF;
239  double rawTime = double(tdc) / sampleDivisions;
240  unsigned chan = ((word >> 16) & 0x7F) + boardstack * 128;
241  unsigned flags = (word >> 24) & 0xFF;
242  int pixelID = mapper.getPixelID(chan);
243  auto* digit = m_digits.appendNew(moduleID, pixelID, rawTime);
244  digit->setTime(geo->getNominalTDC().getTime(tdc));
245  digit->setChannel(chan);
246  digit->setHitQuality((TOPDigit::EHitQuality) flags);
247  }
248 
249  }
250 
251 
252  void TOPUnpackerModule::unpackType0Ver16(const int* buffer, int bufferSize)
253  {
254 
255  B2DEBUG(22, "Unpacking Type0Ver16 to TOPRawDigits, dataSize = " << bufferSize);
256 
257  DataArray array(buffer, bufferSize, m_swapBytes);
258  unsigned word = array.getWord();
259  unsigned short scrodID = word & 0x0FFF;
260 
261  unsigned last = array.getLastWord();
262  int Nhits = last & 0x01FF;
263  if (bufferSize != 5 * Nhits + 2) {
264  B2ERROR("TOPUnpacker: corrupted data (feature-extraction format)."
265  << LogVar("SCROD ID", scrodID));
266  return;
267  }
268 
269  short SDType = last >> 24;
270  short SDValue = (last >> 12) & 0x0FFF;
271  if (SDType != 0) m_slowData.appendNew(scrodID, SDType, SDValue);
272 
273  unsigned short errorFlags = 0;
274  if (((word >> 12) & 0x0F) != 0x0A) errorFlags |= TOPRawDigit::c_HeadMagic;
275  if (((last >> 9) & 0x07) != 0x05) errorFlags |= TOPRawDigit::c_TailMagic;
276 
277  for (int hit = 0; hit < Nhits; hit++) {
278  auto* digit = m_rawDigits.appendNew(scrodID, TOPRawDigit::c_Production);
279 
280  word = array.getWord(); // word 1
281  digit->setCarrierNumber((word >> 30) & 0x03);
282  digit->setASICNumber((word >> 28) & 0x03);
283  digit->setASICChannel((word >> 25) & 0x07);
284  digit->setASICWindow((word >> 16) & 0x1FF);
285  digit->setTFine((word >> 8) & 0x0F);
286  auto flags = errorFlags;
287  if (((word >> 12) & 0x0F) != 0x0B) flags |= TOPRawDigit::c_HitMagic;
288  unsigned short checkSum = sumShorts(word);
289 
290  word = array.getWord(); // word 2
291  digit->setValuePeak(expand13to16bits(word >> 16));
292  digit->setIntegral(word & 0xFFFF);
293  checkSum += sumShorts(word);
294 
295  word = array.getWord(); // word 3
296  digit->setValueRise0(expand13to16bits(word >> 16));
297  digit->setValueRise1(expand13to16bits(word));
298  checkSum += sumShorts(word);
299 
300  word = array.getWord(); // word 4
301  digit->setValueFall0(expand13to16bits(word >> 16));
302  digit->setValueFall1(expand13to16bits(word));
303  checkSum += sumShorts(word);
304 
305  word = array.getWord(); // word 5
306  digit->setSampleRise(word >> 24);
307  digit->setDeltaSamplePeak((word >> 20) & 0x0F);
308  digit->setDeltaSampleFall((word >> 16) & 0x0F);
309  checkSum += sumShorts(word);
310  if (checkSum != 0) flags |= TOPRawDigit::c_HitChecksum;
311 
312  digit->setErrorFlags(flags);
313 
314  }
315 
316  }
317 
318  bool TOPUnpackerModule::unpackHeadersInterimFEVer01(const int* buffer, int bufferSize, bool swapBytes)
319  {
320  B2DEBUG(22, "Checking whether buffer unpacks as InterimFEVer01, dataSize = " << bufferSize);
321 
322  DataArray array(buffer, bufferSize, swapBytes);
323 
324  array.getWord(); // header word 0
325  array.getWord(); // header word 1 (what it contains?)
326  while (array.getRemainingWords() > 0) {
327  unsigned header = array.getWord(); // word 0
328  if ((header & 0xFF) == 0xBE) { //this is a super short FE header
329  continue;
330  }
331 
332  if (header != 0xaaaa0104 and header != 0xaaaa0103 and header != 0xaaaa0100) {//cannot be interim firmware
333  return false; //abort
334  }
335 
336 
337  array.getWord(); // word 1
338  array.getWord(); // word 2
339 
340  if (header != 0xaaaa0104) {
341  // feature-extracted data (positive signal)
342  array.getWord(); // word 3
343  array.getWord(); // word 4
344  array.getWord(); // word 5
345  array.getWord(); // word 6
346  array.getWord(); // word 7
347  array.getWord(); // word 8
348  array.getWord(); // word 9
349  array.getWord(); // word 10
350  array.getWord(); // word 11
351  array.getWord(); // word 12
352  array.getWord(); // word 13
353  array.getWord(); // word 14
354  }
355 
356  unsigned magicWord = array.getWord(); // word 15
357  if (magicWord != 0x7473616c) {//invalid magic word
358  return false; //abort
359  }
360 
361  if (header != 0xaaaa0103) continue;
362  array.getWord(); // word 16
363 
364  array.getWord(); // word 17
365  array.getWord(); // word 18
366  array.getWord(); // word 19
367 
368  array.getWord(); // word 20
369 
370  array.getWord(); // word 21
371 
372  array.getWord(); // word 22
373 
374  int numWords = 4 * 32; // (numPoints + 1) / 2;
375  if (array.getRemainingWords() < numWords) { //not enough remaining words for waveform data
376  return false; //abort
377  }
378 
379  for (int i = 0; i < numWords; i++) {
380  array.getWord();
381  }
382  }
383 
384  return true;
385  }
386 
387 
388  int TOPUnpackerModule::unpackInterimFEVer01(const int* buffer, int bufferSize,
389  bool pedestalSubtracted)
390  {
391 
392  B2DEBUG(22, "Unpacking InterimFEVer01 to TOPRawDigits and TOPRawWaveforms, "
393  "dataSize = " << bufferSize);
394 
395  int moduleID = 0;
396  int boardstack = 0;
397 
398  DataArray array(buffer, bufferSize, m_swapBytes);
399 
400  map<unsigned short, int> evtNumCounter; //counts the occurence of carrier-generated event numbers.
401  std::vector<unsigned short> channelCounter(128, 0); //counts occurence of carrier/asic/channel combinations
402 
403  unsigned word = array.getWord(); // header word 0
404  unsigned short scrodID = word & 0x0FFF;
405  auto* info = m_interimFEInfos.appendNew(scrodID, bufferSize);
406 
407  word = array.getWord(); // header word 1 (what it contains?)
408 
409 
410  while (array.getRemainingWords() > 0) {
411 
412  unsigned header = array.getWord(); // word 0
413 
414  if ((header & 0xFF) == 0xBE) { //this is a super short FE header
415 // B2DEBUG(21, "0b" << std::bitset<8>(header & 0xFF) << " " << std::bitset<8>((header>>8) & 0xFF) << " " << std::bitset<8>((header>>16) & 0xFF) << " " << std::bitset<8>((header>>24) & 0xFF));
416 
417  unsigned short scrodID_SSFE;
418  unsigned short carrier_SSFE;
419  unsigned short asic_SSFE;
420  unsigned short channel_SSFE;
421  unsigned short evtNum_SSFE;
422 
423  evtNum_SSFE = (header >> 8) & 0xFF;
424  scrodID_SSFE = (header >> 16) & 0x7F;
425  channel_SSFE = (header >> 24) & 0x07;
426  asic_SSFE = (header >> 27) & 0x03;
427  carrier_SSFE = (header >> 29) & 0x03;
428 
429  const auto* feemap = m_topgp->getFrontEndMapper().getMap(scrodID_SSFE);
430  if (feemap) {
431  moduleID = feemap->getModuleID();
432  boardstack = feemap->getBoardstackNumber();
433  } else {
434  B2ERROR("TOPUnpacker: no front-end map available."
435  << LogVar("SCROD ID", scrodID_SSFE));
436  info->setErrorFlag(TOPInterimFEInfo::c_InvalidScrodID);
437  }
438 
439  if (scrodID_SSFE != scrodID) {
440  B2ERROR("TOPUnpacker: corrupted data - "
441  << "different scrodID's in HLSB and super short FE header."
442  << LogVar("SCROD", scrodID_SSFE)
443  << LogVar("slot", moduleID)
444  << LogVar("BS", boardstack));
445  B2DEBUG(21, "Different scrodID's in HLSB and FE header: " << scrodID << " " << scrodID_SSFE << " word = 0x" << std::hex << word);
446  info->setErrorFlag(TOPInterimFEInfo::c_DifferentScrodIDs);
447  return array.getRemainingWords();
448  }
449 
450  B2DEBUG(21, scrodID_SSFE << "\t" << carrier_SSFE << "\t" << asic_SSFE << "\t" << channel_SSFE << "\t" << evtNum_SSFE);
451 
452  int channelID = carrier_SSFE * 32 + asic_SSFE * 8 + channel_SSFE;
453  channelCounter[channelID] += 1;
454  evtNumCounter[evtNum_SSFE] += 1;
455 
456  info->incrementFEHeadersCount();
457  info->incrementEmptyFEHeadersCount();
458 
459  continue;
460  }
461 
462  if (header != 0xaaaa0104 and header != 0xaaaa0103 and header != 0xaaaa0100) {
463  B2ERROR("TOPUnpacker: corrupted data - invalid FE header word");
464  B2DEBUG(21, "Invalid FE header word: " << std::hex << header << " 0b" << std::bitset<32>(header));
465  B2DEBUG(21, "SCROD ID: " << scrodID << " " << std::hex << scrodID);
466 
467  info->setErrorFlag(TOPInterimFEInfo::c_InvalidFEHeader);
468  return array.getRemainingWords();
469  }
470 
471 
472  word = array.getWord(); // word 1
473  unsigned short scrodID_FE = word >> 25;
474  unsigned short convertedAddr = (word >> 16) & 0x1FF;
475  unsigned short evtNum_numWin_trigPat_FEheader = word & 0xFFFF;
476  unsigned short evtNum_FEheader = evtNum_numWin_trigPat_FEheader & 0xFF;
477  evtNumCounter[evtNum_FEheader] += 1;
478 
479  if (scrodID_FE != scrodID) {
480  B2ERROR("TOPUnpacker: different scrodID's in HLSB and FE header."
481  << LogVar("scrodID (HSLB)", scrodID)
482  << LogVar("scrodID (FE)", scrodID_FE));
483 
484  info->setErrorFlag(TOPInterimFEInfo::c_DifferentScrodIDs);
485  return array.getRemainingWords();
486  }
487 
488  word = array.getWord(); // word 2
489  // unsigned lastWrAddr = word & 0x1FF;
490  unsigned lastWrAddr = (word & 0x0FF) << 1;
491  //unsigned short asicChannelFE = (word >> 9) & 0x07;
492  unsigned short asicChannelFE = (word >> 8) & 0x07;
493  unsigned short asicFE = (word >> 12) & 0x03;
494  unsigned short carrierFE = (word >> 14) & 0x03;
495  unsigned short channelID = carrierFE * 32 + asicFE * 8 + asicChannelFE;
496  //B2DEBUG(21, "carrier asic chn " << carrierFE << " " << asicFE << " " << asicChannelFE << " " << channelID << " 0b" << std::bitset<32>(word) );
497 
498  B2DEBUG(21, scrodID_FE << "\t" << carrierFE << "\t" << asicFE << "\t" << asicChannelFE << "\t" << evtNum_FEheader);
499 
500  channelCounter[channelID] += 1;
501 
502  std::vector<TOPRawDigit*> digits; // needed for creating relations to waveforms
503 
504  if (header != 0xaaaa0104) {
505  // feature-extracted data (positive signal)
506  array.getWord(); // word 3
507  word = array.getWord(); // word 4
508  short samplePeak_p = word & 0xFFFF;
509  short valuePeak_p = (word >> 16) & 0xFFFF;
510 
511  word = array.getWord(); // word 5
512  short sampleRise_p = word & 0xFFFF;
513  short valueRise0_p = (word >> 16) & 0xFFFF;
514 
515  word = array.getWord(); // word 6
516  short valueRise1_p = word & 0xFFFF;
517  short sampleFall_p = (word >> 16) & 0xFFFF;
518 
519  word = array.getWord(); // word 7
520  short valueFall0_p = word & 0xFFFF;
521  short valueFall1_p = (word >> 16) & 0xFFFF;
522 
523  word = array.getWord(); // word 8
524  short integral_p = word & 0xFFFF;
525  // short qualityFlags_p = (word >> 16) & 0xFFFF;
526 
527  // feature-extracted data (negative signal)
528  array.getWord(); // word 9
529  //word = array.getWord(); // word 9
530  //short n_samp_i = (word >> 16) & 0xFFFF;
531  word = array.getWord(); // word 10
532  short samplePeak_n = word & 0xFFFF;
533  short valuePeak_n = (word >> 16) & 0xFFFF;
534 
535  array.getWord(); // word 11
536  //word = array.getWord(); // word 11
537  //short sampleRise_n = word & 0xFFFF;
538  //short valueRise0_n = (word >> 16) & 0xFFFF;
539 
540  array.getWord(); // word 12
541  //word = array.getWord(); // word 12
542  //short valueRise1_n = word & 0xFFFF;
543  //short sampleFall_n = (word >> 16) & 0xFFFF;
544 
545  array.getWord(); // word 13
546  //word = array.getWord(); // word 13
547  //short valueFall0_n = word & 0xFFFF;
548  //short valueFall1_n = (word >> 16) & 0xFFFF;
549 
550  word = array.getWord(); // word 14
551  short integral_n = word & 0xFFFF;
552  short qualityFlags_n = (word >> 16) & 0xFFFF;
553 
554  if (abs(valuePeak_p) != 9999) {
555  auto* digit = m_rawDigits.appendNew(scrodID, TOPRawDigit::c_Interim);
556  digit->setCarrierNumber(carrierFE);
557  digit->setASICNumber(asicFE);
558  digit->setASICChannel(asicChannelFE);
559  digit->setASICWindow(convertedAddr);
560  digit->setLastWriteAddr(lastWrAddr);
561  digit->setSampleRise(sampleRise_p);
562  digit->setDeltaSamplePeak(samplePeak_p - sampleRise_p);
563  digit->setDeltaSampleFall(sampleFall_p - sampleRise_p);
564  digit->setValueRise0(valueRise0_p);
565  digit->setValueRise1(valueRise1_p);
566  digit->setValuePeak(valuePeak_p);
567  digit->setValueFall0(valueFall0_p);
568  digit->setValueFall1(valueFall1_p);
569  digit->setIntegral(integral_p);
570  // digit->setErrorFlags(qualityFlags_p); // not good solution !
571  digit->addRelationTo(info);
572  digits.push_back(digit);
573  //template fit result is saved in negative pulse fe data
574  if (valuePeak_p < 150) {
575  auto* tlpfResult = m_templateFitResults.appendNew();
576  tlpfResult->setBackgroundOffset(samplePeak_n);
577  tlpfResult->setAmplitude(valuePeak_n);
578  tlpfResult->setChisquare(qualityFlags_n);
579  tlpfResult->setRisingEdgeAndConvert(integral_n);
580  digit->addRelationTo(tlpfResult);
581  }
582  }
583  /*if (abs(valuePeak_n) != 9999) {
584  auto* digit = m_rawDigits.appendNew(scrodID, TOPRawDigit::c_Interim);
585  digit->setCarrierNumber(carrierFE);
586  digit->setASICNumber(asicFE);
587  digit->setASICChannel(asicChannelFE);
588  digit->setASICWindow(convertedAddr);
589  digit->setLastWriteAddr(lastWrAddr);
590  digit->setSampleRise(sampleRise_n);
591  digit->setDeltaSamplePeak(samplePeak_n - sampleRise_n);
592  digit->setDeltaSampleFall(sampleFall_n - sampleRise_n);
593  digit->setValueRise0(valueRise0_n);
594  digit->setValueRise1(valueRise1_n);
595  digit->setValuePeak(valuePeak_n);
596  digit->setValueFall0(valueFall0_n);
597  digit->setValueFall1(valueFall1_n);
598  digit->setIntegral(integral_n);
599  // digit->setErrorFlags(qualityFlags_n); // not good solution !
600  digit->addRelationTo(info);
601  digits.push_back(digit);
602  }*/
603  }
604 
605  // magic word
606  word = array.getWord(); // word 15
607  if (word != 0x7473616c) {
608  //B2ERROR("TOPUnpacker: corrupted data - no magic word at the end of FE header");
609  //B2DEBUG(21, "No magic word at the end of FE header, found: "
610  //<< std::hex << word);
611  info->setErrorFlag(TOPInterimFEInfo::c_InvalidMagicWord);
612  //return array.getRemainingWords(); do not abort event for now as footer is invalid in current debugging version of firmware
613  }
614 
615  // store to raw digits
616 
617  info->incrementFEHeadersCount();
618  if (digits.empty()) info->incrementEmptyFEHeadersCount();
619 
620  if (header != 0xaaaa0103) continue;
621 
622  // waveform header
623  word = array.getWord(); // word 16
624  unsigned long evtNum_numWaves_refWin_WFheader = word;
625  unsigned short evtNum_WFheader = (evtNum_numWaves_refWin_WFheader >> 24) & 0xFF;
626 
627  if (evtNum_WFheader != evtNum_FEheader) {
628  B2ERROR("TOPUnpacker: different carrier event number in WF and FE header."
629  << LogVar("Event number (FE header)", evtNum_FEheader)
630  << LogVar("Event number (WF header)", evtNum_WFheader));
631  }
632 
633  array.getWord(); // word 17
634  array.getWord(); // word 18
635  word = array.getWord(); // word 19
636  // int numPoints = (word >> 16) & 0xFFFF;
637  unsigned short carrier = (word >> 14) & 0x03;
638  unsigned short asic = (word >> 12) & 0x03;
639  unsigned short asicChannel = (word >> 9) & 0x07;
640  unsigned short window = word & 0x1FF;
641 
642  // checks for data corruption
643  if (carrier != carrierFE) {
644  B2ERROR("TOPUnpacker: different carrier numbers in FE and WF header");
645  B2DEBUG(21, "Different carrier numbers in FE and WF header: "
646  << carrierFE << " " << carrier);
647  info->setErrorFlag(TOPInterimFEInfo::c_DifferentCarriers);
648  }
649  if (asic != asicFE) {
650  B2ERROR("TOPUnpacker: different ASIC numbers in FE and WF header");
651  B2DEBUG(21, "Different ASIC numbers in FE and WF header: "
652  << asicFE << " " << asic);
653  info->setErrorFlag(TOPInterimFEInfo::c_DifferentAsics);
654  }
655  if (asicChannel != asicChannelFE) {
656  B2ERROR("TOPUnpacker: different ASIC channel numbers in FE and WF header");
657  B2DEBUG(21, "Different ASIC channel numbers in FE and WF header: "
658  << asicChannelFE << " " << asicChannel);
659  info->setErrorFlag(TOPInterimFEInfo::c_DifferentChannels);
660  }
661  if (window != convertedAddr) {
662  B2ERROR("TOPUnpacker: different window numbers in FE and WF header");
663  B2DEBUG(21, "Different window numbers in FE and WF header: "
664  << convertedAddr << " " << window);
665  info->setErrorFlag(TOPInterimFEInfo::c_DifferentWindows);
666  }
667 
668  // reading out all four window addresses
669  // to be for correcnt alignment of individual readout windows in written waveform
670  std::vector<unsigned short> windows;
671  windows.push_back(window);
672 
673  word = array.getWord(); // word 20
674  windows.push_back(word & 0x1FF);
675 
676  word = array.getWord(); // word 21
677  windows.push_back(word & 0x1FF);
678 
679  word = array.getWord(); // word 22
680  windows.push_back(word & 0x1FF);
681 
682  int numWords = 4 * 32; // (numPoints + 1) / 2;
683  if (array.getRemainingWords() < numWords) {
684  B2ERROR("TOPUnpacker: too few words for waveform data."
685  << LogVar("needed", numWords)
686  << LogVar("available", array.getRemainingWords()));
687  info->setErrorFlag(TOPInterimFEInfo::c_InsufficientWFData);
688  return array.getRemainingWords();
689  }
690 
691  // unpack waveforms
692  std::vector<short> adcData;
693  for (int i = 0; i < numWords; i++) {
694  word = array.getWord();
695  adcData.push_back(word & 0xFFFF);
696  adcData.push_back((word >> 16) & 0xFFFF);
697  }
698  // if (numWords * 2 != numPoints) adcData.pop_back(); // numPoints is even
699 
700  // determine slot number (moduleID) and boardstack
701  moduleID = 0;
702  boardstack = 0;
703  const auto* feemap = m_topgp->getFrontEndMapper().getMap(scrodID);
704  if (feemap) {
705  moduleID = feemap->getModuleID();
706  boardstack = feemap->getBoardstackNumber();
707  } else {
708  B2ERROR("TOPUnpacker: no front-end map available."
709  << LogVar("SCROD ID", scrodID));
710  info->setErrorFlag(TOPInterimFEInfo::c_InvalidScrodID);
711  }
712 
713  // determine hardware channel and pixelID (valid only if feemap available!)
714  const auto& mapper = m_topgp->getChannelMapper();
715  unsigned channel = mapper.getChannel(boardstack, carrier, asic, asicChannel);
716  int pixelID = mapper.getPixelID(channel);
717 
718  // store to raw waveforms
719  auto* waveform = m_waveforms.appendNew(moduleID, pixelID, channel, scrodID,
720  window, 0, adcData);
721  waveform->setLastWriteAddr(lastWrAddr);
722  waveform->setStorageWindows(windows);
723  waveform->setPedestalSubtractedFlag(pedestalSubtracted);
724  waveform->addRelationTo(info);
725  info->incrementWaveformsCount();
726 
727  // create relations btw. raw digits and waveform
728  for (auto& digit : digits) digit->addRelationTo(waveform);
729 
730  }
731 
732  if (evtNumCounter.size() != 1) {
733  B2ERROR("TOPUnpacker: Possible frame shift detected "
734  << "(More than one unique carrier event number in this readout event)."
735  << LogVar("SCROD", scrodID)
736  << LogVar("slot", moduleID)
737  << LogVar("BS", boardstack));
738  }
739 
740  int nASICs = 0;
741 
742  string evtNumOutputString;
743  evtNumOutputString += "Carrier event numbers and their counts for SCROD ID " + std::to_string(scrodID) + ":\n";
744  for (auto const& it : evtNumCounter) {
745  nASICs += it.second;
746  evtNumOutputString += std::to_string(it.first) + ":\t" + std::to_string(it.second) + "\n";
747  }
748  evtNumOutputString += "Total:\t" + std::to_string(nASICs);
749  B2DEBUG(21, evtNumOutputString);
750 
751  int nChannels = 0;
752  int nChannelsDiff = 0;
753 
754  string channelOutputString;
755  channelOutputString += "Detected channels and their counts for SCROD ID (channels with count == 1 are omitted)" + std::to_string(
756  scrodID) + ":\n";
757 
758  int channelIndex(0);
759  for (auto const& it : channelCounter) {
760  if (it > 0) {
761  nChannelsDiff += 1;
762  }
763  nChannels += it;
764 
765  int channelID = channelIndex;
766  int carrier = channelID / 32;
767  int asic = (channelID % 32) / 8;
768  int chn = channelID % 8;
769 
770  if (it != 1) {
771  channelOutputString += "carrier: " + std::to_string(carrier) + " asic: " + std::to_string(asic) + " chn: " + std::to_string(
772  chn) + " occurence: " + std::to_string(it) + "\n";
773  B2WARNING("TOPUnpacker: interim FE - ASIC channel seen more than once"
774  << LogVar("ScrodID", scrodID)
775  << LogVar("carrier", carrier)
776  << LogVar("ASIC", asic)
777  << LogVar("channel", chn)
778  << LogVar("times seen", it));
779  }
780  channelIndex += 1;
781  }
782 
783  m_channelStatistics[nChannels] += 1;
784 
785  channelOutputString += "Total:\t" + std::to_string(nChannels) + " " + std::to_string(nChannelsDiff);
786  B2DEBUG(21, channelOutputString);
787 
788  return array.getRemainingWords();
789 
790 
791  }
792 
793 
794  int TOPUnpackerModule::unpackProdDebug(const int* buffer, int bufferSize, TOP::RawDataType dataFormat,
795  bool pedestalSubtracted)
796  {
797 
798  B2DEBUG(22, "Unpacking Production firmware debug data format to TOPRawDigits "
799  "dataSize = " << bufferSize);
800 
801  DataArray array(buffer, bufferSize, m_swapBytes);
802  unsigned word;
803 
804  word = array.getWord(); // word 0, type(8)/version(8)/0xA(4)/ScrodID(12)
805  unsigned int evtType = word >> 24;
806  unsigned int evtVersion = (word >> 16) & 0xFF;
807  unsigned int evtMagicHeader = (word >> 12) & 0xF;
808  unsigned int evtScrodID = word & 0xFFF;
809 
810  // determine slot number (moduleID) and boardstack
811  int moduleID = 0;
812  int boardstack = 0;
813  const auto* feemap = m_topgp->getFrontEndMapper().getMap(evtScrodID);
814  if (feemap) {
815  moduleID = feemap->getModuleID();
816  boardstack = feemap->getBoardstackNumber();
817  } else {
818  B2WARNING("TOPUnpacker: no front-end map available."
819  << LogVar("SCROD ID", evtScrodID));
820  }
821 
822 
823  B2DEBUG(22, std::dec << array.getIndex() << ":\t" << setfill('0') << setw(4) << std::hex <<
824  (word >> 16) << " " << setfill('0') << setw(4) << (word & 0xFFFF) << std::dec
825  << "\tevtType = " << evtType
826  << ", evtVersion = " << evtVersion
827  << ", evtMagicHeader = " << evtMagicHeader
828  << ", evtScrodID = " << evtScrodID);
829 
830  if (evtMagicHeader != 0xA) {
831  B2WARNING("TOPUnpacker: event header magic word mismatch. should be 0xA."
832  << LogVar("Magic word", evtMagicHeader));
833  return array.getRemainingWords();
834  }
835 
836  word = array.getWord(); // word 1, extra(3)/numWordsBonus(13)/phase(4)/numWordsCore(12)
837  unsigned int evtExtra = word >> 29;
838  unsigned int evtNumWordsBonus = (word >> 16) & 0x1FFF;
839  unsigned int evtPhase = (word >> 12) & 0xF;
840  unsigned int evtNumWordsCore = word & 0xFFF;
841 
842  B2DEBUG(22, std::dec << array.getIndex() << ":\t" << setfill('0') << setw(4) << std::hex <<
843  (word >> 16) << " " << setfill('0') << setw(4) << (word & 0xFFFF) << std::dec
844  << "\tevtExtra = " << evtExtra
845  << ", evtNumWordsBonus = " << evtNumWordsBonus
846  << ", evtPhase = " << evtPhase
847  << ", numWordsCore = " << evtNumWordsCore);
848 
849  word = array.getWord(); // word 2, skipHit(1)/reserved(4)/ctime LSBs(11)/revo9counter(16)
850  bool evtSkipHit = word >> 29;
851  unsigned int evtCtime = (word >> 16) & 0x7FF;
852  unsigned int evtRevo9Counter = word & 0xFFFF;
853 
854  B2DEBUG(22, std::dec << array.getIndex() << ":\t" << setfill('0') << setw(4) << std::hex <<
855  (word >> 16) << " " << setfill('0') << setw(4) << (word & 0xFFFF) << std::dec
856  << "\tevtSkipHit = " << evtSkipHit
857  << ", evtCtime = " << evtCtime
858  << ", evtRevo9Counter = " << evtRevo9Counter);
859 
860  word = array.getWord(); // word 3, asicMask(16)/eventQueueDepth(8)/eventNumberByte(8)
861  unsigned int evtAsicMask = word >> 16;
862  unsigned int evtEventQueueDepth = (word >> 8) & 0xFF;
863  unsigned int evtEventNumberByte = word & 0xFF;
864 
865  B2DEBUG(22, std::dec << array.getIndex() << ":\t" << setfill('0') << setw(4) << std::hex <<
866  (word >> 16) << " " << setfill('0') << setw(4) << (word & 0xFFFF) << std::dec
867  << "\tevtAsicMask = " << evtAsicMask
868  << ", evtEventQueueDepth = " << evtEventQueueDepth
869  << ", evtEventNumberByte = " << evtEventNumberByte);
870 
871  m_productionEventDebugs.appendNew(evtType,
872  evtVersion,
873  evtScrodID,
874  evtSkipHit,
875  evtCtime,
876  evtPhase,
877  evtAsicMask,
878  evtEventQueueDepth,
879  evtEventNumberByte);
880 
881  B2DEBUG(22, "end of event header, start of hits:");
882 
883  const int numWordsPerHit = 4 + evtExtra;
884  unsigned int numHitsFound = 0;
885  unsigned int numExpectedWaveforms = 0;
886 
887  std::vector<TOPRawDigit*> digitsWithWaveform; // digits that have waveforms
888 
889  while (array.getRemainingWords() > numWordsPerHit //one more full hit + one word of footer
890  && array.getIndex() < evtNumWordsCore - 2) { // -1 for 0-based counting, -1 for hit footer word
891  array.resetChecksum();
892 
893 
894  //need to predefine some variables here as we need to branch out between two data format versions for the next two words
895  unsigned int hitCarrier = 0;
896  unsigned int hitAsic = 0;
897  unsigned int hitChannel = 0;
898  unsigned int hitWindow = 0;
899  unsigned int hitMagicHeader = 0;
900  unsigned int hitTFine = 0;
901  bool hitHasWaveform = false;
902  bool hitIsOnHeap = false;
903  unsigned int hitHeapWindow = 0;
904  bool hitIsOnHeapStraddle = false;
905  unsigned int hitHeapWindowStraddle = 0;
906  bool hitIsWindowStraddle = false;
907  short hitIntegral = 0;
908  short hitVPeak = 0;
909 
910  if (dataFormat == TOP::RawDataType::c_ProductionDebug01) { //dataformat 0x0401
911  word = array.getWord(); // hit word 0, carrier(2)/asic(2)/channel(3)/window(9)/0xB(4)/tFine(4)/hasWaveform(1)/isOnHeap(1)/heapWindow(6)
912  hitCarrier = word >> 30;
913  hitAsic = (word >> 28) & 0x3;
914  hitChannel = (word >> 25) & 0x7;
915  hitWindow = (word >> 16) & 0x1FF;
916  hitMagicHeader = (word >> 12) & 0xF;
917  hitTFine = (word >> 8) & 0xF;
918  hitHasWaveform = (word >> 7) & 0x1;
919  hitIsOnHeap = (word >> 6) & 0x1;
920  hitHeapWindow = word & 0x3F;
921 
922 
923  B2DEBUG(22, std::dec << array.getIndex() << ":\t" << setfill('0') << setw(4) << std::hex <<
924  (word >> 16) << " " << setfill('0') << setw(4) << (word & 0xFFFF) << std::dec
925  << "\thitCarrier = " << hitCarrier
926  << ", hitAsic = " << hitAsic
927  << ", hitChannel = " << hitChannel
928  << ", hitWindow = " << hitWindow
929  // << ", hitMagicHeader = " << hitMagicHeader
930  // << ", hitTFine = " << hitTFine
931  << ", hitHasWaveform = " << hitHasWaveform
932  // << ", hitIsOnHeap = " << hitIsOnHeap
933  // << ", hitHeapWindow = " << hitHeapWindow
934  );
935 
936 
937  word = array.getWord(); // hit word 1, reserved(3)/vPeak(13)/integral(16)
938  hitVPeak = expand13to16bits(word >> 16);
939  hitIntegral = word & 0xFFFF;
940  B2DEBUG(22, std::dec << array.getIndex() << ":\t" << setfill('0') << setw(4) << std::hex <<
941  (word >> 16) << " " << setfill('0') << setw(4) << (word & 0xFFFF) << std::dec
942  << "\thitVPeak = " << hitVPeak
943  << ", hitIntegral = " << hitIntegral);
944 
945  } else if (dataFormat == TOP::RawDataType::c_ProductionDebug02) { //dataformat 0x0402
946  word = array.getWord(); // hit word 0, carrier(2)/asic(2)/channel(3)/window(9)/0xB(4)/tFine(4)/hasWaveform(1)/isWindowStraddle(1)/integral(6)
947  hitCarrier = word >> 30;
948  hitAsic = (word >> 28) & 0x3;
949  hitChannel = (word >> 25) & 0x7;
950  hitWindow = (word >> 16) & 0x1FF;
951  hitMagicHeader = (word >> 12) & 0xF;
952  hitTFine = (word >> 8) & 0xF;
953  hitHasWaveform = (word >> 7) & 0x1;
954  hitIsWindowStraddle = (word >> 6) & 0x1;
955  hitIntegral = word & 0x3F;
956 
957 
958  B2DEBUG(22, std::dec << array.getIndex() << ":\t" << setfill('0') << setw(4) << std::hex <<
959  (word >> 16) << " " << setfill('0') << setw(4) << (word & 0xFFFF) << std::dec
960  << "\thitCarrier = " << hitCarrier
961  << ", hitAsic = " << hitAsic
962  << ", hitChannel = " << hitChannel
963  << ", hitWindow = " << hitWindow
964  // << ", hitMagicHeader = " << hitMagicHeader
965  // << ", hitTFine = " << hitTFine
966  << ", hitHasWaveform = " << hitHasWaveform
967  << ", hitIsWindowStraddle = " << hitHasWaveform
968  << ", hitIntegral = " << hitIntegral
969  // << ", hitHeapWindow = " << hitHeapWindow
970  );
971 
972  word = array.getWord(); // hit word 1, reserved(3)/vPeak(13)/isOnHeap1(1)/heapWindow1(7)/isOnHeap0(1)/heapWindow0(7)
973  hitVPeak = expand13to16bits(word >> 16);
974  hitIsOnHeapStraddle = (word >> 15) & 0x1;
975  hitHeapWindowStraddle = (word >> 8) & 0x7F;
976  hitIsOnHeap = (word >> 7) & 0x1;
977  hitHeapWindow = word & 0x1;
978 
979  B2DEBUG(22, std::dec << array.getIndex() << ":\t" << setfill('0') << setw(4) << std::hex <<
980  (word >> 16) << " " << setfill('0') << setw(4) << (word & 0xFFFF) << std::dec
981  << "\thitVPeak = " << hitVPeak
982  << ", hitIsOnHeapStraddle = " << hitIsOnHeapStraddle
983  << ", hitHeapWindowStraddle = " << hitHeapWindowStraddle
984  << ", hitIsOnHeap = " << hitIsOnHeap
985  << ", hitHeapWindow = " << hitHeapWindow);
986  } else { //could not match the data format
987  B2WARNING("TOPUnpacker: could not match data type inside unpackProdDebug()"
988  << LogVar("evtType", evtType) << LogVar("evtVersion", evtVersion));
989  return array.getRemainingWords();
990  }
991 
992 
993  if (hitHasWaveform) {
994  numExpectedWaveforms += 1;
995  }
996 
997  if (hitMagicHeader != 0xB) {
998  B2WARNING("TOPUnpacker: hit header magic word mismatch. should be 0xB."
999  << LogVar("Magic word", hitMagicHeader));
1000  return array.getRemainingWords();
1001  }
1002 
1003  word = array.getWord(); // hit word 2, reserved(3)/vRise0(13)/reserved(3)/vRise1(13)
1004  short hitVRise0 = expand13to16bits(word >> 16);
1005  short hitVRise1 = expand13to16bits(word);
1006  B2DEBUG(22, std::dec << array.getIndex() << ":\t" << setfill('0') << setw(4) << std::hex <<
1007  (word >> 16) << " " << setfill('0') << setw(4) << (word & 0xFFFF) << std::dec
1008  << "\thitVRise0 = " << hitVRise0
1009  << ", hitVRise1 = " << hitVRise1);
1010 
1011  word = array.getWord(); // hit word 3, reserved(3)/vFall0(13)/reserved(3)/vFall1(13)
1012  short hitVFall0 = expand13to16bits(word >> 16);
1013  short hitVFall1 = expand13to16bits(word);
1014  B2DEBUG(22, std::dec << array.getIndex() << ":\t" << setfill('0') << setw(4) << std::hex <<
1015  (word >> 16) << " " << setfill('0') << setw(4) << (word & 0xFFFF) << std::dec
1016  << "\thitVFall0 = " << hitVFall0
1017  << ", hitVFall1 = " << hitVFall1);
1018 
1019  word = array.getWord(); // hit word 4, sampleRise(8)/dSampPeak(4)/dSampFall(4)/headerChecksum(16)
1020  unsigned short hitSampleRise = (word >> 24);
1021  short hitDSampPeak = (word >> 20) & 0xF;
1022  short hitDSampFall = (word >> 16) & 0xF;
1023  unsigned short hitHeaderChecksum = word & 0xFFFF;
1024  B2DEBUG(22, std::dec << array.getIndex() << ":\t" << setfill('0') << setw(4) << std::hex <<
1025  (word >> 16) << " " << setfill('0') << setw(4) << (word & 0xFFFF) << std::dec
1026  << "\thitSampleRise = " << hitSampleRise
1027  << ", hitDSampPeak = " << hitDSampPeak
1028  << ", hitDSampFall = " << hitDSampFall
1029  << ", hitheaderChecksum = " << hitHeaderChecksum
1030  << ", checksum " << (array.validateChecksum() ? "OK" : "NOT OK"));
1031 
1032  if (!array.validateChecksum()) {
1033  B2WARNING("TOPUnpacker: hit checksum invalid.");
1034  return array.getRemainingWords();
1035  }
1036 
1037  // append digit
1038  auto* digit = m_rawDigits.appendNew(evtScrodID, TOPRawDigit::c_ProductionDebug);
1039  digit->setCarrierNumber(hitCarrier);
1040  digit->setASICNumber(hitAsic);
1041  digit->setASICChannel(hitChannel);
1042  digit->setASICWindow(hitWindow);
1043  digit->setLastWriteAddr(0);
1044  digit->setSampleRise(hitSampleRise);
1045  digit->setDeltaSamplePeak(hitDSampPeak);
1046  digit->setDeltaSampleFall(hitDSampFall);
1047  digit->setValueRise0(hitVRise0);
1048  digit->setValueRise1(hitVRise1);
1049  digit->setValuePeak(hitVPeak);
1050  digit->setValueFall0(hitVFall0);
1051  digit->setValueFall1(hitVFall1);
1052  digit->setTFine(hitTFine);
1053  digit->setIntegral(hitIntegral);
1054  digit->setRevo9Counter(evtRevo9Counter);
1055  digit->setPhase(evtPhase);
1056 
1057 
1058  if (hitHasWaveform) {
1059  digitsWithWaveform.push_back(digit);
1060  }
1061 
1062  TOPProductionHitDebug* hitDebug = 0;
1063  if (dataFormat == TOP::RawDataType::c_ProductionDebug01) { // dataformat 0x0401
1064  hitDebug = m_productionHitDebugs.appendNew(hitHasWaveform,
1065  hitIsOnHeap,
1066  hitWindow,
1067  hitIsOnHeap ? 428 + hitHeapWindow : hitWindow, //hitHeapWindow is counted from the start of the heap
1068  hitIsWindowStraddle);
1069  } else if (dataFormat == TOP::RawDataType::c_ProductionDebug02) { // dataformat 0x0402
1070  hitDebug = m_productionHitDebugs.appendNew(hitHasWaveform,
1071  hitIsOnHeap,
1072  hitWindow,
1073  hitIsOnHeap ? 428 + hitHeapWindow : hitWindow, //hitHeapWindow is counted from the start of the heap
1074  hitIsWindowStraddle,
1075  hitWindow + 1, //logical address of straddle window is always +1
1076  hitIsOnHeapStraddle ? 428 + hitHeapWindowStraddle : hitWindow +
1077  1); //physical address might be entirely different if straddled window is on heap
1078  }
1079 
1080  //parse extra words if exist:
1081  for (unsigned int i = 0; i < evtExtra; ++i) {
1082  word = array.getWord(); // extra hit word i, undefined so far
1083  B2DEBUG(22, std::dec << array.getIndex() << ":\t" << setfill('0') << setw(4) << std::hex <<
1084  (word >> 16) << " " << setfill('0') << setw(4) << (word & 0xFFFF) << std::dec
1085  << "\thit extra word " << i << " (" << evtExtra << ")");
1086  hitDebug->appendExtraWord(word);
1087  }
1088 
1089  if (m_addRelations and hitDebug) {
1090  digit->addRelationTo(hitDebug);
1091  }
1092 
1093  numHitsFound += 1;
1094  } // end of hits loop
1095 
1096  word = array.getWord(); // event footer word, sdType(8)/sdData(12)/0x5(3)/nHits(9)
1097  unsigned int evtSdType = (word >> 24);
1098  unsigned int evtSdData = (word >> 12) & 0xFFF;
1099  unsigned int evtMagicFooter = (word >> 9) & 0x7;
1100  unsigned int evtNHits = word & 0x1FF;
1101  B2DEBUG(22, std::dec << array.getIndex() << ":\t" << setfill('0') << setw(4) << std::hex <<
1102  (word >> 16) << " " << setfill('0') << setw(4) << (word & 0xFFFF) << std::dec
1103  << "\tevtSdType = " << evtSdType
1104  << ", evtSdData = " << evtSdData
1105  << ", evtMagicFooter = " << evtMagicFooter
1106  << ", evtNHits = " << evtNHits << " (" << numHitsFound << ")");
1107 
1108  if (evtSdType != 0) {
1109  m_slowData.appendNew(evtScrodID, evtSdType, evtSdData);
1110  }
1111 
1112  if (evtMagicFooter != 0x5) {
1113  B2WARNING("TOPUnpacker: event footer magic word mismatch. should be 0x5."
1114  << LogVar("Magic word", evtMagicFooter));
1115  return array.getRemainingWords();
1116  }
1117 
1118  B2DEBUG(22, "the rest:");
1119 
1120  unsigned int numParsedWaveforms = 0;
1121  while (array.peekWord() != 0x6c617374 //next word is not wf footer word
1122  && array.getRemainingWords() > 0) {
1123 
1124  word = array.getWord(); // waveform word 0, nSamples(16)/0x0(5)/nWindows(3)/0(1)/carrier(2)/asic(2)/channel(3)
1125  unsigned int wfNSamples = (word >> 16);
1126  unsigned int wfNWindows = (word >> 8) & 0x7;
1127  unsigned int wfCarrier = (word >> 5) & 0x3;
1128  unsigned int wfAsic = (word >> 3) & 0x3;
1129  unsigned int wfChannel = word & 0x7;
1130 
1131  // determine hardware channel and pixelID (valid only if feemap available!)
1132  const auto& mapper = m_topgp->getChannelMapper();
1133  unsigned channel = mapper.getChannel(boardstack, wfCarrier, wfAsic, wfChannel);
1134  int pixelID = mapper.getPixelID(channel);
1135 
1136  B2DEBUG(22, std::dec << array.getIndex() << ":\t" << setfill('0') << setw(4) << std::hex <<
1137  (word >> 16) << " " << setfill('0') << setw(4) << (word & 0xFFFF) << std::dec
1138  << "\twfNSamples = " << wfNSamples
1139  << ", wfNWindows = " << wfNWindows
1140  << ", wfCarrier = " << wfCarrier
1141  << ", wfAsic = " << wfAsic
1142  << ", wfChannel " << wfChannel);
1143 
1144  if (wfNSamples != 32 && wfNSamples != 16) {
1145  B2WARNING("TOPUnpacker: suspicious value for wfNSamples."
1146  << LogVar("wfNSamples", wfNSamples));
1147  return array.getRemainingWords();
1148  }
1149 
1150  word = array.getWord(); // waveform word 1, 0x0(1)/startSamp(6)/logAddress(9)/carrierEventNumber(7)/readAddr(9)
1151  unsigned int wfStartSample = (word >> 25) & 0x3F;
1152  unsigned int wfWindowLogic = (word >> 16) & 0x1FF;
1153  unsigned int wfEventNumber = (word >> 9) & 0x7F;
1154  unsigned int wfWindowPhysical = word & 0x1FF;
1155 
1156  B2DEBUG(22, std::dec << array.getIndex() << ":\t" << setfill('0') << setw(4) << std::hex <<
1157  (word >> 16) << " " << setfill('0') << setw(4) << (word & 0xFFFF) << std::dec
1158  << "\twfStartSample = " << wfStartSample
1159  << ", wfWindowLogic = " << wfWindowLogic
1160  << ", wfEventNumber = " << wfEventNumber
1161  << ", wfWindowPhysical = " << wfWindowPhysical);
1162 
1163  std::vector<short> wfSamples;
1164 
1165  for (unsigned int i = 0; i < wfNSamples / 2; ++i) {
1166  short wfSampleLast = 0;
1167  short wfSampleFirst = 0;
1168 
1169 
1170  word = array.getWord(); // waveform sample word i, reserved(4)/sample 2*i+1(12)/reserved(4)/sample 2*i(12)
1171  if (pedestalSubtracted) {
1172  wfSampleLast = (word >> 16);
1173  wfSampleFirst = word & 0xFFFF;
1174  } else {
1175  wfSampleLast = (word >> 16) & 0xFFF;
1176  wfSampleFirst = word & 0xFFF;
1177 
1178  }
1179 
1180  B2DEBUG(22, std::dec << array.getIndex() << ":\t" << setfill('0') << setw(4) << std::hex <<
1181  (word >> 16) << " " << setfill('0') << setw(4) << (word & 0xFFFF) << std::dec
1182  << "\twfSample" << 2 * i + 1 << " = " << wfSampleLast
1183  << ", wfSample" << 2 * i << " = " << wfSampleFirst);
1184 
1185  wfSamples.push_back(wfSampleFirst);
1186  wfSamples.push_back(wfSampleLast);
1187  }
1188 
1189  // append waveform
1190  auto* waveform = m_waveforms.appendNew(moduleID, pixelID, channel, evtScrodID,
1191  wfWindowLogic, wfStartSample, wfSamples);
1192  waveform->setPedestalSubtractedFlag(pedestalSubtracted);
1193  waveform->setPhysicalWindow(wfWindowPhysical);
1194  if (numParsedWaveforms < digitsWithWaveform.size()) {
1195  const auto* digit = digitsWithWaveform[numParsedWaveforms];
1196  if (digit->getScrodChannel() == channel % 128) {
1197  digit->addRelationTo(waveform);
1198  } else {
1199  B2WARNING("TOPUnpacker: hit and its waveform have different channel number."
1200  << LogVar("channel (hit)", digit->getScrodChannel())
1201  << LogVar("channel (waveform)", channel % 128));
1202  }
1203  }
1204  numParsedWaveforms += 1;
1205 
1206  } // end of waveform segments loop
1207 
1208  if (numExpectedWaveforms != numParsedWaveforms) {
1209  B2WARNING("TOPUnpacker: number of expected and parsed waveforms does not match."
1210  << LogVar("expected", numExpectedWaveforms)
1211  << LogVar("parsed", numParsedWaveforms));
1212  }
1213 
1214  return array.getRemainingWords();
1215  }
1216 
1217 
1218  void TOPUnpackerModule::endRun()
1219  {
1220  B2INFO("TOPUnpacker: Channels seen per event statistics:");
1221  B2INFO("TOPUnpacker: nChn\tcount");
1222  for (auto& entry : m_channelStatistics) {
1223  B2INFO("TOPUnpacker: " << entry.first << "\t\t" << entry.second);
1224  }
1225  }
1226 
1227  void TOPUnpackerModule::terminate()
1228  {
1229  }
1230 
1231 
1233 } // end Belle2 namespace
Base class for Modules.
Definition: Module.h:72
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:95
EHitQuality
hit quality enumerators
Definition: TOPDigit.h:33
Class to store debugging information about the hit headers in the TOP production debugging raw data f...
void appendExtraWord(unsigned int extraWord)
Appends extra word to vector of additional event words.
Helper class for getting data words from a finesse buffer Keeps checksum counter for each extracted d...
int getRemainingWords() const
Returns number of remaining words in the buffer.
int getWord()
Returns consecutive data word Updates internal checksum counter for each extracted word.
void resetChecksum()
Resets internal checksum counter.
unsigned int getIndex() const
Returns index of last returned data word.
int peekWord()
Returns next data word without incrementing the memory pointer and without modifying the checksum cou...
bool validateChecksum()
Validates current checksum counter status.
int getLastWord()
Returns last data word.
Class to store variables with their name which were sent to the logging service.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
Abstract base class for different kinds of events.
record to be used to store ASIC info