diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt index b7d83336ca0b9830ac92c5ebc693e474bbc23521..4a93e43c2060cba0a9f7b206dc2bb6bd287b83f5 100644 --- a/algo/CMakeLists.txt +++ b/algo/CMakeLists.txt @@ -6,6 +6,7 @@ add_subdirectory (test) set(SRCS evbuild/EventBuilder.cxx trigger/TimeClusterTrigger.cxx + detectors/sts/UnpackSts.cxx ) add_library(Algo SHARED ${SRCS}) diff --git a/algo/detectors/sts/UnpackSts.cxx b/algo/detectors/sts/UnpackSts.cxx new file mode 100644 index 0000000000000000000000000000000000000000..00c66eaddde4bb059c51a5588124a768b547383e --- /dev/null +++ b/algo/detectors/sts/UnpackSts.cxx @@ -0,0 +1,132 @@ +/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau, Volker Friese [committer] */ + +#include "UnpackSts.h" + +#include <cassert> +#include <vector> + +#include <cmath> + +#include "StsXyterMessage.h" + +using std::vector; + +namespace cbm::algo +{ + + // ---- Algorithm execution --------------------------------------------- + vector<CbmStsDigi> 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; + + // --- Current TS_MSB epoch cycle + auto msTime = msDescr.idx; // Unix time of MS in ns + fCurrentCycle = std::ldiv(msTime, fCycleLength).quot; + + // --- 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); + + // ---Â Number of messages in microslice + auto msSize = msDescr.size; + assert(msSize % sizeof(stsxyter::Message) == 0); + 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) { + + case stsxyter::MessType::Hit: { + ProcessHitMessage(message, digiVec); + break; + } + case stsxyter::MessType::TsMsb: { + ProcessTsmsbMessage(message); + break; + } + default: { + break; + } + + } //? Message type + + } //# Messages + + return digiVec; + } + // -------------------------------------------------------------------------- + + + // ----- Process hit message -------------------------------------------- + void UnpackSts::ProcessHitMessage(const stsxyter::Message& message, vector<CbmStsDigi>& digiVec) const + { + + uint16_t elink = message.GetLinkIndexHitBinning(); + const UnpackStsElinkPar& elinkPar = fParams->GetElinkPar(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; + if (asicNr < fParams->fNumAsicsPerModule / 2) { // front side (n side) + channel = message.GetHitChannel() + fParams->fNumChansPerAsic * asicNr; + } + else { // back side (p side) + channel = numChansPerModule - message.GetHitChannel() + 1; + } + + // --- Time stamp + // --- Expand to full Unix time in clock cycles + uint64_t timeCC = message.GetHitTimeBinning() + fCurrentEpochTime; + // --- Convert time into ns + assert(timeCC >> 59 == 0); // avoid overflow in 64 bit + uint64_t timeNs = (timeCC * fParams->fClockCycleNom) / fParams->fClockCycleDen; + // --- Correct ASIC-wise offsets + timeNs -= elinkPar.fTimeOffset; + // --- Calculate time relative to timeslice + timeNs -= fCurrentTsTime; + // --- TODO: Add walk correction (depends on ADC) + + // --- Charge + double charge = elinkPar.fAdcOffset + (message.GetHitAdc() - 1) * elinkPar.fAdcGain; + + // --- Create output digi + digiVec.emplace_back(address, channel, timeNs, charge); + } + // -------------------------------------------------------------------------- + + + // ----- Process an epoch (TS_MSB) message ------------------------------ + void UnpackSts::ProcessTsmsbMessage(const stsxyter::Message& message) + { + + auto epoch = message.GetTsMsbValBinning(); + + // --- Cycle wrap + if (epoch < fCurrentEpoch) fCurrentCycle++; + + // --- Update current epoch + fCurrentEpoch = epoch; + fCurrentEpochTime = (fCurrentCycle * fParams->fEpochsPerCycle + epoch) * fParams->fEpochLength; + } + // -------------------------------------------------------------------------- + + +} /* namespace cbm::algo */ diff --git a/algo/detectors/sts/UnpackSts.h b/algo/detectors/sts/UnpackSts.h new file mode 100644 index 0000000000000000000000000000000000000000..90ccc1392c23e2bc6b85d66756ffb2fdba30511e --- /dev/null +++ b/algo/detectors/sts/UnpackSts.h @@ -0,0 +1,128 @@ +/* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Pierre-Alain Loizeau, Volker Friese [committer] */ + +#ifndef CBM_ALGO_UNPACKSTS_H +#define CBM_ALGO_UNPACKSTS_H 1 + + +#include "CbmStsDigi.h" + +#include "MicrosliceDescriptor.hpp" +#include "Timeslice.hpp" + +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <memory> +#include <vector> + +#include "StsXyterMessage.h" + +namespace cbm::algo +{ + + + /** @struct UnpackStsAsicPar + ** @author Volker Friese <v.friese@gsi.de> + ** @since 25 November 2021 + ** @brief Unpacking parameters for one eLink / ASIC + **/ + struct UnpackStsElinkPar { + uint32_t fAddress = 0; ///< CbmStsAddress for the connected module + uint32_t fAsicNr = 0; ///< Number of connected ASIC within the module + uint64_t fTimeOffset = 0.; ///< Time calibration parameter + double fAdcOffset = 0.; ///< Charge calibration parameter + double fAdcGain = 0.; ///< Charge calibration parameter + }; + + + /** @struct UnpackStsPar + ** @author Volker Friese <v.friese@gsi.de> + ** @since 25 November 2021 + ** @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 + 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]; + } + }; + + + /** @class UnpackSts + ** @author Pierre-Alain Loizeau <p.-a.loizeau@gsi.de> + ** @author Volker Friese <v.friese@gsi.de> + ** @since 25 November 2021 + ** @brief Unpack algorithm for STS + **/ + class UnpackSts { + + public: + /** @brief Default constructor **/ + UnpackSts() {}; + + + /** @brief Destructor **/ + ~UnpackSts() {}; + + + /** @brief Algorithm execution + ** @param msContent Microslice payload + ** @param msDescr Microslice descriptor + ** @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); + + /** @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; + } + + + private: + /** @brief Process an epoch message (TS_MSB) + ** @param message SMX message (32-bit word) + ** @param digiVec Vector to append the created digi to + **/ + void ProcessTsmsbMessage(const stsxyter::Message& message); + + /** @brief Process a hit message + ** @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; + + private: + 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 + + std::unique_ptr<UnpackStsPar> fParams = nullptr; ///< Parameter container + }; + + +} /* namespace cbm::algo */ + +#endif /* CBM_ALGO_UNPACKSTS_H */