diff --git a/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/DataDecoder.h b/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/DataDecoder.h index 70e1e59ee8f33..fbd5501af11e4 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/DataDecoder.h +++ b/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/DataDecoder.h @@ -177,7 +177,6 @@ class DataDecoder /// Compute the time of all the digits that have been decoded in the current TimeFrame void computeDigitsTimeBCRst(); void computeDigitsTime(); - void checkDigitsTime(); /// Get the vector of digits that have been decoded in the current TimeFrame const RawDigitVector& getDigits() const { return mDigits; } diff --git a/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/ErrorCodes.h b/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/ErrorCodes.h index 43d977a9dfd14..52d5300bffa3e 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/ErrorCodes.h +++ b/Detectors/MUON/MCH/Raw/Decoder/include/MCHRawDecoder/ErrorCodes.h @@ -25,16 +25,18 @@ enum ErrorCodes { ErrorParity = 1, // 1 ErrorHammingCorrectable = 1 << 1, // 2 ErrorHammingUncorrectable = 1 << 2, // 4 - ErrorBadClusterSize = 1 << 3, // 8 - ErrorBadPacketType = 1 << 4, // 16 - ErrorBadHeartBeatPacket = 1 << 5, // 32 - ErrorBadIncompleteWord = 1 << 6, // 64 - ErrorTruncatedData = 1 << 7, // 128 - ErrorBadELinkID = 1 << 8, // 256 - ErrorBadLinkID = 1 << 9, // 512 - ErrorUnknownLinkID = 1 << 10, // 1024 - ErrorInvalidDigitTime = 1 << 11, // 2048 - ErrorNonRecoverableDecodingError = 1 << 12 // 4096 + ErrorBadSyncPacket = 1 << 3, // 8 + ErrorBadHeartBeatPacket = 1 << 4, // 16 + ErrorBadDataPacket = 1 << 5, // 32 + ErrorBadClusterSize = 1 << 6, // 64 + ErrorBadIncompleteWord = 1 << 7, // 128 + ErrorTruncatedData = 1 << 8, // 256 + ErrorUnexpectedSyncPacket = 1 << 9, // 512 + ErrorBadELinkID = 1 << 10, // 1024 + ErrorBadLinkID = 1 << 11, // 2048 + ErrorUnknownLinkID = 1 << 12, // 4096 + ErrorBadHBTime = 1 << 13, // 8192 + ErrorNonRecoverableDecodingError = 1 << 14 // 16384 }; uint32_t getErrorCodesSize(); diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/DataDecoder.cxx b/Detectors/MUON/MCH/Raw/Decoder/src/DataDecoder.cxx index e523ce5fec73d..b0285abaf72cb 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/src/DataDecoder.cxx +++ b/Detectors/MUON/MCH/Raw/Decoder/src/DataDecoder.cxx @@ -564,8 +564,9 @@ void DataDecoder::decodePage(gsl::span page) mHBPackets.emplace_back(solar, ds, chip, bunchCrossing); - if (!mTimeFrameStartRecords[chipId].update(mFirstOrbitInTF, bunchCrossing)) { - if (mErrorCount < MCH_DECODER_MAX_ERROR_COUNT) { + if (mTimeRecoMode == TimeRecoMode::HBPackets) { + bool isOk = mTimeFrameStartRecords[chipId].update(mFirstOrbitInTF, bunchCrossing); + if (!isOk && mErrorCount < MCH_DECODER_MAX_ERROR_COUNT) { auto s = asString(dsElecId); LOGP(warning, "Bad HeartBeat packet received: {}-CHIP{} {}/{} (last {}/{})", s, chip, mFirstOrbitInTF, bunchCrossing, mTimeFrameStartRecords[chipId].mOrbitPrev, mTimeFrameStartRecords[chipId].mBunchCrossingPrev); @@ -814,21 +815,6 @@ void DataDecoder::computeDigitsTimeBCRst() //_________________________________________________________________________________________________ -void DataDecoder::checkDigitsTime() -{ - for (auto& digit : mDigits) { - auto& d = digit.digit; - auto& info = digit.info; - auto tfTime = d.getTime(); - if (tfTime == DataDecoder::tfTimeInvalid) { - // add invalid digit time error - mErrors.emplace_back(o2::mch::DecoderError(info.solar, info.ds, info.chip, ErrorInvalidDigitTime)); - } - } -} - -//_________________________________________________________________________________________________ - void DataDecoder::computeDigitsTime() { switch (mTimeRecoMode) { diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/ErrorCodes.cxx b/Detectors/MUON/MCH/Raw/Decoder/src/ErrorCodes.cxx index 9edf841c3f275..6d3ca8eef7df0 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/src/ErrorCodes.cxx +++ b/Detectors/MUON/MCH/Raw/Decoder/src/ErrorCodes.cxx @@ -20,7 +20,7 @@ namespace raw uint32_t getErrorCodesSize() { - return 13; + return 15; } void append(const char* msg, std::string& to) @@ -49,12 +49,18 @@ std::string errorCodeAsString(uint32_t ec) if (ec & ErrorBadClusterSize) { append("Cluster Size", msg); } - if (ec & ErrorBadPacketType) { - append("Bad Packet Type", msg); + if (ec & ErrorBadSyncPacket) { + append("Bad Sync Packet", msg); + } + if (ec & ErrorUnexpectedSyncPacket) { + append("Unexpected Sync", msg); } if (ec & ErrorBadHeartBeatPacket) { append("Bad HB Packet", msg); } + if (ec & ErrorBadDataPacket) { + append("Bad Data Packet", msg); + } if (ec & ErrorBadIncompleteWord) { append("Bad Incomplete Word", msg); } @@ -70,8 +76,8 @@ std::string errorCodeAsString(uint32_t ec) if (ec & ErrorUnknownLinkID) { append("Unknown Link ID", msg); } - if (ec & ErrorInvalidDigitTime) { - append("Invalid Digit Time", msg); + if (ec & ErrorBadHBTime) { + append("Bad HB Time", msg); } if (ec & ErrorNonRecoverableDecodingError) { append("Non Recoverable", msg); diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicElinkDecoder.cxx b/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicElinkDecoder.cxx index 86eb5477d1ef7..e719671c50894 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicElinkDecoder.cxx +++ b/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicElinkDecoder.cxx @@ -38,4 +38,52 @@ void UserLogicElinkDecoder::prepareAndSendCluster() mSamples.clear(); } +template <> +bool UserLogicElinkDecoder::checkDataHeader() +{ + int chipAddMin = mDsId.elinkIndexInGroup() * 2; + int chipAddMax = chipAddMin + 1; + + // the chip address from the SAMPA header must be consistent with + // the e-Link index + int chipAdd = mSampaHeader.chipAddress(); + if (chipAdd < chipAddMin || chipAdd > chipAddMax) { + return false; + } + + // we expect at least 3 10-bit words + int nof10BitWords = mSampaHeader.nof10BitWords(); + if (nof10BitWords <= 2) { + return false; + } + + return true; +} + +template <> +bool UserLogicElinkDecoder::checkDataHeader() +{ + int chipAddMin = mDsId.elinkIndexInGroup() * 2; + int chipAddMax = chipAddMin + 1; + + // the chip address from the SAMPA header must be consistent with + // the e-Link index + int chipAdd = mSampaHeader.chipAddress(); + if (chipAdd < chipAddMin || chipAdd > chipAddMax) { + return false; + } + + // we expect at least 3 10-bit words + int nof10BitWords = mSampaHeader.nof10BitWords(); + if (nof10BitWords <= 2) { + return false; + } + // in cluster sum mode the number of 10-bit words must be a multiple of 4 + if ((nof10BitWords % 4) != 0) { + return false; + } + + return true; +} + } // namespace o2::mch::raw diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicElinkDecoder.h b/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicElinkDecoder.h index bba31cdaf94a7..7246ebe36d717 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicElinkDecoder.h +++ b/Detectors/MUON/MCH/Raw/Decoder/src/UserLogicElinkDecoder.h @@ -73,6 +73,7 @@ class UserLogicElinkDecoder void completeHeader(); void oneLess10BitWord(); void prepareAndSendCluster(); + bool checkDataHeader(); void sendCluster(const SampaCluster& sc) const; void sendHBPacket(); void sendError(int8_t chip, uint32_t error) const; @@ -118,10 +119,18 @@ void UserLogicElinkDecoder::append(uint64_t data50, uint8_t error, bo if (isSync(data50)) { #ifdef ULDEBUG - debugHeader() << (*this) << fmt::format(" --> SYNC word found {:013x}\n", data50); + debugHeader() << (*this) << fmt::format(" --> SYNC word found {:013x} state={}\n", data50, asString(mState)); #endif - clear(); - transition(State::WaitingHeader); + if (mState != State::WaitingHeader && mState != State::WaitingSync) { +#ifdef ULDEBUG + debugHeader() << (*this) << " SYNC word found while decoding payload --> resetting\n"; +#endif + sendError(static_cast(mSampaHeader.chipAddress()), static_cast(ErrorUnexpectedSyncPacket)); + reset(); + } else { + clear(); + transition(State::WaitingHeader); + } return; } @@ -178,14 +187,18 @@ bool UserLogicElinkDecoder::append10(uint10_t data10) { bool result = false; #ifdef ULDEBUG - debugHeader() << (*this) << fmt::format(" --> data10 {:d}\n", data10); + debugHeader() << (*this) << fmt::format(" --> data10 {:d} state {}\n", data10, asString(mState)); #endif switch (mState) { case State::WaitingHeader: setHeaderPart(data10); if (isHeaderComplete()) { completeHeader(); - if (isSync(mSampaHeader.uint64())) { + if (mSampaHeader.packetType() == SampaPacketType::Sync) { + if (!isSync(mSampaHeader.uint64())) { + mErrorMessage = "badly formatted Sync packet"; + sendError(static_cast(mSampaHeader.chipAddress()), static_cast(ErrorBadSyncPacket)); + } reset(); } else if (mSampaHeader.packetType() == SampaPacketType::HeartBeat) { if (mSampaHeader.isHeartbeat()) { @@ -198,9 +211,15 @@ bool UserLogicElinkDecoder::append10(uint10_t data10) reset(); } } else { - if (mSampaHeader.nof10BitWords() > 2) { - transition(State::WaitingSize); + if (checkDataHeader()) { + if (mSampaHeader.nof10BitWords() > 2) { + transition(State::WaitingSize); + } else { + reset(); + } } else { + mErrorMessage = "badly formatted Data packet"; + sendError(static_cast(mSampaHeader.chipAddress()), static_cast(ErrorBadDataPacket)); reset(); } } @@ -265,6 +284,9 @@ std::string UserLogicElinkDecoder::asString(State s) const case State::WaitingSample: return "WaitingSample"; break; + default: + return "Unknown"; + break; }; } diff --git a/Detectors/MUON/MCH/Raw/Decoder/src/testUserLogicEndpointDecoder.cxx b/Detectors/MUON/MCH/Raw/Decoder/src/testUserLogicEndpointDecoder.cxx index 750808aaeb5c7..43aefe520cb6e 100644 --- a/Detectors/MUON/MCH/Raw/Decoder/src/testUserLogicEndpointDecoder.cxx +++ b/Detectors/MUON/MCH/Raw/Decoder/src/testUserLogicEndpointDecoder.cxx @@ -367,9 +367,10 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(SyncInTheMiddleChargeSumModeTwoChannels, V, testTy DsElecId{361, 6, 2}, 63, {cl1, cl2}, DsElecId{361, 6, 2}, 47, {cl3, cl4}, 5); - BOOST_CHECK_EQUAL(r, - "S361-J6-DS2-ch-63-ts-345-q-123456-cs-789\n" - "S361-J6-DS2-ch-63-ts-346-q-789012-cs-345\n"); + std::string r2 = "S361-J6-DS2-ch-63-ts-345-q-123456-cs-789\n"; + r2 += "S361-J6-DS2-ch-63-ts-346-q-789012-cs-345\n"; + r2 += fmt::format("S361-J6-DS2-chip-5-error-{}\n", ErrorUnexpectedSyncPacket); + BOOST_CHECK_EQUAL(r, r2); } BOOST_AUTO_TEST_CASE_TEMPLATE(TestCruPageOK, V, testTypes) diff --git a/Detectors/MUON/MCH/Workflow/src/DataDecoderSpec.cxx b/Detectors/MUON/MCH/Workflow/src/DataDecoderSpec.cxx index fb80fde805bae..402544d5f8b15 100644 --- a/Detectors/MUON/MCH/Workflow/src/DataDecoderSpec.cxx +++ b/Detectors/MUON/MCH/Workflow/src/DataDecoderSpec.cxx @@ -243,7 +243,6 @@ class DataDecoderTask } } mDecoder->computeDigitsTime(); - mDecoder->checkDigitsTime(); auto tEnd = std::chrono::high_resolution_clock::now(); mTimeDecoding += tEnd - tStart; diff --git a/Detectors/MUON/MCH/Workflow/src/cru-page-reader-workflow.cxx b/Detectors/MUON/MCH/Workflow/src/cru-page-reader-workflow.cxx index a3ae4284d88bc..da11113fdc364 100644 --- a/Detectors/MUON/MCH/Workflow/src/cru-page-reader-workflow.cxx +++ b/Detectors/MUON/MCH/Workflow/src/cru-page-reader-workflow.cxx @@ -320,9 +320,10 @@ class FileReaderTask } if (mPrint) { - std::cout << "Sending TF" << std::endl + std::cout << "Sending TF " << orbitMin << " (previous " << mLastTForbit << " delta " << (orbitMin - mLastTForbit) << ")" << std::endl << std::endl; } + mLastTForbit = orbitMin; auto freefct = [](void* data, void* /*hint*/) { free(data); }; pc.outputs().adoptChunk(Output{"RDT", "RAWDATA"}, outBuf, outSize, freefct, nullptr); @@ -448,7 +449,7 @@ class FileReaderTask // increment the total buffer size mTimeFrameSizes[feeID][linkID] += pageSize; - if ((triggerType & 0x800) != 0 && stopBit == 0 && pageCounter == 0 && bc == 0) { + if ((triggerType & 0x800) != 0 && /*stopBit == 0 && pageCounter == 0 &&*/ bc == 0) { // This is the start of a new TimeFrame, so we need to push a new empty TimeFrame in the queue if (mPrint) { std::cout << "tfQueue.size(): " << tfQueue.size() << std::endl; @@ -615,6 +616,7 @@ class FileReaderTask bool mFullTF; ///< send full time frames bool mSaveTF; ///< save individual time frames to file int mOverlap; ///< overlap between contiguous TimeFrames + int mLastTForbit{0}; ///< first orbit number of last transmitted TimeFrame bool mPrint = false; ///< print debug messages o2::dataformats::TFIDInfo mTFIDInfo{}; // struct to modify output headers