Belle II Software  release-08-01-10
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  // int revoClockLast = -1;
248  // int cntr127Last = -1;
249 
250  // error counter for possible data corruption
251  // unsigned int errorCountEvent = 0;
252 
253  // 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)
254  // int t0CombinedDecisionLast = -1;
255  // int logLSumLast = -1;
256  // int logLSumNow = 0;
257 
258  bool performBufferAnalysis = true;
259  bool reportAllErrors = true;
260  // bool reportSummaryErrors = true;
261 
262  // check if this event's buffer is a dummy buffer
263  int counterDummyWindows = 0;
264  unsigned int testPatternDummyEvent = 0xbbbb;
265  for (int iWindow = 0; iWindow < numberOfWindows; iWindow++) {
266  int index = iWindow * windowSize + 3;
267  // various test patterns will be used to check the data
268  unsigned int testPattern = (rdat[index] >> 16) & 0xffff;
269  if (testPattern == testPatternDummyEvent) {
270  counterDummyWindows++;
271  }
272 
273  // March 30, 2022: need to be able to override the settings in data
274  if (!m_overrideControlBits) {
275  // Oct. 31, 2020: three most significant bits are now used to control unpacker from FW
276  // Note that setting either flag for any of the windows changes it for all windows here
277  testPattern = (rdat[index + 2] >> 29) & 0x7;
278  if (testPattern & 0x1) performBufferAnalysis = false;
279  if (testPattern & 0x2) reportAllErrors = false;
280  // if (testPattern & 0x4) reportSummaryErrors = false;
281  }
282  }
283 
284  // note that events with empty buffer have numberOfWindows=0
285  if (counterDummyWindows == numberOfWindows) {
286  performBufferAnalysis = false;
287  } else {
288  if (counterDummyWindows != 0) {
289  if (reportAllErrors) B2ERROR("Corrupted data? numberOfWindows = " << numberOfWindows << ", counterDummyWindows = " <<
290  counterDummyWindows);
291  performBufferAnalysis = false;
292  }
293  }
294 
295  /*
296  int numberRvcJumps = 0;
297  int numberCntr127Jumps = 0;
298  int windowRvcJumpFirst = -1;
299  int windowCntr127JumpFirst = -1;
300  // int clocksRvcJumpFirst = -1;
301  // int clocksCntr127JumpFirst = -1;
302 
303  if (performBufferAnalysis) {
304  for (int iWindow = 0; iWindow < numberOfWindows; iWindow++) {
305  int index = iWindow * windowSize + 3;
306 
307  // revoclk (comes from b2tt) has the range between 0 and 1279 @127MHz => 1279*7.8ns ~10us = 1 revolution (11bits are used)
308  int revoClockNow = rdat[index] & 0x7ff;
309  // B2INFO("rvc now = " << revoClockNow);
310  // first need to know max revoClock (1279)
311  if (revoClockLast != -1) {
312  // if (revoClockLast != -1 && revoClockNow > revoClockLast) {
313  int revoClockDeltaNow = revoClockNow - revoClockLast;
314  if (revoClockDeltaNow != revoClockDeltaExpected) {
315  // -1276 is simply going to the next cycle of rvc counting
316  if (revoClockDeltaNow != -1276) {
317  if (reportAllErrors) B2INFO("rvc changed by an unexpected number of units: " << revoClockDeltaNow << ", last rvc = " <<
318  revoClockLast <<
319  ", current rvc = " << revoClockNow << ", window " << iWindow << ", index = " << index);
320  numberRvcJumps++;
321  if (windowRvcJumpFirst < 0) {
322  windowRvcJumpFirst = iWindow;
323  // clocksRvcJumpFirst = revoClockDeltaNow;
324  }
325  }
326  }
327  }
328  revoClockLast = revoClockNow;
329 
330  int cntr127Now = (rdat[index + 1] >> 16) & 0xffff;
331  // B2INFO("cntr127 now = " << cntr127Now);
332  // first need to know max cntr127
333  if (cntr127Last != -1) {
334  // if (cntr127Last != -1 && cntr127Now > cntr127Last) {
335  int cntr127DeltaNow = cntr127Now - cntr127Last;
336  if (cntr127DeltaNow != cntr127DeltaExpected) {
337  // 65444 is the value of the difference in cntr127 (VME counter) because we use 16 bits of 64 bit-long counter
338  if (cntr127DeltaNow != 65444) {
339  if (reportAllErrors) B2INFO("cntr127 changed by an unexpected number of units: " << cntr127DeltaNow << ", cntr127 last = " <<
340  cntr127Last <<
341  ", cntr127 now = " << cntr127Now << ", window " << iWindow << ", index = " << index + 1);
342  numberCntr127Jumps++;
343  if (windowCntr127JumpFirst < 0) {
344  windowCntr127JumpFirst = iWindow;
345  // clocksCntr127JumpFirst = cntr127DeltaNow;
346  }
347  }
348  }
349  }
350  cntr127Last = cntr127Now;
351  }
352  }
353  */
354 
355  /*
356  if (numberRvcJumps > 0) {
357  B2INFO("The number of rvc jumps = " << numberRvcJumps);
358  B2INFO("The window of the first rvc jump = " << windowRvcJumpFirst);
359  B2INFO("The number of clock cycles associated with the first rvc jump = " << clocksRvcJumpFirst);
360  }
361 
362  if (numberCntr127Jumps > 0) {
363  B2INFO("The number of cntr127 jumps = " << numberCntr127Jumps);
364  B2INFO("The window of the first cntr127 jump = " << windowCntr127JumpFirst);
365  B2INFO("The number of clock cycles associated with the first cntr127 jump = " << clocksCntr127JumpFirst);
366  }
367  */
368 
369  // debugging: report everything from every single window when we are seeing unexpected jumps in either of the two counters
370  /*
371  if (numberRvcJumps > 0 || numberCntr127Jumps > 0) {
372  B2INFO("===========================================================================================================");
373  B2INFO("l1_rvc from header = " << l1_revo);
374  B2INFO("trgtag (evt) from buffer header = " << trgtag);
375  B2INFO("Reporting the entire data buffer");
376  B2INFO("Header 0 = : " << std::hex << rdat[0] << std::dec);
377  B2INFO("Header 1 = : " << std::hex << rdat[1] << std::dec);
378  B2INFO("Header 2 = : " << std::hex << rdat[2] << std::dec);
379  for (int iWindow = 0; iWindow < numberOfWindows; iWindow++) {
380  int index = iWindow * windowSize + 3;
381 
382  B2INFO("---------------------------------------------------------------------------------");
383  int revoClockNow = rdat[index] & 0x7ff;
384  B2INFO("w rvc ---------------------------- = " << iWindow << " " << revoClockNow);
385 
386  int cntr127Now = (rdat[index + 1] >> 16) & 0xffff;
387  B2INFO("w cntr127 ---------------------------- = " << iWindow << " " << cntr127Now);
388 
389  for (int i = 0; i < 24; i++) {
390  B2INFO("w i = : " << iWindow << " " << i << " " << std::hex << rdat[index+i] << std::dec);
391  }
392  }
393  }
394  */
395 
396  // events with no buffer (i.e. no payload), empty (i.e. dummy) windows and presumably corrupted events are NOT analyzed
397  if (performBufferAnalysis) {
398 
399  for (int iWindow = 0; iWindow < numberOfWindows; iWindow++) {
400  int index = iWindow * windowSize + 3;
401  int dataFormatVersionNow = (rdat[index] >> 11) & 0x1f;
402  if (dataFormatVersionNow < 4) return;
403  }
404 
405  // clear TimeStamps - this should be done elsewhere automatically
406  // m_TRGTOPWaveFormTimeStampsSlots.clear();
407  // m_TRGTOPWaveFormTimeStamps.clear();
408 
409  // store waveforms in event store
410 
411  for (int i = 0; i < 8; i++) {
412 
413  int slot = i + 1;
414  if (channel == 0) slot = slot + 8;
415 
416  auto* timeStampsSlotStore = m_TRGTOPWaveFormTimeStampsSlots.appendNew(slot, 4 * numberOfWindows);
417 
418  int nActualTimeStamps = 0;
419 
420  int firstActualTimeStampValue = -1;
421  int firstActualTimeStampClockCycle = -1;
422 
423  // Loop over windows in B2L buffer and retrieve the waveforms
424  for (int iWindow = 0; iWindow < numberOfWindows; iWindow++) {
425 
426  int clockCycle = iWindow * 4;
427 
428  // a pointer-like variable for accessing the data in the buffer sequentially
429  int index = iWindow * windowSize + 3;
430 
431  // data start at rdat[index+16]
432 
433  int shift_data = i * 2;
434 
435  int value1 = (rdat[index + 16 + shift_data] >> 16) & 0xffff;
436  int value2 = (rdat[index + 16 + shift_data]) & 0xffff;
437  int value3 = (rdat[index + 17 + shift_data] >> 16) & 0xffff;
438  int value4 = (rdat[index + 17 + shift_data]) & 0xffff;
439 
440  TRGTOPWaveFormTimeStamp timeStamp1(value1, slot);
441  TRGTOPWaveFormTimeStamp timeStamp2(value2, slot);
442  TRGTOPWaveFormTimeStamp timeStamp3(value3, slot);
443  TRGTOPWaveFormTimeStamp timeStamp4(value4, slot);
444 
445  auto* timeStampStore = m_TRGTOPWaveFormTimeStamps.appendNew(timeStamp1);
446  timeStampsSlotStore->addRelationTo(timeStampStore);
447  timeStampStore->addRelationTo(timeStampsSlotStore);
448 
449  timeStampStore = m_TRGTOPWaveFormTimeStamps.appendNew(timeStamp2);
450  timeStampsSlotStore->addRelationTo(timeStampStore);
451  timeStampStore->addRelationTo(timeStampsSlotStore);
452 
453  timeStampStore = m_TRGTOPWaveFormTimeStamps.appendNew(timeStamp3);
454  timeStampsSlotStore->addRelationTo(timeStampStore);
455  timeStampStore->addRelationTo(timeStampsSlotStore);
456 
457  timeStampStore = m_TRGTOPWaveFormTimeStamps.appendNew(timeStamp4);
458  timeStampsSlotStore->addRelationTo(timeStampStore);
459  timeStampStore->addRelationTo(timeStampsSlotStore);
460 
461  if (!timeStamp1.isEmptyClockCycle()) {
462  nActualTimeStamps++;
463  if (nActualTimeStamps == 1) {
464  firstActualTimeStampValue = value1;
465  firstActualTimeStampClockCycle = clockCycle;
466  }
467  }
468  clockCycle++;
469 
470  if (!timeStamp2.isEmptyClockCycle()) {
471  nActualTimeStamps++;
472  if (nActualTimeStamps == 1) {
473  firstActualTimeStampValue = value2;
474  firstActualTimeStampClockCycle = clockCycle;
475  }
476  }
477  clockCycle++;
478 
479  if (!timeStamp3.isEmptyClockCycle()) {
480  nActualTimeStamps++;
481  if (nActualTimeStamps == 1) {
482  firstActualTimeStampValue = value3;
483  firstActualTimeStampClockCycle = clockCycle;
484  }
485  }
486  clockCycle++;
487 
488  if (!timeStamp4.isEmptyClockCycle()) {
489  nActualTimeStamps++;
490  if (nActualTimeStamps == 1) {
491  firstActualTimeStampValue = value4;
492  firstActualTimeStampClockCycle = clockCycle;
493  }
494  }
495  clockCycle++;
496 
497  }
498 
499  timeStampsSlotStore->setNumberOfActualTimeStamps(nActualTimeStamps);
500  timeStampsSlotStore->setFirstActualTimeStampValue(firstActualTimeStampValue);
501  timeStampsSlotStore->setFirstActualTimeStampClockCycle(firstActualTimeStampClockCycle);
502 
503  }
504  }
505 
506 }
507 
508 
510 {
511 }
512 
514 {
515 }
516 
517 
518 
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.
REG_MODULE(arichBtest)
Register the Module.
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
int GetDetectorNwords(int n, int finesse_num)
get Detector buffer length
Definition: RawCOPPER.h:657
int * GetDetectorBuffer(int n, int finesse_num)
get Detector buffer
Definition: RawCOPPER.h:681
Abstract base class for different kinds of events.