diff --git a/algo/detectors/sts/UnpackSts.cxx b/algo/detectors/sts/UnpackSts.cxx index 00c66eaddde4bb059c51a5588124a768b547383e..ec8389ce1775c78f37cd47be61525468831c0c2c 100644 --- a/algo/detectors/sts/UnpackSts.cxx +++ b/algo/detectors/sts/UnpackSts.cxx @@ -5,62 +5,70 @@ #include "UnpackSts.h" #include <cassert> +#include <utility> #include <vector> #include <cmath> #include "StsXyterMessage.h" +using std::unique_ptr; using std::vector; namespace cbm::algo { // ---- Algorithm execution --------------------------------------------- - vector<CbmStsDigi> UnpackSts::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr, - const uint64_t tTimeslice) + UnpackSts::resultType UnpackSts::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr, + const uint64_t tTimeslice) { // --- Assert that parameters are set assert(fParams); - fCurrentTsTime = tTimeslice; - // --- Output vector - vector<CbmStsDigi> digiVec; + // --- Output data + vector<CbmStsDigi> digiVec = {}; + UnpackStsMonitorData moni = {}; + + // --- Current Timeslice time and TS_MSB epoch cycle + fCurrentTsTime = tTimeslice; + auto msTime = msDescr.idx; // Unix time of MS in ns + fCurrentCycle = std::ldiv(msTime, fkCycleLength).quot; - // --- Current TS_MSB epoch cycle - auto msTime = msDescr.idx; // Unix time of MS in ns - fCurrentCycle = std::ldiv(msTime, fCycleLength).quot; + // --- Interpret MS content as sequence of SMX messages + auto message = reinterpret_cast<const stsxyter::Message*>(msContent); // --- Get first TS_MSB (first message in microslice must be of type ts_msb) - const stsxyter::Message firstMessage(msContent[0]); - assert(firstMessage.GetMessType() == stsxyter::MessType::TsMsb); - ProcessTsmsbMessage(firstMessage); + if (message[0].GetMessType() != stsxyter::MessType::TsMsb) { + moni.fNumErrInvalidFirstMessage++; + return std::make_pair(digiVec, moni); + } + ProcessTsmsbMessage(message[0]); // ---Â Number of messages in microslice auto msSize = msDescr.size; - assert(msSize % sizeof(stsxyter::Message) == 0); + if (msSize % sizeof(stsxyter::Message) != 0) { + moni.fNumErrInvalidMsSize++; + return std::make_pair(digiVec, moni); + } const uint32_t numMessages = msSize / sizeof(stsxyter::Message); // --- Message loop for (uint32_t messageNr = 1; messageNr < numMessages; messageNr++) { - // --- Cast MS content to STSXYTER message - const stsxyter::Message message(msContent[messageNr]); - const stsxyter::MessType type = message.GetMessType(); - // --- Action depending on message type - switch (type) { + switch (message[messageNr].GetMessType()) { case stsxyter::MessType::Hit: { - ProcessHitMessage(message, digiVec); + ProcessHitMessage(message[messageNr], digiVec, moni); break; } case stsxyter::MessType::TsMsb: { - ProcessTsmsbMessage(message); + ProcessTsmsbMessage(message[messageNr]); break; } default: { + moni.fNumNonHitOrTsbMessage++; break; } @@ -68,23 +76,29 @@ namespace cbm::algo } //# Messages - return digiVec; + return std::make_pair(digiVec, moni); } // -------------------------------------------------------------------------- // ----- Process hit message -------------------------------------------- - void UnpackSts::ProcessHitMessage(const stsxyter::Message& message, vector<CbmStsDigi>& digiVec) const + void UnpackSts::ProcessHitMessage(const stsxyter::Message& message, vector<CbmStsDigi>& digiVec, + UnpackStsMonitorData& moni) const { - uint16_t elink = message.GetLinkIndexHitBinning(); - const UnpackStsElinkPar& elinkPar = fParams->GetElinkPar(elink); + // --- Check eLink and get parameters + uint16_t elink = message.GetLinkIndexHitBinning(); + if (elink >= fParams->fElinkParams.size()) { + moni.fNumErrElinkOutOfRange++; + return; + } + const UnpackStsElinkPar& elinkPar = fParams->fElinkParams.at(elink); uint32_t asicNr = elinkPar.fAsicNr; - uint32_t numChansPerModule = fParams->fNumAsicsPerModule * fParams->fNumChansPerAsic; // --- Hardware-to-software address - uint32_t address = elinkPar.fAddress; - uint32_t channel = 0; + uint32_t numChansPerModule = fParams->fNumAsicsPerModule * fParams->fNumChansPerAsic; + uint32_t address = elinkPar.fAddress; + uint32_t channel = 0; if (asicNr < fParams->fNumAsicsPerModule / 2) { // front side (n side) channel = message.GetHitChannel() + fParams->fNumChansPerAsic * asicNr; } @@ -94,10 +108,13 @@ namespace cbm::algo // --- Time stamp // --- Expand to full Unix time in clock cycles - uint64_t timeCC = message.GetHitTimeBinning() + fCurrentEpochTime; + uint64_t timeCc = message.GetHitTimeBinning() + fCurrentEpochTime; + if (timeCc >> 59 != 0) { // avoid overflow in 64 bit // TODO: Hard-coded number! + moni.fNumErrTimestampOverflow++; + return; + } // --- Convert time into ns - assert(timeCC >> 59 == 0); // avoid overflow in 64 bit - uint64_t timeNs = (timeCC * fParams->fClockCycleNom) / fParams->fClockCycleDen; + uint64_t timeNs = (timeCc * fkClockCycleNom + fkClockCycleDen / 2) / fkClockCycleDen; // --- Correct ASIC-wise offsets timeNs -= elinkPar.fTimeOffset; // --- Calculate time relative to timeslice @@ -124,7 +141,7 @@ namespace cbm::algo // --- Update current epoch fCurrentEpoch = epoch; - fCurrentEpochTime = (fCurrentCycle * fParams->fEpochsPerCycle + epoch) * fParams->fEpochLength; + fCurrentEpochTime = (fCurrentCycle * fkEpochsPerCycle + epoch) * fkEpochLength; } // -------------------------------------------------------------------------- diff --git a/algo/detectors/sts/UnpackSts.h b/algo/detectors/sts/UnpackSts.h index 90ccc1392c23e2bc6b85d66756ffb2fdba30511e..855844104db53b5633952b5245323a66d70f6939 100644 --- a/algo/detectors/sts/UnpackSts.h +++ b/algo/detectors/sts/UnpackSts.h @@ -23,10 +23,10 @@ namespace cbm::algo { - /** @struct UnpackStsAsicPar + /** @struct UnpackStsElinkPar ** @author Volker Friese <v.friese@gsi.de> ** @since 25 November 2021 - ** @brief Unpacking parameters for one eLink / ASIC + ** @brief STS Unpacking parameters for one eLink / ASIC **/ struct UnpackStsElinkPar { uint32_t fAddress = 0; ///< CbmStsAddress for the connected module @@ -43,22 +43,23 @@ namespace cbm::algo ** @brief Parameters required for the STS unpacking (specific to one component) **/ struct UnpackStsPar { + uint32_t fNumChansPerAsic = 0; ///< Number of channels per ASIC + uint32_t fNumAsicsPerModule = 0; ///< Number of ASICS per module + std::vector<UnpackStsElinkPar> fElinkParams = {}; ///< Parameters for each eLink + }; + - uint32_t fNumChansPerAsic = 0; ///< Number of channels per ASIC - uint32_t fNumAsicsPerModule = 0; ///< Number of ASICS per module - uint64_t fEpochsPerCycle = 0; ///< TS_MSB epochs per epoch cycle - uint64_t fEpochLength = 0; ///< Length of TS_MSB epoch in clock cycles - uint32_t fClockCycleNom = 0; ///< Clock cycle nominator [ns] - uint32_t fClockCycleDen = 0.; ///< Clock cycle denominator - std::vector<UnpackStsElinkPar> fElinkParams; ///< Parameters for each eLink - - size_t GetNumElinks() const { return fElinkParams.size(); } - - const UnpackStsElinkPar& GetElinkPar(size_t eLink) const - { - assert(eLink < GetNumElinks()); - return fElinkParams[eLink]; - } + /** @struct UnpackStsMoni + ** @author Volker Friese <v.friese@gsi.de> + ** @since 2 December 2021 + ** @brief Monitoring data for STS unpacking + **/ + struct UnpackStsMonitorData { + uint32_t fNumNonHitOrTsbMessage = 0; + uint32_t fNumErrElinkOutOfRange = 0; ///< Elink not contained in parameters + uint32_t fNumErrInvalidFirstMessage = 0; ///< First message is not TS_MSB + uint32_t fNumErrInvalidMsSize = 0; ///< Microslice size is not multiple of message size + uint32_t fNumErrTimestampOverflow = 0; ///< Overflow in 64 bit time stamp }; @@ -71,6 +72,9 @@ namespace cbm::algo class UnpackSts { public: + typedef std::pair<std::vector<CbmStsDigi>, UnpackStsMonitorData> resultType; + + /** @brief Default constructor **/ UnpackSts() {}; @@ -85,39 +89,43 @@ namespace cbm::algo ** @param tTimeslice Unix start time of timeslice [ns] ** @return STS digi data **/ - std::vector<CbmStsDigi> operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr, - const uint64_t tTimeslice); + resultType operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr, + const uint64_t tTimeslice); /** @brief Set the parameter container ** @param params Pointer to parameter container **/ - void SetParams(std::unique_ptr<UnpackStsPar> params) - { - fParams = std::move(params); - fCycleLength = (fParams->fEpochsPerCycle * fParams->fEpochLength * fParams->fClockCycleNom); - fCycleLength /= fParams->fClockCycleDen; - } + void SetParams(std::unique_ptr<UnpackStsPar> params) { fParams = std::move(params); } - private: - /** @brief Process an epoch message (TS_MSB) + private: // methods + /** @brief Process a hit message ** @param message SMX message (32-bit word) ** @param digiVec Vector to append the created digi to **/ - void ProcessTsmsbMessage(const stsxyter::Message& message); + void ProcessHitMessage(const stsxyter::Message& message, std::vector<CbmStsDigi>& digiVec, + UnpackStsMonitorData& moni) const; - /** @brief Process a hit message + /** @brief Process an epoch message (TS_MSB) ** @param message SMX message (32-bit word) ** @param digiVec Vector to append the created digi to **/ - void ProcessHitMessage(const stsxyter::Message& message, std::vector<CbmStsDigi>& digiVec) const; + void ProcessTsmsbMessage(const stsxyter::Message& message); + - private: + private: // members uint64_t fCurrentTsTime = 0; ///< Unix time of timeslice in ns uint64_t fCurrentCycle = 0; ///< Current epoch cycle uint32_t fCurrentEpoch = 0; ///< Current epoch number within epoch cycle uint64_t fCurrentEpochTime = 0; ///< Unix time of current epoch in clock cycles - uint64_t fCycleLength = 0; ///< Epoch cycle length in ns + + static constexpr uint64_t fkEpochsPerCycle = stsxyter::kuTsMsbNbTsBinsBinning; ///< TS_MSB epochs per epoch cycle + static constexpr uint64_t fkEpochLength = + stsxyter::kuHitNbTsBinsBinning; ///< Length of TS_MSB epoch in clock cycles + static constexpr uint32_t fkClockCycleNom = stsxyter::kulClockCycleNom; ///< Clock cycle nominator [ns] + static constexpr uint32_t fkClockCycleDen = stsxyter::kulClockCycleDen; ///< Clock cycle denominator + static constexpr uint64_t fkCycleLength = + (fkEpochsPerCycle * fkEpochLength * fkClockCycleNom) / fkClockCycleDen; ///< Epoch cycle length in ns std::unique_ptr<UnpackStsPar> fParams = nullptr; ///< Parameter container }; diff --git a/core/data/raw/StsXyterMessage.h b/core/data/raw/StsXyterMessage.h index 408401595826ecd4283c7ea82979c7a12b078087..903e0436e68a1c70c7cddf9b0914a3c5c03a6d7a 100644 --- a/core/data/raw/StsXyterMessage.h +++ b/core/data/raw/StsXyterMessage.h @@ -155,10 +155,11 @@ namespace stsxyter static const uint32_t kuTsMsbNbTsBins = (0 < kusLenTsMsbVal ? 1 << kusLenTsMsbVal : 0); static const uint64_t kulTsCycleNbBins = static_cast<uint64_t>(kuTsMsbNbTsBins) * static_cast<uint64_t>(kuHitNbTsBins); - static const uint16_t kusMaskTsMsbOver = (1 << kusLenHitTsOver) - 1; - static const double kdClockCycleNs = 3.125; // ns, equivalent to 2*160 MHz clock - /// Binning FW adds 1 bit to TS in HIT message - /// => Quick and dirty hack is a factor 2!!! + static const uint16_t kusMaskTsMsbOver = (1 << kusLenHitTsOver) - 1; + static constexpr uint32_t kulClockCycleNom = 25; ///< Clock cycle nominator [ns], equivalent to 2*160 MHz clock + static constexpr uint32_t kulClockCycleDen = 8; ///< Clock cycle denominator, equivalent to 2*160 MHz clock + static constexpr double kdClockCycleNs = static_cast<double>(kulClockCycleNom) / kulClockCycleDen; // ns, not rounded + static const uint32_t kuHitNbTsBinsBinning = 1 << 10; static const uint32_t kuTsMsbNbTsBinsBinning = 1 << kusLenTsMsbValBinning; static const uint64_t kulTsCycleNbBinsBinning =