Project
Loading...
Searching...
No Matches
GBTLink.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
15#ifndef _ALICEO2_ITSMFT_GBTLINK_H_
16#define _ALICEO2_ITSMFT_GBTLINK_H_
17
18#define _RAW_READER_ERROR_CHECKS_ // comment this to disable error checking
19
20#include <string>
21#include <memory>
22#include <gsl/gsl>
33
34#define GBTLINK_DECODE_ERRORCHECK(errRes, errEval) \
35 errRes = errEval; \
36 if ((errRes)&uint8_t(ErrorPrinted)) { \
37 ruPtr->linkHBFToDump[(uint64_t(subSpec) << 32) + hbfEntry] = irHBF.orbit; \
38 errRes &= ~uint8_t(ErrorPrinted); \
39 } \
40 if ((errRes)&uint8_t(Abort)) { \
41 discardData(); \
42 return (status = AbortedOnError); \
43 }
44
45namespace o2
46{
47namespace itsmft
48{
49
50struct RUDecodeData; // forward declaration to allow its linking in the GBTlink
51struct GBTHeader;
52struct GBTTrailer;
53struct GBTTrigger;
54
56struct GBTLink {
57
61
62 enum RawDataDumps : int { DUMP_NONE, // no raw data dumps on error
63 DUMP_HBF, // dump HBF for FEEID with error
64 DUMP_TF, // dump whole TF at error
66
67 enum CollectedDataStatus : int8_t { None,
72 CachedDataExist }; // None is set before starting collectROFCableData
73
74 enum ErrorType : uint8_t { NoError = 0x0,
75 Warning = 0x1,
76 Skip = 0x2,
77 Abort = 0x4,
78 ErrorPrinted = 0x1 << 7 };
79
80 enum Verbosity : int8_t { Silent = -1,
85
88 static constexpr int CRUPageAlignment = 16; // use such alignment (in bytes) for CRU pages
90 CollectedDataStatus statusInTF = None; // this link was seen or not in the TF or its data were exhausted
91
93 std::vector<PhysTrigger>* extTrigVec = nullptr;
94 uint8_t idInRU = 0; // link ID within the RU
95 uint8_t idInCRU = 0; // link ID within the CRU
96 uint8_t endPointID = 0; // endpoint ID of the CRU
97 bool gbtErrStatUpadated = false;
98 uint16_t cruID = 0; // CRU ID
99 uint16_t feeID = 0; // FEE ID
100 uint16_t channelID = 0; // channel ID in the reader input
101 uint16_t lastPageSize = 0; // size of the last CRU page
102 uint32_t lanes = 0; // lanes served by this link
103 uint32_t subSpec = 0; // link subspec
104 // RS do we need this >> ? // Legacy from old data format encoder
105 int nTriggers = 0; // number of triggers loaded (the last one might be incomplete)
106 // << ?
107
108 PayLoadCont data; // data buffer used for encoding
109
110 // transient data filled from current RDH
111 int wordLength = o2::itsmft::GBTPaddedWordLength; // padded (16bytes) vs non-padded (10bytes) words
112 bool alwaysParseTrigger = false;
113 bool expectPadding = true;
114 bool rofJumpWasSeen = false; // this link had jump in ROF IR
115 uint32_t lanesActive = 0; // lanes declared by the payload header
116 uint32_t lanesStop = 0; // lanes received stop in the payload trailer
117 uint32_t lanesTimeOut = 0; // lanes received timeout
118 uint32_t lanesWithData = 0; // lanes with data transmitted
119 int32_t packetCounter = -1; // current packet counter from RDH (RDH.packetCounter)
120 uint32_t trigger = 0; // trigger word
121 uint32_t errorBits = 0; // bits of the error code of last frame decoding (if any)
122 uint32_t hbfEntry = 0; // entry of the current HBF page in the rawData SG list
123 const RDH* lastRDH = nullptr;
125 o2::InteractionRecord ir; // interaction record of the ROF
126 o2::InteractionRecord irHBF; // interaction record of the HBF
127 GBTLinkDecodingStat statistics; // link decoding statistics
128 ChipStat chipStat; // chip decoding statistics
129 RUDecodeData* ruPtr = nullptr; // pointer on the parent RU
130
131 PayLoadSG rawData; // scatter-gatter buffer for cached CRU pages, each starting with RDH
132 size_t dataOffset = 0; //
133 //------------------------------------------------------------------------
134
135 GBTLink() = default;
136 GBTLink(uint16_t _cru, uint16_t _fee, uint8_t _ep, uint8_t _idInCru = 0, uint16_t _chan = 0);
137 std::string describe() const;
138 void clear(bool resetStat = true, bool resetTFRaw = false);
139
140 template <class Mapping>
142
143 void cacheData(const void* ptr, size_t sz)
144 {
145 rawData.add(reinterpret_cast<const PayLoadSG::DataType*>(ptr), sz);
146 if (verbosity >= VerboseRawDump) {
147
148 LOGP(info, "Caching new RDH block for {}", describe());
149 const auto* rdh = reinterpret_cast<const RDH*>(ptr);
150 if (!rdh) {
151 return;
152 }
154 long szd = RDHUtils::getMemorySize(*rdh);
155 long offs = sizeof(RDH);
156 char* ptrR = ((char*)ptr) + sizeof(RDH);
157 while (offs < szd) {
158 const GBTWord* w = reinterpret_cast<const o2::itsmft::GBTWord*>(ptrR);
159 std::string com = fmt::format(" | FeeID:{:#06x} offs: {:6} ", feeID, offs);
160 if (w->isData()) {
161 com += "data word";
162 } else if (w->isDataHeader()) {
163 com += "data header";
164 } else if (w->isDataTrailer()) {
165 com += "data trailer";
166 } else if (w->isTriggerWord()) {
167 const GBTTrigger* trw = (const GBTTrigger*)w;
168 com += fmt::format("trigger word bc:{} orbit:{} noData:{} int:{} cont:{}", trw->bc, trw->orbit, trw->noData, trw->internal, trw->continuation);
169 } else if (w->isDiagnosticWord()) {
170 com += "diag word";
171 } else if (w->isCalibrationWord()) {
172 com += fmt::format("calib word count:{:5} data:{:#08x}", ((const GBTCalibration*)w)->calibCounter, ((const GBTCalibration*)w)->calibUserField);
173 } else if (w->isCableDiagnostic()) {
174 com += "cable diag word";
175 } else if (w->isStatus()) {
176 com += "status word";
177 }
178 w->printX(expectPadding, com);
179 offs += wordLength;
180 ptrR += wordLength;
181 }
182 }
183 }
184
185 bool needToPrintError(uint32_t count) { return verbosity == Silent ? false : (verbosity > VerboseErrors || count == 1); }
187
188 private:
189 void discardData() { rawData.setDone(); }
190 void printTrigger(const GBTTrigger* gbtTrg, int offs);
191 void printHeader(const GBTDataHeader* gbtH, int offs);
192 void printHeader(const GBTDataHeaderL* gbtH, int offs);
193 void printTrailer(const GBTDataTrailer* gbtT, int offs);
194 void printDiagnostic(const GBTDiagnostic* gbtD, int offs);
195 void printCableDiagnostic(const GBTCableDiagnostic* gbtD);
196 void printCalibrationWord(const GBTCalibration* gbtCal, int offs);
197 void printCableStatus(const GBTCableStatus* gbtS);
198 bool nextCRUPage();
199
200 bool isAlignmentPadding()
201 {
202 if ((!expectPadding) && // page alignment padding is expected only for GBT words w/o padding
203 (currRawPiece->data[dataOffset] == 0xff) && //
205 return (((dataOffset + GBTWordLength) <= lastPageSize) && currRawPiece->data[dataOffset + GBTWordLength - 1] != 0xff) ? false : true;
206 }
207 return false;
208 }
209
210#ifndef _RAW_READER_ERROR_CHECKS_ // define dummy inline check methods, will be compiled out
211 bool checkErrorsRDH(const RDH& rdh) const
212 {
213 return true;
214 }
215 uint8_t checkErrorsAlignmentPadding() const { return NoError; }
216 uint8_t checkErrorsRDHStop(const RDH& rdh) const { return NoError; }
217 uint8_t checkErrorsRDHStopPageEmpty(const RDH& rdh) const { return NoError; }
218 uint8_t checkErrorsTriggerWord(const GBTTrigger* gbtTrg) const { return NoError; }
219 uint8_t checkErrorsHeaderWord(const GBTDataHeader* gbtH) const { return NoError; }
220 uint8_t checkErrorsHeaderWord(const GBTDataHeaderL* gbtH) const { return NoError; }
221 uint8_t checkErrorsActiveLanes(int cables) const { return NoError; }
222 uint8_t checkErrorsGBTData(int cablePos) const { return NoError; }
223 uint8_t checkErrorsTrailerWord(const GBTDataTrailer* gbtT) const { return NoError; }
224 uint8_t checkErrorsPacketDoneMissing(const GBTDataTrailer* gbtT, bool notEnd) const { return NoError; }
225 uint8_t checkErrorsLanesStops() const { return NoError; }
226 uint8_t checkErrorsDiagnosticWord(const GBTDiagnostic* gbtD) const { return NoError; }
227 uint8_t checkErrorsCalibrationWord(const GBTCalibration* gbtCal) const { return NoError; }
228 uint8_t checkErrorsCableID(const GBTData* gbtD, uint8_t cableSW) const { return NoError; }
229 uint8_t checkErrorsIRNotExtracted() const { return NoError; }
230
231#else
232 uint8_t checkErrorsAlignmentPadding();
233 uint8_t checkErrorsRDH(const RDH& rdh);
234 uint8_t checkErrorsRDHStop(const RDH& rdh);
235 uint8_t checkErrorsRDHStopPageEmpty(const RDH& rdh);
236 uint8_t checkErrorsTriggerWord(const GBTTrigger* gbtTrg);
237 uint8_t checkErrorsHeaderWord(const GBTDataHeader* gbtH);
238 uint8_t checkErrorsHeaderWord(const GBTDataHeaderL* gbtH);
239 uint8_t checkErrorsActiveLanes(int cables);
240 uint8_t checkErrorsGBTData(int cablePos);
241 uint8_t checkErrorsTrailerWord(const GBTDataTrailer* gbtT);
242 uint8_t checkErrorsPacketDoneMissing(const GBTDataTrailer* gbtT, bool notEnd);
243 uint8_t checkErrorsLanesStops();
244 uint8_t checkErrorsDiagnosticWord(const GBTDiagnostic* gbtD);
245 uint8_t checkErrorsCalibrationWord(const GBTCalibration* gbtCal);
246 uint8_t checkErrorsCableID(const GBTData* gbtD, uint8_t cableSW);
247 uint8_t checkErrorsIRNotExtracted();
248
249#endif
250 uint8_t checkErrorsGBTDataID(const GBTData* dbtD);
251
252 ClassDefNV(GBTLink, 1);
253};
254
258template <class Mapping>
260{
261 status = None;
262 if (rofJumpWasSeen) { // make sure this link does not have yet unused data due to the ROF/HBF jump
264 return status;
265 }
267 uint8_t errRes = uint8_t(GBTLink::NoError);
268 bool expectPacketDone = false;
269 bool verboseRawData = verbosity > 0 && ((verbosity % VerboseData) == 0);
270 ir.clear();
271 while (currRawPiece) { // we may loop over multiple CRU page
272 if (dataOffset >= currRawPiece->size) {
273 dataOffset = 0; // start of the RDH
274 if (!(currRawPiece = rawData.nextPiece())) { // fetch next CRU page
275 break; // Data chunk (TF?) is done
276 }
277 }
278 if (!dataOffset) { // here we always start with the RDH
279 auto hbfEntrySav = hbfEntry;
280 hbfEntry = 0xffffffff; // in case of problems with RDH, dump full TF
281 const auto* rdh = reinterpret_cast<const RDH*>(&currRawPiece->data[dataOffset]);
282 if (verbosity >= VerboseHeaders) {
284 }
285 GBTLINK_DECODE_ERRORCHECK(errRes, checkErrorsRDH(*rdh)); // make sure we are dealing with RDH
286 hbfEntry = hbfEntrySav; // critical check of RDH passed
287 lastRDH = rdh;
289 if (RDHUtils::getPageCounter(*rdh) == 0 || irHBF.isDummy()) { // for the threshold scan data it is not guaranteed that the page0 is found)
290 irHBF = RDHUtils::getHeartBeatIR(*rdh);
292 }
293 GBTLINK_DECODE_ERRORCHECK(errRes, checkErrorsRDHStop(*rdh)); // if new HB starts, the lastRDH must have stop
294 // GBTLINK_DECODE_ERRORCHECK(checkErrorsRDHStopPageEmpty(*rdh)); // end of HBF should be an empty page with stop
295 dataOffset += sizeof(RDH);
296 lastPageSize = RDHUtils::getMemorySize(*rdh);
297 if (lastPageSize == sizeof(RDH)) {
298 continue; // filter out empty page
299 }
300 if (RDHUtils::getStop(*rdh)) { // only diagnostic word can be present after the stop
301 auto gbtDiag = reinterpret_cast<const GBTDiagnostic*>(&currRawPiece->data[dataOffset]);
302 if (verbosity >= VerboseHeaders) {
303 printDiagnostic(gbtDiag, dataOffset);
304 }
305 GBTLINK_DECODE_ERRORCHECK(errRes, checkErrorsDiagnosticWord(gbtDiag));
306 dataOffset += RDHUtils::getOffsetToNext(*rdh) - sizeof(RDH);
307 continue;
308 }
309
310 // data must start with the GBTHeader
311 auto gbtH = reinterpret_cast<const GBTDataHeader*>(&currRawPiece->data[dataOffset]); // process GBT header
312 if (verbosity >= VerboseHeaders) {
313 printHeader(gbtH, dataOffset);
314 }
316 GBTLINK_DECODE_ERRORCHECK(errRes, checkErrorsHeaderWord(gbtH));
317 lanesActive = gbtH->activeLanes; // TODO do we need to update this for every page?
318
319 GBTLINK_DECODE_ERRORCHECK(errRes, checkErrorsActiveLanes(chmap.getCablesOnRUType(ruPtr->ruInfo->ruType)));
320
321 continue;
322 }
323 bool cruPageAlignmentPaddingSeen = false;
324
325 // then we expect GBT trigger word
326 {
327 int ntrig = 0;
328 const GBTTrigger* gbtTrg = nullptr;
329 while (dataOffset < currRawPiece->size) { // we may have multiple trigger words in case there were physics triggers
330 const GBTTrigger* gbtTrgTmp = reinterpret_cast<const GBTTrigger*>(&currRawPiece->data[dataOffset]);
331 if (gbtTrgTmp->isTriggerWord()) {
332 ntrig++;
333 if (verbosity >= VerboseHeaders) {
334 printTrigger(gbtTrgTmp, dataOffset);
335 }
337 if (gbtTrgTmp->noData == 0 || gbtTrgTmp->internal) {
338 gbtTrg = gbtTrgTmp; // this is a trigger describing the following data
339 } else {
340 if (extTrigVec) { // this link collects external triggers
341 extTrigVec->emplace_back(PhysTrigger{o2::InteractionRecord(uint16_t(gbtTrgTmp->bc), uint32_t(gbtTrgTmp->orbit)), uint64_t(gbtTrgTmp->triggerType)});
342 }
343 }
344 if (gbtTrgTmp->internal == 0) { // external trigger, may have others
345 continue;
346 }
347 }
348 auto gbtC = reinterpret_cast<const o2::itsmft::GBTCalibration*>(&currRawPiece->data[dataOffset]);
349 if (gbtC->isCalibrationWord()) {
350 if (verbosity >= VerboseHeaders) {
351 printCalibrationWord(gbtC, dataOffset);
352 }
354 LOGP(debug, "SetCalibData for RU:{} at bc:{}/orb:{} : [{}/{}]", ruPtr->ruSWID, gbtTrg ? gbtTrg->bc : -1, gbtTrg ? gbtTrg->orbit : -1, gbtC->calibCounter, gbtC->calibUserField);
355 ruPtr->calibData = {gbtC->calibCounter, gbtC->calibUserField};
356 continue;
357 }
358 break;
359 }
360 if (gbtTrg) {
361 if (!gbtTrg->continuation || alwaysParseTrigger) { // this is a continuation from the previous CRU page
362 statistics.nTriggers += gbtTrg->continuation == 0;
363 ir.bc = gbtTrg->bc;
364 ir.orbit = gbtTrg->orbit;
365 trigger = gbtTrg->triggerType;
366 lanesStop = 0;
367 lanesWithData = 0;
368 }
369 if (gbtTrg->noData) {
370 if (verbosity >= VerboseHeaders) {
371 LOGP(info, "Offs {} Returning with status {} for {}", dataOffset, int(status), describe());
372 }
373 return status;
374 }
375 }
376 if (dataOffset >= currRawPiece->size || (cruPageAlignmentPaddingSeen = isAlignmentPadding())) { // end of CRU page was reached while scanning triggers
377 if (cruPageAlignmentPaddingSeen) {
378 // GBTLINK_DECODE_ERRORCHECK(errRes, checkErrorsAlignmentPadding());
380 }
381 if (verbosity >= VerboseHeaders) {
382 LOGP(info, "Offs {} End of the CRU page reached while scanning triggers, continue to next page, {}", dataOffset, int(status), describe());
383 }
384 continue;
385 }
386 // trigger is supposed to be seen
387 GBTLINK_DECODE_ERRORCHECK(errRes, checkErrorsIRNotExtracted());
388 }
389
390 auto gbtD = reinterpret_cast<const o2::itsmft::GBTData*>(&currRawPiece->data[dataOffset]);
391 expectPacketDone = true;
392
393 while (!gbtD->isDataTrailer() && !(cruPageAlignmentPaddingSeen = isAlignmentPadding())) { // start reading real payload
394 if (verboseRawData) {
395 gbtD->printX(expectPadding);
396 }
397 GBTLINK_DECODE_ERRORCHECK(errRes, checkErrorsGBTDataID(gbtD));
398 if (errRes != uint8_t(GBTLink::Skip)) {
399 int cableHW = gbtD->getCableID(), cableSW = chmap.cableHW2SW(ruPtr->ruInfo->ruType, cableHW);
400 GBTLINK_DECODE_ERRORCHECK(errRes, checkErrorsCableID(gbtD, cableSW));
401 if (errRes != uint8_t(GBTLink::Skip)) {
402 // GBTLINK_DECODE_ERRORCHECK(errRes, checkErrorsGBTData(chmap.cableHW2Pos(ruPtr->ruInfo->ruType, cableHW)));
403 ruPtr->cableData[cableSW].add(gbtD->getW8(), 9);
404 ruPtr->cableHWID[cableSW] = cableHW;
405 ruPtr->cableLinkID[cableSW] = idInRU;
406 ruPtr->cableLinkPtr[cableSW] = this;
407 }
408 }
410 gbtD = reinterpret_cast<const o2::itsmft::GBTData*>(&currRawPiece->data[dataOffset]);
411 } // we are at the trailer, packet is over, check if there are more data on the next page
412 if (cruPageAlignmentPaddingSeen) {
413 // GBTLINK_DECODE_ERRORCHECK(errRes, checkErrorsAlignmentPadding());
415 } else {
416 auto gbtT = reinterpret_cast<const o2::itsmft::GBTDataTrailer*>(&currRawPiece->data[dataOffset]); // process GBT trailer
417 if (verbosity >= VerboseHeaders) {
418 printTrailer(gbtT, dataOffset);
419 }
421
422 GBTLINK_DECODE_ERRORCHECK(errRes, checkErrorsTrailerWord(gbtT));
423 // are we at the end of the page?
424 if ((cruPageAlignmentPaddingSeen = isAlignmentPadding())) {
426 }
427 // we finished the GBT page, but there might be continuation on the next CRU page
428 if (!gbtT->packetDone) {
429 GBTLINK_DECODE_ERRORCHECK(errRes, checkErrorsPacketDoneMissing(gbtT, (dataOffset < currRawPiece->size && !cruPageAlignmentPaddingSeen)));
430 continue; // keep reading next CRU page
431 }
432 // accumulate packet states
433 statistics.packetStates[gbtT->getPacketState()]++;
434 if (verbosity >= VerboseHeaders) {
435 LOGP(info, "Offs {} Leaving collectROFCableData for {} with DataSeen", dataOffset, describe());
436 }
437 }
438 return (status = DataSeen);
439 }
440
441 if (expectPacketDone) { // no trailer with packet done was encountered, register error
442 GBTLINK_DECODE_ERRORCHECK(errRes, checkErrorsPacketDoneMissing(nullptr, false));
443 return (status = DataSeen);
444 }
445 return (status = StoppedOnEndOfData);
446}
447
448} // namespace itsmft
449} // namespace o2
450
451#endif // _ALICEO2_ITSMFT_GBTLINK_H_
Alpide Chip and GBT link decoding statistics.
Declaration of class for continuos buffer of ALPIDE data.
Declaration of class for scatter-gather buffer.
Definition Physics trigger record extracted from the ITS/MFT stream.
Definition of the RAW Data Header.
Declaration of the Readout Unite decoder class.
void printHeader()
TBranch * ptr
std::ostringstream debug
Checks validity of hardware address (HW) and transform it to digit AbsId index.
const SGPiece * currentPiece() const
Definition PayLoadSG.h:116
const SGPiece * nextPiece()
Definition PayLoadSG.h:118
size_t & currentPieceID()
Definition PayLoadSG.h:110
unsigned char DataType
Definition PayLoadSG.h:32
void add(const DataType *ptr, size_t n)
read current character value from buffer w/o stepping forward
Definition PayLoadSG.h:38
GLint GLsizei count
Definition glcorearb.h:399
GLsizeiptr size
Definition glcorearb.h:659
GLubyte GLubyte GLubyte GLubyte w
Definition glcorearb.h:852
uint8_t itsSharedClusterMap uint8_t
constexpr int GBTPaddedWordLength
Definition GBTWord.h:56
constexpr int GBTWordLength
Definition GBTWord.h:55
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
uint32_t orbit
LHC orbit.
uint16_t bc
bunch crossing ID of interaction
Statistics for per-link decoding.
std::array< uint32_t, GBTDataTrailer::MaxStateCombinations > packetStates
uint64_t continuation
13 No data expected (too close to previous trigger or error)
Definition GBTWord.h:94
uint64_t noData
12 Used in Continuous Mode for internally generated trigger
Definition GBTWord.h:93
uint64_t internal
0:11 12 lowest bits of trigger type received from CTP
Definition GBTWord.h:92
uint64_t orbit
28:31 reserved
Definition GBTWord.h:98
bool isTriggerWord() const
check if the GBT Header corresponds to GBT trigger word
Definition GBTWord.h:133
uint64_t triggerType
Definition GBTWord.h:91
void printX(bool padded=true, std::string com="") const
Definition GBTWord.cxx:21
uint64_t bc
15 reserved
Definition GBTWord.h:96
std::array< PayLoadCont, MaxCablesPerRU > cableData
std::array< uint8_t, MaxCablesPerRU > cableHWID
std::array< GBTLink *, MaxCablesPerRU > cableLinkPtr
std::array< uint8_t, MaxCablesPerRU > cableLinkID
uint8_t ruType
Definition RUInfo.h:35
static void printRDH(const RDHv4 &rdh)
Definition RDHUtils.cxx:26
vec clear()