Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:17:18

0001 // @file GBTLink.h
0002 // @brief Declarations of helper classes for the ITS/MFT raw data decoding
0003 // @sa <O2/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/GBTLink.>
0004 //     <760019308>
0005 
0006 #ifndef MVTXDECODER_GBTLINK_H
0007 #define MVTXDECODER_GBTLINK_H
0008 
0009 #define _RAW_READER_ERROR_CHECKS_ // comment this to disable error checking
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 /// support for the GBT single link data
0040 struct GBTLink
0041 {
0042 //  enum RawDataDumps : int { DUMP_NONE, // no raw data dumps on error
0043 //                            DUMP_HBF,  // dump HBF for FEEID with error
0044 //                            DUMP_TF,   // dump whole TF at error
0045 //                            DUMP_NTYPES };
0046 
0047   enum CollectedDataStatus : int8_t { None,
0048                                       AbortedOnError,
0049                                       StoppedOnEndOfData,
0050                                       DataSeen }; // None is set before starting collectROFCableData
0051 
0052 //  enum ErrorType : uint8_t { NoError = 0x0,
0053 //                             Warning = 0x1,
0054 //                             Skip = 0x2,
0055 //                             Abort = 0x4,
0056 //                             ErrorPrinted = 0x1 << 7 };
0057 
0058   static constexpr int RawBufferMargin = 500000;                      // keep uploaded at least this amount
0059   static constexpr int RawBufferSize = 1000000 + 2 * RawBufferMargin; // size in MB
0060   static constexpr uint8_t MaxCablesPerLink = 3;
0061 
0062   CollectedDataStatus status = None;
0063 
0064   uint16_t flxId = 0;     // FLX ID
0065   uint16_t feeId = 0;     // FEE ID
0066 
0067   PayLoadCont data; // data buffer for single feeeid
0068   std::array<PayLoadCont, MaxCablesPerLink> cableData;
0069 
0070 
0071   uint32_t hbfEntry = 0;      // entry of the current HBF page in the rawData SG list
0072   InteractionRecord ir = {};
0073 
0074   GBTLinkDecodingStat statistics; // link decoding 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;         // scatter-gatter buffer for cached CRU pages, each starting with RDH
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 /// collect cables data for single ROF, return number of real payload words seen,
0213 /// -1 in case of critical error
0214 inline GBTLink::CollectedDataStatus GBTLink::collectROFCableData(/*const Mapping& chmap*/)
0215 {
0216   bool prev_evt_complete = false;
0217   bool header_found = false;
0218 //  bool trailer_found = false;
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   { // we may loop over multiple FLX page
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       // start of the RDH
0237       if (! (currRawPiece = rawData.nextPiece()))
0238       { // fetch next CRU page
0239         break;                                     // Data chunk (TF?) is done
0240       }
0241     }
0242 
0243     if (currRawPiece->hasError != mvtx::PayLoadSG::HBF_ERRORS::NoError) // Skip
0244     {
0245       dataOffset = currRawPiece->size;
0246       ++hbf_count;
0247       continue;
0248     }
0249 
0250     if (! dataOffset)
0251     {
0252       hbf_start = data.getPtr();
0253     }
0254 
0255     // here we always start with the RDH
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       // In case of corrupt RDH, skip HBF
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     //Fill statistics
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         // move buffer pointer to begin of RDH and reset dataOffset
0275         dataOffset = 0;
0276       }
0277       detectorField = (*rdhP).detectorField;
0278       statistics.clear();
0279       //TODO: initialize/clear alpide data buffer
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(); // in case of problems with RDH, dump full TF
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; // skip RDH
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()) // ITS HEADER WORD
0325         {
0326           //TODO assert first word after RDH and active lanes
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()) // TRIGGER DATA HEADER (TDH)
0337         {
0338           header_found = true;
0339           ir.orbit = gbtWord.bco;
0340           ir.bc = gbtWord.bc;
0341 
0342           if (gbtWord.bc) //statistic trigger for first bc already filled on RDH
0343           {
0344             for (uint32_t trg = GBTLinkDecodingStat::BitMaps::ORBIT; trg < GBTLinkDecodingStat::nBitMap; ++trg)
0345             {
0346               if (trg == GBTLinkDecodingStat::BitMaps::FE_RST) //  TDH save first 12 bits only
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           } // end if not cont
0366         } // end TDH
0367         else if (gbtWord.isCDW()) // CALIBRATION DATA WORD
0368         {
0369           mTrgData.back().hasCDW = true;
0370           mTrgData.back().calWord = *(reinterpret_cast<GBTCalibDataWord*>(&gbtWord));
0371         }
0372         else if (gbtWord.isTDT())
0373         {
0374           // trailer_found = true;
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               // TODO: Add error counter
0383             }
0384           }
0385           prev_evt_complete = gbtWord.packet_done;
0386           //TODO: YCM Add warning and counter for timeout and violation
0387         }
0388         else if (gbtWord.isDDW()) // DIAGNOSTIC DATA WORD (DDW)
0389         {
0390           if (! (*rdhP).stopBit)
0391           {
0392             log_error << "DDW was found in a packet with stop bit: " <<  (*rdhP).stopBit << std::endl;
0393             //TODO: YCM Add warning and counter DDW not in final packet
0394           }
0395         }
0396         else if (gbtWord.isDiagnosticIB()) // IB DIAGNOSTIC DATA
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()) //IS IB DATA
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 //          trailer_found = false;
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; // currently we just print stuff, but we will add stuff to our
0447                // structures and return a status later (that's why it's not a const function)
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 ) // BUSY ON
0476     {
0477       busy_on = true ;
0478     }
0479     else if ( dataC == 0xF0 ) // BUSY OFF
0480     {
0481       busy_off = true;
0482     }
0483     else if ((dataC & 0xF0) == 0xF0) // APE
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) // EMPTY
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) // REGION HEADER
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           // TODO: move first region header out of loop, asserting its existence
0515           reg = dataC & 0x1F;
0516         }
0517         else if((dataC & 0xC0) == 0x40) // DATA SHORT
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) // DATA LONG
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) // CHIP TRAILER
0569         {
0570 //          uint8_t flag = (dataC & 0x0F);
0571           //TODO: YCM add chipdata statistic
0572           chip_trailer_found = true;
0573           busy_on = busy_off = chip_header_found = false;
0574         }
0575         else // ERROR
0576         {
0577           AlpideByteError(chipId, buffer);
0578         }
0579       }
0580       else
0581       {
0582         if ((dataC & 0xF0) == 0xA0) // CHIP HEADER
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 ) // PADDING
0599         {
0600           continue;
0601         }
0602         else
0603         { // ERROR
0604           AlpideByteError(chipId, buffer);
0605         } // else !chip_header_found
0606       }  // if chip_header_found
0607     } // busy_on, busy_off, chip_empty, other
0608     if (busy_on)
0609     {
0610     }
0611     if (busy_off)
0612     {
0613     }
0614   }  // while
0615 
0616   return ret;
0617 }
0618 
0619 
0620 } // namespace mvtx
0621 
0622 #endif // _MVTX_DECODER_ITSMFT_GBTLINK_H_