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