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 break;
637 }
638 }
639 }
640
641 nlinks += decodeNextRUData(ruDecode);
642 mDecodingStat.nRUsProcessed++;
643 }
644 if (nlinks) {
645 mDecodingStat.nTriggersProcessed++;
646 }
647 mCurRUDecodeID = 0;
648 mMinTriggersCached--;
649 return nlinks;
650 }
651
652 //_____________________________________
654 {
655 // process data of single RU trigger from its links buffers
656 int minTriggers = INT_MAX;
657 int res = 0;
658 ruDecData.clear();
659 bool aborted = false;
660 for (auto linkID : ruDecData.links) { // loop over links to fill cable buffers
661 auto* link = getGBTLink(linkID);
662 if (link && !link->data.isEmpty()) {
663 link->data.setPtr(decodeRUData(link->data.getPtr(), ruDecData, aborted));
664 // we don't need to check the "abort" status since the checks for links data presence and synchronization
665 // should have been done in advance
666 if (--link->nTriggers < minTriggers) { // decrement counter of cached triggers
667 minTriggers = link->nTriggers;
668 }
669 res++;
670 if (link->data.isEmpty()) {
671 link->data.clear();
672 }
673 }
674 }
675 if (ruDecData.ruInfo->nCables) { // there are cables with data to decode
676 decodeAlpideData(ruDecData); // decode Alpide data from the compressed RU Data
677 }
678 return res;
679 }
680
681 //_____________________________________
683 {
684 // keep reading GRB words until RDH is found
685 size_t nRead = 0;
686 int scan = 0;
687 bool goodRDH = false;
688 auto ptr = buffer.getPtr();
689 o2::header::RAWDataHeader* rdh = nullptr;
690 do {
691 if (buffer.isEmpty()) {
692 auto nrl = loadInput(buffer);
693 if (!nrl) {
694 break;
695 }
696 nRead += nrl;
697 ptr = buffer.getPtr();
698 }
699 scan++;
700 ptr += mGBTWordSize;
701 buffer.setPtr(ptr);
702 if (!buffer.isEmpty()) {
703 rdh = reinterpret_cast<o2::header::RAWDataHeader*>(ptr);
704 } else {
705 break;
706 }
707 } while (!(goodRDH = RDHUtils::checkRDH(rdh)));
708 LOG(info) << "End of pointer recovery after skipping " << scan << " GBT words, RDH is"
709 << (goodRDH ? "" : " not") << " found";
710 return goodRDH;
711 }
712
713 //_____________________________________
714 uint8_t* decodeRUData(uint8_t* raw, RUDecodeData& ruDecData, bool& aborted)
715 {
721
722 aborted = false;
723
724 // data must start by RDH
725 auto rdh = reinterpret_cast<o2::header::RAWDataHeader*>(raw);
726
727#ifdef _RAW_READER_ERROR_CHECKS_
728 if (!RDHUtils::checkRDH(rdh)) {
729 LOG(error) << "Page does not start with RDH";
731 for (int i = 0; i < 4; i++) {
732 auto gbtD = reinterpret_cast<const o2::itsmft::GBTData*>(raw + i * 16);
733 gbtD->printX(mPadding128);
734 }
735 raw += mGBTWordSize;
736 aborted = true;
737 return raw;
738 }
739#endif
740
741 int ruIDSW = mMAP.FEEId2RUSW(RDHUtils::getFEEID(rdh));
742#ifdef _RAW_READER_ERROR_CHECKS_
743 if (ruIDSW >= mMAP.getNRUs()) {
744 mDecodingStat.errorCounts[RawDecodingStat::ErrInvalidFEEId]++;
745 LOG(error) << mDecodingStat.ErrNames[RawDecodingStat::ErrInvalidFEEId]
746 << " : FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << ", skipping CRU page";
748 raw += RDHUtils::getOffsetToNext(rdh);
749 return raw;
750 }
751
752 if (ruIDSW != ruDecData.ruInfo->idSW) { // should not happen with cached data
753 LOG(error) << "RDG RU IDSW " << ruIDSW << " differs from expected " << ruDecData.ruInfo->idSW;
755 }
756#endif
757
758 uint16_t lr, ruOnLr, linkIDinRU;
759 mMAP.expandFEEId(RDHUtils::getFEEID(rdh), lr, ruOnLr, linkIDinRU);
760 auto* ruLink = getGBTLink(ruDecData.links[linkIDinRU]);
761 auto& ruLinkStat = ruLink->statistics;
762 ruLink->lastRDH = reinterpret_cast<o2::header::RDHAny*>(rdh); // hack but this reader should be outphased anyway
763 ruLinkStat.nPackets++;
764
765#ifdef _RAW_READER_ERROR_CHECKS_
766 if (RDHUtils::getPacketCounter(rdh) > ruLink->packetCounter + 1) {
767 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrPacketCounterJump]++;
768 LOG(warn) << ruLinkStat.ErrNames[GBTLinkDecodingStat::ErrPacketCounterJump]
769 << " : FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << ": jump from " << int(ruLink->packetCounter)
770 << " to " << int(RDHUtils::getPacketCounter(rdh));
772 }
773#endif
774 while (1) {
775 ruLink->packetCounter = RDHUtils::getPacketCounter(rdh);
776
777 mDecodingStat.nBytesProcessed += RDHUtils::getMemorySize(rdh);
778 mDecodingStat.nPagesProcessed++;
779 raw += RDHUtils::getHeaderSize(rdh);
780 int nGBTWords = (RDHUtils::getMemorySize(rdh) - RDHUtils::getHeaderSize(rdh)) / mGBTWordSize - 2; // number of GBT words excluding header/trailer
781 auto gbtH = reinterpret_cast<const o2::itsmft::GBTDataHeaderL*>(raw); // process GBT header
782
783#ifdef _RAW_READER_ERROR_CHECKS_
784 if (mVerbose) {
786 gbtH->printX(mPadding128);
787 LOG(info) << "Expect " << nGBTWords << " GBT words";
788 }
789
790 if (!gbtH->isDataHeader()) {
791 gbtH->printX(mPadding128);
792 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " GBT payload header was expected, abort page decoding";
794 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrMissingGBTHeader]++;
795 gbtH->printX(mPadding128);
796 aborted = true;
797 return raw;
798 }
799
800 if (gbtH->packetIdx != RDHUtils::getPageCounter(rdh)) {
801 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Different GBT header " << gbtH->packetIdx
802 << " and RDH page " << RDHUtils::getPageCounter(rdh) << " counters";
804 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrRDHvsGBTHPageCnt]++;
805 }
806
807 if (ruLink->lanesActive == ruLink->lanesStop) { // all lanes received their stop, new page 0 expected
808 if (RDHUtils::getPageCounter(rdh)) { // flag lanes of this FEE
809 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Non-0 page counter (" << RDHUtils::getPageCounter(rdh) << ") while all lanes were stopped";
811 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrNonZeroPageAfterStop]++;
812 }
813 }
814
815 ruLink->lanesActive = gbtH->activeLanes; // TODO do we need to update this for every page?
816
817 if (~(mMAP.getCablesOnRUType(ruDecData.ruInfo->ruType)) & ruLink->lanesActive) { // are there wrong lanes?
818 std::bitset<32> expectL(mMAP.getCablesOnRUType(ruDecData.ruInfo->ruType)), gotL(ruLink->lanesActive);
819 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Active lanes pattern " << gotL
820 << " conflicts with expected " << expectL << " for given RU type, skip page";
822 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrInvalidActiveLanes]++;
823 raw = ((uint8_t*)rdh) + RDHUtils::getOffsetToNext(rdh); // jump to the next packet
824 return raw;
825 }
826
827 if (!RDHUtils::getPageCounter(rdh)) { // reset flags
828 ruLink->lanesStop = 0;
829 ruLink->lanesWithData = 0;
830 }
831
832#endif
833 raw += mGBTWordSize;
834 for (int iw = 0; iw < nGBTWords; iw++, raw += mGBTWordSize) {
835 auto gbtD = reinterpret_cast<const o2::itsmft::GBTData*>(raw);
836 // 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
837
838 if (mVerbose > 1) {
839 printf("W%4d |", iw);
840 gbtD->printX(mPadding128);
841 }
842 if (gbtD->isDataTrailer()) {
843 nGBTWords = iw;
844 break; // this means that the nGBTWords estimate was wrong
845 }
846
847 int cableHW = gbtD->getCableID();
848 int cableSW = mMAP.cableHW2SW(ruDecData.ruInfo->ruType, cableHW);
849 ruDecData.cableData[cableSW].add(gbtD->getW8(), 9);
850 ruDecData.cableHWID[cableSW] = cableHW;
851
852#ifdef _RAW_READER_ERROR_CHECKS_
853 int cableHWPos = mMAP.cableHW2Pos(ruDecData.ruInfo->ruType, cableHW);
854 ruDecData.cableLinkID[cableSW] = linkIDinRU;
855 ruLink->lanesWithData |= 0x1 << cableHWPos; // flag that the data was seen on this lane
856 if (ruLink->lanesStop & (0x1 << cableHWPos)) { // make sure stopped lanes do not transmit the data
857 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrDataForStoppedLane]++;
858 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Data received for stopped lane " << cableHW << " (sw:" << cableSW << ")";
860 }
861#endif
862
863 } // we are at the trailer, packet is over, check if there are more for the same ru
864
865 auto gbtT = reinterpret_cast<const o2::itsmft::GBTDataTrailer*>(raw); // process GBT trailer
866#ifdef _RAW_READER_ERROR_CHECKS_
867
868 if (mVerbose) {
869 gbtT->printX(mPadding128);
870 }
871
872 if (!gbtT->isDataTrailer()) {
873 gbtT->printX(mPadding128);
874 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << std::dec
875 << " GBT payload trailer was expected, abort page decoding NW" << nGBTWords;
877 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrMissingGBTTrailer]++;
878 aborted = true;
879 return raw;
880 }
881
882 ruLink->lanesTimeOut |= gbtT->lanesTimeout; // register timeouts
883 ruLink->lanesStop |= gbtT->lanesStops; // register stops
884#endif
885 raw += mGBTWordSize;
886 // we finished the GBT page, see if there is a continuation and if it belongs to the same multipacket
887
888 if (!RDHUtils::getOffsetToNext(rdh)) { // RS TODO: what the last page in memory will contain as offsetToNext, is it 0?
889 break;
890 }
891
892 raw = ((uint8_t*)rdh) + RDHUtils::getOffsetToNext(rdh); // jump to the next packet:
893 auto rdhN = reinterpret_cast<o2::header::RAWDataHeader*>(raw);
894 // 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
895 if (!isSameRUandTrigger(rdh, rdhN)) {
896
897#ifdef _RAW_READER_ERROR_CHECKS_
898 // make sure all lane stops for finished page are received
899 if ((ruLink->lanesActive & ~ruLink->lanesStop) && nGBTWords) {
900 if (RDHUtils::getTriggerType(rdh) != o2::trigger::SOT) { // only SOT trigger allows unstopped lanes?
901 std::bitset<32> active(ruLink->lanesActive), stopped(ruLink->lanesStop);
902 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " end of FEE data but not all lanes received stop"
903 << "| active: " << active << " stopped: " << stopped;
905 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrUnstoppedLanes]++;
906 }
907 }
908
909 // make sure all active lanes (except those in time-out) have sent some data
910 if ((~ruLink->lanesWithData & ruLink->lanesActive) != ruLink->lanesTimeOut && nGBTWords) {
911 std::bitset<32> withData(ruLink->lanesWithData), active(ruLink->lanesActive), timeOut(ruLink->lanesTimeOut);
912 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Lanes not in time-out but not sending data"
913 << "\n| with data: " << withData << " active: " << active << " timeOut: " << timeOut;
915 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrNoDataForActiveLane]++;
916 }
917#endif
918 // accumulate packet states
919 ruLinkStat.packetStates[gbtT->getPacketState()]++;
920
921 break;
922 }
923#ifdef _RAW_READER_ERROR_CHECKS_
924 // check if the page counter increases
925 if (RDHUtils::getPageCounter(rdhN) != RDHUtils::getPageCounter(rdh) + 1) {
926 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Discontinuity in the RDH page counter of the same RU trigger: old "
927 << RDHUtils::getPageCounter(rdh) << " new: " << RDHUtils::getPageCounter(rdhN);
929 RDHUtils::printRDH(rdhN);
930 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrPageCounterDiscontinuity]++;
931 }
932#endif
933 rdh = rdhN;
934 ruLink->lastRDH = reinterpret_cast<o2::header::RDHAny*>(rdh);
935 }
936
937#ifdef _RAW_READER_ERROR_CHECKS_
938// if (RDHUtils::getPageCounter(rdh) && !RDHUtils::getStop(rdh)) {
939// LOG(warning) << "Last packet(" << RDHUtils::getPageCounter(rdh) << ") of GBT multi-packet is reached w/o STOP set in the RDH";
940// }
941#endif
942
943 return raw;
944 }
945
946 //_____________________________________
948 {
949 if (mIOFile) {
950 loadInput(mRawBuffer); // if needed, upload additional data to the buffer
951 }
952
953 int res = 0;
954 if (!mRawBuffer.isEmpty()) {
955 bool aborted = false;
956
957 auto ptr = skimPaddedRUData(mRawBuffer.getPtr(), outBuffer, aborted);
958 mDecodingStat.nRUsProcessed++;
959 if (!aborted) {
960 mRawBuffer.setPtr(ptr);
961 res = 1; // success
962 if (mRawBuffer.isEmpty()) {
963 mRawBuffer.clear();
964 }
965 } else { // try to seek to the next RDH, can be done only for 128b padded GBT words
966 if (findNextRDH(mRawBuffer)) {
967 ptr = mRawBuffer.getPtr();
968 res = 1;
969 } else {
970 mRawBuffer.clear(); // did not find new RDH
971 }
972 } // try to seek to the next ...
973 }
974 return res;
975 }
976
977 //_____________________________________
978 uint8_t* skimPaddedRUData(uint8_t* raw, PayLoadCont& outBuffer, bool& aborted)
979 {
982
983 aborted = false;
984
985 // data must start by RDH
986 auto rdh = reinterpret_cast<o2::header::RAWDataHeader*>(raw);
987#ifdef _RAW_READER_ERROR_CHECKS_
988 if (!RDHUtils::checkRDH(rdh)) {
989 LOG(error) << "Page does not start with RDH";
991 for (int i = 0; i < 4; i++) {
992 auto gbtD = reinterpret_cast<const o2::itsmft::GBTData*>(raw + i * 16);
993 gbtD->printX(mPadding128);
994 }
995 aborted = true;
996 return raw;
997 }
998 int ruIDSWD = mMAP.FEEId2RUSW(RDHUtils::getFEEID(rdh));
999 if (ruIDSWD >= mMAP.getNRUs()) {
1000 mDecodingStat.errorCounts[RawDecodingStat::ErrInvalidFEEId]++;
1001 LOG(error) << mDecodingStat.ErrNames[RawDecodingStat::ErrInvalidFEEId]
1002 << " : FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << ", skipping CRU page";
1003 RDHUtils::printRDH(rdh);
1004 raw += RDHUtils::getOffsetToNext(rdh);
1005 return raw;
1006 }
1007#endif
1008 uint16_t lr, ruOnLr, linkIDinRU;
1009 mMAP.expandFEEId(RDHUtils::getFEEID(rdh), lr, ruOnLr, linkIDinRU);
1010 int ruIDSW = mMAP.FEEId2RUSW(RDHUtils::getFEEID(rdh));
1011 auto& ruDecode = getCreateRUDecode(ruIDSW);
1012 auto ruInfo = mMAP.getRUInfoSW(ruIDSW);
1013
1014 if (ruDecode.links[linkIDinRU] < 0) {
1015 ruDecode.links[linkIDinRU] = addGBTLink();
1016 getGBTLink(ruDecode.links[linkIDinRU])->statistics.feeID = RDHUtils::getFEEID(rdh);
1017 mNLinks++;
1018 }
1019
1020 mInteractionRecord = RDHUtils::getTriggerIR(rdh);
1021
1022 mTrigger = RDHUtils::getTriggerType(rdh);
1023
1024 auto ruLink = getGBTLink(ruDecode.links[linkIDinRU]);
1025 auto& ruLinkStat = ruLink->statistics;
1026 ruLink->lastRDH = reinterpret_cast<o2::header::RDHAny*>(rdh); // hack but this reader should be outphased anyway
1027 ruLinkStat.nPackets++;
1028
1029#ifdef _RAW_READER_ERROR_CHECKS_
1030 if (RDHUtils::getPacketCounter(rdh) > ruLink->packetCounter + 1) {
1031 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrPacketCounterJump]++;
1032 LOG(warn) << ruLinkStat.ErrNames[GBTLinkDecodingStat::ErrPacketCounterJump]
1033 << " : FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << ": jump from " << int(ruLink->packetCounter)
1034 << " to " << int(RDHUtils::getPacketCounter(rdh));
1035 RDHUtils::printRDH(rdh);
1036 }
1037#endif
1038 ruLink->packetCounter = RDHUtils::getPacketCounter(rdh);
1039
1040 int sizeAtEntry = outBuffer.getSize(); // save the size of outbuffer size at entry, in case of severe error we will need to rewind to it.
1041
1042 while (1) {
1043 mDecodingStat.nPagesProcessed++;
1044 mDecodingStat.nBytesProcessed += RDHUtils::getMemorySize(rdh);
1045 raw += RDHUtils::getHeaderSize(rdh);
1046 // number of 128 b GBT words excluding header/trailer
1047 int nGBTWords = (RDHUtils::getMemorySize(rdh) - RDHUtils::getHeaderSize(rdh)) / o2::itsmft::GBTPaddedWordLength - 2;
1048 auto gbtH = reinterpret_cast<const o2::itsmft::GBTDataHeaderL*>(raw); // process GBT header
1049
1050#ifdef _RAW_READER_ERROR_CHECKS_
1051 if (mVerbose) {
1052 RDHUtils::printRDH(rdh);
1053 gbtH->printX(true);
1054 LOG(info) << "Expect " << nGBTWords << " GBT words";
1055 }
1056 if (!gbtH->isDataHeader()) {
1057 gbtH->printX(true);
1058 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " GBT payload header was expected, abort page decoding";
1059 RDHUtils::printRDH(rdh);
1060 gbtH->printX(true);
1061 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrMissingGBTHeader]++;
1062 aborted = true;
1063 outBuffer.shrinkToSize(sizeAtEntry); // reset output buffer to initial state
1064 return raw;
1065 }
1066 if (gbtH->packetIdx != RDHUtils::getPageCounter(rdh)) {
1067 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Different GBT header " << gbtH->packetIdx
1068 << " and RDH page " << RDHUtils::getPageCounter(rdh) << " counters";
1069 RDHUtils::printRDH(rdh);
1070 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrRDHvsGBTHPageCnt]++;
1071 }
1072
1073 if (ruLink->lanesActive == ruLink->lanesStop) { // all lanes received their stop, new page 0 expected
1074 if (RDHUtils::getPageCounter(rdh)) { // flag lanes of this FEE
1075 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Non-0 page counter (" << RDHUtils::getPageCounter(rdh) << ") while all lanes were stopped";
1076 RDHUtils::printRDH(rdh);
1077 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrNonZeroPageAfterStop]++;
1078 }
1079 }
1080
1081 ruLink->lanesActive = gbtH->activeLanes; // TODO do we need to update this for every page?
1082
1083 if (!RDHUtils::getPageCounter(rdh)) { // reset flags
1084 ruLink->lanesStop = 0;
1085 ruLink->lanesWithData = 0;
1086 }
1087
1088#endif
1089 // start writting skimmed data for this page, making sure the buffer has enough free slots
1090 outBuffer.ensureFreeCapacity(8 * 1024);
1091 auto rdhS = reinterpret_cast<o2::header::RAWDataHeader*>(outBuffer.getEnd()); // save RDH and make saved copy editable
1092 outBuffer.addFast(reinterpret_cast<const uint8_t*>(rdh), RDHUtils::getHeaderSize(rdh));
1093
1094 outBuffer.addFast(reinterpret_cast<const uint8_t*>(gbtH), mGBTWordSize); // save gbt header w/o 128b padding
1095
1097 for (int iw = 0; iw < nGBTWords; iw++, raw += o2::itsmft::GBTPaddedWordLength) {
1098 auto gbtD = reinterpret_cast<const o2::itsmft::GBTData*>(raw);
1099 // 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
1100
1101 if (mVerbose > 1) {
1102 printf("W%4d |", iw);
1103 gbtD->printX(mPadding128);
1104 }
1105 if (gbtD->isDataTrailer()) {
1106 nGBTWords = iw;
1107 break; // this means that the nGBTWords estimate was wrong
1108 }
1109
1110 int cableHW = gbtD->getCableID();
1111 int cableSW = mMAP.cableHW2SW(ruInfo->ruType, cableHW);
1112
1113 outBuffer.addFast(reinterpret_cast<const uint8_t*>(gbtD), mGBTWordSize); // save gbt word w/o 128b padding
1114
1115#ifdef _RAW_READER_ERROR_CHECKS_
1116 int cableHWPos = mMAP.cableHW2Pos(ruInfo->ruType, cableHW);
1117 ruLink->lanesWithData |= 0x1 << cableHWPos; // flag that the data was seen on this lane
1118 if (ruLink->lanesStop & (0x1 << cableHWPos)) { // make sure stopped lanes do not transmit the data
1119 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrDataForStoppedLane]++;
1120 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Data received for stopped lane " << cableHW << " (sw:" << cableSW << ")";
1121 RDHUtils::printRDH(rdh);
1122 }
1123#endif
1124
1125 } // we are at the trailer, packet is over, check if there are more for the same ru
1126
1127 auto gbtT = reinterpret_cast<const o2::itsmft::GBTDataTrailer*>(raw); // process GBT trailer
1128#ifdef _RAW_READER_ERROR_CHECKS_
1129
1130 if (mVerbose) {
1131 gbtT->printX(true);
1132 }
1133
1134 if (!gbtT->isDataTrailer()) {
1135 gbtT->printX(true);
1136 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " GBT payload trailer was expected, abort page decoding at NW" << nGBTWords;
1137 RDHUtils::printRDH(rdh);
1138 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrMissingGBTTrailer]++;
1139 aborted = true;
1140 outBuffer.shrinkToSize(sizeAtEntry); // reset output buffer to initial state
1141 return raw;
1142 }
1143
1144 ruLink->lanesTimeOut |= gbtT->lanesTimeout; // register timeouts
1145 ruLink->lanesStop |= gbtT->lanesStops; // register stops
1146#endif
1147
1148 outBuffer.addFast(reinterpret_cast<const uint8_t*>(gbtT), mGBTWordSize); // save gbt trailer w/o 128b padding
1149
1151
1152 // we finished the GBT page, register in the stored RDH the memory size and new offset
1153 RDHUtils::setMemorySize(rdhS, RDHUtils::getHeaderSize(rdhS) + (2 + nGBTWords) * mGBTWordSize);
1154 RDHUtils::setOffsetToNext(rdhS, RDHUtils::getMemorySize(rdhS));
1155
1156 if (!RDHUtils::getOffsetToNext(rdh)) { // RS TODO: what the last page in memory will contain as offsetToNext, is it 0?
1157 break;
1158 }
1159
1160 raw = ((uint8_t*)rdh) + RDHUtils::getOffsetToNext(rdh); // jump to the next packet:
1161 auto rdhN = reinterpret_cast<o2::header::RAWDataHeader*>(raw);
1162 // 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
1163 if (!isSameRUandTrigger(rdh, rdhN)) {
1164
1165#ifdef _RAW_READER_ERROR_CHECKS_
1166 // make sure all lane stops for finished page are received
1167 if (ruLink->lanesActive != ruLink->lanesStop && nGBTWords) {
1168 if (RDHUtils::getTriggerType(rdh) != o2::trigger::SOT) { // only SOT trigger allows unstopped lanes?
1169 std::bitset<32> active(ruLink->lanesActive), stopped(ruLink->lanesStop);
1170 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " end of FEE data but not all lanes received stop"
1171 << "| active: " << active << " stopped: " << stopped;
1172 RDHUtils::printRDH(rdh);
1173 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrUnstoppedLanes]++;
1174 }
1175 }
1176
1177 // make sure all active lanes (except those in time-out) have sent some data
1178 if ((~ruLink->lanesWithData & ruLink->lanesActive) != ruLink->lanesTimeOut && nGBTWords) {
1179 std::bitset<32> withData(ruLink->lanesWithData), active(ruLink->lanesActive), timeOut(ruLink->lanesTimeOut);
1180 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Lanes not in time-out but not sending data"
1181 << "| with data: " << withData << " active: " << active << " timeOut: " << timeOut;
1182 RDHUtils::printRDH(rdh);
1183 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrNoDataForActiveLane]++;
1184 }
1185
1186 // accumulate packet states
1187 ruLinkStat.packetStates[gbtT->getPacketState()]++;
1188#endif
1189
1190 break;
1191 }
1192#ifdef _RAW_READER_ERROR_CHECKS_
1193 // check if the page counter increases
1194 if (RDHUtils::getPageCounter(rdhN) != RDHUtils::getPageCounter(rdh) + 1) {
1195 LOG(error) << "FEEId:" << OUTHEX(RDHUtils::getFEEID(rdh), 4) << " Discontinuity in the RDH page counter of the same RU trigger: old "
1196 << RDHUtils::getPageCounter(rdh) << " new: " << RDHUtils::getPageCounter(rdhN);
1197 RDHUtils::printRDH(rdh);
1198 RDHUtils::printRDH(rdhN);
1199 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrPageCounterDiscontinuity]++;
1200 }
1201#endif
1202 rdh = rdhN;
1203 ruLink->lastRDH = reinterpret_cast<o2::header::RDHAny*>(rdh); // hack but this reader should be outphased anyway
1204 }
1205
1206#ifdef _RAW_READER_ERROR_CHECKS_
1207// if (RDHUtils::getPageCounter(rdh) && !RDHUtils::getStop(rdh)) {
1208// LOG(warning) << "Last packet(" << RDHUtils::getPageCounter(rdh) << ") of GBT multi-packet is reached w/o STOP set in the RDH";
1209// }
1210#endif
1211
1212 return raw;
1213 }
1214
1215 //_____________________________________
1217 {
1219 if (RDHUtils::getPageCounter(rdhNew) == 0 || RDHUtils::getFEEID(rdhNew) != RDHUtils::getFEEID(rdhOld) ||
1220 RDHUtils::getTriggerIR(rdhNew) != RDHUtils::getTriggerIR(rdhOld) ||
1221 RDHUtils::getHeartBeatIR(rdhNew) != RDHUtils::getHeartBeatIR(rdhOld) ||
1222 !(RDHUtils::getTriggerType(rdhNew) & RDHUtils::getTriggerType(rdhOld))) {
1223 return false;
1224 }
1225 return true;
1226 }
1227
1228 //_____________________________________
1230 {
1232
1233 auto* chipData = &decData.chipsData[0];
1234
1235 decData.nChipsFired = decData.lastChipChecked = 0;
1236 int ntot = 0;
1237 for (int icab = 0; icab < decData.ruInfo->nCables; icab++) {
1238 auto& cableData = decData.cableData[icab];
1239 int res = 0;
1240
1241#ifdef _RAW_READER_ERROR_CHECKS_
1242 auto& ruLinkStat = getGBTLink(decData.links[decData.cableLinkID[icab]])->statistics;
1243
1244 // make sure the lane data starts with chip header or empty chip
1245 uint8_t h;
1246 if (cableData.current(h) && !mCoder.isChipHeaderOrEmpty(h)) {
1247 LOG(error) << "FEEId:" << OUTHEX(decData.ruInfo->idHW, 4) << " cable " << icab
1248 << " data does not start with ChipHeader or ChipEmpty";
1249 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrCableDataHeadWrong]++;
1250 RDHUtils::printRDH(reinterpret_cast<const o2::header::RAWDataHeader*>(getGBTLink(decData.links[decData.cableLinkID[icab]])->lastRDH));
1251 }
1252#endif
1253 auto cabHW = decData.cableHWID[icab];
1254 auto ri = decData.ruInfo;
1255 auto chIdGetter = [this, cabHW, ri](int cid) {
1256 return this->mMAP.getGlobalChipID(cid, cabHW, *ri);
1257 };
1258 std::vector<uint16_t> dummyStat;
1259 while ((res = mCoder.decodeChip(*chipData, cableData, dummyStat, chIdGetter))) { // we register only chips with hits or errors flags set
1260 if (res > 0) {
1261#ifdef _RAW_READER_ERROR_CHECKS_
1262 // for the IB staves check if the cable ID is the same as the chip ID on the module
1263 if (mMAP.getName() == "ITS" && decData.ruInfo->ruType == 0) { // ATTENTION: this is a hack tailored for temporary check
1264 if (chipData->getChipID() != icab) {
1265 LOG(error) << "FEEId:" << OUTHEX(decData.ruInfo->idHW, 4) << " IB cable " << icab
1266 << " shipped chip ID= " << chipData->getChipID();
1267 ruLinkStat.errorCounts[GBTLinkDecodingStat::ErrIBChipLaneMismatch]++;
1268 RDHUtils::printRDH(reinterpret_cast<const o2::header::RAWDataHeader*>(getGBTLink(decData.links[decData.cableLinkID[icab]])->lastRDH));
1269 }
1270 }
1271#endif
1272 // convert HW chip id within the module to absolute chip id
1273 // chipData->setChipID(mMAP.getGlobalChipID(chipData->getChipID(), decData.cableHWID[icab], *decData.ruInfo));
1274 chipData->setInteractionRecord(mInteractionRecord);
1275 chipData->setTrigger(mTrigger);
1276 mDecodingStat.nNonEmptyChips++;
1277 mDecodingStat.nHitsDecoded += chipData->getData().size();
1278 ntot += res;
1279 // fetch next free chip
1280 if (++decData.nChipsFired < int(decData.chipsData.size())) {
1281 chipData = &decData.chipsData[decData.nChipsFired];
1282 } else {
1283 break; // last chip decoded
1284 }
1285 }
1286 }
1287 }
1288 return ntot;
1289 }
1290
1291 //_____________________________________
1292 bool getNextChipData(ChipPixelData& chipData) override
1293 {
1295
1296 if (mCurRUDecodeID >= 0) { // make sure current RU has fired chips to extract
1297 for (; mCurRUDecodeID < mNRUs; mCurRUDecodeID++) {
1298 auto& ru = mRUDecodeVec[mCurRUDecodeID];
1299 if (ru.lastChipChecked < ru.nChipsFired) {
1300 chipData.swap(ru.chipsData[ru.lastChipChecked++]);
1301 return true;
1302 }
1303 }
1304 mCurRUDecodeID = 0; // no more decoded data if reached this place,
1305 }
1306
1307 // will need to decode new trigger
1308 if (!mDecodeNextAuto) { // no more data in the current ROF and no automatic decoding of next one was requested
1309 return false;
1310 }
1311
1312 if (mMinTriggersCached < 2) { // last trigger might be incomplete, need to cache more data
1313 cacheLinksData(mRawBuffer);
1314 }
1315 if (mMinTriggersCached < 1 || !decodeNextTrigger()) {
1316 mCurRUDecodeID = -1;
1317 return false; // nothing left
1318 }
1319 return getNextChipData(chipData); // is it ok to use recursion here?
1320 }
1321
1322 //_____________________________________
1323 void openInput(const std::string filename)
1324 {
1325 // open input for raw data decoding from file
1326 mSWIO.Stop();
1327 mSWIO.Start();
1328 clear(false); // do not reset statistics
1329 LOG(info) << "opening raw data input file " << filename;
1330 mIOFile.open(filename.c_str(), std::ifstream::binary);
1331 assert(mIOFile.good());
1332 mRawBuffer.clear();
1333 mRawBuffer.expand(RawBufferSize);
1334 mSWIO.Stop();
1335 }
1336
1337 //_____________________________________
1339 {
1341 static_assert(RawBufferMargin > MaxGBTPacketBytes * 100 &&
1342 RawBufferSize > 3 * RawBufferMargin,
1343 "raw buffer size is too small");
1344
1345 if (!mIOFile) {
1346 return 0;
1347 }
1348 if (buffer.getUnusedSize() > RawBufferMargin) { // bytes read but not used yet are enough
1349 return 0;
1350 }
1351 mSWIO.Start(false);
1352 auto readFromFile = [this](uint8_t* ptr, int n) {
1353 mIOFile.read(reinterpret_cast<char*>(ptr), n);
1354 return mIOFile.gcount(); // fread( ptr, sizeof(uint8_t), n, mIOFile);
1355 };
1356 auto nread = buffer.append(readFromFile);
1357 mSWIO.Stop();
1358 return nread;
1359 }
1360
1361 // get statics of FEE with sequential idSW
1362 const GBTLinkDecodingStat* getGBTLinkDecodingStatSW(uint16_t idSW, int ruLink) const
1363 {
1364 if (mRUEntry[idSW] < 0 || ruLink >= RUDecodeData::MaxLinksPerRU || mRUDecodeVec[mRUEntry[idSW]].links[ruLink] < 0) {
1365 return nullptr;
1366 } else {
1367 return &getGBTLink(mRUDecodeVec[mRUEntry[idSW]].links[ruLink])->statistics;
1368 }
1369 }
1370
1371 // get statics of FEE with given HW id
1372 const GBTLinkDecodingStat* getGBTLinkDecodingStatHW(uint16_t idHW, int ruLink) const
1373 {
1374 int idsw = mMAP.FEEId2RUSW(idHW);
1375 assert(idsw != 0xffff);
1376 return getGBTLinkDecodingStatSW(idsw, ruLink);
1377 }
1378
1379 // aliases for BWD compatibility
1380 const GBTLinkDecodingStat* getRUDecodingStatSW(uint16_t idSW, int ruLink = 0) const { return getGBTLinkDecodingStatSW(idSW, ruLink); }
1381 const GBTLinkDecodingStat* getRUDecodingStatHW(uint16_t idHW, int ruLink = 0) const { return getGBTLinkDecodingStatHW(idHW, ruLink); }
1382
1383 // get global decoding statistics
1384 const RawDecodingStat& getDecodingStat() const { return mDecodingStat; }
1385
1386 void setVerbosity(int v) { mVerbose = v; }
1387 int getVerbosity() const { return mVerbose; }
1388
1389 Mapping& getMapping() { return mMAP; }
1390
1391 // get currently processed RU container
1392 const RUDecodeData* getCurrRUDecodeData() const { return mCurRUDecodeID < 0 ? nullptr : &mRUDecodeVec[mCurRUDecodeID]; }
1393
1394 PayLoadCont& getRawBuffer() { return mRawBuffer; }
1395
1396 // number of links seen in the data
1397 int getNLinks() const { return mNLinks; }
1398
1399 // number of RUs seen in the data
1400 int getNRUs() const { return mNRUs; }
1401
1402 // get vector of RU decode containers for RUs seen in the data
1403 const std::array<RUDecodeData, Mapping::getNRUs()>& getRUDecodeVec() const { return mRUDecodeVec; }
1404
1405 const std::array<int, Mapping::getNRUs()>& getRUEntries() const { return mRUEntry; }
1406
1407 // get RU decode container for RU with given SW ID
1408 const RUDecodeData* getRUDecode(int ruSW) const
1409 {
1410 return mRUEntry[ruSW] < 0 ? nullptr : &mRUDecodeVec[mRUEntry[ruSW]];
1411 }
1412
1413 // get RU decode container for RU with given SW ID, if does not exist, create it
1415 {
1416 assert(ruSW < mMAP.getNRUs());
1417 if (mRUEntry[ruSW] < 0) {
1418 mRUEntry[ruSW] = mNRUs++;
1419 mRUDecodeVec[mRUEntry[ruSW]].ruInfo = mMAP.getRUInfoSW(ruSW); // info on the stave/RU
1420 mRUDecodeVec[mRUEntry[ruSW]].chipsData.resize(mMAP.getNChipsOnRUType(mMAP.getRUInfoSW(ruSW)->ruType));
1421 LOG(info) << "Defining container for RU " << ruSW << " at slot " << mRUEntry[ruSW];
1422 }
1423 return mRUDecodeVec[mRUEntry[ruSW]];
1424 }
1425
1426 // create new gbt link
1428 {
1429 int sz = mGBTLinks.size();
1430 mGBTLinks.emplace_back();
1431 return sz;
1432 }
1433
1434 // get the link
1435 GBTLink* getGBTLink(int i) { return i < 0 ? nullptr : &mGBTLinks[i]; }
1436 const GBTLink* getGBTLink(int i) const { return i < 0 ? nullptr : &mGBTLinks[i]; }
1437
1438 private:
1439 std::ifstream mIOFile;
1440 Coder mCoder;
1441 Mapping mMAP;
1442 int mVerbose = 0;
1443 int mCurRUDecodeID = -1;
1444
1445 PayLoadCont mRawBuffer;
1446
1447 std::array<RUDecodeData, Mapping::getNRUs()> mRUDecodeVec; // decoding buffers for all active RUs
1448 std::array<int, Mapping::getNRUs()> mRUEntry;
1449 std::vector<GBTLink> mGBTLinks;
1450 int mNRUs = 0;
1451 int mNLinks = 0;
1452
1454 int mMinTriggersToCache = NCRUPagesPerSuperpage + 10;
1455 int mMinTriggersCached = 0;
1456
1457 // statistics
1458 RawDecodingStat mDecodingStat;
1459
1460 TStopwatch mSWIO;
1461 TStopwatch mSWCache;
1462
1463 static constexpr int RawBufferMargin = 5000000; // keep uploaded at least this amount
1464 static constexpr int RawBufferSize = 10000000 + 2 * RawBufferMargin; // size in MB
1465 bool mPadding128 = true; // is payload padded to 128 bits
1466 bool mImposeMaxPage = true; // standard CRU data comes in 8KB pages
1467 // number of bytes the GBT word, including optional padding to 128 bits
1468 int mGBTWordSize = mPadding128 ? o2::itsmft::GBTPaddedWordLength : o2::itsmft::GBTWordLength;
1469
1470 ClassDefOverride(RawPixelReader, 1);
1471};
1472
1473template <class Mapping>
1474constexpr int RawPixelReader<Mapping>::RawBufferMargin;
1475
1476template <class Mapping>
1477constexpr int RawPixelReader<Mapping>::RawBufferSize;
1478
1479} // namespace itsmft
1480} // namespace o2
1481
1482#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
o2::raw::RawFileWriter * raw
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:68
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:258
static void setDetectorField(H &rdh, uint32_t v, NOTPTR(H))
Definition RDHUtils.h:584
static void setTriggerType(H &rdh, uint32_t v, NOTPTR(H))
Definition RDHUtils.h:525
static void setPageCounter(H &rdh, uint16_t v, NOTPTR(H))
Definition RDHUtils.h:559
static void setMemorySize(H &rdh, uint16_t v, NOTPTR(H))
Definition RDHUtils.h:242
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:435
static void setTriggerOrbit(RDHv4 &rdh, uint32_t v)
Definition RDHUtils.h:469
static void setHeartBeatOrbit(RDHv4 &rdh, uint32_t v)
Definition RDHUtils.h:364
static void setFEEID(RDHv4 &rdh, uint16_t v)
Definition RDHUtils.h:148
static void setOffsetToNext(H &rdh, uint16_t v, NOTPTR(H))
Definition RDHUtils.h:226
static void setStop(H &rdh, uint8_t v, NOTPTR(H))
Definition RDHUtils.h:646
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)
vec clear()