diff --git a/algo/detectors/sts/UnpackSts.cxx b/algo/detectors/sts/UnpackSts.cxx index eeb33bf047390c30084cfea30bf66dd66a32ef05..4d25a03410930148d46134572428fbaad96de958 100644 --- a/algo/detectors/sts/UnpackSts.cxx +++ b/algo/detectors/sts/UnpackSts.cxx @@ -26,10 +26,14 @@ namespace cbm::algo // --- Output data resultType result = {}; - // --- 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 Timeslice start time in epoch units. Note that it is always a multiple of epochs + // --- and the epoch is a multiple of ns. + const uint64_t epochLengthInNs = fkEpochLength * fkClockCycleNom / fkClockCycleDen; + fCurrentTsTime = tTimeslice / epochLengthInNs; + + // --- Current TS_MSB epoch cycle + auto const msTime = msDescr.idx; // Unix time of MS in ns + fCurrentCycle = std::ldiv(msTime, fkCycleLength).quot; // ---Â Number of messages in microslice auto msSize = msDescr.size; @@ -46,18 +50,18 @@ namespace cbm::algo // --- Interpret MS content as sequence of SMX messages auto message = reinterpret_cast<const stsxyter::Message*>(msContent); - // --- The first message in the MS is expected to be of type EPOCH and can be ignored + // --- The first message in the MS is expected to be of type EPOCH and can be ignored. if (message[0].GetMessType() != stsxyter::MessType::Epoch) { result.second.fNumErrInvalidFirstMessage++; return result; } - // --- The second message must be of type ts_msb + // --- The second message must be of type ts_msb. if (message[1].GetMessType() != stsxyter::MessType::TsMsb) { result.second.fNumErrInvalidFirstMessage++; return result; } - ProcessTsmsbMessage(message[1], result.second); + ProcessTsmsbMessage(message[1]); // --- Message loop for (uint32_t messageNr = 2; messageNr < numMessages; messageNr++) { @@ -70,7 +74,7 @@ namespace cbm::algo break; } case stsxyter::MessType::TsMsb: { - ProcessTsmsbMessage(message[messageNr], result.second); + ProcessTsmsbMessage(message[messageNr]); break; } default: { @@ -112,10 +116,12 @@ namespace cbm::algo channel = numChansPerModule - message.GetHitChannel() + 1; } - // --- Convert time stamp from clock cycles to ns - uint64_t messageTime = (message.GetHitTimeBinning() * fkClockCycleNom + fkClockCycleDen / 2) / fkClockCycleDen; - // --- Expand to time within timeslice - messageTime += fCurrentEpochTime; + // --- Expand time stamp to time within timeslice (in clock cycle) + uint64_t messageTime = message.GetHitTimeBinning() + fCurrentEpochTime; + + // --- Convert time stamp from clock cycles to ns. Round to nearest full ns. + messageTime = (messageTime * fkClockCycleNom + fkClockCycleDen / 2) / fkClockCycleDen; + // --- Correct ASIC-wise offsets messageTime -= elinkPar.fTimeOffset; // --- TODO: Add walk correction (depends on ADC) @@ -130,25 +136,26 @@ namespace cbm::algo // ----- Process an epoch (TS_MSB) message ------------------------------ - inline void UnpackSts::ProcessTsmsbMessage(const stsxyter::Message& message, UnpackStsMonitorData& monitor) + inline void UnpackSts::ProcessTsmsbMessage(const stsxyter::Message& message) { - + // The compression of time is based on the hierarchy epoch cycle - epoch - message time. + // Cycles are counted from the start of Unix time and are multiples of an epoch (ts_msb). + // The epoch number is counted within each cycle. The time in the hit message is expressed + // in units of the readout clock cycle relative to the current epoch. + // The ts_msb message indicates the start of a new epoch. Its basic information is the epoch + // number within the current cycle. A cycle wrap resets the epoch number to zero, so it is + // indicated by the epoch number being smaller than the previous one (epoch messages are + // seemingly not consecutively in the data stream, but only if there are hit messages in between). auto epoch = message.GetTsMsbValBinning(); // --- Cycle wrap if (epoch < fCurrentEpoch) fCurrentCycle++; - // --- Update current epoch - fCurrentEpoch = epoch; - uint64_t epochTimeInCc = (fCurrentCycle * fkEpochsPerCycle + epoch) * fkEpochLength; - if (epochTimeInCc >> 59 != 0) { // avoid overflow in 64 bit // TODO: Hard-coded number! - monitor.fNumErrTimestampOverflow++; - return; - } + // --- Update current epoch counter + fCurrentEpoch = epoch; - // --- Calculate epoch time in ns relative to timeslice start time - fCurrentEpochTime = (epochTimeInCc * fkClockCycleNom + fkClockCycleDen / 2) / fkClockCycleDen; - fCurrentEpochTime -= fCurrentTsTime; + // --- Calculate epoch time in clocks cycles relative to timeslice start time + fCurrentEpochTime = (fCurrentCycle * fkEpochsPerCycle + epoch - fCurrentTsTime) * fkEpochLength; } // -------------------------------------------------------------------------- diff --git a/algo/detectors/sts/UnpackSts.h b/algo/detectors/sts/UnpackSts.h index 05989d375367dcc617c39b117e3a59c0f97c263f..ed1fd22a253c3c35a2b80fcf152f87e588966e4e 100644 --- a/algo/detectors/sts/UnpackSts.h +++ b/algo/detectors/sts/UnpackSts.h @@ -115,27 +115,29 @@ namespace cbm::algo /** @brief Process an epoch message (TS_MSB) ** @param message SMX message (32-bit word) - ** @param monitor Reference to monitor object **/ - void ProcessTsmsbMessage(const stsxyter::Message& message, UnpackStsMonitorData& monitor); + void ProcessTsmsbMessage(const stsxyter::Message& message); + + + private: // members + uint64_t fCurrentTsTime = 0; ///< Unix time of timeslice in units of epoch length + uint64_t fCurrentCycle = 0; ///< Current epoch cycle + uint32_t fCurrentEpoch = 0; ///< Current epoch number within epoch cycle + uint64_t fCurrentEpochTime = 0; ///< Current epoch time relative to timeslice in clock cycles + UnpackStsPar fParams = {}; ///< Parameter container + /** Number of TS_MSB epochs per cycle **/ + static constexpr uint64_t fkEpochsPerCycle = stsxyter::kuTsMsbNbTsBinsBinning; - 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 + /** Length of TS_MSB epoch in clock cycles **/ + static constexpr uint64_t fkEpochLength = stsxyter::kuHitNbTsBinsBinning; - 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 + /** Clock cycle nominator [ns] and denominator. The clock cycle in ns is nominator / denominator. **/ + static constexpr uint32_t fkClockCycleNom = stsxyter::kulClockCycleNom; + static constexpr uint32_t fkClockCycleDen = stsxyter::kulClockCycleDen; - //std::unique_ptr<UnpackStsPar> fParams = nullptr; ///< Parameter container - UnpackStsPar fParams = {}; ///< Parameter container + /** Epoch cycle length in ns **/ + static constexpr uint64_t fkCycleLength = (fkEpochsPerCycle * fkEpochLength * fkClockCycleNom) / fkClockCycleDen; };