Belle II Software development
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 ---------------------------------------------- *
12If you have more complex parameter types in your class then simple int,
13double or std::vector of those you might need to uncomment the following
14include 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;
21using namespace Belle2;
22
23//-----------------------------------------------------------------
24// Register the Module
25//-----------------------------------------------------------------
26REG_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
65TRGTOPUnpackerWaveformModule::~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{
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
153void 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) {
223 B2INFO("Unknown data format / error / exiting. This condition is reported only once per run.");
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.
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:657
int * GetDetectorBuffer(int n, int finesse_num)
get Detector buffer
Definition: RawCOPPER.h:681
Abstract base class for different kinds of events.