Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:20:06

0001 // @file GBTLink.h
0002 // @brief Declarations of helper classes for the ITS/MFT raw data decoding
0003 // @sa
0004 // <O2/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/GBTLink.>
0005 //     <760019308>
0006 
0007 #ifndef MVTXDECODER_GBTLINK_H
0008 #define MVTXDECODER_GBTLINK_H
0009 
0010 #define _RAW_READER_ERROR_CHECKS_  // comment this to disable error checking
0011 
0012 #include "DecodingStat.h"
0013 #include "GBTWord.h"
0014 #include "InteractionRecord.h"
0015 #include "PayLoadCont.h"
0016 #include "PayLoadSG.h"
0017 #include "mvtx_utils.h"
0018 
0019 // #include "MVTXDecoder/RUDecodeData.h"
0020 // #include "MVTXDecoder/RUInfo.h"
0021 // #include "MVTXDecoder/RAWDataHeader.h"
0022 // #include "MVTXDecoder/RDHUtils.h"
0023 // #include "MVTXDecoder/PhysTrigger.h"
0024 
0025 #include <iomanip>
0026 #include <iostream>
0027 #include <memory>
0028 
0029 #define GBTLINK_DECODE_ERRORCHECK(errRes, errEval)                            \
0030   errRes = errEval;                                                           \
0031   if ((errRes) & uint8_t(ErrorPrinted))                                       \
0032   {                                                                           \
0033     ruPtr->linkHBFToDump[(uint64_t(subSpec) << 32) + hbfEntry] = irHBF.orbit; \
0034     errRes &= ~uint8_t(ErrorPrinted);                                         \
0035   }                                                                           \
0036   if ((errRes) & uint8_t(Abort))                                              \
0037   {                                                                           \
0038     discardData();                                                            \
0039     return AbortedOnError;                                                    \
0040   }
0041 
0042 namespace mvtx
0043 {
0044   using namespace mvtx_utils;
0045 
0046   struct TRGData
0047   {
0048     InteractionRecord ir = {};
0049     bool hasCDW = false;
0050     GBTCalibDataWord calWord = {};
0051     size_t first_hit_pos = 0;
0052     size_t n_hits = 0;
0053 
0054     TRGData(uint64_t orb, uint16_t b)
0055       : ir(orb, b) {};
0056 
0057     void clear()
0058     {
0059       ir.clear();
0060       hasCDW = false;
0061       calWord = {};
0062       first_hit_pos = 0;
0063       n_hits = 0;
0064     }
0065   };
0066 
0067   struct mvtx_hit
0068   {
0069     uint8_t chip_id = 0xf;
0070     uint16_t bunchcounter = 0xFFFF;
0071     uint16_t row_pos = 0xFFFF;
0072     uint16_t col_pos = 0xFFFF;
0073   };
0074 
0075   /// support for the GBT single link data
0076   struct GBTLink
0077   {
0078     //  enum RawDataDumps : int { DUMP_NONE, // no raw data dumps on error
0079     //                            DUMP_HBF,  // dump HBF for FEEID with error
0080     //                            DUMP_TF,   // dump whole TF at error
0081     //                            DUMP_NTYPES };
0082 
0083     enum CollectedDataStatus : int8_t
0084     {
0085       None,
0086       AbortedOnError,
0087       StoppedOnEndOfData,
0088       DataSeen
0089     };  // None is set before starting collectROFCableData
0090 
0091     //  enum ErrorType : uint8_t { NoError = 0x0,
0092     //                             Warning = 0x1,
0093     //                             Skip = 0x2,
0094     //                             Abort = 0x4,
0095     //                             ErrorPrinted = 0x1 << 7 };
0096 
0097     static constexpr int RawBufferMargin =
0098         5000000;  // keep uploaded at least this amount
0099     static constexpr int RawBufferSize =
0100         10000000 + 2 * RawBufferMargin;  // size in MB
0101     static constexpr uint8_t MaxCablesPerLink = 3;
0102 
0103     CollectedDataStatus status = None;
0104 
0105     uint16_t flxId = 0;  // FLX ID
0106     uint16_t feeId = 0;  // FEE ID
0107 
0108     PayLoadCont data;  // data buffer for single feeeid
0109     std::array<PayLoadCont, MaxCablesPerLink> cableData;
0110 
0111     uint32_t hbfEntry = 0;  // entry of the current HBF page in the rawData SG list
0112     InteractionRecord ir = {};
0113 
0114     GBTLinkDecodingStat statistics;  // link decoding statistics
0115 
0116     bool hbf_error = false;
0117 
0118     uint32_t hbf_length = 0;
0119     uint32_t prev_pck_cnt = 0;
0120     uint32_t hbf_count = 0;
0121 
0122     PayLoadSG rawData;      // scatter-gatter buffer for cached CRU pages, each
0123                             // starting with RDH
0124     size_t dataOffset = 0;  //
0125     std::vector<InteractionRecord> mL1TrgTime;
0126     std::vector<TRGData> mTrgData;
0127     int RDHErrors = 0;
0128 
0129     std::vector<mvtx_hit *> hit_vector = {};
0130 
0131     std::vector<uint64_t> tdt_lanestatus_error_vector = {};
0132 
0133     // std::vector<uint16_t> APE_error_vector = {};
0134 
0135     std::vector<std::pair<int, int>> decoder_error_vector = {};
0136 
0137     //------------------------------------------------------------------------
0138     GBTLink() = default;
0139     GBTLink(uint16_t _flx, uint16_t _fee);
0140     void clear(bool resetStat = true, bool resetTFRaw = false);
0141 
0142     CollectedDataStatus collectROFCableData();
0143 
0144     void cacheData(size_t start, size_t sz) { rawData.add(start, sz); }
0145 
0146     void clearCableData()
0147     {
0148       for (auto &&data : cableData)
0149       {
0150         data.clear();
0151       }
0152     }
0153 
0154     int readFlxWord(GBTWord *gbtwords, uint16_t &w16);
0155     int decode_lane(const uint8_t chipId, PayLoadCont &buffer);
0156 
0157     void getRowCol(const uint8_t reg, const uint16_t addr, uint16_t &row,
0158                    uint16_t &col)
0159     {
0160       row = (addr >> 0x1) & 0x1FF;
0161       col = (reg << 5 | ((addr >> 9) & 0x1E)) | ((addr ^ addr >> 1) & 0x1);
0162     }
0163 
0164     void addHit(const uint8_t laneId, const uint8_t bc, uint8_t reg,
0165                 const uint16_t addr)
0166     {
0167       auto *hit = new mvtx_hit();
0168       memset(hit, 0, sizeof(*hit));
0169 
0170       hit->chip_id = laneId;
0171       hit->bunchcounter = bc;
0172       getRowCol(reg, addr, hit->row_pos, hit->col_pos);
0173 
0174       hit_vector.push_back(hit);
0175     }
0176 
0177     void check_APE(const uint8_t &chipId, const uint8_t &dataC)
0178     {
0179       std::cerr << "Link: " << feeId << ", Chip: " << (int) chipId;
0180       switch (dataC)
0181       {
0182       case 0xF2:
0183         std::cerr << " APE_STRIP_START" << std::endl;
0184         decoder_error_vector.push_back(
0185             std::make_pair(static_cast<int>(chipId), 11));
0186         break;
0187       case 0xF4:
0188         std::cerr << " APE_DET_TIMEOUT" << std::endl;
0189         decoder_error_vector.push_back(
0190             std::make_pair(static_cast<int>(chipId), 12));
0191         break;
0192       case 0xF5:
0193         std::cerr << " APE_OOT" << std::endl;
0194         decoder_error_vector.push_back(
0195             std::make_pair(static_cast<int>(chipId), 13));
0196         break;
0197       case 0xF6:
0198         std::cerr << " APE_PROTOCOL_ERROR" << std::endl;
0199         decoder_error_vector.push_back(
0200             std::make_pair(static_cast<int>(chipId), 14));
0201         break;
0202       case 0xF7:
0203         std::cerr << " APE_LANE_FIFO_OVERFLOW_ERROR" << std::endl;
0204         decoder_error_vector.push_back(
0205             std::make_pair(static_cast<int>(chipId), 15));
0206         break;
0207       case 0xF8:
0208         std::cerr << " APE_FSM_ERROR" << std::endl;
0209         decoder_error_vector.push_back(
0210             std::make_pair(static_cast<int>(chipId), 16));
0211         break;
0212       case 0xF9:
0213         std::cerr << " APE_PENDING_DETECTOR_EVENT_LIMIT" << std::endl;
0214         decoder_error_vector.push_back(
0215             std::make_pair(static_cast<int>(chipId), 17));
0216         break;
0217       case 0xFA:
0218         std::cerr << " APE_PENDING_LANE_EVENT_LIMIT" << std::endl;
0219         decoder_error_vector.push_back(
0220             std::make_pair(static_cast<int>(chipId), 18));
0221         break;
0222       case 0xFB:
0223         std::cerr << " APE_O2N_ERROR" << std::endl;
0224         decoder_error_vector.push_back(
0225             std::make_pair(static_cast<int>(chipId), 19));
0226         break;
0227       case 0xFC:
0228         std::cerr << " APE_RATE_MISSING_TRG_ERROR" << std::endl;
0229         decoder_error_vector.push_back(
0230             std::make_pair(static_cast<int>(chipId), 20));
0231         break;
0232       case 0xFD:
0233         std::cerr << " APE_PE_DATA_MISSING" << std::endl;
0234         decoder_error_vector.push_back(
0235             std::make_pair(static_cast<int>(chipId), 21));
0236         break;
0237       case 0xFE:
0238         std::cerr << " APE_OOT_DATA_MISSING" << std::endl;
0239         decoder_error_vector.push_back(
0240             std::make_pair(static_cast<int>(chipId), 22));
0241         break;
0242       default:
0243         std::cerr << " Unknown APE code" << std::endl;
0244         decoder_error_vector.push_back(
0245             std::make_pair(static_cast<int>(chipId), 23));
0246       }
0247       return;
0248     }
0249 
0250     void AlpideByteError(const uint8_t &chipId, PayLoadCont &buffer)
0251     {
0252       uint8_t dataC = 0;
0253 
0254       std::cerr << "Link: " << feeId << ", Chip: " << (int) chipId;
0255       std::cerr << " invalid byte 0x" << std::hex << (int) (dataC) << std::endl;
0256       decoder_error_vector.push_back(
0257           std::make_pair(static_cast<int>(chipId), 10));
0258       while (buffer.next(dataC))
0259       {
0260         std::cerr << " " << std::hex << (int) (dataC) << " ";
0261       }
0262       std::cerr << std::endl;
0263       buffer.clear();
0264       return;
0265     }
0266 
0267     void PrintFlxWord(std::ostream &os, uint8_t *pos)
0268     {
0269       os << std::setfill('0');
0270       for (int i = 0; i < 32; i++)
0271       {
0272         os << std::hex << std::setw(2) << (int) pos[i] << " " << std::dec;
0273       }
0274       os << std::setfill(' ') << std::endl;
0275     }
0276 
0277     void PrintBlock(std::ostream &os, uint8_t *pos, size_t n)
0278     {
0279       for (uint32_t i = 0; i < n; ++i)
0280       {
0281         PrintFlxWord(os, pos + 32 * i);
0282       }
0283     }
0284 
0285     //  ClassDefNV(GBTLink, 1);
0286   };
0287 
0288   ///_________________________________________________________________
0289   /// collect cables data for single ROF, return number of real payload words
0290   /// seen, -1 in case of critical error
0291   inline GBTLink::CollectedDataStatus
0292       GBTLink::collectROFCableData(/*const Mapping& chmap*/)
0293   {
0294     bool prev_evt_complete = false;
0295     bool header_found = false;
0296     bool trailer_found = false;
0297     uint8_t *hbf_start = nullptr;
0298 
0299     status = None;
0300 
0301     auto currRawPiece = rawData.currentPiece();
0302     dataOffset = 0;
0303     while (currRawPiece)
0304     {  // we may loop over multiple FLX page
0305       uint32_t n_no_continuation = 0;
0306       uint32_t n_packet_done = 0;
0307 
0308       if (dataOffset >= currRawPiece->size)
0309       {
0310         data.movePtr(currRawPiece->size);
0311         dataOffset = 0;
0312         // start of the RDH
0313         if (!(currRawPiece = rawData.nextPiece()))
0314         {         // fetch next CRU page
0315           break;  // Data chunk (TF?) is done
0316         }
0317       }
0318 
0319       if (currRawPiece->hasError)  // Skip
0320       {
0321         decoder_error_vector.push_back(std::make_pair(-1, 1));
0322         dataOffset = currRawPiece->size;
0323         ++hbf_count;
0324         continue;
0325       }
0326 
0327       if (!dataOffset)
0328       {
0329         hbf_start = data.getPtr();
0330       }
0331 
0332       // here we always start with the RDH
0333       RdhExt_t rdh = {};
0334       uint8_t *rdh_start = data.getPtr() + dataOffset;
0335       rdh.decode(rdh_start);
0336       if (!rdh.checkRDH(true))
0337       {
0338         dataOffset = currRawPiece->size;
0339         ++hbf_count;
0340         continue;
0341       }
0342 
0343       size_t pagesize = (rdh.pageSize + 1) * FLXWordLength;
0344       const size_t nFlxWords = (pagesize - (2 * FLXWordLength)) / FLXWordLength;
0345       // Fill statistics
0346       if (!rdh.packetCounter)
0347       {
0348         if (dataOffset)
0349         {
0350           log_error << "Wrong dataOffset value " << dataOffset
0351                     << " at the start of a HBF" << std::endl;
0352           decoder_error_vector.push_back(std::make_pair(-1, 2));
0353           assert(false);
0354           return CollectedDataStatus::AbortedOnError;
0355         }
0356         statistics.clear();
0357         // TODO: initialize/clear alpide data buffer
0358         for (uint32_t trg = GBTLinkDecodingStat::BitMaps::ORBIT;
0359              trg < GBTLinkDecodingStat::nBitMap; ++trg)
0360         {
0361           if ((rdh.trgType >> trg) & 1)
0362           {
0363             statistics.trgBitCounts[trg]++;
0364           }
0365         }
0366         hbfEntry =
0367             rawData
0368                 .currentPieceId();  // in case of problems with RDH, dump full TF
0369         ++hbf_count;
0370       }
0371       else if (!rdh.stopBit)
0372       {
0373         if (prev_evt_complete)
0374         {
0375           log_error << "Previous event was already completed" << std::endl;
0376           decoder_error_vector.push_back(std::make_pair(-1, 3));
0377           assert(false);
0378           return CollectedDataStatus::AbortedOnError;
0379         }
0380       }
0381 
0382       dataOffset += 2 * FLXWordLength;
0383       int prev_gbt_cnt = 3;
0384       GBTWord gbtWords[3];
0385       uint16_t w16 = 0;
0386       for (size_t iflx = 0; iflx < nFlxWords; ++iflx)
0387       {
0388         readFlxWord(gbtWords, w16);
0389         int16_t n_gbt_cnt = (w16 & 0x3FF) - prev_gbt_cnt;
0390         prev_gbt_cnt = (w16 & 0x3FF);
0391         if (n_gbt_cnt < 1 || n_gbt_cnt > 3)
0392         {
0393           log_error << "Bad gbt counter in the flx packet. FLX: " << flxId
0394                     << ", Feeid: " << feeId << ", n_gbt_cnt: " << n_gbt_cnt
0395                     << ", prev_gbt_cnt: " << prev_gbt_cnt
0396                     << ", size: " << currRawPiece->size
0397                     << ", dataOffset: " << dataOffset << std::endl;
0398           decoder_error_vector.push_back(std::make_pair(-1, 4));
0399           // PrintBlock(std::cerr, rdh_start, nFlxWords + 2);
0400           log_error << "rdh_start length: " << (nFlxWords + 2) << std::endl;
0401           std::cerr << "Full HBF" << std::endl;
0402           // PrintBlock(std::cerr, hbf_start, (currRawPiece->size/32) );
0403           log_error << "hbf_start length: " << (currRawPiece->size / 32)
0404                     << std::endl;
0405           break;
0406         }
0407         for (int i = 0; i < n_gbt_cnt; ++i)
0408         {
0409           auto &gbtWord = gbtWords[i];
0410           if (gbtWord.isIHW())  // ITS HEADER WORD
0411           {
0412             // TODO assert first word after RDH and active lanes
0413             if (!(!gbtWord.activeLanes ||
0414                   ((gbtWord.activeLanes >> 0) & 0x7) == 0x7 ||
0415                   ((gbtWord.activeLanes >> 3) & 0x7) == 0x7 ||
0416                   ((gbtWord.activeLanes >> 6) & 0x7) == 0x7))
0417             {
0418               log_error << "Expected all active lanes for links, but "
0419                         << gbtWord.activeLanes << "found in HBF " << hbfEntry
0420                         << ", " << gbtWord.asString().data() << std::endl;
0421               decoder_error_vector.push_back(std::make_pair(-1, 5));
0422               assert(false);
0423               return CollectedDataStatus::AbortedOnError;
0424             }
0425           }
0426           else if (gbtWord.isTDH())  // TRIGGER DATA HEADER (TDH)
0427           {
0428             header_found = true;
0429             ir.orbit = gbtWord.bco;
0430             ir.bc = gbtWord.bc;
0431             if (gbtWord
0432                     .bc)  // statistic trigger for first bc already filled on RDH
0433             {
0434               for (uint32_t trg = GBTLinkDecodingStat::BitMaps::ORBIT;
0435                    trg < GBTLinkDecodingStat::nBitMap; ++trg)
0436               {
0437                 if (trg ==
0438                     GBTLinkDecodingStat::BitMaps::FE_RST)  //  TDH save first 12
0439                                                            //  bits only
0440                   break;
0441                 if (((gbtWord.triggerType >> trg) & 1))
0442                 {
0443                   statistics.trgBitCounts[trg]++;
0444                 }
0445               }
0446             }
0447 
0448             if ((gbtWord.triggerType >> GBTLinkDecodingStat::BitMaps::PHYSICS) &
0449                 0x1)
0450             {
0451               mL1TrgTime.push_back(ir);
0452             }
0453 
0454             if (!gbtWord.continuation && !gbtWord.noData)
0455             {
0456               n_no_continuation++;
0457               mTrgData.emplace_back(ir.orbit, ir.bc);
0458             }  // end if not cont
0459           }  // end TDH
0460           else if (gbtWord.isCDW())  // CALIBRATION DATA WORD
0461           {
0462             mTrgData.back().hasCDW = true;
0463             mTrgData.back().calWord =
0464                 *(reinterpret_cast<GBTCalibDataWord *>(&gbtWord));
0465           }
0466           else if (gbtWord.isTDT())
0467           {
0468             trailer_found = true;
0469             if (gbtWord.packet_done)
0470             {
0471               n_packet_done++;
0472               if (n_packet_done < n_no_continuation)
0473               {
0474                 log_error << "TDT packet done before TDH no continuation "
0475                           << n_no_continuation << " != " << n_packet_done
0476                           << std::endl;
0477                 decoder_error_vector.push_back(std::make_pair(-1, 6));
0478                 assert(false);
0479                 return CollectedDataStatus::AbortedOnError;
0480               }
0481             }
0482 
0483             if (gbtWord.lane_status != 0x0)
0484               tdt_lanestatus_error_vector.push_back(gbtWord.lane_status);
0485 
0486             prev_evt_complete = gbtWord.packet_done;
0487             // TODO: YCM Add warning and counter for timeout and violation
0488           }
0489           else if (gbtWord.isDDW())  // DIAGNOSTIC DATA WORD (DDW)
0490           {
0491             if (!rdh.stopBit)
0492             {
0493               log_error << "" << std::endl;
0494               decoder_error_vector.push_back(std::make_pair(-1, 7));
0495               assert(false);
0496               return CollectedDataStatus::AbortedOnError;
0497             }
0498           }
0499           else if (gbtWord.isDiagnosticIB())  // IB DIAGNOSTIC DATA
0500           {
0501             std::cout << "WARNING: IB Diagnostic word found." << std::endl;
0502             std::cout << "diagnostic_lane_id: " << (gbtWord.id >> 5);
0503             std::cout << " lane_error_id: " << gbtWord.lane_error_id;
0504             std::cout << " diasnotic_data: 0x" << std::hex
0505                       << gbtWord.diagnostic_data << std::endl;
0506           }
0507           else if (gbtWord.isData())  // IS IB DATA
0508           {
0509             if (!header_found)
0510             {
0511               log_error << "Trigger header not found before chip data"
0512                         << std::endl;
0513               decoder_error_vector.push_back(std::make_pair(-1, 8));
0514               assert(false);
0515               return CollectedDataStatus::AbortedOnError;
0516             }
0517             auto lane = (gbtWord.data8[9] & 0x1F) % 3;
0518             cableData[lane].add(gbtWord.getW8(), 9);
0519           }
0520 
0521           if (prev_evt_complete)
0522           {
0523             bool decode_failed = false;
0524             auto &&trgData = mTrgData.back();
0525             trgData.first_hit_pos = hit_vector.size();
0526             for (auto &&itr = cableData.begin(); itr != cableData.end(); ++itr)
0527             {
0528               if (!itr->isEmpty())
0529               {
0530                 int status =
0531                     decode_lane(std::distance(cableData.begin(), itr), *itr);
0532                 if (status == -1)
0533                   decode_failed = true;
0534               }
0535             }
0536             trgData.n_hits = hit_vector.size() - trgData.first_hit_pos;
0537             prev_evt_complete = false;
0538             header_found = false;
0539             trailer_found = false;
0540             clearCableData();
0541             if (decode_failed)
0542               return CollectedDataStatus::AbortedOnError;
0543           }
0544         }
0545       }
0546     }
0547     return (status = StoppedOnEndOfData);
0548   }
0549 
0550   //_________________________________________________
0551   inline int GBTLink::decode_lane(const uint8_t chipId, PayLoadCont &buffer)
0552   {
0553     int ret = 0;  // currently we just print stuff, but we will add stuff to our
0554                   // structures and return a status later (that's why it's not a
0555                   // const function)
0556     if (buffer.getSize() < 3)
0557     {
0558       log_error << "chip data is too short: " << buffer.getSize() << std::endl;
0559       decoder_error_vector.push_back(std::make_pair(static_cast<int>(chipId), 9));
0560       assert(false);
0561       return -1;
0562     }
0563 
0564     uint8_t dataC = 0;
0565     uint16_t dataS = 0;
0566 
0567     bool busy_on = false, busy_off = false;
0568     bool chip_header_found = false;
0569     bool chip_trailer_found = false;
0570 
0571     uint8_t laneId = 0xFF;
0572     uint8_t bc = 0xFF;
0573     uint8_t reg = 0xFF;
0574 
0575     if (!((buffer[0] & 0xF0) == 0xE0 || (buffer[0] & 0xF0) == 0xA0 ||
0576           (buffer[0] == 0xF0) || (buffer[0] == 0xF1) ||
0577           (buffer[0] & 0xF0) == 0xF0))
0578     {
0579       AlpideByteError(chipId, buffer);
0580       return 0;
0581     }
0582 
0583     while (buffer.next(dataC))
0584     {
0585       if (dataC == 0xF1)  // BUSY ON
0586       {
0587         busy_on = true;
0588       }
0589       else if (dataC == 0xF0)  // BUSY OFF
0590       {
0591         busy_off = true;
0592       }
0593       else if ((dataC & 0xF0) == 0xF0)  // APE
0594       {
0595         check_APE(chipId, dataC);
0596         // APE_error_vector.push_back((((uint16_t)chipId << 8) | dataC));
0597         chip_trailer_found = 1;
0598         busy_on = busy_off = chip_header_found = 0;
0599       }
0600       else if ((dataC & 0xF0) == 0xE0)  // EMPTY
0601       {
0602         chip_header_found = false;
0603         chip_trailer_found = true;
0604         laneId = (dataC & 0x0F) % 3;
0605         if (laneId != chipId)
0606         {
0607           log_error << "Error laneId " << laneId << " (" << (dataC & 0xF)
0608                     << ") and chipId " << chipId << std::endl;
0609           decoder_error_vector.push_back(
0610               std::make_pair(static_cast<int>(chipId), 24));
0611           assert(false);
0612           return -1;
0613         }
0614         buffer.next(bc);
0615         busy_on = busy_off = false;
0616       }
0617       else
0618       {
0619         if (chip_header_found)
0620         {
0621           if ((dataC & 0xE0) == 0xC0)  // REGION HEADER
0622           {
0623             if (buffer.getUnusedSize() < 2)
0624             {
0625               log_error << "No data short would fit (at least a data short after "
0626                            "region header!)"
0627                         << std::endl;
0628               decoder_error_vector.push_back(
0629                   std::make_pair(static_cast<int>(chipId), 25));
0630               assert(false);
0631               return -1;
0632             }
0633             // TODO: move first region header out of loop, asserting its existence
0634             reg = dataC & 0x1F;
0635           }
0636           else if ((dataC & 0xC0) == 0x40)  // DATA SHORT
0637           {
0638             if (buffer.isEmpty())
0639             {
0640               log_error << "data short do not fit" << std::endl;
0641               assert(false);
0642               return -1;
0643             }
0644             if (reg == 0xFF)
0645             {
0646               log_error << "data short at " << buffer.getOffset()
0647                         << " before region header" << std::endl;
0648               decoder_error_vector.push_back(
0649                   std::make_pair(static_cast<int>(chipId), 26));
0650               assert(false);
0651               return -1;
0652             }
0653             dataS = (dataC << 8);
0654             buffer.next(dataC);
0655             dataS |= dataC;
0656             addHit(laneId, bc, reg, (dataS & 0x3FFF));
0657           }
0658           else if ((dataC & 0xC0) == 0x00)  // DATA LONG
0659           {
0660             if (buffer.getUnusedSize() < 3)
0661             {
0662               log_error << "No data long would fit (at least a data short after "
0663                            "region header!)"
0664                         << std::endl;
0665               decoder_error_vector.push_back(
0666                   std::make_pair(static_cast<int>(chipId), 27));
0667               assert(false);
0668               return -1;
0669             }
0670             if (reg == 0xFF)
0671             {
0672               log_error << "data short at " << buffer.getOffset()
0673                         << " before region header" << std::endl;
0674               decoder_error_vector.push_back(
0675                   std::make_pair(static_cast<int>(chipId), 28));
0676               assert(false);
0677               return -1;
0678             }
0679             buffer.next(dataS);
0680             uint16_t addr = ((dataC & 0x3F) << 8) | ((dataS >> 8) & 0xFF);
0681             addHit(laneId, bc, reg, addr);
0682             uint8_t hit_map = (dataS & 0xFF);
0683             if (hit_map & 0x80)
0684             {
0685               log_error << "Wrong bit before DATA LONG bit map" << std::endl;
0686               decoder_error_vector.push_back(
0687                   std::make_pair(static_cast<int>(chipId), 29));
0688               assert(false);
0689               return -1;
0690             }
0691             while (hit_map != 0x00)
0692             {
0693               ++addr;
0694               if (hit_map & 1)
0695               {
0696                 addHit(laneId, bc, reg, addr);
0697               }
0698               hit_map >>= 1;
0699             }
0700           }
0701           else if ((dataC & 0xF0) == 0xB0)  // CHIP TRAILER
0702           {
0703             //          uint8_t flag = (dataC & 0x0F);
0704             // TODO: YCM add chipdata statistic
0705             chip_trailer_found = 1;
0706             busy_on = busy_off = chip_header_found = 0;
0707           }
0708           else  // ERROR
0709           {
0710             AlpideByteError(chipId, buffer);
0711             decoder_error_vector.push_back(
0712                 std::make_pair(static_cast<int>(chipId), 10));
0713           }
0714         }
0715         else
0716         {
0717           if ((dataC & 0xF0) == 0xA0)  // CHIP HEADER
0718           {
0719             chip_header_found = true;
0720             chip_trailer_found = false;
0721             laneId = (dataC & 0x0F) % 3;
0722             if (laneId != chipId)
0723             {
0724               log_error << "Error laneId " << laneId << " (" << (dataC & 0xF)
0725                         << ") and chipId " << chipId << std::endl;
0726               decoder_error_vector.push_back(
0727                   std::make_pair(static_cast<int>(chipId), 23));
0728               assert(false);
0729               return -1;
0730             }
0731             buffer.next(bc);
0732             reg = 0xFF;
0733           }
0734           else if (dataC == 0x00)  // PADDING
0735           {
0736             continue;
0737           }
0738           else
0739           {  // ERROR
0740             AlpideByteError(chipId, buffer);
0741             decoder_error_vector.push_back(
0742                 std::make_pair(static_cast<int>(chipId), 10));
0743           }  // else !chip_header_found
0744         }  // if chip_header_found
0745       }  // busy_on, busy_off, chip_empty, other
0746     }  // while
0747 
0748     return ret;
0749   }
0750 
0751 }  // namespace mvtx
0752 
0753 #endif  // _MVTX_DECODER_ITSMFT_GBTLINK_H_