Belle II Software  release-06-01-15
trgtopUnpackerWaveformModule.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 #include <trg/top/modules/trgtopUnpackerWaveform/trgtopUnpackerWaveformModule.h>
10 
11 /* --------------- WARNING ---------------------------------------------- *
12 If you have more complex parameter types in your class then simple int,
13 double or std::vector of those you might need to uncomment the following
14 include directive to avoid an undefined reference on compilation.
15 * ---------------------------------------------------------------------- */
16 // #include <framework/core/ModuleParam.templateDetails.h>
17 
18 #include <iostream>
19 
20 //using namespace std;
21 using namespace Belle2;
22 
23 //-----------------------------------------------------------------
24 // Register the Module
25 //-----------------------------------------------------------------
26 REG_MODULE(TRGTOPUnpackerWaveform);
27 
29 {
30  return std::string("1.00");
31 }
32 
33 //-----------------------------------------------------------------
34 // Implementation
35 //-----------------------------------------------------------------
36 
38  : Module::Module(), m_eventNumber(0), m_trigType(0), m_nodeId(0), m_nWords(0), m_reportedAlreadyRun_1(false),
39  m_reportedAlreadyRun_2(false)
40 {
41  // Set module properties
42 
43 
44  std::string desc = "TRGTOPUnpackerWaveformModule(" + version() + ")" + "Unpacks TOP TRG waveforms";
45  setDescription(desc);
47 
48  B2DEBUG(20, "TRGTOPUnpackerWaveform: Constructor done.");
49 
50  // Parameter definitions
51 
52  addParam("outputTimeStampsSlotsName", m_outputWaveFormTimeStampsSlotsName,
53  "name of TRGTOPWaveFormTimeStampsSlot store array", std::string(""));
54 
55  addParam("outputTimeStampsName", m_outputWaveFormTimeStampsName,
56  "name of TRGTOPWaveFormTimeStamp store array", std::string(""));
57 
58  addParam("overrideControlBits", m_overrideControlBits,
59  "Override control bits in data",
60  true);
61  // false);
62 
63 }
64 
65 TRGTOPUnpackerWaveformModule::~TRGTOPUnpackerWaveformModule()
66 {
67 }
68 
70 {
71 
72  // m_TRGTOPWaveFormTimeStampsSlots.isRequired(m_outputTimeStampsSlotsName);
73  // m_TRGTOPWaveFormTimeStamps.isRequired(m_outputTimeStampsName);
74 
75  m_TRGTOPWaveFormTimeStampsSlots.registerInDataStore(m_outputWaveFormTimeStampsSlotsName);
76  m_TRGTOPWaveFormTimeStamps.registerInDataStore(m_outputWaveFormTimeStampsName);
77 
78  m_TRGTOPWaveFormTimeStampsSlots.registerRelationTo(m_TRGTOPWaveFormTimeStamps);
79  m_TRGTOPWaveFormTimeStamps.registerRelationTo(m_TRGTOPWaveFormTimeStampsSlots);
80 }
81 
82 
84 {
85  m_reportedAlreadyRun_1 = false;
86  m_reportedAlreadyRun_2 = false;
87 }
88 
90 {
91 
92  StoreArray<RawTRG> raw_trgarray;
93 
94  for (int i = 0; i < raw_trgarray.getEntries(); i++) {
95 
96  // Check PCIe40 data or Copper data
97  if (raw_trgarray[i]->GetMaxNumOfCh(0) == 48) { m_pciedata = true; }
98  else if (raw_trgarray[i]->GetMaxNumOfCh(0) == 4) { m_pciedata = false; }
99  else { B2FATAL("TRGTOPUnpackerModule: Invalid value of GetMaxNumOfCh from raw data: " << LogVar("Number of ch: ", raw_trgarray[i]->GetMaxNumOfCh(0))); }
100 
101  int node_id = 0;
102  int ch_id_1 = 0;
103  int ch_id_2 = 1;
104  if (m_pciedata) {
105  node_id = 0x10000001;
106  ch_id_1 = 23;
107  ch_id_2 = 24;
108  } else {
109  node_id = 0x12000001;
110  ch_id_1 = 0;
111  ch_id_2 = 1;
112  }
113 
114  for (int j = 0; j < raw_trgarray[i]->GetNumEntries(); j++) {
115 
116  m_nodeId = raw_trgarray[i]->GetNodeID(j);
117 
118  if (m_nodeId == node_id) {
119 
120  int numberOfChannels = raw_trgarray[i]->GetMaxNumOfCh(i);
121 
122  // B2INFO("raw_trgarray.GetMaxNumOfCh() = " << numberOfChannels);
123 
124  for (int channel = 0; channel < numberOfChannels; channel++) {
125 
126  if (channel != ch_id_1 && channel != ch_id_2) continue;
127 
128  m_nWords = raw_trgarray[i]->GetDetectorNwords(j, channel);
129 
130  // B2INFO("raw_trgarray[" << i << "]->GetDetectorNwords(" << j << ", " << channel << ") = " << m_nWords);
131 
132  // if ( m_nWords > 3 ) { ////general header is 3 words long
133  if (m_nWords > 0) {
134 
135  m_eventNumber = raw_trgarray[i]->GetEveNo(j);
136  m_trigType = raw_trgarray[i]->GetTRGType(j);
137 
138  // B2INFO("raw_trgarray.getEntries() = " << raw_trgarray.getEntries());
139  // B2INFO("raw_trgarray[i]->GetNumEntries() = " << raw_trgarray[i]->GetNumEntries());
140  // B2INFO("raw_trgarray[]->GetEveNo(j) = " << raw_trgarray[i]->GetEveNo(j));
141  // B2INFO("raw_trgarray[]->GetNodeID(j) = " << std::hex << raw_trgarray[i]->GetNodeID(j) << std::dec);
142  // B2INFO("raw_trgarray[]->GetDetectorNwords(j,0) = " << m_nWords);
143 
144  readDAQEvent(raw_trgarray[i], j, channel);
145 
146  }
147  }
148  }
149  }
150  }
151 }
152 
153 void TRGTOPUnpackerWaveformModule::readDAQEvent(RawTRG* raw_daq, int j, int channel)
154 {
155  // if (raw_daq->GetDetectorNwords(j, channel) > 3) { ///general header is 3 words long
156  if (raw_daq->GetDetectorNwords(j, channel) > 0) {
157  unpackWaveforms(raw_daq->GetDetectorBuffer(j, channel), channel);
158  }
159 }
160 
161 
163 {
164 
165  // B2INFO("channel, data size (32bit words) = " << channel << ", " << m_nWords);
166 
167  // Information for each data window
168 
169  // rvc from the header of the buffer
170  // int l1_revo = rdat[2] & 0x7ff; /// L1 timestamp (11 bits)
171 
172  // L1 event number
173  // int trgtag = (rdat[2] >> 12) & 0xfffff; /// 20 LSBs of trgtag (sequential trigger number)
174 
175  // B2INFO("l1_rvc from header = " << l1_revo);
176  // B2INFO("trgtag (evt) from buffer header = " << trgtag);
177 
178  bool dataFormatKnown = false;
179 
180  int windowSize = -1;
181  int numberOfWindows = -1;
182 
183  // int dataFormatVersionExpected = -1;
184  // int revoClockDeltaExpected = 4;
185  // int cntr127DeltaExpected = 4;
186 
187  // 3 = 3: header only
188  // 1875 = 3 + 48*39: format used starting ~June 30 2019 and until Oct. 1, 2019 (until Receive FW version 0x02067301)
189  // 771 = 3 + 24*32: format used starting ~Oct. 1, 2019 (Receive FW version 0x02067301 and newer)
190  // 1539 = 3 + 48*32: format used starting ~Mar. 25, 2021 (Receive FW version 0x03020003 and newer)
191  // 3075 = 3 + 96*32: format used starting ~Mar. 25, 2021 (Receive FW version 0x03020003 and newer)
192 
193  // m_nWords==3 means only a header
194  if (m_nWords == 3) {
195  windowSize = 0;
196  numberOfWindows = 0;
197  dataFormatKnown = true;
198  // dataFormatVersionExpected = 0;
199  } else if (m_nWords == 771) {
200  windowSize = 32;
201  numberOfWindows = 24;
202  dataFormatKnown = true;
203  // dataFormatVersionExpected = 2;
204  } else if (m_nWords == 1875) {
205  windowSize = 39;
206  numberOfWindows = 48;
207  dataFormatKnown = true;
208  // dataFormatVersionExpected = 1;
209  } else if (m_nWords == 1539) {
210  windowSize = 32;
211  numberOfWindows = 48;
212  dataFormatKnown = true;
213  // dataFormatVersionExpected = 4;
214  } else if (m_nWords == 3075) {
215  windowSize = 32;
216  numberOfWindows = 96;
217  dataFormatKnown = true;
218  // dataFormatVersionExpected = 4;
219  }
220 
221  if (!dataFormatKnown) {
222  if (!m_reportedAlreadyRun_1) {
223  B2INFO("Unknown data format / error / exiting. This condition is reported only once per run.");
224  m_reportedAlreadyRun_1 = true;
225  }
226  return;
227  }
228 
229  // FTSW / rvc / the difference is 1280 (expected)
230  // int revoClockDeltaJump1 = -92;
231  // int revoClockDeltaJump2 = 1188;
232 
233  // VME / 16bit counter
234  // int cntr127DeltaJump1 = -92;
235  // int cntr127DeltaJump2 = -65532;
236 
237  // if ( dataFormatVersionExpected > 0 ) B2INFO("---------------------------------------------------------------------------------------------------------------");
238 
239  // B2INFO("Data format version (as expected according to data size) = " << dataFormatVersionExpected);
240 
241  // if ( numberOfWindows != 0 ) {
242  // B2INFO("Number of 32bit words in TOP L1 data buffer = " << m_nWords);
243  // B2INFO("Number of windows = " << numberOfWindows);
244  // B2INFO("Window size in 32bit words = " << windowSize);
245  // }
246 
247  // various test patterns will be used to check the data
248  unsigned int testPattern;
249 
250  // int revoClockLast = -1;
251  // int cntr127Last = -1;
252 
253  // error counter for possible data corruption
254  // unsigned int errorCountEvent = 0;
255 
256  // need to know when a new decision is made (there could be more than one TOP L1 timing decision stored in the same B2L buffer)
257  // cppcheck-suppress variableScope
258  // int t0CombinedDecisionLast = -1;
259  // int logLSumLast = -1;
260  // int logLSumNow = 0;
261 
262  bool performBufferAnalysis = true;
263  bool reportAllErrors = true;
264  // bool reportSummaryErrors = true;
265 
266  // check if this event's buffer is a dummy buffer
267  int counterDummyWindows = 0;
268  unsigned int testPatternDummyEvent = 0xbbbb;
269  for (int iWindow = 0; iWindow < numberOfWindows; iWindow++) {
270  int index = iWindow * windowSize + 3;
271  testPattern = (rdat[index] >> 16) & 0xffff;
272  if (testPattern == testPatternDummyEvent) {
273  counterDummyWindows++;
274  }
275 
276  // March 30, 2022: need to be able to override the settings in data
277  if (!m_overrideControlBits) {
278  // Oct. 31, 2020: three most significant bits are now used to control unpacker from FW
279  // Note that setting either flag for any of the windows changes it for all windows here
280  testPattern = (rdat[index + 2] >> 29) & 0x7;
281  if (testPattern & 0x1) performBufferAnalysis = false;
282  if (testPattern & 0x2) reportAllErrors = false;
283  // if (testPattern & 0x4) reportSummaryErrors = false;
284  }
285  }
286 
287  // note that events with empty buffer have numberOfWindows=0
288  if (counterDummyWindows == numberOfWindows) {
289  performBufferAnalysis = false;
290  } else {
291  if (counterDummyWindows != 0) {
292  if (reportAllErrors) B2ERROR("Corrupted data? numberOfWindows = " << numberOfWindows << ", counterDummyWindows = " <<
293  counterDummyWindows);
294  performBufferAnalysis = false;
295  }
296  }
297 
298  /*
299  int numberRvcJumps = 0;
300  int numberCntr127Jumps = 0;
301  int windowRvcJumpFirst = -1;
302  int windowCntr127JumpFirst = -1;
303  // int clocksRvcJumpFirst = -1;
304  // int clocksCntr127JumpFirst = -1;
305 
306  if (performBufferAnalysis) {
307  for (int iWindow = 0; iWindow < numberOfWindows; iWindow++) {
308  int index = iWindow * windowSize + 3;
309 
310  // revoclk (comes from b2tt) has the range between 0 and 1279 @127MHz => 1279*7.8ns ~10us = 1 revolution (11bits are used)
311  int revoClockNow = rdat[index] & 0x7ff;
312  // B2INFO("rvc now = " << revoClockNow);
313  // first need to know max revoClock (1279)
314  if (revoClockLast != -1) {
315  // if (revoClockLast != -1 && revoClockNow > revoClockLast) {
316  int revoClockDeltaNow = revoClockNow - revoClockLast;
317  if (revoClockDeltaNow != revoClockDeltaExpected) {
318  // -1276 is simply going to the next cycle of rvc counting
319  if (revoClockDeltaNow != -1276) {
320  if (reportAllErrors) B2INFO("rvc changed by an unexpected number of units: " << revoClockDeltaNow << ", last rvc = " <<
321  revoClockLast <<
322  ", current rvc = " << revoClockNow << ", window " << iWindow << ", index = " << index);
323  numberRvcJumps++;
324  if (windowRvcJumpFirst < 0) {
325  windowRvcJumpFirst = iWindow;
326  // clocksRvcJumpFirst = revoClockDeltaNow;
327  }
328  }
329  }
330  }
331  revoClockLast = revoClockNow;
332 
333  int cntr127Now = (rdat[index + 1] >> 16) & 0xffff;
334  // B2INFO("cntr127 now = " << cntr127Now);
335  // first need to know max cntr127
336  if (cntr127Last != -1) {
337  // if (cntr127Last != -1 && cntr127Now > cntr127Last) {
338  int cntr127DeltaNow = cntr127Now - cntr127Last;
339  if (cntr127DeltaNow != cntr127DeltaExpected) {
340  // 65444 is the value of the difference in cntr127 (VME counter) because we use 16 bits of 64 bit-long counter
341  if (cntr127DeltaNow != 65444) {
342  if (reportAllErrors) B2INFO("cntr127 changed by an unexpected number of units: " << cntr127DeltaNow << ", cntr127 last = " <<
343  cntr127Last <<
344  ", cntr127 now = " << cntr127Now << ", window " << iWindow << ", index = " << index + 1);
345  numberCntr127Jumps++;
346  if (windowCntr127JumpFirst < 0) {
347  windowCntr127JumpFirst = iWindow;
348  // clocksCntr127JumpFirst = cntr127DeltaNow;
349  }
350  }
351  }
352  }
353  cntr127Last = cntr127Now;
354  }
355  }
356  */
357 
358  /*
359  if (numberRvcJumps > 0) {
360  B2INFO("The number of rvc jumps = " << numberRvcJumps);
361  B2INFO("The window of the first rvc jump = " << windowRvcJumpFirst);
362  B2INFO("The number of clock cycles associated with the first rvc jump = " << clocksRvcJumpFirst);
363  }
364 
365  if (numberCntr127Jumps > 0) {
366  B2INFO("The number of cntr127 jumps = " << numberCntr127Jumps);
367  B2INFO("The window of the first cntr127 jump = " << windowCntr127JumpFirst);
368  B2INFO("The number of clock cycles associated with the first cntr127 jump = " << clocksCntr127JumpFirst);
369  }
370  */
371 
372  // debugging: report everything from every single window when we are seeing unexpected jumps in either of the two counters
373  /*
374  if (numberRvcJumps > 0 || numberCntr127Jumps > 0) {
375  B2INFO("===========================================================================================================");
376  B2INFO("l1_rvc from header = " << l1_revo);
377  B2INFO("trgtag (evt) from buffer header = " << trgtag);
378  B2INFO("Reporting the entire data buffer");
379  B2INFO("Header 0 = : " << std::hex << rdat[0] << std::dec);
380  B2INFO("Header 1 = : " << std::hex << rdat[1] << std::dec);
381  B2INFO("Header 2 = : " << std::hex << rdat[2] << std::dec);
382  for (int iWindow = 0; iWindow < numberOfWindows; iWindow++) {
383  int index = iWindow * windowSize + 3;
384 
385  B2INFO("---------------------------------------------------------------------------------");
386  int revoClockNow = rdat[index] & 0x7ff;
387  B2INFO("w rvc ---------------------------- = " << iWindow << " " << revoClockNow);
388 
389  int cntr127Now = (rdat[index + 1] >> 16) & 0xffff;
390  B2INFO("w cntr127 ---------------------------- = " << iWindow << " " << cntr127Now);
391 
392  for (int i = 0; i < 24; i++) {
393  B2INFO("w i = : " << iWindow << " " << i << " " << std::hex << rdat[index+i] << std::dec);
394  }
395  }
396  }
397  */
398 
399  // events with no buffer (i.e. no payload), empty (i.e. dummy) windows and presumably corrupted events are NOT analyzed
400  if (performBufferAnalysis) {
401 
402  for (int iWindow = 0; iWindow < numberOfWindows; iWindow++) {
403  int index = iWindow * windowSize + 3;
404  int dataFormatVersionNow = (rdat[index] >> 11) & 0x1f;
405  if (dataFormatVersionNow < 4) return;
406  }
407 
408  // clear TimeStamps - this should be done elsewhere automatically
409  // m_TRGTOPWaveFormTimeStampsSlots.clear();
410  // m_TRGTOPWaveFormTimeStamps.clear();
411 
412  // store waveforms in event store
413 
414  for (int i = 0; i < 8; i++) {
415 
416  int slot = i + 1;
417  if (channel == 0) slot = slot + 8;
418 
419  auto* timeStampsSlotStore = m_TRGTOPWaveFormTimeStampsSlots.appendNew(slot, 4 * numberOfWindows);
420 
421  int nActualTimeStamps = 0;
422 
423  int firstActualTimeStampValue = -1;
424  int firstActualTimeStampClockCycle = -1;
425 
426  // Loop over windows in B2L buffer and retrieve the waveforms
427  for (int iWindow = 0; iWindow < numberOfWindows; iWindow++) {
428 
429  int clockCycle = iWindow * 4;
430 
431  // a pointer-like variable for accessing the data in the buffer sequentially
432  int index = iWindow * windowSize + 3;
433 
434  // data start at rdat[index+16]
435 
436  int shift_data = i * 2;
437 
438  int value1 = (rdat[index + 16 + shift_data] >> 16) & 0xffff;
439  int value2 = (rdat[index + 16 + shift_data]) & 0xffff;
440  int value3 = (rdat[index + 17 + shift_data] >> 16) & 0xffff;
441  int value4 = (rdat[index + 17 + shift_data]) & 0xffff;
442 
443  TRGTOPWaveFormTimeStamp timeStamp1(value1, slot);
444  TRGTOPWaveFormTimeStamp timeStamp2(value2, slot);
445  TRGTOPWaveFormTimeStamp timeStamp3(value3, slot);
446  TRGTOPWaveFormTimeStamp timeStamp4(value4, slot);
447 
448  auto* timeStampStore = m_TRGTOPWaveFormTimeStamps.appendNew(timeStamp1);
449  timeStampsSlotStore->addRelationTo(timeStampStore);
450  timeStampStore->addRelationTo(timeStampsSlotStore);
451 
452  timeStampStore = m_TRGTOPWaveFormTimeStamps.appendNew(timeStamp2);
453  timeStampsSlotStore->addRelationTo(timeStampStore);
454  timeStampStore->addRelationTo(timeStampsSlotStore);
455 
456  timeStampStore = m_TRGTOPWaveFormTimeStamps.appendNew(timeStamp3);
457  timeStampsSlotStore->addRelationTo(timeStampStore);
458  timeStampStore->addRelationTo(timeStampsSlotStore);
459 
460  timeStampStore = m_TRGTOPWaveFormTimeStamps.appendNew(timeStamp4);
461  timeStampsSlotStore->addRelationTo(timeStampStore);
462  timeStampStore->addRelationTo(timeStampsSlotStore);
463 
464  if (!timeStamp1.isEmptyClockCycle()) {
465  nActualTimeStamps++;
466  if (nActualTimeStamps == 1) {
467  firstActualTimeStampValue = value1;
468  firstActualTimeStampClockCycle = clockCycle;
469  }
470  }
471  clockCycle++;
472 
473  if (!timeStamp2.isEmptyClockCycle()) {
474  nActualTimeStamps++;
475  if (nActualTimeStamps == 1) {
476  firstActualTimeStampValue = value2;
477  firstActualTimeStampClockCycle = clockCycle;
478  }
479  }
480  clockCycle++;
481 
482  if (!timeStamp3.isEmptyClockCycle()) {
483  nActualTimeStamps++;
484  if (nActualTimeStamps == 1) {
485  firstActualTimeStampValue = value3;
486  firstActualTimeStampClockCycle = clockCycle;
487  }
488  }
489  clockCycle++;
490 
491  if (!timeStamp4.isEmptyClockCycle()) {
492  nActualTimeStamps++;
493  if (nActualTimeStamps == 1) {
494  firstActualTimeStampValue = value4;
495  firstActualTimeStampClockCycle = clockCycle;
496  }
497  }
498  clockCycle++;
499 
500  }
501 
502  timeStampsSlotStore->setNumberOfActualTimeStamps(nActualTimeStamps);
503  timeStampsSlotStore->setFirstActualTimeStampValue(firstActualTimeStampValue);
504  timeStampsSlotStore->setFirstActualTimeStampClockCycle(firstActualTimeStampClockCycle);
505 
506  }
507  }
508 
509 }
510 
511 
513 {
514 }
515 
517 {
518 }
519 
520 
521 
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: RawTRG.h:27
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
int getEntries() const
Get the number of objects in the array.
Definition: StoreArray.h:216
virtual void readDAQEvent(RawTRG *, int, int)
Read data from TRG DAQ.
bool m_reportedAlreadyRun_1
PCIe40 data or copper data.
std::string m_outputWaveFormTimeStampsSlotsName
name of TOPTRGTimeStampsSlot store array
virtual void initialize() override
Initialize the Module.
TRGTOPUnpackerWaveformModule()
Constructor: Sets the description, the properties and the parameters of the module.
virtual void event() override
This method is the core of the module.
virtual void endRun() override
This method is called if the current run ends.
virtual void terminate() override
This method is called at the end of the event processing.
std::string m_outputWaveFormTimeStampsName
name of TOPTRGTimeStamp store array
virtual void beginRun() override
Called when entering a new run.
int m_trigType
Event number (according to L1/global)
virtual void unpackWaveforms(int *, int)
Unpacker main function.
std::string version() const
returns version of TRGTOPUnpackerWaveformModule.
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 GetDetectorNwords(int n, int finesse_num)
get Detector buffer length
Definition: RawCOPPER.h:654
int * GetDetectorBuffer(int n, int finesse_num)
get Detector buffer
Definition: RawCOPPER.h:678
Abstract base class for different kinds of events.