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