Project
Loading...
Searching...
No Matches
RawPixelReader.h
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
14#ifndef ALICEO2_ITSMFT_RAWPIXELREADER_H_
15#define ALICEO2_ITSMFT_RAWPIXELREADER_H_
16
21#include "ITSMFTReconstruction/ChipMappingITS.h" // this will become template parameter
27
31
32#include <TTree.h>
33#include <TStopwatch.h>
34#include <fairlogger/Logger.h>
35#include <vector>
36#include <limits>
37#include <climits>
38#include <memory>
39#include <algorithm>
40#include <cassert>
41#include <fstream>
42#include <string_view>
43#include <array>
44#include <bitset>
45#include <iomanip>
46
47#define _RAW_READER_ERROR_CHECKS_
48
49#define OUTHEX(v, l) "0x" << std::hex << std::setfill('0') << std::setw(l) << v << std::dec
50
51namespace o2
52{
53namespace itsmft
54{
55
56constexpr int MaxGBTPacketBytes = 8 * 1024; // Max size of GBT packet in bytes (8KB)
57constexpr int NCRUPagesPerSuperpage = 256; // Expected max number of CRU pages per superpage
59
61 enum DecErrors : int {
62 ErrInvalidFEEId, // RDH provided invalid FEEId
64 };
65
66 using ULL = unsigned long long;
67 uint64_t nTriggersProcessed = 0; // total number of triggers processed
68 uint64_t nPagesProcessed = 0; // total number of pages processed
69 uint64_t nRUsProcessed = 0; // total number of RUs processed (1 RU may take a few pages)
70 uint64_t nBytesProcessed = 0; // total number of bytes (rdh->memorySize) processed
71 uint64_t nNonEmptyChips = 0; // number of non-empty chips found
72 uint64_t nHitsDecoded = 0; // number of hits found
73 std::array<int, NErrorsDefined> errorCounts = {}; // error counters
74
75 RawDecodingStat() = default;
76
77 void clear()
78 {
81 nRUsProcessed = 0;
84 nHitsDecoded = 0;
85 errorCounts.fill(0);
86 }
87
88 void print(bool skipNoErr = true) const
89 {
90 printf("\nDecoding statistics\n");
91 printf("%llu bytes for %llu RUs processed in %llu pages for %llu triggers\n", (ULL)nBytesProcessed, (ULL)nRUsProcessed,
93 printf("%llu hits found in %llu non-empty chips\n", (ULL)nHitsDecoded, (ULL)nNonEmptyChips);
94 int nErr = 0;
95 for (int i = NErrorsDefined; i--;) {
96 nErr += errorCounts[i];
97 }
98 printf("Decoding errors: %d\n", nErr);
99 for (int i = 0; i < NErrorsDefined; i++) {
100 if (!skipNoErr || errorCounts[i]) {
101 printf("%-70s: %d\n", ErrNames[i].data(), errorCounts[i]);
102 }
103 }
104 }
105
106 static constexpr std::array<std::string_view, NErrorsDefined> ErrNames = {
107 "RDH cointains invalid FEEID" // ErrInvalidFEEId
108 };
109
111};
112
118
119template <class Mapping = o2::itsmft::ChipMappingITS>
121{
123
124 public:
126 {
127 mRUEntry.fill(-1); // no known links in the beginning
128 }
129
131 {
132 mSWIO.Stop();
133 printf("RawPixelReader IO time: ");
134 mSWIO.Print();
135
136 printf("Cache filling time: ");
137 mSWCache.Print();
138 }
139
141 bool isPadding128() const { return mPadding128; }
142
144 bool isMaxPageImposed() const { return mImposeMaxPage; }
145
147 int getGBTWordSize() const { return mGBTWordSize; }
148
150 void setPadding128(bool v)
151 {
152 mPadding128 = v;
153 mGBTWordSize = mPadding128 ? o2::itsmft::GBTPaddedWordLength : o2::itsmft::GBTWordLength;
154 }
155
157 void setMinTriggersToCache(int n) { mMinTriggersToCache = n > NCRUPagesPerSuperpage ? n : NCRUPagesPerSuperpage + 1; }
158
159 int getMinTriggersToCache() const { return mMinTriggersToCache; }
160
162 void imposeMaxPage(bool v) { mImposeMaxPage = v; }
163
165 ChipPixelData* getNextChipData(std::vector<ChipPixelData>& chipDataVec) override
166 {
167 // decode new RU if no cached non-empty chips
168
169 if (mCurRUDecodeID >= 0) { // make sure current RU has fired chips to extract
170 for (; mCurRUDecodeID < mNRUs; mCurRUDecodeID++) {
171 auto& ru = mRUDecodeVec[mCurRUDecodeID];
172 if (ru.lastChipChecked < ru.nChipsFired) {
173 auto& chipData = ru.chipsData[ru.lastChipChecked++];
174 int id = chipData.getChipID();
175 chipDataVec[id].swap(chipData);
176 return &chipDataVec[id];
177 }
178 }
179 mCurRUDecodeID = 0; // no more decoded data if reached this place,
180 }
181 // will need to decode new trigger
182 if (!mDecodeNextAuto) { // no more data in the current ROF and no automatic decoding of next one was requested
183 return nullptr;
184 }
185 if (mMinTriggersCached < 2) { // last trigger might be incomplete, need to cache more data
186 cacheLinksData(mRawBuffer);
187 }
188 if (mMinTriggersCached < 1 || !decodeNextTrigger()) {
189 mCurRUDecodeID = -1;
190 return nullptr; // nothing left
191 }
192 return getNextChipData(chipDataVec); // is it ok to use recursion here?
193 }
194
196 void init() override{};
197
199 void clear(bool resetStat = true)
200 {
201 LOG(info) << "Cleaning decoder, reset_statistics_flag " << resetStat;
202 if (resetStat) {
203 mDecodingStat.clear();
204 }
205 for (auto& rudec : mRUDecodeVec) {
206 rudec.clear();
207 }
208 for (auto& lnk : mGBTLinks) {
209 lnk.clear(resetStat);
210 }
211 mMinTriggersCached = 0;
212 mCurRUDecodeID = -1;
213 mIOFile.close();
214 mRawBuffer.clear();
215 }
216
218
220 int digits2raw(const std::vector<o2::itsmft::Digit>& digiVec, int from, int ndig, const o2::InteractionRecord& bcData,
221 uint8_t ruSWMin = 0, uint8_t ruSWMax = 0xff)
222 {
223 // Convert ndig digits belonging to the same trigger to raw data
224 // The digits in the vector must be in increasing chipID order
225 // Return the number of pages in the link with smallest amount of pages
226
227 int nDigTot = digiVec.size();
228 assert(from < nDigTot);
229 int last = (from + ndig <= nDigTot) ? from + ndig : nDigTot;
230 RUDecodeData* curRUDecode = nullptr;
231 ChipPixelData* curChipData = nullptr;
232 ChipInfo chInfo;
233 UShort_t curChipID = 0xffff; // currently processed SW chip id
234 mInteractionRecord = bcData;
235 ruSWMax = (ruSWMax < uint8_t(mMAP.getNRUs())) ? ruSWMax : mMAP.getNRUs() - 1;
236
237 if (mNRUs < int(ruSWMax) - ruSWMin) { // book containers if needed
238 for (uint8_t ru = ruSWMin; ru <= ruSWMax; ru++) {
239 auto& ruData = getCreateRUDecode(ru);
240 int nLinks = 0;
241 for (int il = 0; il < RUDecodeData::MaxLinksPerRU; il++) {
242 nLinks += ruData.links[il] < 0 ? 0 : 1;
243 }
244 mNLinks += nLinks;
245 if (!nLinks) {
246 LOG(info) << "Imposing single link readout for RU " << int(ru);
247 ruData.links[0] = addGBTLink();
248 getGBTLink(ruData.links[0])->lanes = mMAP.getCablesOnRUType(ruData.ruInfo->ruType);
249 mNLinks++;
250 }
251 }
252 }
253
254 // place digits into corresponding chip buffers
255 for (int id = from; id < last; id++) {
256 const auto& dig = digiVec[id];
257 if (curChipID != dig.getChipIndex()) {
258 mMAP.getChipInfoSW(dig.getChipIndex(), chInfo);
259 if (chInfo.ru < ruSWMin || chInfo.ru > ruSWMax) { // ignore this chip?
260 continue;
261 }
262 curChipID = dig.getChipIndex();
263 mCurRUDecodeID = chInfo.ru;
264 curRUDecode = &mRUDecodeVec[mCurRUDecodeID];
265 curChipData = &curRUDecode->chipsData[curRUDecode->nChipsFired++];
266 curChipData->setChipID(chInfo.chOnRU->id); // set ID within the RU
267 }
268 curChipData->getData().emplace_back(&dig); // add new digit to the container
269 }
270 // convert digits to alpide data in the per-cable buffers
271 int minPages = 0xffffff;
272 for (mCurRUDecodeID = ruSWMin; mCurRUDecodeID <= int(ruSWMax); mCurRUDecodeID++) {
273 curRUDecode = &mRUDecodeVec[mCurRUDecodeID];
274 uint16_t next2Proc = 0, nchTot = mMAP.getNChipsOnRUType(curRUDecode->ruInfo->ruType);
275 for (int ich = 0; ich < curRUDecode->nChipsFired; ich++) {
276 auto& chipData = curRUDecode->chipsData[ich];
277 convertEmptyChips(next2Proc, chipData.getChipID()); // if needed store EmptyChip flags
278 next2Proc = chipData.getChipID() + 1;
279 convertChip(chipData);
280 chipData.clear();
281 }
282 convertEmptyChips(next2Proc, nchTot); // if needed store EmptyChip flags
283 int minPageRU = fillGBTLinks(); // flush per-lane buffers to link buffers
284 if (minPageRU < minPages) {
285 minPages = minPageRU;
286 }
287 }
288
289 return minPages;
290 }
291
292 //___________________________________________________________________________________
294 {
296
297 auto& ruData = mRUDecodeVec[mCurRUDecodeID]; // current RU container
298 // fetch info of the chip with chipData->getChipID() ID within the RU
299 const auto& chip = *mMAP.getChipOnRUInfo(ruData.ruInfo->ruType, chipData.getChipID());
300 ruData.cableHWID[chip.cableHWPos] = chip.cableHW; // register the cable HW ID
301
302 auto& pixels = chipData.getData();
303 std::sort(pixels.begin(), pixels.end(),
304 [](auto lhs, auto rhs) {
305 if (lhs.getRow() < rhs.getRow()) {
306 return true;
307 }
308 if (lhs.getRow() > rhs.getRow()) {
309 return false;
310 }
311 return lhs.getCol() < rhs.getCol();
312 });
313 ruData.cableData[chip.cableHWPos].ensureFreeCapacity(40 * (2 + pixels.size())); // make sure buffer has enough capacity
314 mCoder.encodeChip(ruData.cableData[chip.cableHWPos], chipData, chip.chipOnModuleHW, mInteractionRecord.bc);
315 }
316
317 //______________________________________________________
318 void convertEmptyChips(int fromChip, int uptoChip)
319 {
320 // add empty chip words to respective cable's buffers for all chips of the current RU container
321 auto& ruData = mRUDecodeVec[mCurRUDecodeID]; // current RU container
322 for (int chipIDSW = fromChip; chipIDSW < uptoChip; chipIDSW++) { // flag chips w/o data
323 const auto& chip = *mMAP.getChipOnRUInfo(ruData.ruInfo->ruType, chipIDSW);
324 ruData.cableHWID[chip.cableHWPos] = chip.cableHW; // register the cable HW ID
325 ruData.cableData[chip.cableHWPos].ensureFreeCapacity(100);
326 mCoder.addEmptyChip(ruData.cableData[chip.cableHWPos], chip.chipOnModuleHW, mInteractionRecord.bc);
327 }
328 }
329
330 //___________________________________________________________________________________
332 {
333 // fill data of the RU to links buffer, return the number of pages in the link with smallest amount of pages
334 constexpr uint8_t zero16[o2::itsmft::GBTPaddedWordLength] = {0}; // to speedup padding
335 const int dummyNPages = 0xffffff; // any large number
336 int minPages = dummyNPages;
337 auto& ruData = mRUDecodeVec[mCurRUDecodeID];
339
340 RDHUtils::setTriggerOrbit(rdh, mInteractionRecord.orbit);
341 RDHUtils::setHeartBeatOrbit(rdh, mInteractionRecord.orbit);
342 RDHUtils::setTriggerBC(rdh, mInteractionRecord.orbit);
343 RDHUtils::setHeartBeatBC(rdh, mInteractionRecord.orbit);
345 RDHUtils::setDetectorField(rdh, mMAP.getRUDetectorField());
346
347 int maxGBTWordsPerPacket = (MaxGBTPacketBytes - RDHUtils::getHeaderSize(rdh)) / mGBTWordSize - 2;
348
349 int nGBTW[RUDecodeData::MaxLinksPerRU] = {0};
350 for (int il = 0; il < RUDecodeData::MaxLinksPerRU; il++) {
351
352 auto* link = getGBTLink(ruData.links[il]);
353 if (!link) {
354 continue;
355 }
356 int nGBTWordsNeeded = 0;
357 for (int icab = ruData.ruInfo->nCables; icab--;) { // calculate number of GBT words per link
358 if ((link->lanes & (0x1 << icab))) {
359 int nb = ruData.cableData[icab].getSize();
360 nGBTWordsNeeded += nb ? 1 + (nb - 1) / 9 : 0;
361 }
362 }
363 // move data in padded GBT words from cable buffers to link buffers
364 RDHUtils::setFEEID(rdh, mMAP.RUSW2FEEId(ruData.ruInfo->idSW, il)); // write on link 0 always
365 RDHUtils::setLinkID(rdh, il);
367 RDHUtils::setStop(rdh, 0);
368 int loadsize = RDHUtils::getHeaderSize(rdh) + (nGBTWordsNeeded + 2) * mGBTWordSize; // total data to dump
369 RDHUtils::setMemorySize(rdh, loadsize < MaxGBTPacketBytes ? loadsize : MaxGBTPacketBytes);
370 RDHUtils::setOffsetToNext(rdh, mImposeMaxPage ? MaxGBTPacketBytes : RDHUtils::getMemorySize(rdh));
371
372 link->data.ensureFreeCapacity(MaxGBTPacketBytes);
373 link->data.addFast(reinterpret_cast<uint8_t*>(&rdh), RDHUtils::getHeaderSize(rdh)); // write RDH for current packet
374 link->nTriggers++; // acknowledge the page, note: here we count pages, not triggers
375 o2::itsmft::GBTDataHeaderL gbtHeader(0, link->lanes);
376 o2::itsmft::GBTDataTrailer gbtTrailer; // lanes will be set on closing the last page
377
378 gbtHeader.packetIdx = RDHUtils::getPageCounter(rdh);
379 link->data.addFast(gbtHeader.getW8(), mGBTWordSize); // write GBT header for current packet
380 if (mVerbose) {
381 LOG(info) << "Filling RU data";
383 gbtHeader.printX(mPadding128);
384 }
385
386 // now loop over the lanes served by this link, writing each time at most 9 bytes, untill all lanes are copied
387 int nGBTWordsInPacket = 0;
388 do {
389 for (int icab = 0; icab < ruData.ruInfo->nCables; icab++) {
390 if ((link->lanes & (0x1 << icab))) {
391 auto& cableData = ruData.cableData[icab];
392 int nb = cableData.getUnusedSize();
393 if (!nb) {
394 continue; // write 80b word only if there is something to write
395 }
396 if (nb > 9) {
397 nb = 9;
398 }
399 int gbtWordStart = link->data.getSize(); // beginning of the current GBT word in the link
400 link->data.addFast(cableData.getPtr(), nb); // fill payload of cable
401 link->data.addFast(zero16, mGBTWordSize - nb); // fill the rest of the GBT word by 0
402 link->data[gbtWordStart + 9] = mMAP.getGBTHeaderRUType(ruData.ruInfo->ruType, ruData.cableHWID[icab]); // set cable flag
403 cableData.setPtr(cableData.getPtr() + nb);
404 nGBTWordsNeeded--;
405 if (mVerbose > 1) {
406 ((GBTData*)(&link->data[gbtWordStart]))->printX(mPadding128);
407 }
408 if (++nGBTWordsInPacket == maxGBTWordsPerPacket) { // check if new GBT packet must be created
409 break;
410 }
411 } // storing data of single cable
412 } // loop over cables of this link
413
414 if (nGBTWordsNeeded && nGBTWordsInPacket >= maxGBTWordsPerPacket) {
415 // more data to write, write trailer and add new GBT packet
416 link->data.add(gbtTrailer.getW8(), mGBTWordSize); // write empty GBT trailer for current packet
417 if (mVerbose) {
418 gbtTrailer.printX(mPadding128);
419 }
420 RDHUtils::setPageCounter(rdh, RDHUtils::getPageCounter(rdh) + 1); // flag new page
421 RDHUtils::setStop(rdh, nGBTWordsNeeded < maxGBTWordsPerPacket); // flag if this is the last packet of multi-packet
422 // update remaining size, using padded GBT words (as CRU writes)
423 loadsize = RDHUtils::getHeaderSize(rdh) + (nGBTWordsNeeded + 2) * mGBTWordSize; // update remaining size
424 RDHUtils::setMemorySize(rdh, loadsize < MaxGBTPacketBytes ? loadsize : MaxGBTPacketBytes);
425 RDHUtils::setOffsetToNext(rdh, mImposeMaxPage ? MaxGBTPacketBytes : RDHUtils::getMemorySize(rdh));
426 link->data.ensureFreeCapacity(MaxGBTPacketBytes);
427 link->data.addFast(reinterpret_cast<uint8_t*>(&rdh), RDHUtils::getHeaderSize(rdh)); // write RDH for current packet
428 link->nTriggers++; // acknowledge the page, note: here we count pages, not triggers
429 if (mVerbose) {
431 }
432 gbtHeader.packetIdx = RDHUtils::getPageCounter(rdh);
433 link->data.addFast(gbtHeader.getW8(), mGBTWordSize); // write GBT header for current packet
434 if (mVerbose) {
435 gbtHeader.printX(mPadding128);
436 }
437 nGBTWordsInPacket = 0; // reset counter of words in the packet
438 }
439 } while (nGBTWordsNeeded);
440
441 gbtTrailer.lanesStops = link->lanes;
442 gbtTrailer.packetDone = true;
443 link->data.addFast(gbtTrailer.getW8(), mGBTWordSize); // write GBT trailer for the last packet
444 if (mVerbose) {
445 gbtTrailer.printX(mPadding128);
446 }
447 // NOTE: here we don't pad the page to 8KB, will do this when flushing everything to the sink
448
449 if (minPages > link->nTriggers) {
450 minPages = link->nTriggers;
451 }
452
453 } // loop over links of RU
454 ruData.clear();
455 return minPages == dummyNPages ? 0 : minPages;
456 }
457
458 //___________________________________________________________________________________
459 int flushSuperPages(int maxPages, PayLoadCont& sink, bool unusedToHead = true)
460 {
461 // flush superpage (at most maxPages) of each link to the output,
462 // return total number of pages flushed
463
464 int totPages = 0;
465 for (int ru = 0; ru < mMAP.getNRUs(); ru++) {
466 auto* ruData = getRUDecode(ru);
467 if (!ruData) {
468 continue;
469 }
470 for (int il = 0; il < RUDecodeData::MaxLinksPerRU; il++) {
471 auto link = getGBTLink(ruData->links[il]);
472 if (!link || link->data.isEmpty()) {
473 continue;
474 }
475 int nPages = 0;
476 sink.ensureFreeCapacity(maxPages * MaxGBTPacketBytes);
477 const auto* ptrIni = link->data.getPtr();
478 while (nPages < maxPages && !link->data.isEmpty()) {
479 const auto ptr = link->data.getPtr();
481 sink.addFast(ptr, RDHUtils::getMemorySize(rdh)); // copy header + payload
482 sink.fillFast(0, MaxGBTPacketBytes - RDHUtils::getMemorySize(rdh)); // complete with 0's till the end of the page
483 link->data.setPtr(ptr + RDHUtils::getMemorySize(rdh));
484 link->nTriggers--; // here we count pages, not triggers
485 nPages++;
486 }
487 totPages += nPages;
488 if (unusedToHead) {
489 link->data.moveUnusedToHead();
490 }
491 } // loop over links
492 } // loop over RUs
493 return totPages;
494 }
495
497
498 //_____________________________________
500 {
501 // distribute data from the single buffer among the links caches
502
503 LOG(info) << "Caching links data, currently in cache: " << mMinTriggersCached << " triggers";
504 auto nRead = loadInput(buffer);
505 if (buffer.isEmpty()) {
506 return nRead;
507 }
508 mSWCache.Start(false);
509 enum LinkFlag : int8_t { NotUpdated,
510 Updated,
511 HasEnoughTriggers };
512 LinkFlag linkFlags[Mapping::getNRUs()][3] = {NotUpdated}; // flag that enough triggeres were loaded for this link
513 int nLEnoughTriggers = 0; // number of links for we which enough number of triggers were loaded
514 auto ptr = buffer.getPtr();
516
517 do {
518 if (!RDHUtils::checkRDH(rdh)) { // does it look like RDH?
519 if (!findNextRDH(buffer)) { // try to recover the pointer
520 break; // no data to continue
521 }
522 ptr = buffer.getPtr();
523 rdh = reinterpret_cast<o2::header::RAWDataHeader*>(ptr);
524 }
525 if (mVerbose) {
527 }
528
529 int ruIDSW = mMAP.FEEId2RUSW(RDHUtils::getFEEID(rdh));
530#ifdef _RAW_READER_ERROR_CHECKS_
531 if (ruIDSW >= mMAP.getNRUs()) {
532 mDecodingStat.errorCounts[RawDecodingStat::ErrInvalidFEEId]++;
533 LOG(error) << mDecodingStat.ErrNames[RawDecodingStat::ErrInvalidFEEId]
534 << " : FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << ", skipping CRU page";
536 ptr += RDHUtils::getOffsetToNext(rdh);
537 buffer.setPtr(ptr);
538 if (buffer.getUnusedSize() < MaxGBTPacketBytes) {
539 nRead += loadInput(buffer); // update
540 ptr = buffer.getPtr(); // pointer might have been changed
541 }
542 continue;
543 }
544#endif
545 auto& ruDecode = getCreateRUDecode(ruIDSW);
546
547 bool newTrigger = true; // check if we see new trigger
548 uint16_t lr, ruOnLr, linkIDinRU;
549 mMAP.expandFEEId(RDHUtils::getFEEID(rdh), lr, ruOnLr, linkIDinRU);
550 auto link = getGBTLink(ruDecode.links[linkIDinRU]);
551 if (link) { // was there any data seen on this link before?
552 const auto rdhPrev = reinterpret_cast<o2::header::RAWDataHeader*>(link->data.getEnd() - link->lastPageSize); // last stored RDH
553 if (isSameRUandTrigger(rdhPrev, rdh)) {
554 newTrigger = false;
555 }
556 } else { // a new link was added
557 ruDecode.links[linkIDinRU] = addGBTLink();
558 link = getGBTLink(ruDecode.links[linkIDinRU]);
559 link->statistics.feeID = RDHUtils::getFEEID(rdh);
560 LOG(info) << "Adding new GBT LINK FEEId:" << OUTHEX(link->statistics.feeID, 4);
561 mNLinks++;
562 }
563 if (linkFlags[ruIDSW][linkIDinRU] == NotUpdated) {
564 link->data.moveUnusedToHead(); // reuse space of already processed data
565 linkFlags[ruIDSW][linkIDinRU] = Updated;
566 }
567 // copy data to the buffer of the link and memorize its RDH pointer
568 link->data.add(ptr, RDHUtils::getMemorySize(rdh));
569 link->lastPageSize = RDHUtils::getMemorySize(rdh); // account new added size
570 auto rdhC = reinterpret_cast<o2::header::RAWDataHeader*>(link->data.getEnd() - link->lastPageSize);
571 RDHUtils::setOffsetToNext(rdhC, RDHUtils::getMemorySize(rdh)); // since we skip 0-s, we have to modify the offset
572
573 if (newTrigger) {
574 link->nTriggers++; // acknowledge 1st trigger
575 if (link->nTriggers >= mMinTriggersToCache && linkFlags[ruIDSW][linkIDinRU] != HasEnoughTriggers) {
576 nLEnoughTriggers++;
577 linkFlags[ruIDSW][linkIDinRU] = HasEnoughTriggers;
578 }
579 }
580
581 ptr += RDHUtils::getOffsetToNext(rdh);
582 buffer.setPtr(ptr);
583 if (buffer.getUnusedSize() < MaxGBTPacketBytes) {
584 nRead += loadInput(buffer); // update
585 ptr = buffer.getPtr(); // pointer might have been changed
586 }
587
588 rdh = reinterpret_cast<o2::header::RAWDataHeader*>(ptr);
589
590 if (mNLinks == nLEnoughTriggers) {
591 break;
592 }
593
594 } while (!buffer.isEmpty());
595
596 if (mNLinks == nLEnoughTriggers) {
597 mMinTriggersCached = mMinTriggersToCache; // wanted number of triggers acquired
598 } else { // there were no enough triggers to fulfill mMinTriggersToCache requirement
599 mMinTriggersCached = INT_MAX;
600 for (int ir = 0; ir < mNRUs; ir++) {
601 const auto& ruDecData = mRUDecodeVec[ir];
602 for (auto linkID : ruDecData.links) {
603 const auto* link = getGBTLink(linkID);
604 if (link && link->nTriggers < mMinTriggersCached) {
605 mMinTriggersCached = link->nTriggers;
606 }
607 }
608 }
609 }
610 mSWCache.Stop();
611 LOG(info) << "Cached at least " << mMinTriggersCached << " triggers on " << mNLinks << " links of " << mNRUs << " RUs";
612
613 return nRead;
614 }
615
616 //_____________________________________
618 {
619 // Decode next trigger from the cached links data and decrease cached triggers counter, return N links decoded
620 if (mMinTriggersCached < 1) {
621 cacheLinksData(mRawBuffer);
622 if (mMinTriggersCached < 1) {
623 return 0;
624 }
625 }
626 int nlinks = 0;
627 for (int ir = mNRUs; ir--;) {
628 auto& ruDecode = mRUDecodeVec[ir];
629 if (!nlinks) { // on 1st occasion extract trigger data
630 for (auto linkID : ruDecode.links) { // loop over links to fill cable buffers
631 auto* link = getGBTLink(linkID);
632 if (link && !link->data.isEmpty()) {
633 const auto rdh = reinterpret_cast<const o2::header::RAWDataHeader*>(link->data.getPtr());
634 mInteractionRecord = RDHUtils::getTriggerIR(rdh);
635 mTrigger = RDHUtils::getTriggerType(rdh);
636 mInteractionRecordHB = RDHUtils::getHeartBeatIR(rdh);
637 break;
638 }
639 }
640 }
641
642 nlinks += decodeNextRUData(ruDecode);
643 mDecodingStat.nRUsProcessed++;
644 }
645 if (nlinks) {
646 mDecodingStat.nTriggersProcessed++;
647 }
648 mCurRUDecodeID = 0;
649 mMinTriggersCached--;
650 return nlinks;
651 }
652
653 //_____________________________________
655 {
656 // process data of single RU trigger from its links buffers
657 int minTriggers = INT_MAX;
658 int res = 0;
659 ruDecData.clear();
660 bool aborted = false;
661 for (auto linkID : ruDecData.links) { // loop over links to fill cable buffers
662 auto* link = getGBTLink(linkID);
663 if (link && !link->data.isEmpty()) {
664 link->data.setPtr(decodeRUData(link->data.getPtr(), ruDecData, aborted));
665 // we don't need to check the "abort" status since the checks for links data presence and synchronization
666 // should have been done in advance
667 if (--link->nTriggers < minTriggers) { // decrement counter of cached triggers
668 minTriggers = link->nTriggers;
669 }
670 res++;
671 if (link->data.isEmpty()) {
672 link->data.clear();
673 }
674 }
675 }
676 if (ruDecData.ruInfo->nCables) { // there are cables with data to decode
677 decodeAlpideData(ruDecData); // decode Alpide data from the compressed RU Data
678 }
679 return res;
680 }
681
682 //_____________________________________
684 {
685 // keep reading GRB words until RDH is found
686 size_t nRead = 0;
687 int scan = 0;
688 bool goodRDH = false;
689 auto ptr = buffer.getPtr();
690 o2::header::RAWDataHeader* rdh = nullptr;
691 do {
692 if (buffer.isEmpty()) {
693 auto nrl = loadInput(buffer);
694 if (!nrl) {
695 break;
696 }
697 nRead += nrl;
698 ptr = buffer.getPtr();
699 }
700 scan++;
701 ptr += mGBTWordSize;
702 buffer.setPtr(ptr);
703 if (!buffer.isEmpty()) {
704 rdh = reinterpret_cast<o2::header::RAWDataHeader*>(ptr);
705 } else {
706 break;
707 }
708 } while (!(goodRDH = RDHUtils::checkRDH(rdh)));
709 LOG(info) << "End of pointer recovery after skipping " << scan << " GBT words, RDH is"
710 << (goodRDH ? "" : " not") << " found";
711 return goodRDH;
712 }
713
714 //_____________________________________
715 uint8_t* decodeRUData(uint8_t* raw, RUDecodeData& ruDecData, bool& aborted)
716 {
722
723 aborted = false;
724
725 // data must start by RDH
726 auto rdh = reinterpret_cast<o2::header::RAWDataHeader*>(raw);
727
728#ifdef _RAW_READER_ERROR_CHECKS_
729 if (!RDHUtils::checkRDH(rdh)) {
730 LOG(error) << "Page does not start with RDH";
732 for (int i = 0; i < 4; i++) {
733 auto gbtD = reinterpret_cast<const o2::itsmft::GBTData*>(raw + i * 16);
734 gbtD->printX(mPadding128);
735 }
736 raw += mGBTWordSize;
737 aborted = true;
738 return raw;
739 }
740#endif
741
742 int ruIDSW = mMAP.FEEId2RUSW(RDHUtils::getFEEID(rdh));
743#ifdef _RAW_READER_ERROR_CHECKS_
744 if (ruIDSW >= mMAP.getNRUs()) {
745 mDecodingStat.errorCounts[RawDecodingStat::ErrInvalidFEEId]++;
746 LOG(error) << mDecodingStat.ErrNames[RawDecodingStat::ErrInvalidFEEId]
747 << " : FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << ", skipping CRU page";
749 raw += RDHUtils::getOffsetToNext(rdh);
750 return raw;
751 }
752
753 if (ruIDSW != ruDecData.ruInfo->idSW) { // should not happen with cached data
754 LOG(error) << "RDG RU IDSW " << ruIDSW << " differs from expected " << ruDecData.ruInfo->idSW;
756 }
757#endif
758
759 uint16_t lr, ruOnLr, linkIDinRU;
760 mMAP.expandFEEId(RDHUtils::getFEEID(rdh), lr, ruOnLr, linkIDinRU);
761 auto* ruLink = getGBTLink(ruDecData.links[linkIDinRU]);
762 auto& ruLinkStat = ruLink->statistics;
763 ruLink->lastRDH = reinterpret_cast<o2::header::RDHAny*>(rdh); // hack but this reader should be outphased anyway
764 ruLinkStat.nPackets++;
765
766#ifdef _RAW_READER_ERROR_CHECKS_
767 if (RDHUtils::getPacketCounter(rdh) > ruLink->packetCounter + 1) {
768 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrPacketCounterJump]++;
769 LOG(warn) << ruLinkStat.ErrNames[GBTLinkDecodingStat::ErrPacketCounterJump]
770 << " : FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << ": jump from " << int(ruLink->packetCounter)
771 << " to " << int(RDHUtils::getPacketCounter(rdh));
773 }
774#endif
775 while (1) {
776 ruLink->packetCounter = RDHUtils::getPacketCounter(rdh);
777
778 mDecodingStat.nBytesProcessed += RDHUtils::getMemorySize(rdh);
779 mDecodingStat.nPagesProcessed++;
780 raw += RDHUtils::getHeaderSize(rdh);
781 int nGBTWords = (RDHUtils::getMemorySize(rdh) - RDHUtils::getHeaderSize(rdh)) / mGBTWordSize - 2; // number of GBT words excluding header/trailer
782 auto gbtH = reinterpret_cast<const o2::itsmft::GBTDataHeaderL*>(raw); // process GBT header
783
784#ifdef _RAW_READER_ERROR_CHECKS_
785 if (mVerbose) {
787 gbtH->printX(mPadding128);
788 LOG(info) << "Expect " << nGBTWords << " GBT words";
789 }
790
791 if (!gbtH->isDataHeader()) {
792 gbtH->printX(mPadding128);
793 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " GBT payload header was expected, abort page decoding";
795 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrMissingGBTHeader]++;
796 gbtH->printX(mPadding128);
797 aborted = true;
798 return raw;
799 }
800
801 if (gbtH->packetIdx != RDHUtils::getPageCounter(rdh)) {
802 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Different GBT header " << gbtH->packetIdx
803 << " and RDH page " << RDHUtils::getPageCounter(rdh) << " counters";
805 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrRDHvsGBTHPageCnt]++;
806 }
807
808 if (ruLink->lanesActive == ruLink->lanesStop) { // all lanes received their stop, new page 0 expected
809 if (RDHUtils::getPageCounter(rdh)) { // flag lanes of this FEE
810 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Non-0 page counter (" << RDHUtils::getPageCounter(rdh) << ") while all lanes were stopped";
812 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrNonZeroPageAfterStop]++;
813 }
814 }
815
816 ruLink->lanesActive = gbtH->activeLanes; // TODO do we need to update this for every page?
817
818 if (~(mMAP.getCablesOnRUType(ruDecData.ruInfo->ruType)) & ruLink->lanesActive) { // are there wrong lanes?
819 std::bitset<32> expectL(mMAP.getCablesOnRUType(ruDecData.ruInfo->ruType)), gotL(ruLink->lanesActive);
820 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Active lanes pattern " << gotL
821 << " conflicts with expected " << expectL << " for given RU type, skip page";
823 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrInvalidActiveLanes]++;
824 raw = ((uint8_t*)rdh) + RDHUtils::getOffsetToNext(rdh); // jump to the next packet
825 return raw;
826 }
827
828 if (!RDHUtils::getPageCounter(rdh)) { // reset flags
829 ruLink->lanesStop = 0;
830 ruLink->lanesWithData = 0;
831 }
832
833#endif
834 raw += mGBTWordSize;
835 for (int iw = 0; iw < nGBTWords; iw++, raw += mGBTWordSize) {
836 auto gbtD = reinterpret_cast<const o2::itsmft::GBTData*>(raw);
837 // TODO: need to clarify if the nGBTWords from the RDHUtils::getMemorySize(rdh) is reliable estimate of the real payload, at the moment this is not the case
838
839 if (mVerbose > 1) {
840 printf("W%4d |", iw);
841 gbtD->printX(mPadding128);
842 }
843 if (gbtD->isDataTrailer()) {
844 nGBTWords = iw;
845 break; // this means that the nGBTWords estimate was wrong
846 }
847
848 int cableHW = gbtD->getCableID();
849 int cableSW = mMAP.cableHW2SW(ruDecData.ruInfo->ruType, cableHW);
850 ruDecData.cableData[cableSW].add(gbtD->getW8(), 9);
851 ruDecData.cableHWID[cableSW] = cableHW;
852
853#ifdef _RAW_READER_ERROR_CHECKS_
854 int cableHWPos = mMAP.cableHW2Pos(ruDecData.ruInfo->ruType, cableHW);
855 ruDecData.cableLinkID[cableSW] = linkIDinRU;
856 ruLink->lanesWithData |= 0x1 << cableHWPos; // flag that the data was seen on this lane
857 if (ruLink->lanesStop & (0x1 << cableHWPos)) { // make sure stopped lanes do not transmit the data
858 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrDataForStoppedLane]++;
859 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Data received for stopped lane " << cableHW << " (sw:" << cableSW << ")";
861 }
862#endif
863
864 } // we are at the trailer, packet is over, check if there are more for the same ru
865
866 auto gbtT = reinterpret_cast<const o2::itsmft::GBTDataTrailer*>(raw); // process GBT trailer
867#ifdef _RAW_READER_ERROR_CHECKS_
868
869 if (mVerbose) {
870 gbtT->printX(mPadding128);
871 }
872
873 if (!gbtT->isDataTrailer()) {
874 gbtT->printX(mPadding128);
875 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << std::dec
876 << " GBT payload trailer was expected, abort page decoding NW" << nGBTWords;
878 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrMissingGBTTrailer]++;
879 aborted = true;
880 return raw;
881 }
882
883 ruLink->lanesTimeOut |= gbtT->lanesTimeout; // register timeouts
884 ruLink->lanesStop |= gbtT->lanesStops; // register stops
885#endif
886 raw += mGBTWordSize;
887 // we finished the GBT page, see if there is a continuation and if it belongs to the same multipacket
888
889 if (!RDHUtils::getOffsetToNext(rdh)) { // RS TODO: what the last page in memory will contain as offsetToNext, is it 0?
890 break;
891 }
892
893 raw = ((uint8_t*)rdh) + RDHUtils::getOffsetToNext(rdh); // jump to the next packet:
894 auto rdhN = reinterpret_cast<o2::header::RAWDataHeader*>(raw);
895 // check if data of given RU are over, i.e. we the page counter was wrapped to 0 (should be enough!) or other RU/trigger started
896 if (!isSameRUandTrigger(rdh, rdhN)) {
897
898#ifdef _RAW_READER_ERROR_CHECKS_
899 // make sure all lane stops for finished page are received
900 if ((ruLink->lanesActive & ~ruLink->lanesStop) && nGBTWords) {
901 if (RDHUtils::getTriggerType(rdh) != o2::trigger::SOT) { // only SOT trigger allows unstopped lanes?
902 std::bitset<32> active(ruLink->lanesActive), stopped(ruLink->lanesStop);
903 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " end of FEE data but not all lanes received stop"
904 << "| active: " << active << " stopped: " << stopped;
906 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrUnstoppedLanes]++;
907 }
908 }
909
910 // make sure all active lanes (except those in time-out) have sent some data
911 if ((~ruLink->lanesWithData & ruLink->lanesActive) != ruLink->lanesTimeOut && nGBTWords) {
912 std::bitset<32> withData(ruLink->lanesWithData), active(ruLink->lanesActive), timeOut(ruLink->lanesTimeOut);
913 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Lanes not in time-out but not sending data"
914 << "\n| with data: " << withData << " active: " << active << " timeOut: " << timeOut;
916 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrNoDataForActiveLane]++;
917 }
918#endif
919 // accumulate packet states
920 ruLinkStat.packetStates[gbtT->getPacketState()]++;
921
922 break;
923 }
924#ifdef _RAW_READER_ERROR_CHECKS_
925 // check if the page counter increases
926 if (RDHUtils::getPageCounter(rdhN) != RDHUtils::getPageCounter(rdh) + 1) {
927 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Discontinuity in the RDH page counter of the same RU trigger: old "
928 << RDHUtils::getPageCounter(rdh) << " new: " << RDHUtils::getPageCounter(rdhN);
930 RDHUtils::printRDH(rdhN);
931 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrPageCounterDiscontinuity]++;
932 }
933#endif
934 rdh = rdhN;
935 ruLink->lastRDH = reinterpret_cast<o2::header::RDHAny*>(rdh);
936 }
937
938#ifdef _RAW_READER_ERROR_CHECKS_
939// if (RDHUtils::getPageCounter(rdh) && !RDHUtils::getStop(rdh)) {
940// LOG(warning) << "Last packet(" << RDHUtils::getPageCounter(rdh) << ") of GBT multi-packet is reached w/o STOP set in the RDH";
941// }
942#endif
943
944 return raw;
945 }
946
947 //_____________________________________
949 {
950 if (mIOFile) {
951 loadInput(mRawBuffer); // if needed, upload additional data to the buffer
952 }
953
954 int res = 0;
955 if (!mRawBuffer.isEmpty()) {
956 bool aborted = false;
957
958 auto ptr = skimPaddedRUData(mRawBuffer.getPtr(), outBuffer, aborted);
959 mDecodingStat.nRUsProcessed++;
960 if (!aborted) {
961 mRawBuffer.setPtr(ptr);
962 res = 1; // success
963 if (mRawBuffer.isEmpty()) {
964 mRawBuffer.clear();
965 }
966 } else { // try to seek to the next RDH, can be done only for 128b padded GBT words
967 if (findNextRDH(mRawBuffer)) {
968 ptr = mRawBuffer.getPtr();
969 res = 1;
970 } else {
971 mRawBuffer.clear(); // did not find new RDH
972 }
973 } // try to seek to the next ...
974 }
975 return res;
976 }
977
978 //_____________________________________
979 uint8_t* skimPaddedRUData(uint8_t* raw, PayLoadCont& outBuffer, bool& aborted)
980 {
983
984 aborted = false;
985
986 // data must start by RDH
987 auto rdh = reinterpret_cast<o2::header::RAWDataHeader*>(raw);
988#ifdef _RAW_READER_ERROR_CHECKS_
989 if (!RDHUtils::checkRDH(rdh)) {
990 LOG(error) << "Page does not start with RDH";
992 for (int i = 0; i < 4; i++) {
993 auto gbtD = reinterpret_cast<const o2::itsmft::GBTData*>(raw + i * 16);
994 gbtD->printX(mPadding128);
995 }
996 aborted = true;
997 return raw;
998 }
999 int ruIDSWD = mMAP.FEEId2RUSW(RDHUtils::getFEEID(rdh));
1000 if (ruIDSWD >= mMAP.getNRUs()) {
1001 mDecodingStat.errorCounts[RawDecodingStat::ErrInvalidFEEId]++;
1002 LOG(error) << mDecodingStat.ErrNames[RawDecodingStat::ErrInvalidFEEId]
1003 << " : FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << ", skipping CRU page";
1004 RDHUtils::printRDH(rdh);
1005 raw += RDHUtils::getOffsetToNext(rdh);
1006 return raw;
1007 }
1008#endif
1009 uint16_t lr, ruOnLr, linkIDinRU;
1010 mMAP.expandFEEId(RDHUtils::getFEEID(rdh), lr, ruOnLr, linkIDinRU);
1011 int ruIDSW = mMAP.FEEId2RUSW(RDHUtils::getFEEID(rdh));
1012 auto& ruDecode = getCreateRUDecode(ruIDSW);
1013 auto ruInfo = mMAP.getRUInfoSW(ruIDSW);
1014
1015 if (ruDecode.links[linkIDinRU] < 0) {
1016 ruDecode.links[linkIDinRU] = addGBTLink();
1017 getGBTLink(ruDecode.links[linkIDinRU])->statistics.feeID = RDHUtils::getFEEID(rdh);
1018 mNLinks++;
1019 }
1020
1021 mInteractionRecord = RDHUtils::getTriggerIR(rdh);
1022
1023 mTrigger = RDHUtils::getTriggerType(rdh);
1024
1025 auto ruLink = getGBTLink(ruDecode.links[linkIDinRU]);
1026 auto& ruLinkStat = ruLink->statistics;
1027 ruLink->lastRDH = reinterpret_cast<o2::header::RDHAny*>(rdh); // hack but this reader should be outphased anyway
1028 ruLinkStat.nPackets++;
1029
1030#ifdef _RAW_READER_ERROR_CHECKS_
1031 if (RDHUtils::getPacketCounter(rdh) > ruLink->packetCounter + 1) {
1032 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrPacketCounterJump]++;
1033 LOG(warn) << ruLinkStat.ErrNames[GBTLinkDecodingStat::ErrPacketCounterJump]
1034 << " : FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << ": jump from " << int(ruLink->packetCounter)
1035 << " to " << int(RDHUtils::getPacketCounter(rdh));
1036 RDHUtils::printRDH(rdh);
1037 }
1038#endif
1039 ruLink->packetCounter = RDHUtils::getPacketCounter(rdh);
1040
1041 int sizeAtEntry = outBuffer.getSize(); // save the size of outbuffer size at entry, in case of severe error we will need to rewind to it.
1042
1043 while (1) {
1044 mDecodingStat.nPagesProcessed++;
1045 mDecodingStat.nBytesProcessed += RDHUtils::getMemorySize(rdh);
1046 raw += RDHUtils::getHeaderSize(rdh);
1047 // number of 128 b GBT words excluding header/trailer
1048 int nGBTWords = (RDHUtils::getMemorySize(rdh) - RDHUtils::getHeaderSize(rdh)) / o2::itsmft::GBTPaddedWordLength - 2;
1049 auto gbtH = reinterpret_cast<const o2::itsmft::GBTDataHeaderL*>(raw); // process GBT header
1050
1051#ifdef _RAW_READER_ERROR_CHECKS_
1052 if (mVerbose) {
1053 RDHUtils::printRDH(rdh);
1054 gbtH->printX(true);
1055 LOG(info) << "Expect " << nGBTWords << " GBT words";
1056 }
1057 if (!gbtH->isDataHeader()) {
1058 gbtH->printX(true);
1059 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " GBT payload header was expected, abort page decoding";
1060 RDHUtils::printRDH(rdh);
1061 gbtH->printX(true);
1062 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrMissingGBTHeader]++;
1063 aborted = true;
1064 outBuffer.shrinkToSize(sizeAtEntry); // reset output buffer to initial state
1065 return raw;
1066 }
1067 if (gbtH->packetIdx != RDHUtils::getPageCounter(rdh)) {
1068 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Different GBT header " << gbtH->packetIdx
1069 << " and RDH page " << RDHUtils::getPageCounter(rdh) << " counters";
1070 RDHUtils::printRDH(rdh);
1071 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrRDHvsGBTHPageCnt]++;
1072 }
1073
1074 if (ruLink->lanesActive == ruLink->lanesStop) { // all lanes received their stop, new page 0 expected
1075 if (RDHUtils::getPageCounter(rdh)) { // flag lanes of this FEE
1076 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Non-0 page counter (" << RDHUtils::getPageCounter(rdh) << ") while all lanes were stopped";
1077 RDHUtils::printRDH(rdh);
1078 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrNonZeroPageAfterStop]++;
1079 }
1080 }
1081
1082 ruLink->lanesActive = gbtH->activeLanes; // TODO do we need to update this for every page?
1083
1084 if (!RDHUtils::getPageCounter(rdh)) { // reset flags
1085 ruLink->lanesStop = 0;
1086 ruLink->lanesWithData = 0;
1087 }
1088
1089#endif
1090 // start writting skimmed data for this page, making sure the buffer has enough free slots
1091 outBuffer.ensureFreeCapacity(8 * 1024);
1092 auto rdhS = reinterpret_cast<o2::header::RAWDataHeader*>(outBuffer.getEnd()); // save RDH and make saved copy editable
1093 outBuffer.addFast(reinterpret_cast<const uint8_t*>(rdh), RDHUtils::getHeaderSize(rdh));
1094
1095 outBuffer.addFast(reinterpret_cast<const uint8_t*>(gbtH), mGBTWordSize); // save gbt header w/o 128b padding
1096
1098 for (int iw = 0; iw < nGBTWords; iw++, raw += o2::itsmft::GBTPaddedWordLength) {
1099 auto gbtD = reinterpret_cast<const o2::itsmft::GBTData*>(raw);
1100 // TODO: need to clarify if the nGBTWords from the RDHUtils::getMemorySize(rdh) is reliable estimate of the real payload, at the moment this is not the case
1101
1102 if (mVerbose > 1) {
1103 printf("W%4d |", iw);
1104 gbtD->printX(mPadding128);
1105 }
1106 if (gbtD->isDataTrailer()) {
1107 nGBTWords = iw;
1108 break; // this means that the nGBTWords estimate was wrong
1109 }
1110
1111 int cableHW = gbtD->getCableID();
1112 int cableSW = mMAP.cableHW2SW(ruInfo->ruType, cableHW);
1113
1114 outBuffer.addFast(reinterpret_cast<const uint8_t*>(gbtD), mGBTWordSize); // save gbt word w/o 128b padding
1115
1116#ifdef _RAW_READER_ERROR_CHECKS_
1117 int cableHWPos = mMAP.cableHW2Pos(ruInfo->ruType, cableHW);
1118 ruLink->lanesWithData |= 0x1 << cableHWPos; // flag that the data was seen on this lane
1119 if (ruLink->lanesStop & (0x1 << cableHWPos)) { // make sure stopped lanes do not transmit the data
1120 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrDataForStoppedLane]++;
1121 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Data received for stopped lane " << cableHW << " (sw:" << cableSW << ")";
1122 RDHUtils::printRDH(rdh);
1123 }
1124#endif
1125
1126 } // we are at the trailer, packet is over, check if there are more for the same ru
1127
1128 auto gbtT = reinterpret_cast<const o2::itsmft::GBTDataTrailer*>(raw); // process GBT trailer
1129#ifdef _RAW_READER_ERROR_CHECKS_
1130
1131 if (mVerbose) {
1132 gbtT->printX(true);
1133 }
1134
1135 if (!gbtT->isDataTrailer()) {
1136 gbtT->printX(true);
1137 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " GBT payload trailer was expected, abort page decoding at NW" << nGBTWords;
1138 RDHUtils::printRDH(rdh);
1139 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrMissingGBTTrailer]++;
1140 aborted = true;
1141 outBuffer.shrinkToSize(sizeAtEntry); // reset output buffer to initial state
1142 return raw;
1143 }
1144
1145 ruLink->lanesTimeOut |= gbtT->lanesTimeout; // register timeouts
1146 ruLink->lanesStop |= gbtT->lanesStops; // register stops
1147#endif
1148
1149 outBuffer.addFast(reinterpret_cast<const uint8_t*>(gbtT), mGBTWordSize); // save gbt trailer w/o 128b padding
1150
1152
1153 // we finished the GBT page, register in the stored RDH the memory size and new offset
1154 RDHUtils::setMemorySize(rdhS, RDHUtils::getHeaderSize(rdhS) + (2 + nGBTWords) * mGBTWordSize);
1155 RDHUtils::setOffsetToNext(rdhS, RDHUtils::getMemorySize(rdhS));
1156
1157 if (!RDHUtils::getOffsetToNext(rdh)) { // RS TODO: what the last page in memory will contain as offsetToNext, is it 0?
1158 break;
1159 }
1160
1161 raw = ((uint8_t*)rdh) + RDHUtils::getOffsetToNext(rdh); // jump to the next packet:
1162 auto rdhN = reinterpret_cast<o2::header::RAWDataHeader*>(raw);
1163 // check if data of given RU are over, i.e. we the page counter was wrapped to 0 (should be enough!) or other RU/trigger started
1164 if (!isSameRUandTrigger(rdh, rdhN)) {
1165
1166#ifdef _RAW_READER_ERROR_CHECKS_
1167 // make sure all lane stops for finished page are received
1168 if (ruLink->lanesActive != ruLink->lanesStop && nGBTWords) {
1169 if (RDHUtils::getTriggerType(rdh) != o2::trigger::SOT) { // only SOT trigger allows unstopped lanes?
1170 std::bitset<32> active(ruLink->lanesActive), stopped(ruLink->lanesStop);
1171 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " end of FEE data but not all lanes received stop"
1172 << "| active: " << active << " stopped: " << stopped;
1173 RDHUtils::printRDH(rdh);
1174 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrUnstoppedLanes]++;
1175 }
1176 }
1177
1178 // make sure all active lanes (except those in time-out) have sent some data
1179 if ((~ruLink->lanesWithData & ruLink->lanesActive) != ruLink->lanesTimeOut && nGBTWords) {
1180 std::bitset<32> withData(ruLink->lanesWithData), active(ruLink->lanesActive), timeOut(ruLink->lanesTimeOut);
1181 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Lanes not in time-out but not sending data"
1182 << "| with data: " << withData << " active: " << active << " timeOut: " << timeOut;
1183 RDHUtils::printRDH(rdh);
1184 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrNoDataForActiveLane]++;
1185 }
1186
1187 // accumulate packet states
1188 ruLinkStat.packetStates[gbtT->getPacketState()]++;
1189#endif
1190
1191 break;
1192 }
1193#ifdef _RAW_READER_ERROR_CHECKS_
1194 // check if the page counter increases
1195 if (RDHUtils::getPageCounter(rdhN) != RDHUtils::getPageCounter(rdh) + 1) {
1196 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Discontinuity in the RDH page counter of the same RU trigger: old "
1197 << RDHUtils::getPageCounter(rdh) << " new: " << RDHUtils::getPageCounter(rdhN);
1198 RDHUtils::printRDH(rdh);
1199 RDHUtils::printRDH(rdhN);
1200 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrPageCounterDiscontinuity]++;
1201 }
1202#endif
1203 rdh = rdhN;
1204 ruLink->lastRDH = reinterpret_cast<o2::header::RDHAny*>(rdh); // hack but this reader should be outphased anyway
1205 }
1206
1207#ifdef _RAW_READER_ERROR_CHECKS_
1208// if (RDHUtils::getPageCounter(rdh) && !RDHUtils::getStop(rdh)) {
1209// LOG(warning) << "Last packet(" << RDHUtils::getPageCounter(rdh) << ") of GBT multi-packet is reached w/o STOP set in the RDH";
1210// }
1211#endif
1212
1213 return raw;
1214 }
1215
1216 //_____________________________________
1218 {
1220 if (RDHUtils::getPageCounter(rdhNew) == 0 || RDHUtils::getFEEID(rdhNew) != RDHUtils::getFEEID(rdhOld) ||
1221 RDHUtils::getTriggerIR(rdhNew) != RDHUtils::getTriggerIR(rdhOld) ||
1222 RDHUtils::getHeartBeatIR(rdhNew) != RDHUtils::getHeartBeatIR(rdhOld) ||
1223 !(RDHUtils::getTriggerType(rdhNew) & RDHUtils::getTriggerType(rdhOld))) {
1224 return false;
1225 }
1226 return true;
1227 }
1228
1229 //_____________________________________
1231 {
1233
1234 auto* chipData = &decData.chipsData[0];
1235
1236 decData.nChipsFired = decData.lastChipChecked = 0;
1237 int ntot = 0;
1238 for (int icab = 0; icab < decData.ruInfo->nCables; icab++) {
1239 auto& cableData = decData.cableData[icab];
1240 int res = 0;
1241
1242#ifdef _RAW_READER_ERROR_CHECKS_
1243 auto& ruLinkStat = getGBTLink(decData.links[decData.cableLinkID[icab]])->statistics;
1244
1245 // make sure the lane data starts with chip header or empty chip
1246 uint8_t h;
1247 if (cableData.current(h) && !mCoder.isChipHeaderOrEmpty(h)) {
1248 LOG(error) << "FEEId:" << OUTHEX(decData.ruInfo->idHW, 4) << " cable " << icab
1249 << " data does not start with ChipHeader or ChipEmpty";
1250 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrCableDataHeadWrong]++;
1251 RDHUtils::printRDH(reinterpret_cast<const o2::header::RAWDataHeader*>(getGBTLink(decData.links[decData.cableLinkID[icab]])->lastRDH));
1252 }
1253#endif
1254 auto cabHW = decData.cableHWID[icab];
1255 auto ri = decData.ruInfo;
1256 auto chIdGetter = [this, cabHW, ri](int cid) {
1257 return this->mMAP.getGlobalChipID(cid, cabHW, *ri);
1258 };
1259 std::vector<uint16_t> dummyStat;
1260 while ((res = mCoder.decodeChip(*chipData, cableData, dummyStat, chIdGetter))) { // we register only chips with hits or errors flags set
1261 if (res > 0) {
1262#ifdef _RAW_READER_ERROR_CHECKS_
1263 // for the IB staves check if the cable ID is the same as the chip ID on the module
1264 if (mMAP.getName() == "ITS" && decData.ruInfo->ruType == 0) { // ATTENTION: this is a hack tailored for temporary check
1265 if (chipData->getChipID() != icab) {
1266 LOG(error) << "FEEId:" << OUTHEX(decData.ruInfo->idHW, 4) << " IB cable " << icab
1267 << " shipped chip ID= " << chipData->getChipID();
1268 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrIBChipLaneMismatch]++;
1269 RDHUtils::printRDH(reinterpret_cast<const o2::header::RAWDataHeader*>(getGBTLink(decData.links[decData.cableLinkID[icab]])->lastRDH));
1270 }
1271 }
1272#endif
1273 // convert HW chip id within the module to absolute chip id
1274 // chipData->setChipID(mMAP.getGlobalChipID(chipData->getChipID(), decData.cableHWID[icab], *decData.ruInfo));
1275 chipData->setInteractionRecord(mInteractionRecord);
1276 chipData->setTrigger(mTrigger);
1277 mDecodingStat.nNonEmptyChips++;
1278 mDecodingStat.nHitsDecoded += chipData->getData().size();
1279 ntot += res;
1280 // fetch next free chip
1281 if (++decData.nChipsFired < int(decData.chipsData.size())) {
1282 chipData = &decData.chipsData[decData.nChipsFired];
1283 } else {
1284 break; // last chip decoded
1285 }
1286 }
1287 }
1288 }
1289 return ntot;
1290 }
1291
1292 //_____________________________________
1293 bool getNextChipData(ChipPixelData& chipData) override
1294 {
1296
1297 if (mCurRUDecodeID >= 0) { // make sure current RU has fired chips to extract
1298 for (; mCurRUDecodeID < mNRUs; mCurRUDecodeID++) {
1299 auto& ru = mRUDecodeVec[mCurRUDecodeID];
1300 if (ru.lastChipChecked < ru.nChipsFired) {
1301 chipData.swap(ru.chipsData[ru.lastChipChecked++]);
1302 return true;
1303 }
1304 }
1305 mCurRUDecodeID = 0; // no more decoded data if reached this place,
1306 }
1307
1308 // will need to decode new trigger
1309 if (!mDecodeNextAuto) { // no more data in the current ROF and no automatic decoding of next one was requested
1310 return false;
1311 }
1312
1313 if (mMinTriggersCached < 2) { // last trigger might be incomplete, need to cache more data
1314 cacheLinksData(mRawBuffer);
1315 }
1316 if (mMinTriggersCached < 1 || !decodeNextTrigger()) {
1317 mCurRUDecodeID = -1;
1318 return false; // nothing left
1319 }
1320 return getNextChipData(chipData); // is it ok to use recursion here?
1321 }
1322
1323 //_____________________________________
1324 void openInput(const std::string filename)
1325 {
1326 // open input for raw data decoding from file
1327 mSWIO.Stop();
1328 mSWIO.Start();
1329 clear(false); // do not reset statistics
1330 LOG(info) << "opening raw data input file " << filename;
1331 mIOFile.open(filename.c_str(), std::ifstream::binary);
1332 assert(mIOFile.good());
1333 mRawBuffer.clear();
1334 mRawBuffer.expand(RawBufferSize);
1335 mSWIO.Stop();
1336 }
1337
1338 //_____________________________________
1340 {
1342 static_assert(RawBufferMargin > MaxGBTPacketBytes * 100 &&
1343 RawBufferSize > 3 * RawBufferMargin,
1344 "raw buffer size is too small");
1345
1346 if (!mIOFile) {
1347 return 0;
1348 }
1349 if (buffer.getUnusedSize() > RawBufferMargin) { // bytes read but not used yet are enough
1350 return 0;
1351 }
1352 mSWIO.Start(false);
1353 auto readFromFile = [this](uint8_t* ptr, int n) {
1354 mIOFile.read(reinterpret_cast<char*>(ptr), n);
1355 return mIOFile.gcount(); // fread( ptr, sizeof(uint8_t), n, mIOFile);
1356 };
1357 auto nread = buffer.append(readFromFile);
1358 mSWIO.Stop();
1359 return nread;
1360 }
1361
1362 // get statics of FEE with sequential idSW
1363 const GBTLinkDecodingStat* getGBTLinkDecodingStatSW(uint16_t idSW, int ruLink) const
1364 {
1365 if (mRUEntry[idSW] < 0 || ruLink >= RUDecodeData::MaxLinksPerRU || mRUDecodeVec[mRUEntry[idSW]].links[ruLink] < 0) {
1366 return nullptr;
1367 } else {
1368 return &getGBTLink(mRUDecodeVec[mRUEntry[idSW]].links[ruLink])->statistics;
1369 }
1370 }
1371
1372 // get statics of FEE with given HW id
1373 const GBTLinkDecodingStat* getGBTLinkDecodingStatHW(uint16_t idHW, int ruLink) const
1374 {
1375 int idsw = mMAP.FEEId2RUSW(idHW);
1376 assert(idsw != 0xffff);
1377 return getGBTLinkDecodingStatSW(idsw, ruLink);
1378 }
1379
1380 // aliases for BWD compatibility
1381 const GBTLinkDecodingStat* getRUDecodingStatSW(uint16_t idSW, int ruLink = 0) const { return getGBTLinkDecodingStatSW(idSW, ruLink); }
1382 const GBTLinkDecodingStat* getRUDecodingStatHW(uint16_t idHW, int ruLink = 0) const { return getGBTLinkDecodingStatHW(idHW, ruLink); }
1383
1384 // get global decoding statistics
1385 const RawDecodingStat& getDecodingStat() const { return mDecodingStat; }
1386
1387 void setVerbosity(int v) { mVerbose = v; }
1388 int getVerbosity() const { return mVerbose; }
1389
1390 Mapping& getMapping() { return mMAP; }
1391
1392 // get currently processed RU container
1393 const RUDecodeData* getCurrRUDecodeData() const { return mCurRUDecodeID < 0 ? nullptr : &mRUDecodeVec[mCurRUDecodeID]; }
1394
1395 PayLoadCont& getRawBuffer() { return mRawBuffer; }
1396
1397 // number of links seen in the data
1398 int getNLinks() const { return mNLinks; }
1399
1400 // number of RUs seen in the data
1401 int getNRUs() const { return mNRUs; }
1402
1403 // get vector of RU decode containers for RUs seen in the data
1404 const std::array<RUDecodeData, Mapping::getNRUs()>& getRUDecodeVec() const { return mRUDecodeVec; }
1405
1406 const std::array<int, Mapping::getNRUs()>& getRUEntries() const { return mRUEntry; }
1407
1408 // get RU decode container for RU with given SW ID
1409 const RUDecodeData* getRUDecode(int ruSW) const
1410 {
1411 return mRUEntry[ruSW] < 0 ? nullptr : &mRUDecodeVec[mRUEntry[ruSW]];
1412 }
1413
1414 // get RU decode container for RU with given SW ID, if does not exist, create it
1416 {
1417 assert(ruSW < mMAP.getNRUs());
1418 if (mRUEntry[ruSW] < 0) {
1419 mRUEntry[ruSW] = mNRUs++;
1420 mRUDecodeVec[mRUEntry[ruSW]].ruInfo = mMAP.getRUInfoSW(ruSW); // info on the stave/RU
1421 mRUDecodeVec[mRUEntry[ruSW]].chipsData.resize(mMAP.getNChipsOnRUType(mMAP.getRUInfoSW(ruSW)->ruType));
1422 LOG(info) << "Defining container for RU " << ruSW << " at slot " << mRUEntry[ruSW];
1423 }
1424 return mRUDecodeVec[mRUEntry[ruSW]];
1425 }
1426
1427 // create new gbt link
1429 {
1430 int sz = mGBTLinks.size();
1431 mGBTLinks.emplace_back();
1432 return sz;
1433 }
1434
1435 // get the link
1436 GBTLink* getGBTLink(int i) { return i < 0 ? nullptr : &mGBTLinks[i]; }
1437 const GBTLink* getGBTLink(int i) const { return i < 0 ? nullptr : &mGBTLinks[i]; }
1438
1439 private:
1440 std::ifstream mIOFile;
1441 Coder mCoder;
1442 Mapping mMAP;
1443 int mVerbose = 0;
1444 int mCurRUDecodeID = -1;
1445
1446 PayLoadCont mRawBuffer;
1447
1448 std::array<RUDecodeData, Mapping::getNRUs()> mRUDecodeVec; // decoding buffers for all active RUs
1449 std::array<int, Mapping::getNRUs()> mRUEntry;
1450 std::vector<GBTLink> mGBTLinks;
1451 int mNRUs = 0;
1452 int mNLinks = 0;
1453
1455 int mMinTriggersToCache = NCRUPagesPerSuperpage + 10;
1456 int mMinTriggersCached = 0;
1457
1458 // statistics
1459 RawDecodingStat mDecodingStat;
1460
1461 TStopwatch mSWIO;
1462 TStopwatch mSWCache;
1463
1464 static constexpr int RawBufferMargin = 5000000; // keep uploaded at least this amount
1465 static constexpr int RawBufferSize = 10000000 + 2 * RawBufferMargin; // size in MB
1466 bool mPadding128 = true; // is payload padded to 128 bits
1467 bool mImposeMaxPage = true; // standard CRU data comes in 8KB pages
1468 // number of bytes the GBT word, including optional padding to 128 bits
1469 int mGBTWordSize = mPadding128 ? o2::itsmft::GBTPaddedWordLength : o2::itsmft::GBTWordLength;
1470
1471 ClassDefOverride(RawPixelReader, 1);
1472};
1473
1474template <class Mapping>
1475constexpr int RawPixelReader<Mapping>::RawBufferMargin;
1476
1477template <class Mapping>
1478constexpr int RawPixelReader<Mapping>::RawBufferSize;
1479
1480} // namespace itsmft
1481} // namespace o2
1482
1483#endif /* ALICEO2_ITS_RAWPIXELREADER_H */
class for the ALPIDE data decoding/encoding
Definition of the 32 Central Trigger System (CTS) Trigger Types defined in https://twiki....
uint64_t nGBTWords
int32_t i
Declaration of class for continuos buffer of ALPIDE data.
Declaration of class for scatter-gather buffer.
Transient data classes for single pixel and set of pixels from current chip.
Abstract class for Alpide data reader class.
Definition of the RAW Data Header.
Declaration of the Readout Unite decoder class.
uint32_t res
Definition RawData.h:0
#define OUTHEX(v, l)
TBranch * ptr
Checks validity of hardware address (HW) and transform it to digit AbsId index.
Class for time synchronization of RawReader instances.
void setChipID(uint16_t id)
Definition PixelData.h:119
void swap(ChipPixelData &other)
Definition PixelData.h:156
uint16_t getChipID() const
Definition PixelData.h:108
const std::vector< PixelData > & getData() const
Definition PixelData.h:115
void ensureFreeCapacity(size_t n)
fill n bytes with given symbol w/o checking for the size
Definition PayLoadCont.h:76
void shrinkToSize(size_t sz)
direct const access to value at a given slot, w/o checking for overflow
size_t getSize() const
get offset of the current ptr from the head
Definition PayLoadCont.h:64
void clear()
get unused size
Definition PayLoadCont.h:54
void addFast(const uint8_t *ptr, size_t n)
add new byte to the buffer w/o checking for the size
Definition PayLoadCont.h:91
void fillFast(const uint8_t c, size_t n)
add n bytes to the buffer w/o checking for the size
Definition PayLoadCont.h:84
PixelReader class for the ITSMFT.
Definition PixelReader.h:34
o2::InteractionRecord mInteractionRecord
Definition PixelReader.h:73
int digits2raw(const std::vector< o2::itsmft::Digit > &digiVec, int from, int ndig, const o2::InteractionRecord &bcData, uint8_t ruSWMin=0, uint8_t ruSWMax=0xff)
================================== Encoding methods ========================
void setMinTriggersToCache(int n)
set min number of triggers to cache per frame
const GBTLinkDecodingStat * getGBTLinkDecodingStatHW(uint16_t idHW, int ruLink) const
bool getNextChipData(ChipPixelData &chipData) override
void imposeMaxPage(bool v)
CRU pages are of max size of 8KB.
int skimNextRUData(PayLoadCont &outBuffer)
uint8_t * decodeRUData(uint8_t *raw, RUDecodeData &ruDecData, bool &aborted)
int decodeNextRUData(RUDecodeData &ruDecData)
const GBTLinkDecodingStat * getGBTLinkDecodingStatSW(uint16_t idSW, int ruLink) const
const GBTLinkDecodingStat * getRUDecodingStatSW(uint16_t idSW, int ruLink=0) const
void openInput(const std::string filename)
const std::array< int, Mapping::getNRUs()> & getRUEntries() const
bool isPadding128() const
do we interpred GBT words as padded to 128 bits?
size_t cacheLinksData(PayLoadCont &buffer)
================================== Decoding methods ========================
uint8_t * skimPaddedRUData(uint8_t *raw, PayLoadCont &outBuffer, bool &aborted)
bool isMaxPageImposed() const
do we treat CRU pages as having max size?
const GBTLinkDecodingStat * getRUDecodingStatHW(uint16_t idHW, int ruLink=0) const
const RawDecodingStat & getDecodingStat() const
int getGBTWordSize() const
assumed GBT word size (accounting for eventual padding)
void convertEmptyChips(int fromChip, int uptoChip)
void convertChip(o2::itsmft::ChipPixelData &chipData)
void clear(bool resetStat=true)
bool isSameRUandTrigger(const o2::header::RAWDataHeader *rdhOld, const o2::header::RAWDataHeader *rdhNew) const
const RUDecodeData * getCurrRUDecodeData() const
int decodeAlpideData(RUDecodeData &decData)
size_t loadInput(PayLoadCont &buffer)
int flushSuperPages(int maxPages, PayLoadCont &sink, bool unusedToHead=true)
bool findNextRDH(PayLoadCont &buffer)
const std::array< RUDecodeData, Mapping::getNRUs()> & getRUDecodeVec() const
void setPadding128(bool v)
impose padding model for GBT words
RUDecodeData & getCreateRUDecode(int ruSW)
const RUDecodeData * getRUDecode(int ruSW) const
ChipPixelData * getNextChipData(std::vector< ChipPixelData > &chipDataVec) override
const GBTLink * getGBTLink(int i) const
TGeoManager * readFromFile(std::string filename)
GLdouble n
Definition glcorearb.h:1982
GLuint buffer
Definition glcorearb.h:655
const GLdouble * v
Definition glcorearb.h:832
GLboolean * data
Definition glcorearb.h:298
GLint GLint GLsizei GLint GLenum GLenum const void * pixels
Definition glcorearb.h:275
GLuint id
Definition glcorearb.h:650
constexpr int GBTPaddedWordLength
Definition GBTWord.h:56
constexpr int MaxGBTPacketBytes
constexpr int GBTWordLength
Definition GBTWord.h:55
constexpr int NCRUPagesPerSuperpage
constexpr uint32_t PhT
Definition Triggers.h:30
constexpr uint32_t SOT
Definition Triggers.h:33
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string filename()
uint16_t bc
bunch crossing ID of interaction
uint32_t orbit
bit 12 to 31: reserved
const ChipOnRUInfo * chOnRU
Definition RUInfo.h:59
std::uint16_t ru
Definition RUInfo.h:63
std::uint8_t id
Definition RUInfo.h:42
Statistics for per-link decoding.
const uint8_t * getW8() const
Definition GBTWord.h:164
uint64_t lanesStops
Definition GBTWord.h:78
void printX(bool padded=true, std::string com="") const
Definition GBTWord.cxx:21
uint64_t packetIdx
Definition GBTWord.h:70
uint64_t packetDone
56:63 reserved
Definition GBTWord.h:81
std::vector< o2::itsmft::ChipPixelData > chipsData
std::array< int, MaxLinksPerRU > links
std::array< PayLoadCont, MaxCablesPerRU > cableData
static constexpr int MaxLinksPerRU
std::array< uint8_t, MaxCablesPerRU > cableHWID
std::array< uint8_t, MaxCablesPerRU > cableLinkID
uint16_t idSW
Definition RUInfo.h:31
uint8_t nCables
Definition RUInfo.h:36
uint16_t idHW
Definition RUInfo.h:32
uint8_t ruType
Definition RUInfo.h:35
std::array< int, NErrorsDefined > errorCounts
static constexpr std::array< std::string_view, NErrorsDefined > ErrNames
void print(bool skipNoErr=true) const
ClassDefNV(RawDecodingStat, 2)
static void setLinkID(H &rdh, uint8_t v, NOTPTR(H))
Definition RDHUtils.h:256
static void setDetectorField(H &rdh, uint32_t v, NOTPTR(H))
Definition RDHUtils.h:582
static void setTriggerType(H &rdh, uint32_t v, NOTPTR(H))
Definition RDHUtils.h:523
static void setPageCounter(H &rdh, uint16_t v, NOTPTR(H))
Definition RDHUtils.h:557
static void setMemorySize(H &rdh, uint16_t v, NOTPTR(H))
Definition RDHUtils.h:240
static void printRDH(const RDHv4 &rdh)
Definition RDHUtils.cxx:26
static bool checkRDH(const RDHv4 &rdh, bool verbose=true, bool checkZeros=false)
Definition RDHUtils.cxx:133
static void setTriggerBC(RDHv4 &rdh, uint16_t v)
Definition RDHUtils.h:433
static void setTriggerOrbit(RDHv4 &rdh, uint32_t v)
Definition RDHUtils.h:467
static void setHeartBeatOrbit(RDHv4 &rdh, uint32_t v)
Definition RDHUtils.h:362
static void setFEEID(RDHv4 &rdh, uint16_t v)
Definition RDHUtils.h:146
static void setOffsetToNext(H &rdh, uint16_t v, NOTPTR(H))
Definition RDHUtils.h:224
static void setStop(H &rdh, uint8_t v, NOTPTR(H))
Definition RDHUtils.h:644
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)
vec clear()