File indexing completed on 2025-08-06 08:17:18
0001
0002
0003
0004
0005
0006 #ifndef MVTXDECODER_GBTLINK_H
0007 #define MVTXDECODER_GBTLINK_H
0008
0009 #define _RAW_READER_ERROR_CHECKS_
0010
0011 #include "mvtx_utils.h"
0012 #include "RDH.h"
0013 #include "PayLoadCont.h"
0014 #include "PayLoadSG.h"
0015 #include "DecodingStat.h"
0016 #include "GBTWord.h"
0017 #include "InteractionRecord.h"
0018 #include "StrobeData.h"
0019
0020 #include <iostream>
0021 #include <memory>
0022 #include <iomanip>
0023
0024 #define GBTLINK_DECODE_ERRORCHECK(errRes, errEval) \
0025 errRes = errEval; \
0026 if ((errRes)&uint8_t(ErrorPrinted)) { \
0027 ruPtr->linkHBFToDump[(uint64_t(subSpec) << 32) + hbfEntry] = irHBF.orbit; \
0028 errRes &= ~uint8_t(ErrorPrinted); \
0029 } \
0030 if ((errRes)&uint8_t(Abort)) { \
0031 discardData(); \
0032 return AbortedOnError; \
0033 }
0034
0035 namespace mvtx {
0036
0037 using namespace mvtx_utils;
0038
0039
0040 struct GBTLink
0041 {
0042
0043
0044
0045
0046
0047 enum CollectedDataStatus : int8_t { None,
0048 AbortedOnError,
0049 StoppedOnEndOfData,
0050 DataSeen };
0051
0052
0053
0054
0055
0056
0057
0058 static constexpr int RawBufferMargin = 500000;
0059 static constexpr int RawBufferSize = 1000000 + 2 * RawBufferMargin;
0060 static constexpr uint8_t MaxCablesPerLink = 3;
0061
0062 CollectedDataStatus status = None;
0063
0064 uint16_t flxId = 0;
0065 uint16_t feeId = 0;
0066
0067 PayLoadCont data;
0068 std::array<PayLoadCont, MaxCablesPerLink> cableData;
0069
0070
0071 uint32_t hbfEntry = 0;
0072 InteractionRecord ir = {};
0073
0074 GBTLinkDecodingStat statistics;
0075
0076 uint8_t hbf_error = 0;
0077 uint32_t hbf_length = 0;
0078 uint32_t prev_pck_cnt = 0;
0079 uint32_t hbf_count = 0;
0080
0081 bool hbf_skip = false;
0082
0083 PayLoadSG rawData;
0084 size_t dataOffset = 0;
0085 std::vector<InteractionRecord> mL1TrgTime;
0086 std::vector<StrobeData> mTrgData;
0087
0088
0089 GBTLink() = default;
0090 GBTLink(uint16_t _flx, uint16_t _fee);
0091 void clear(bool resetStat = true, bool resetTFRaw = false);
0092
0093 CollectedDataStatus collectROFCableData();
0094
0095 void cacheData(size_t start, size_t sz)
0096 {
0097 rawData.add(start, sz);
0098 }
0099
0100 void clearCableData()
0101 {
0102 for (auto& _data : cableData)
0103 {
0104 _data.clear();
0105 }
0106 }
0107
0108 int readFlxWord(GBTWord* gbtwords, uint16_t& w16);
0109 int decode_lane(const uint8_t chipId, PayLoadCont& buffer);
0110
0111 void getRowCol(const uint8_t reg, const uint16_t addr, uint16_t& row, uint16_t& col)
0112 {
0113 row = (addr >> 0x1) & 0x1FF;
0114 col = (reg << 5 | ((addr >> 9) & 0x1E)) | ((addr ^ addr >> 1) & 0x1);
0115 }
0116
0117 void addHit(const uint8_t laneId, const uint8_t bc, uint8_t reg, const uint16_t addr)
0118 {
0119 auto* hit = new mvtx_hit();
0120
0121 hit->chip_id = laneId;
0122 hit->bunchcounter = bc;
0123 getRowCol(reg, addr, hit->row_pos, hit->col_pos);
0124
0125 mTrgData.back().hit_vector.push_back(hit);
0126 }
0127
0128 void check_APE(const uint8_t& chipId, const uint8_t& dataC)
0129 {
0130 std::cerr << "Link: " << feeId << ", Chip: " << (int)chipId;
0131 switch (dataC)
0132 {
0133 case 0xF2:
0134 std::cerr << " APE_STRIP_START" << std::endl;
0135 break;
0136 case 0xF4:
0137 std::cerr << " APE_DET_TIMEOUT" << std::endl;
0138 break;
0139 case 0xF5:
0140 std::cerr << " APE_OOT" << std::endl;
0141 break;
0142 case 0xF6:
0143 std::cerr << " APE_PROTOCOL_ERROR" << std::endl;
0144 break;
0145 case 0xF7:
0146 std::cerr << " APE_LANE_FIFO_OVERFLOW_ERROR" << std::endl;
0147 break;
0148 case 0xF8:
0149 std::cerr << " APE_FSM_ERROR" << std::endl;
0150 break;
0151 case 0xF9:
0152 std::cerr << " APE_PENDING_DETECTOR_EVENT_LIMIT" << std::endl;
0153 break;
0154 case 0xFA:
0155 std::cerr << " APE_PENDING_LANE_EVENT_LIMIT" << std::endl;
0156 break;
0157 case 0xFB:
0158 std::cerr << " APE_O2N_ERROR" << std::endl;
0159 break;
0160 case 0xFC:
0161 std::cerr << " APE_RATE_MISSING_TRG_ERROR" << std::endl;
0162 break;
0163 case 0xFD:
0164 std::cerr << " APE_PE_DATA_MISSING" << std::endl;
0165 break;
0166 case 0xFE:
0167 std::cerr << " APE_OOT_DATA_MISSING" << std::endl;
0168 break;
0169 default:
0170 std::cerr << " Unknown APE code" << std::endl;
0171 }
0172 return;
0173 }
0174
0175 void AlpideByteError(const uint8_t& chipId, PayLoadCont& buffer)
0176 {
0177 uint8_t dataC = 0;
0178
0179 std::cerr << "Link: " << feeId << ", Chip: " << (int)chipId;
0180 std::cerr << " invalid byte 0x" << std::hex << (int)(dataC) << std::endl;
0181 while (buffer.next(dataC))
0182 {
0183 std::cerr << " " << std::hex << (int)(dataC) << " ";
0184 }
0185 std::cerr << std::endl;
0186 buffer.clear();
0187 return;
0188 }
0189
0190 void PrintFlxWord(std::ostream& os, uint8_t* pos)
0191 {
0192 os << std::setfill('0');
0193 for ( int i = 0; i < 32 ; i++)
0194 {
0195 os << std::hex << std::setw(2) << (int)pos[i] << " " << std::dec;
0196 }
0197 os << std::setfill(' ') << std::endl;
0198 }
0199
0200 void PrintBlock(std::ostream& os, uint8_t* pos, size_t n)
0201 {
0202 for (uint32_t i = 0; i < n; ++i)
0203 {
0204 PrintFlxWord(os, pos + 32 * i);
0205 }
0206 }
0207
0208 ClassDefNV(GBTLink, 1);
0209 };
0210
0211
0212
0213
0214 inline GBTLink::CollectedDataStatus GBTLink::collectROFCableData()
0215 {
0216 bool prev_evt_complete = false;
0217 bool header_found = false;
0218
0219 uint8_t* hbf_start = nullptr;
0220
0221 status = None;
0222
0223 uint32_t detectorField = 0;
0224
0225 auto currRawPiece = rawData.currentPiece();
0226 dataOffset = 0;
0227 while (currRawPiece)
0228 {
0229 uint32_t n_no_continuation = 0;
0230 uint32_t n_packet_done = 0;
0231
0232 if (dataOffset >= currRawPiece->size)
0233 {
0234 data.movePtr(currRawPiece->size);
0235 dataOffset = 0;
0236
0237 if (! (currRawPiece = rawData.nextPiece()))
0238 {
0239 break;
0240 }
0241 }
0242
0243 if (currRawPiece->hasError != mvtx::PayLoadSG::HBF_ERRORS::NoError)
0244 {
0245 dataOffset = currRawPiece->size;
0246 ++hbf_count;
0247 continue;
0248 }
0249
0250 if (! dataOffset)
0251 {
0252 hbf_start = data.getPtr();
0253 }
0254
0255
0256 uint8_t* rdh_start = data.getPtr() + dataOffset;
0257 const auto* rdhP = reinterpret_cast<const mvtx::RDH*>(rdh_start);
0258 if (! mvtx::RDHUtils::checkRDH(mvtx::RDHAny::voidify(*rdhP), true, true))
0259 {
0260
0261 dataOffset = currRawPiece->size;
0262 ++hbf_count;
0263 continue;
0264 }
0265
0266 size_t pagesize = ((*rdhP).pageSize + 1) * FLXWordLength;
0267 const size_t nFlxWords = (pagesize - (2 * FLXWordLength)) / FLXWordLength;
0268
0269 if (! (*rdhP).packetCounter)
0270 {
0271 if (dataOffset)
0272 {
0273 log_error << "Wrong dataOffset value " << dataOffset << " at the start of a HBF" << std::endl;
0274
0275 dataOffset = 0;
0276 }
0277 detectorField = (*rdhP).detectorField;
0278 statistics.clear();
0279
0280 for (uint32_t trg = GBTLinkDecodingStat::BitMaps::ORBIT; trg < GBTLinkDecodingStat::nBitMap; ++trg)
0281 {
0282 if (((*rdhP).trgType >> trg) & 1)
0283 {
0284 ++statistics.trgBitCounts[trg];
0285 }
0286 }
0287 hbfEntry = rawData.currentPieceId();
0288 ++hbf_count;
0289 }
0290 else if (! (*rdhP).stopBit)
0291 {
0292 if (prev_evt_complete)
0293 {
0294 log_error << "Previous event was already completed" << std::endl;
0295 dataOffset = currRawPiece->size;
0296 ++hbf_count;
0297 continue;
0298 }
0299 }
0300
0301 dataOffset += 2 * FLXWordLength;
0302 int prev_gbt_cnt = (*rdhP).rdhGBTcounter;
0303 GBTWord gbtWords[3];
0304 uint16_t w16 = 0;
0305 for (size_t iflx = 0; iflx < nFlxWords; ++iflx)
0306 {
0307 readFlxWord(gbtWords, w16);
0308 int16_t n_gbt_cnt = (w16 & 0x3FF) - prev_gbt_cnt;
0309 prev_gbt_cnt = (w16 & 0x3FF);
0310 if (n_gbt_cnt < 1 || n_gbt_cnt > 3)
0311 {
0312 log_error << "Bad gbt counter in the flx packet. FLX: " << flxId << ", Feeid: " << feeId << ", n_gbt_cnt: " << n_gbt_cnt \
0313 << ", prev_gbt_cnt: " << prev_gbt_cnt << ", size: " << currRawPiece->size << ", dataOffset: " << dataOffset << std::endl;
0314 PrintBlock(std::cerr, rdh_start, nFlxWords + 2);
0315 std::cerr << "Full HBF" << std::endl;
0316 PrintBlock(std::cerr, hbf_start, (currRawPiece->size/32) );
0317 hbf_skip = true;
0318 break;
0319 }
0320
0321 for (int i = 0; i < n_gbt_cnt; ++i)
0322 {
0323 auto &gbtWord = gbtWords[i];
0324 if (gbtWord.isIHW())
0325 {
0326
0327 if (! ((!gbtWord.activeLanes) ||
0328 ((gbtWord.activeLanes >> 0) & 0x7) == 0x7 ||
0329 ((gbtWord.activeLanes >> 3) & 0x7) == 0x7 ||
0330 ((gbtWord.activeLanes >> 6) & 0x7) == 0x7) )
0331 {
0332 log_error << "Expected all active lanes for links, but " << gbtWord.activeLanes << "found in HBF " << hbfEntry << ", " \
0333 << gbtWord.asString().data() << std::endl;
0334 }
0335 }
0336 else if (gbtWord.isTDH())
0337 {
0338 header_found = true;
0339 ir.orbit = gbtWord.bco;
0340 ir.bc = gbtWord.bc;
0341
0342 if (gbtWord.bc)
0343 {
0344 for (uint32_t trg = GBTLinkDecodingStat::BitMaps::ORBIT; trg < GBTLinkDecodingStat::nBitMap; ++trg)
0345 {
0346 if (trg == GBTLinkDecodingStat::BitMaps::FE_RST)
0347 break;
0348 if (((gbtWord.triggerType >> trg) & 1))
0349 {
0350 ++statistics.trgBitCounts[trg];
0351 }
0352 }
0353 }
0354
0355 if ((gbtWord.triggerType >> GBTLinkDecodingStat::BitMaps::PHYSICS) & 0x1)
0356 {
0357 mL1TrgTime.push_back(ir);
0358 }
0359
0360 if ((! gbtWord.continuation) && (! gbtWord.noData))
0361 {
0362 n_no_continuation++;
0363 mTrgData.emplace_back(ir.orbit, ir.bc);
0364 mTrgData.back().detectorField = detectorField;
0365 }
0366 }
0367 else if (gbtWord.isCDW())
0368 {
0369 mTrgData.back().hasCDW = true;
0370 mTrgData.back().calWord = *(reinterpret_cast<GBTCalibDataWord*>(&gbtWord));
0371 }
0372 else if (gbtWord.isTDT())
0373 {
0374
0375 if (gbtWord.packet_done)
0376 {
0377 ++n_packet_done;
0378 if (n_packet_done < n_no_continuation)
0379 {
0380 log_error << "TDT packet done before TDH no continuation " << n_no_continuation \
0381 << " != " << n_packet_done << std::endl;
0382
0383 }
0384 }
0385 prev_evt_complete = gbtWord.packet_done;
0386
0387 }
0388 else if (gbtWord.isDDW())
0389 {
0390 if (! (*rdhP).stopBit)
0391 {
0392 log_error << "DDW was found in a packet with stop bit: " << (*rdhP).stopBit << std::endl;
0393
0394 }
0395 }
0396 else if (gbtWord.isDiagnosticIB())
0397 {
0398 std::cout << "WARNING: IB Diagnostic word found." << std::endl;
0399 std::cout << "diagnostic_lane_id: " << (gbtWord.id >> 5);
0400 std::cout << " lane_error_id: " << gbtWord.lane_error_id;
0401 std::cout << " diasnotic_data: 0x" << std::hex << gbtWord.diagnostic_data << std::endl;
0402 }
0403 else if (gbtWord.isData())
0404 {
0405 if (! header_found )
0406 {
0407 log_error << "Trigger header not found before chip data. skipping data" << std::endl;
0408 clearCableData();
0409 continue;
0410 }
0411 auto lane = (gbtWord.data8[9] & 0x1F) % 3;
0412 cableData[lane].add(gbtWord.getW8(), 9);
0413 }
0414
0415 if (prev_evt_complete)
0416 {
0417 for (auto&& itr = cableData.begin(); itr != cableData.end(); ++itr)
0418 {
0419 if (! itr->isEmpty())
0420 {
0421 decode_lane(std::distance(cableData.begin(), itr), *itr);
0422 }
0423 }
0424 prev_evt_complete = false;
0425 header_found = false;
0426
0427 clearCableData();
0428 }
0429 }
0430 }
0431 if (hbf_skip)
0432 {
0433 hbf_skip = false;
0434 clearCableData();
0435 dataOffset = currRawPiece->size;
0436 ++hbf_count;
0437 continue;
0438 }
0439 }
0440 return (status = StoppedOnEndOfData);
0441 }
0442
0443
0444 inline int GBTLink::decode_lane(const uint8_t chipId, PayLoadCont& buffer)
0445 {
0446 int ret = 0;
0447
0448
0449 if (buffer.getSize() < 3)
0450 {
0451 log_error << "chip data is too short: " << buffer.getSize() << std::endl;
0452 return -1;
0453 }
0454
0455 uint8_t dataC = 0;
0456 uint16_t dataS = 0;
0457
0458 bool busy_on = false, busy_off = false;
0459 bool chip_header_found = false;
0460 bool chip_trailer_found = true;
0461
0462 uint8_t laneId = 0xFF;
0463 uint8_t bc = 0xFF;
0464 uint8_t reg = 0xFF;
0465
0466 if ( !( (buffer[0] & 0xF0) == 0xE0 || (buffer[0] & 0xF0) == 0xA0 ||\
0467 (buffer[0] == 0xF0) || (buffer[0] == 0xF1) || (buffer[0] & 0xF0) == 0xF0 ) )
0468 {
0469 AlpideByteError(chipId, buffer);
0470 return 0;
0471 }
0472
0473 while (buffer.next(dataC))
0474 {
0475 if ( dataC == 0xF1 )
0476 {
0477 busy_on = true ;
0478 }
0479 else if ( dataC == 0xF0 )
0480 {
0481 busy_off = true;
0482 }
0483 else if ((dataC & 0xF0) == 0xF0)
0484 {
0485 check_APE(chipId, dataC);
0486 chip_trailer_found = true;
0487 busy_on = busy_off = chip_header_found = 0;
0488 }
0489 else if ((dataC & 0xF0) == 0xE0)
0490 {
0491 chip_header_found = false;
0492 chip_trailer_found = true;
0493 laneId = (dataC & 0x0F) % 3;
0494 if (laneId != chipId)
0495 {
0496 log_error << "Error laneId " << laneId << " (" << (dataC & 0xF) << ") and chipId " << chipId << std::endl;
0497 }
0498 buffer.next(bc);
0499 busy_on = busy_off = false;
0500 }
0501 else
0502 {
0503 if (chip_header_found)
0504 {
0505 if ((dataC & 0xE0) == 0xC0)
0506 {
0507 if (buffer.getUnusedSize() < 2)
0508 {
0509 log_error << "No data short would fit (at least a data short after region header!)" << std::endl;
0510 buffer.erase(buffer.getUnusedSize());
0511 chip_header_found = false;
0512 continue;
0513 }
0514
0515 reg = dataC & 0x1F;
0516 }
0517 else if((dataC & 0xC0) == 0x40)
0518 {
0519 if(buffer.isEmpty())
0520 {
0521 log_error << "data short do not fit" << std::endl;
0522 chip_header_found = false;
0523 continue;
0524 }
0525 if (reg == 0xFF)
0526 {
0527 log_error << "data short at " << buffer.getOffset() << " before region header" << std::endl;
0528 continue;
0529 }
0530 dataS = (dataC << 8);
0531 buffer.next(dataC);
0532 dataS |= dataC;
0533 addHit(laneId, bc, reg, (dataS & 0x3FFF));
0534 }
0535 else if ((dataC & 0xC0) == 0x00)
0536 {
0537 if (buffer.getUnusedSize() < 3)
0538 {
0539 log_error << "No data long would fit (at least a data short after region header!)" << std::endl;
0540 buffer.erase(buffer.getUnusedSize());
0541 chip_header_found = false;
0542 continue;
0543 }
0544 if (reg == 0xFF)
0545 {
0546 log_error << "data short at " << buffer.getOffset() << " before region header" << std::endl;
0547 continue;
0548 }
0549 buffer.next(dataS);
0550 uint16_t addr = ((dataC & 0x3F) << 8) | ((dataS >> 8) & 0xFF);
0551 uint8_t hit_map = (dataS & 0xFF);
0552 if (hit_map & 0x80)
0553 {
0554 log_error << "Wrong bit before DATA LONG bit map" << std::endl;
0555 continue;
0556 }
0557 addHit(laneId, bc, reg, addr);
0558 while(hit_map != 0x00)
0559 {
0560 ++addr;
0561 if (hit_map & 0x1)
0562 {
0563 addHit(laneId, bc, reg, addr);
0564 }
0565 hit_map >>= 1;
0566 }
0567 }
0568 else if ((dataC & 0xF0) == 0xB0)
0569 {
0570
0571
0572 chip_trailer_found = true;
0573 busy_on = busy_off = chip_header_found = false;
0574 }
0575 else
0576 {
0577 AlpideByteError(chipId, buffer);
0578 }
0579 }
0580 else
0581 {
0582 if ((dataC & 0xF0) == 0xA0)
0583 {
0584 if (! chip_trailer_found)
0585 {
0586 log_error << "New chip header found before a previous chip trailer" << std::endl;
0587 }
0588 chip_header_found = true;
0589 chip_trailer_found = false;
0590 laneId = (dataC & 0x0F) % 3;
0591 if (laneId != chipId )
0592 {
0593 log_error << "Error laneId " << laneId << " (" << (dataC & 0xF) << ") and chipId " << chipId << std::endl;
0594 }
0595 buffer.next(bc);
0596 reg = 0xFF;
0597 }
0598 else if ( dataC == 0x00 )
0599 {
0600 continue;
0601 }
0602 else
0603 {
0604 AlpideByteError(chipId, buffer);
0605 }
0606 }
0607 }
0608 if (busy_on)
0609 {
0610 }
0611 if (busy_off)
0612 {
0613 }
0614 }
0615
0616 return ret;
0617 }
0618
0619
0620 }
0621
0622 #endif