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