Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-06-04 22:36:08

0001 #include <array>
0002 #include <iomanip>
0003 #include <iostream>
0004 #include <iterator>
0005 #include <vector>
0006 
0007 #include "CondFormats/HGCalObjects/interface/HGCalMappingCellIndexer.h"
0008 #include "CondFormats/HGCalObjects/interface/HGCalMappingModuleIndexer.h"
0009 #include "DataFormats/FEDRawData/interface/FEDRawData.h"
0010 #include "DataFormats/HGCalDigi/interface/HGCalDigiHost.h"
0011 #include "DataFormats/HGCalDigi/interface/HGCalECONDPacketInfoHost.h"
0012 #include "DataFormats/HGCalDigi/interface/HGCalFEDPacketInfoHost.h"
0013 #include "DataFormats/HGCalDigi/interface/HGCalRawDataDefinitions.h"
0014 #include "EventFilter/HGCalRawToDigi/interface/HGCalUnpacker.h"
0015 #include "EventFilter/HGCalRawToDigi/interface/UnpackerTools.h"
0016 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0017 #include "FWCore/Utilities/interface/Exception.h"
0018 
0019 using namespace hgcal;
0020 
0021 uint16_t HGCalUnpacker::parseFEDData(unsigned fedId,
0022                                      const FEDRawData& fed_data,
0023                                      const HGCalMappingModuleIndexer& moduleIndexer,
0024                                      const HGCalConfiguration& config,
0025                                      hgcaldigi::HGCalDigiHost& digis,
0026                                      hgcaldigi::HGCalECONDPacketInfoHost& econdPacketInfo,
0027                                      bool headerOnlyMode) {
0028   // ReadoutSequence object for this FED
0029   const auto& fedReadoutSequence = moduleIndexer.getFEDReadoutSequences()[fedId];
0030   // Configuration object for this FED
0031   const auto& fedConfig = config.feds[fedId];
0032 
0033   // helper functions
0034   auto to_32b_words = [](const uint64_t* ptr_64b) {
0035     auto* ptr_32b = reinterpret_cast<const uint32_t*>(ptr_64b);
0036     return std::array<uint32_t, 2>{{ptr_32b[1], ptr_32b[0]}};
0037   };
0038 
0039   auto to_econd_payload = [](const uint64_t* ptr_64b, uint64_t payload_length) -> std::vector<uint32_t> {
0040     std::vector<uint32_t> payload(payload_length, 0);
0041     auto* ptr_32b = reinterpret_cast<const uint32_t*>(ptr_64b);
0042     for (unsigned i = 0; i < payload_length; ++i) {
0043       payload[i] = ptr_32b[(i % 2 == 0) ? i + 1 : i - 1];
0044     }
0045     return payload;
0046   };
0047 
0048   // Endianness assumption
0049   // From 32-bit word(ECOND) to 64-bit word(capture block): little endianness
0050   // Others: big endianness
0051   const auto* const header = reinterpret_cast<const uint64_t*>(fed_data.data());
0052   const auto* const trailer = reinterpret_cast<const uint64_t*>(fed_data.data() + fed_data.size());
0053   LogDebug("[HGCalUnpacker]") << "fedId = " << fedId << " nwords (64b) = " << std::distance(header, trailer);
0054   const auto* ptr = header;
0055 
0056 #ifdef EDM_ML_DEBUG
0057   for (unsigned iword = 0; ptr < trailer; ++iword) {
0058     LogDebug("[HGCalUnpacker]") << std::setw(8) << iword << ": 0x" << std::hex << std::setfill('0') << std::setw(16)
0059                                 << *ptr << " (" << std::setfill('0') << std::setw(8)
0060                                 << *(reinterpret_cast<const uint32_t*>(ptr) + 1) << " " << std::setfill('0')
0061                                 << std::setw(8) << *reinterpret_cast<const uint32_t*>(ptr) << ")" << std::dec;
0062     ++ptr;
0063   }
0064   LogDebug("[HGCalUnpacker]") << "@@@\n";
0065   ptr = header;
0066 #endif
0067 
0068   // check SLink header (128b)
0069   // sanity check
0070   auto slink_header = *(ptr + 1);
0071   if (((slink_header >> (BACKEND_FRAME::SLINK_BOE_POS + 32)) & BACKEND_FRAME::SLINK_BOE_MASK) !=
0072       fedConfig.slinkHeaderMarker) {
0073     uint32_t ECONDdenseIdx = moduleIndexer.getIndexForModule(fedId, 0);
0074     econdPacketInfo.view()[ECONDdenseIdx].exception() = 1;
0075     econdPacketInfo.view()[ECONDdenseIdx].location() = 0;
0076     edm::LogWarning("[HGCalUnpacker]") << "Expected a S-Link header (BOE: 0x" << std::hex << fedConfig.slinkHeaderMarker
0077                                        << "), got 0x" << std::hex
0078                                        << ((slink_header >> (BACKEND_FRAME::SLINK_BOE_POS + 32)) &
0079                                            BACKEND_FRAME::SLINK_BOE_MASK)
0080                                        << " from " << slink_header << ".";
0081     return (0x1 << hgcaldigi::FEDUnpackingFlags::ErrorSLinkHeader);
0082   }
0083 
0084   ptr += 2;
0085   // counter for the global index of ECON-D in the FED
0086   // initialize with -1 (overflow) to start with 0 in the loop
0087   uint32_t globalECONDIdx = static_cast<uint32_t>(-1);
0088 
0089   // parse SLink body (capture blocks)
0090   bool hasActiveCBFlags(false);
0091   for (uint32_t captureblockIdx = 0; captureblockIdx < HGCalMappingModuleIndexer::maxCBperFED_ && ptr < trailer - 2;
0092        captureblockIdx++) {
0093     // check capture block header (64b)
0094     LogDebug("[HGCalUnpacker]") << "@" << std::setw(8) << std::distance(header, ptr) << ": 0x" << std::hex
0095                                 << std::setfill('0') << std::setw(16) << *ptr << std::dec;
0096     auto cb_header = *ptr;
0097     LogDebug("[HGCalUnpacker]") << "fedId = " << fedId << ", captureblockIdx = " << captureblockIdx
0098                                 << ", cb_header = " << std::hex << std::setfill('0') << std::setw(16) << cb_header
0099                                 << std::dec;
0100     // sanity check
0101     if (((cb_header >> (BACKEND_FRAME::CAPTUREBLOCK_RESERVED_POS + 32)) & BACKEND_FRAME::CAPTUREBLOCK_RESERVED_MASK) !=
0102         fedConfig.cbHeaderMarker) {
0103       //if word is a 0x0 it probably means that it's a 64b padding word: check that we are ending
0104       //the s-link may have less capture blocks than the maxCBperFED_ so for now this is considered normal
0105       uint32_t ECONDdenseIdx = moduleIndexer.getIndexForModule(fedId, 0);
0106       econdPacketInfo.view()[ECONDdenseIdx].location() = (uint32_t)(ptr - header);
0107       if (cb_header == 0x0) {
0108         auto nToEnd = (fed_data.size() / 8 - 2) - std::distance(header, ptr);
0109         if (nToEnd == 1) {
0110           ptr++;
0111           LogDebug("[HGCalUnpacker]")
0112               << "fedId = " << fedId
0113               << ", 64b padding word caught before parsing all max capture blocks, captureblockIdx = "
0114               << captureblockIdx;
0115           econdPacketInfo.view()[ECONDdenseIdx].exception() = 7;
0116           return (0x1 << hgcaldigi::FEDUnpackingFlags::ErrorCaptureBlockHeader);
0117         }
0118       }
0119       econdPacketInfo.view()[ECONDdenseIdx].exception() = 2;
0120       edm::LogWarning("[HGCalUnpacker]") << "Expected a capture block header at word " << std::dec
0121                                          << (uint32_t)(ptr - header) << "/0x" << std::hex << (uint32_t)(ptr - header)
0122                                          << " (reserved word: 0x" << fedConfig.cbHeaderMarker << "), got 0x"
0123                                          << ((cb_header >> (BACKEND_FRAME::CAPTUREBLOCK_RESERVED_POS + 32)) &
0124                                              BACKEND_FRAME::CAPTUREBLOCK_RESERVED_MASK)
0125                                          << " from 0x" << cb_header << ".";
0126       return (0x1 << hgcaldigi::FEDUnpackingFlags::ErrorCaptureBlockHeader);
0127     }
0128     ++ptr;
0129 
0130     // parse Capture Block body (ECON-Ds)
0131     for (uint32_t econdIdx = 0; econdIdx < HGCalMappingModuleIndexer::maxECONDperCB_; econdIdx++) {
0132       auto econd_pkt_status = (cb_header >> (3 * econdIdx)) & 0b111;
0133       LogDebug("[HGCalUnpacker]") << "fedId = " << fedId << ", captureblockIdx = " << captureblockIdx
0134                                   << ", econdIdx = " << econdIdx << ", econd_pkt_status = " << econd_pkt_status;
0135       if (econd_pkt_status != backend::ECONDPacketStatus::InactiveECOND) {
0136         // always increment the global ECON-D index (unless inactive/unconnected)
0137         globalECONDIdx++;
0138       }
0139       hasActiveCBFlags = (econd_pkt_status != backend::ECONDPacketStatus::Normal) &&
0140                          (econd_pkt_status != backend::ECONDPacketStatus::InactiveECOND);
0141       bool pkt_exists =
0142           (econd_pkt_status == backend::ECONDPacketStatus::Normal) ||
0143           (econd_pkt_status == backend::ECONDPacketStatus::PayloadCRCError) ||
0144           (econd_pkt_status == backend::ECONDPacketStatus::EventIDMismatch) ||
0145           (fedConfig.mismatchPassthroughMode && econd_pkt_status == backend::ECONDPacketStatus::BCIDOrbitIDMismatch);
0146       if (!pkt_exists) {
0147         continue;
0148       }
0149 
0150       // ECON-D header (two 32b words)
0151       LogDebug("[HGCalUnpacker]") << "@" << std::setw(8) << std::distance(header, ptr) << ": 0x" << std::hex
0152                                   << std::setfill('0') << std::setw(16) << *ptr << std::dec;
0153       auto econd_headers = to_32b_words(ptr);
0154       uint32_t ECONDdenseIdx = moduleIndexer.getIndexForModule(fedId, globalECONDIdx);
0155       econdPacketInfo.view()[ECONDdenseIdx].location() = (uint32_t)(ptr - header);
0156       const auto econd_payload_length = ((econd_headers[0] >> ECOND_FRAME::PAYLOAD_POS) & ECOND_FRAME::PAYLOAD_MASK);
0157 
0158       // sanity check
0159       if (((econd_headers[0] >> ECOND_FRAME::HEADER_POS) & ECOND_FRAME::HEADER_MASK) !=
0160           fedConfig.econds[globalECONDIdx].headerMarker) {
0161         econdPacketInfo.view()[ECONDdenseIdx].exception() = 3;
0162         edm::LogWarning("[HGCalUnpacker]")
0163             << "Expected a ECON-D header at word " << std::dec << (uint32_t)(ptr - header) << "/0x" << std::hex
0164             << (uint32_t)(ptr - header) << " (marker: 0x" << fedConfig.econds[globalECONDIdx].headerMarker
0165             << "), got 0x" << econd_headers[0] << " and payload=" << econd_payload_length << ".";
0166         return (0x1 << hgcaldigi::FEDUnpackingFlags::ErrorECONDHeader) |
0167                (hasActiveCBFlags << hgcaldigi::FEDUnpackingFlags::ActiveCaptureBlockFlags);
0168       }
0169 
0170       // Compute ECON-D trailer CRC
0171       bool crcvalid = hgcal::econdCRCAnalysis(ptr, 0, econd_payload_length);
0172       LogDebug("[HGCalUnpacker]") << "crc value " << crcvalid;
0173       ++ptr;
0174 
0175       if (!crcvalid) {
0176         hasActiveCBFlags = true;
0177         econd_pkt_status |=
0178             backend::ECONDPacketStatus::OfflinePayloadCRCError;  //If CRC errors in the trailer, update the pkt status
0179       }
0180       econdPacketInfo.view()[ECONDdenseIdx].cbFlag() = (uint16_t)(econd_pkt_status);
0181 
0182       // ECON-D payload length (num of 32b words)
0183       // NOTE: in the capture blocks, ECON-D packets do not have the trailing IDLE word
0184       if (econd_payload_length > 469) {
0185         econdPacketInfo.view()[ECONDdenseIdx].exception() = 4;
0186         edm::LogWarning("[HGCalUnpacker]")
0187             << "Unpacked payload length=" << econd_payload_length << " exceeds the maximal length=469";
0188         return (0x1 << hgcaldigi::FEDUnpackingFlags::ECONDPayloadLengthOverflow) |
0189                (hasActiveCBFlags << hgcaldigi::FEDUnpackingFlags::ActiveCaptureBlockFlags);
0190       }
0191       const auto econdFlag = ((econd_headers[0] >> ECOND_FRAME::BITT_POS) & 0b1111111) +
0192                              (((econd_headers[1] >> ECOND_FRAME::BITS_POS) & 0b1) << hgcaldigi::ECONDFlag::BITS_POS);
0193       econdPacketInfo.view()[ECONDdenseIdx].payloadLength() = (uint16_t)econd_payload_length;
0194       econdPacketInfo.view()[ECONDdenseIdx].econdFlag() = (uint8_t)econdFlag;
0195       econdPacketInfo.view()[ECONDdenseIdx].exception() = 0;
0196 
0197       // convert ECON-D packets into 32b words -- need to swap the order of the two 32b words in the 64b word
0198       auto econd_payload = to_econd_payload(ptr, econd_payload_length);
0199 
0200       // forward ptr to the next ECON-D; use integer division with (... + 1) / 2 to round up
0201       ptr += (econd_payload_length + 1) / 2;
0202 
0203       LogDebug("[HGCalUnpacker]") << "fedId = " << fedId << ", captureblockIdx = " << captureblockIdx
0204                                   << ", econdIdx = " << econdIdx << ", econd_headers = " << std::hex
0205                                   << std::setfill('0') << std::setw(8) << econd_headers[0] << " " << econd_headers[1]
0206                                   << std::dec << ", econd_payload_length = " << econd_payload_length;
0207       //quality check for ECON-D (check econd_pkt_status here for error in trailer CRC)
0208       if ((((econd_headers[0] >> ECOND_FRAME::HT_POS) & ECOND_FRAME::HT_MASK) >= 0b10) ||
0209           (((econd_headers[0] >> ECOND_FRAME::EBO_POS) & ECOND_FRAME::EBO_MASK) >= 0b10) ||
0210           (((econd_headers[0] >> ECOND_FRAME::BITM_POS) & 0b1) == 0) || econd_payload_length == 0 ||
0211           econd_pkt_status == backend::ECONDPacketStatus::OfflinePayloadCRCError ||
0212           econd_pkt_status == backend::ECONDPacketStatus::InactiveECOND || headerOnlyMode) {
0213         continue;
0214       }
0215 
0216       // parse ECON-D body(eRx subpackets)
0217       const auto enabledErx = fedReadoutSequence.enabledErx_[globalECONDIdx];
0218       const auto erxMax = moduleIndexer.getGlobalTypesNErx()[fedReadoutSequence.readoutTypes_[globalECONDIdx]];
0219       const bool pass_through_mode = (econd_headers[0] >> ECOND_FRAME::BITP_POS) & 0b1;
0220 
0221       unsigned iword = 0;
0222       if (!pass_through_mode) {
0223         // Standard ECON-D
0224         LogDebug("[HGCalUnpacker]") << "Standard ECON-D, erxMax=" << erxMax << "enabledErx= " << enabledErx;
0225         for (uint32_t erxIdx = 0; erxIdx < erxMax; erxIdx++) {
0226           // check if the eRx is enabled
0227           if ((enabledErx >> erxIdx & 1) == 0) {
0228             continue;
0229           }
0230           LogDebug("[HGCalUnpacker]") << "fedId = " << fedId << ", captureblockIdx = " << captureblockIdx
0231                                       << ", econdIdx = " << econdIdx << ", erxIdx=" << erxIdx;
0232 
0233           econdPacketInfo.view()[ECONDdenseIdx].cm()(erxIdx, 0) =
0234               (econd_payload[iword] >> ECOND_FRAME::COMMONMODE0_POS) & ECOND_FRAME::COMMONMODE0_MASK;
0235           econdPacketInfo.view()[ECONDdenseIdx].cm()(erxIdx, 1) =
0236               (econd_payload[iword] >> ECOND_FRAME::COMMONMODE1_POS) & ECOND_FRAME::COMMONMODE1_MASK;
0237           // check if the eRx sub-packet is empty (the "F" flag in the eRx sub-packet header)
0238           if (((econd_payload[iword] >> ECOND_FRAME::ERXFORMAT_POS) & ECOND_FRAME::ERXFORMAT_MASK) == 1) {
0239             LogDebug("[HGCalUnpacker]") << "eRx " << erxIdx << " is empty";
0240             iword += 1;  // length of an empty eRx header (32 bits)
0241             continue;    // go to the next eRx
0242           }
0243 
0244           // erx header
0245           uint16_t cmSum = ((econd_payload[iword] >> ECOND_FRAME::COMMONMODE0_POS) & ECOND_FRAME::COMMONMODE0_MASK) +
0246                            ((econd_payload[iword] >> ECOND_FRAME::COMMONMODE1_POS) & ECOND_FRAME::COMMONMODE1_MASK);
0247           uint64_t erxHeader = ((uint64_t)econd_payload[iword] << 32) | ((uint64_t)econd_payload[iword + 1]);
0248           LogDebug("[HGCalUnpacker]") << "erx_headers = 0x" << std::hex << std::setfill('0') << std::setw(16)
0249                                       << erxHeader << ", cmSum = " << std::dec << cmSum;
0250           iword += 2;
0251 
0252           // parse erx body (channel data)
0253           uint32_t iBit = 0;
0254           for (uint32_t channelIdx = 0; channelIdx < HGCalMappingCellIndexer::maxChPerErx_; channelIdx++) {
0255             uint32_t denseIdx = moduleIndexer.getIndexForModuleData(fedId, globalECONDIdx, erxIdx, channelIdx);
0256 
0257             // check if the channel has data
0258             if (((erxHeader >> channelIdx) & 1) == 0) {
0259               continue;
0260             }
0261 
0262             const uint32_t tempIndex = iBit / 32 + iword;
0263             const uint32_t tempBit = iBit % 32;
0264             const uint32_t temp = (tempBit == 0) ? econd_payload[tempIndex]
0265                                                  : (econd_payload[tempIndex] << tempBit) |
0266                                                        (econd_payload[tempIndex + 1] >> (32 - tempBit));
0267             const uint32_t code = temp >> 28;
0268             digis.view()[denseIdx].tctp() = tctp_[code];
0269             digis.view()[denseIdx].adcm1() = (temp >> adcm1Shift_[code]) & adcm1Mask_[code];
0270             digis.view()[denseIdx].adc() = (temp >> adcShift_[code]) & adcMask_[code];
0271             digis.view()[denseIdx].tot() = (temp >> totShift_[code]) & totMask_[code];
0272             digis.view()[denseIdx].toa() = (temp >> toaShift_[code] & toaMask_[code]);
0273             digis.view()[denseIdx].cm() = cmSum;
0274             digis.view()[denseIdx].flags() = 0;
0275             iBit += erxBodyBits_[code];
0276           }
0277           iword += iBit / 32;
0278           if (iBit % 32 != 0) {
0279             iword += 1;
0280           }
0281         }
0282       } else {
0283         // Passthrough ECON-D
0284         LogDebug("[HGCalUnpacker]") << "Passthrough ECON-D, erxMax=" << erxMax << "enabledErx= " << enabledErx;
0285         for (uint32_t erxIdx = 0; erxIdx < erxMax; erxIdx++) {
0286           // check if the eRx is enabled
0287           if ((enabledErx >> erxIdx & 1) == 0) {
0288             continue;
0289           }
0290           LogDebug("[HGCalUnpacker]") << "fedId = " << fedId << ", captureblockIdx = " << captureblockIdx
0291                                       << ", econdIdx = " << econdIdx << ", erxIdx=" << erxIdx;
0292 
0293           econdPacketInfo.view()[ECONDdenseIdx].cm()(erxIdx, 0) =
0294               (econd_payload[iword] >> ECOND_FRAME::COMMONMODE0_POS) & ECOND_FRAME::COMMONMODE0_MASK;
0295           econdPacketInfo.view()[ECONDdenseIdx].cm()(erxIdx, 1) =
0296               (econd_payload[iword] >> ECOND_FRAME::COMMONMODE1_POS) & ECOND_FRAME::COMMONMODE1_MASK;
0297           // check if the eRx sub-packet is empty (the "F" flag in the eRx sub-packet header)
0298           if (((econd_payload[iword] >> ECOND_FRAME::ERXFORMAT_POS) & ECOND_FRAME::ERXFORMAT_MASK) == 1) {
0299             LogDebug("[HGCalUnpacker]") << "eRx " << erxIdx << " is empty";
0300             iword += 1;  // length of an empty eRx header (32 bits)
0301             continue;    // go to the next eRx
0302           }
0303 
0304           // erx header
0305           uint16_t cmSum = ((econd_payload[iword] >> ECOND_FRAME::COMMONMODE0_POS) & ECOND_FRAME::COMMONMODE0_MASK) +
0306                            ((econd_payload[iword] >> ECOND_FRAME::COMMONMODE1_POS) & ECOND_FRAME::COMMONMODE1_MASK);
0307           uint64_t erxHeader = ((uint64_t)econd_payload[iword] << 32) | ((uint64_t)econd_payload[iword + 1]);
0308           LogDebug("[HGCalUnpacker]") << "erx_headers = 0x" << std::hex << std::setfill('0') << std::setw(16)
0309                                       << erxHeader << ", cmSum = " << std::dec << cmSum;
0310           iword += 2;
0311 
0312           // parse erx body (channel data)
0313           for (uint32_t channelIdx = 0; channelIdx < HGCalMappingCellIndexer::maxChPerErx_; channelIdx++) {
0314             uint32_t denseIdx = moduleIndexer.getIndexForModuleData(fedId, globalECONDIdx, erxIdx, channelIdx);
0315 
0316             // check if the channel has data
0317             if (((erxHeader >> channelIdx) & 1) == 0) {
0318               continue;
0319             }
0320 
0321             // check if in characterization mode
0322             if (fedConfig.econds[globalECONDIdx].rocs[erxIdx / 2].charMode) {
0323               //characterization mode
0324               digis.view()[denseIdx].tctp() = (econd_payload[iword] >> 30) & 0b11;
0325               digis.view()[denseIdx].adcm1() = 0;
0326               digis.view()[denseIdx].adc() = (econd_payload[iword] >> 20) & 0b1111111111;
0327               digis.view()[denseIdx].tot() = (econd_payload[iword] >> 10) & 0b1111111111;
0328               digis.view()[denseIdx].toa() = econd_payload[iword] & 0b1111111111;
0329               digis.view()[denseIdx].cm() = cmSum;
0330               digis.view()[denseIdx].flags() = hgcal::DIGI_FLAG::Characterization;
0331             } else {
0332               //not characteristic mode
0333               digis.view()[denseIdx].tctp() = (econd_payload[iword] >> 30) & 0b11;
0334 
0335               digis.view()[denseIdx].adcm1() = (econd_payload[iword] >> 20) & 0b1111111111;
0336               if (econd_payload[iword] >> 31 & 0b1) {
0337                 digis.view()[denseIdx].adc() = 0;
0338                 digis.view()[denseIdx].tot() = (econd_payload[iword] >> 10) & 0b1111111111;
0339               } else {
0340                 digis.view()[denseIdx].adc() = (econd_payload[iword] >> 10) & 0b1111111111;
0341                 digis.view()[denseIdx].tot() = 0;
0342               }
0343               digis.view()[denseIdx].toa() = econd_payload[iword] & 0b1111111111;
0344               digis.view()[denseIdx].cm() = cmSum;
0345               digis.view()[denseIdx].flags() = hgcal::DIGI_FLAG::Normal;
0346             }
0347 
0348             iword += 1;
0349           }
0350         }
0351       }
0352       // end of ECON-D parsing
0353       if (iword != econd_payload_length - 1) {
0354         econdPacketInfo.view()[ECONDdenseIdx].exception() = 5;
0355         edm::LogWarning("[HGCalUnpacker]")
0356             << "Mismatch between unpacked and expected ECON-D #" << (int)globalECONDIdx << " payload length\n"
0357             << "  unpacked payload length=" << iword + 1 << "\n"
0358             << "  expected payload length=" << econd_payload_length;
0359         return (0x1 << hgcaldigi::FEDUnpackingFlags::ECONDPayloadLengthMismatch) |
0360                (hasActiveCBFlags << hgcaldigi::FEDUnpackingFlags::ActiveCaptureBlockFlags);
0361       }
0362     }
0363   }
0364 
0365   // skip the padding word as the last capture block will be aligned to 128b if needed
0366   if (std::distance(ptr, header) % 2) {
0367     ++ptr;
0368   }
0369   // check SLink trailer (128b)
0370   // TODO
0371   if (ptr + 2 != trailer) {
0372     uint32_t ECONDdenseIdx = moduleIndexer.getIndexForModule(fedId, 0);
0373     econdPacketInfo.view()[ECONDdenseIdx].exception() = 6;
0374     edm::LogWarning("[HGCalUnpacker]") << "Error finding the S-link trailer, expected at" << std::dec
0375                                        << (uint32_t)(trailer - header) << "/0x" << std::hex
0376                                        << (uint32_t)(trailer - header) << "Unpacked trailer at" << std::dec
0377                                        << (uint32_t)(trailer - header + 2) << "/0x" << std::hex
0378                                        << (uint32_t)(ptr - header + 2);
0379     return (0x1 << hgcaldigi::FEDUnpackingFlags::ErrorSLinkTrailer) |
0380            (hasActiveCBFlags << hgcaldigi::FEDUnpackingFlags::ActiveCaptureBlockFlags);
0381   }
0382 
0383   return (0x1 << hgcaldigi::FEDUnpackingFlags::NormalUnpacking) |
0384          (hasActiveCBFlags << hgcaldigi::FEDUnpackingFlags::ActiveCaptureBlockFlags);
0385 }