diff --git a/core/data/CMakeLists.txt b/core/data/CMakeLists.txt index 60276a916df095743b896188d821dff5b442c86e..57cfea793442d17eadea422c85e72a681a2ca140 100644 --- a/core/data/CMakeLists.txt +++ b/core/data/CMakeLists.txt @@ -134,7 +134,7 @@ SET_SOURCE_FILES_PROPERTIES(tof/etof/star_rhicf.c PROPERTIES COMPILE_FLAGS -Wno- list(APPEND HEADERS base/CbmDigiData.h global/CbmDigiEvent.h global/CbmDigiTimeslice.h bmon/CbmBmonDigiData.h sts/CbmStsDigiData.h much/CbmMuchDigiData.h rich/CbmRichDigiData.h trd/CbmTrdDigiData.h -tof/CbmTofDigiData.h psd/CbmPsdDigiData.h fsd/CbmFsdDigiData.h) +tof/CbmTofDigiData.h psd/CbmPsdDigiData.h fsd/CbmFsdDigiData.h trd/CbmTrdFexMessageSpadic.h) set(LIBRARY_NAME CbmData) set(LINKDEF ${LIBRARY_NAME}LinkDef.h) diff --git a/core/data/trd/CbmTrdFexMessageSpadic.h b/core/data/trd/CbmTrdFexMessageSpadic.h new file mode 100644 index 0000000000000000000000000000000000000000..326813b814052150b1c10798e159447c1a377fdc --- /dev/null +++ b/core/data/trd/CbmTrdFexMessageSpadic.h @@ -0,0 +1,116 @@ +/* Copyright (C) 2024 Goethe-University Frankfurt, Frankfurt + SPDX-License-Identifier: GPL-3.0-only + Authors: David Schledt [committer] */ + +#ifndef CbmTrdFexMessageSpadic_H +#define CbmTrdFexMessageSpadic_H + +#include "fmt/format.h" + +#include <array> +#include <stdexcept> + + +namespace Spadic +{ + + template<std::uint8_t sys_ver> + constexpr std::uint8_t BytesPerWord() + { + switch (sys_ver) { + case 0x01: return 8; + case 0x10: return 8; + default: return 0; + } + } + + template<size_t bytes> + struct NByteContainer { + std::array<std::uint8_t, bytes> b; + + operator std::uint64_t() + { + std::uint64_t r = 0; + for (std::uint8_t i = 0; i < bytes; ++i) + r |= (std::uint64_t) b[i] << (8 * i); + return r; + } + + size_t range(std::uint8_t h, std::uint8_t l) + { + + if (l > h) { + throw std::invalid_argument(fmt::format("Reverse ranges not supported : low={:#x} > high={:#x}", l, h)); + } + // get high and low byte positions + std::uint16_t bh = h >> 3; + std::uint16_t bl = l >> 3; + // get number of bytes that need to be accessed + std::uint16_t rbytes = bh - bl; + if ((bh + 1) > bytes) { + throw std::invalid_argument(fmt::format("High value: out-of-range, got={:#x}, size={:#x}", h, (bytes * 8 - 1))); + } + if ((bl + 1) > bytes) { + throw std::invalid_argument(fmt::format("Low value: out-of-range, got={:#x}, size={:#x}", l, (bytes * 8 - 1))); + } + // calculate bit positions for high and low byte + std::uint16_t bits_in_h = h - (8 * bh - 1); + std::uint16_t bits_in_l = l - (8 * bl); + std::uint16_t mask_h = (1 << bits_in_h) - 1; + + // assemble return value + size_t r = b[bl] >> bits_in_l; + if (bh != bl) r |= (b[bh] & mask_h) << (rbytes * 8); + for (int i = 1; i < rbytes; ++i) + r |= b[bl + i] << (i * 8); + return r; + } + }; + + // Define template specialisations for each system version + template<std::uint8_t sys_ver> + struct FexWord { + }; + + + // sys_ver 0x10 (c.f.git.cbm.gsi.de/trd/reports/technical-notes/integrated-data-format) + template<> + struct FexWord<0x10> { + std::uint8_t elink; + std::uint8_t channel; + std::uint64_t timestamp; + float prec_time; + std::uint16_t maxAdc; + std::uint16_t timesample; + std::uint8_t iMA; + std::uint8_t ht; + std::uint8_t mh; + + FexWord(NByteContainer<BytesPerWord<0x10>()> word) + { + constexpr int hts = 62; + constexpr int els = hts - 8; + constexpr int chs = els - 4; + constexpr int maxs = chs - 9; + constexpr int imas = maxs - 3; + constexpr int trs = imas - 9; + constexpr int mhs = trs - 3; + constexpr int pts = mhs - 5; + + ht = (word >> 62) & 0x3; // TODO ext trigger + if (ht != 0) { + elink = (word >> els) & 0xff; + channel = (word >> chs) & 0xf; + maxAdc = (word >> maxs) & 0x1ff; + iMA = (word >> imas) & 0x3; + timesample = (word >> trs) & 0x1ff; + mh = (word >> mhs) & 0x3; + prec_time = (float) ((word >> pts) & 0x1f) / float(1 << 4); + timestamp = word & 0x1fffff; + } + } + }; + +} // namespace Spadic + +#endif // CbmTrdFexMessageSpadic_H diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackAlgoR.cxx b/reco/detectors/trd/unpack/CbmTrdUnpackAlgoR.cxx index 888bd043d694b252660f9ab4e26df62faadbee8c..f12519401d3324001eb88d91491e35cb25fd691e 100644 --- a/reco/detectors/trd/unpack/CbmTrdUnpackAlgoR.cxx +++ b/reco/detectors/trd/unpack/CbmTrdUnpackAlgoR.cxx @@ -13,12 +13,12 @@ #include <Logger.h> #include <RtypesCore.h> -#include <typeinfo> #include <algorithm> #include <bitset> #include <cstdint> #include <memory> +#include <typeinfo> CbmTrdUnpackAlgoR::CbmTrdUnpackAlgoR(/* args */) : CbmTrdUnpackAlgoBaseR("CbmTrdUnpackAlgoR") {} @@ -35,7 +35,9 @@ CbmTrdUnpackAlgoR::GetParContainerRequest(std::string geoTag, std::uint32_t runI // Digest the runId information in case of runId = 0 we use the default fall back std::string runpath = ""; - if (runId != 0) { runpath = ".run" + std::to_string(runId); } + if (runId != 0) { + runpath = ".run" + std::to_string(runId); + } // Get .asic parameter container temppath = basepath + runpath + ".asic" + ".par"; @@ -75,7 +77,9 @@ void CbmTrdUnpackAlgoR::digestInfoMsg(const std::uint32_t frame, std::uint16_t c std::uint16_t elinkId) { /// Save info message if needed. - if (fOptOutBVec) { fOptOutBVec->emplace_back(std::make_pair(fLastFulltime, frame)); } + if (fOptOutBVec) { + fOptOutBVec->emplace_back(std::make_pair(fLastFulltime, frame)); + } fNrCreatedInfoMsgs++; Spadic::MsInfoType infotype = getInfoType(frame, criId, crobId, elinkId); // "Spadic_Info_Types"; @@ -95,19 +99,27 @@ void CbmTrdUnpackAlgoR::digestMsFlags(const std::uint16_t flags, std::uint16_t c if (flags & static_cast<std::uint16_t>(fles::MicrosliceFlags::CrcValid)) { fNrCrcValidFlags++; - if (fMonitor) { fMonitor->FillHisto(fles::MicrosliceFlags::CrcValid, moduleid); } + if (fMonitor) { + fMonitor->FillHisto(fles::MicrosliceFlags::CrcValid, moduleid); + } } if (flags & static_cast<std::uint16_t>(fles::MicrosliceFlags::OverflowFlim)) { fNrOverflowFlimFlags++; - if (fMonitor) { fMonitor->FillHisto(fles::MicrosliceFlags::OverflowFlim, moduleid); } + if (fMonitor) { + fMonitor->FillHisto(fles::MicrosliceFlags::OverflowFlim, moduleid); + } } if (flags & static_cast<std::uint16_t>(fles::MicrosliceFlags::OverflowUser)) { fNrOverflowUserFlags++; - if (fMonitor) { fMonitor->FillHisto(fles::MicrosliceFlags::OverflowUser, moduleid); } + if (fMonitor) { + fMonitor->FillHisto(fles::MicrosliceFlags::OverflowUser, moduleid); + } } if (flags & static_cast<std::uint16_t>(fles::MicrosliceFlags::DataError)) { fNrDataErrorFlags++; - if (fMonitor) { fMonitor->FillHisto(fles::MicrosliceFlags::DataError, moduleid); } + if (fMonitor) { + fMonitor->FillHisto(fles::MicrosliceFlags::DataError, moduleid); + } } } @@ -304,6 +316,38 @@ void CbmTrdUnpackAlgoR::makeDigi(CbmTrdRawMessageSpadic raw) digestOutput(std::move(digi), raw); } +// ---- makeDigi ---- +void CbmTrdUnpackAlgoR::makeDigi(Spadic::FexWord<0x10> fw, std::uint32_t criid) +{ + auto rawTriggerType = static_cast<Spadic::eTriggerType>(fw.ht); + auto triggerType = CbmTrdRawToDigiBaseR::GetDigiTriggerType(rawTriggerType); + + // Get the address of the originating spadic + auto asicAddress = getAsicAddress(criid, 0, fw.elink); + if (asicAddress) { + // Get the unique module id from the asic address + Int_t uniqueModuleId = asicAddress / 1000; + + // Get the channel id on the module + auto padChNr = getChannelId(asicAddress, fw.elink, fw.channel); + + // Store the full time information to last full-time member for error message handling + // Get the time information and apply the necessary correction + ULong64_t time = (fw.timestamp - fw.prec_time) * fSpadic->GetClockCycle() + fMsStartTimeRelCC; + + auto energy = fSpadic->MaxAdcToEnergyCal(fw.maxAdc); + + time -= fSystemTimeOffset; + + auto digi = std::unique_ptr<CbmTrdDigi>(new CbmTrdDigi(padChNr, uniqueModuleId, energy, time, triggerType, 0)); + + // If the message was flagged as multi hit, forward this info to the digi + if (fw.mh != 0) digi->SetTriggerType(CbmTrdDigi::eTriggerType::kMulti); + + fOutputVec.emplace_back(*std::move(digi)); + } +} + // ---- makeRaw ---- CbmTrdRawMessageSpadic CbmTrdUnpackAlgoR::makeRaw(const std::uint32_t frame, std::uint16_t criId, std::uint8_t crobId, std::uint16_t elinkId, std::uint8_t istream) @@ -339,32 +383,46 @@ bool CbmTrdUnpackAlgoR::unpack(const fles::Timeslice* ts, std::uint16_t icomp, U // The UTC is already to large for storing it CbmTrdRawMessageSpadic due to a cast, caused by the multiplication with a double used in the raw message fMsStartTimeRelCC = (msdesc.idx - fTsStartTime) / fSpadic->GetClockCycle(); - // We only want to count on TS_MSB per Stream per TS_MSB package (each eLink sends its own TS_MSB frame) so we store the current TS_MSB and compare it to the incoming. - std::int8_t currTsMsb = 0; + // Get the hardware ids from which the current µSlice is coming + std::uint8_t crobId = 0; + auto criId = msdesc.eq_id; - // Reset the TS_MSB counter for the new µSlice we unpack - fNrTsMsbVec.clear(); - fNrTsMsbVec.resize(fStreamsPerWord); + // Digest the flags from the µSlice + digestMsFlags(msdesc.flags, criId, crobId); + + const auto mspointer = ts->content(icomp, imslice); + + const auto mscontent = reinterpret_cast<const size_t*>(mspointer); + + if (msdesc.sys_ver == 0x10) { + return unpackFex<0x10>(msdesc, mscontent); + } + else { + return unpackRaw(msdesc, mscontent); + } + return unpackOk; +} +bool CbmTrdUnpackAlgoR::unpackRaw(const fles::MicrosliceDescriptor msdesc, const size_t* mscontent) +{ // Get the µslice size in bytes to calculate the number of completed words auto mssize = msdesc.size; + // We have 32 bit spadic frames in this readout version + std::uint32_t nwords = mssize / fBytesPerWord; // Get the hardware ids from which the current µSlice is coming std::uint8_t crobId = 0; auto criId = msdesc.eq_id; - // Digest the flags from the µSlice - digestMsFlags(msdesc.flags, criId, crobId); - - // Get the number of complete words in the input MS buffer. - std::uint32_t nwords = mssize / fBytesPerWord; - - const auto mspointer = ts->content(icomp, imslice); + bool unpackOk = true; + // We only want to count on TS_MSB per Stream per TS_MSB package (each eLink sends its own TS_MSB frame) so we store the current TS_MSB and compare it to the incoming. + std::int8_t currTsMsb = 0; - // We have 32 bit spadic frames in this readout version - const auto mscontent = reinterpret_cast<const size_t*>(mspointer); + // Reset the TS_MSB counter for the new µSlice we unpack + fNrTsMsbVec.clear(); + fNrTsMsbVec.resize(fStreamsPerWord); // Loop over all 64bit-Spadic-Words in the current µslice for (std::uint32_t istream = 0; istream < fStreamsPerWord; istream++) { @@ -540,4 +598,35 @@ bool CbmTrdUnpackAlgoR::unpack(const fles::Timeslice* ts, std::uint16_t icomp, U return unpackOk; } +template<std::uint8_t sys_ver> +bool CbmTrdUnpackAlgoR::unpackFex(const fles::MicrosliceDescriptor msdesc, const size_t* mscontent) +{ + constexpr std::uint8_t bytes = Spadic::BytesPerWord<sys_ver>(); + if constexpr (bytes == 0) { + // TODO log something + return false; + } + bool unpackOk = true; + + // Get the µslice size in bytes to calculate the number of completed words + auto mssize = msdesc.size; + std::uint32_t nwords = mssize / bytes; + // Get the hardware ids from which the current µSlice is coming + std::uint8_t crobId = 0; + auto criId = msdesc.eq_id; + + const Spadic::NByteContainer<bytes>* bp = reinterpret_cast<const Spadic::NByteContainer<bytes>*>(mscontent); + + for (std::uint32_t iword = 0; iword < nwords; ++iword) { + Spadic::NByteContainer<bytes> bCont = bp[iword]; + Spadic::FexWord<sys_ver> fw(bCont); + if (fw.ht != 0) { + makeDigi(fw, criId); + } + } + return unpackOk; +} + +template bool CbmTrdUnpackAlgoR::unpackFex<0x10>(const fles::MicrosliceDescriptor msdesc, const size_t* mscontent); + ClassImp(CbmTrdUnpackAlgoR) diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackAlgoR.h b/reco/detectors/trd/unpack/CbmTrdUnpackAlgoR.h index 845bf5155e054905fff7d26cadfb20cb7061b0e9..1d16c3eefd9505a1c00b3642f48d9e94df9b491c 100644 --- a/reco/detectors/trd/unpack/CbmTrdUnpackAlgoR.h +++ b/reco/detectors/trd/unpack/CbmTrdUnpackAlgoR.h @@ -19,6 +19,7 @@ #ifndef CbmTrdUnpackAlgoR_H #define CbmTrdUnpackAlgoR_H +#include "CbmTrdFexMessageSpadic.h" #include "CbmTrdRawMessageSpadic.h" #include "CbmTrdUnpackAlgoBaseR.h" @@ -29,17 +30,17 @@ #include <Rtypes.h> // for types #include <RtypesCore.h> +#include <cmath> #include <cstdint> #include <vector> -#include <cmath> class CbmTrdUnpackAlgoR : public CbmTrdUnpackAlgoBaseR { -private: + private: /* data */ -public: + public: /** @brief Create the Cbm Trd Unpack AlgoBase object */ CbmTrdUnpackAlgoR(/* args */); @@ -65,7 +66,7 @@ public: GetParContainerRequest(std::string geoTag, std::uint32_t runId); -protected: + protected: /** * @brief Digest the aditional flags stored in the 4 "cccc" bits of the EPO messages. * @param frame @@ -155,6 +156,15 @@ protected: */ void makeDigi(CbmTrdRawMessageSpadic raw); + /** + * @brief Create an actual digi from the fex message + * + * @param fw FexWord for a given sys_ver + * @param criid the eq_is of a FLIM channel + */ + + void makeDigi(Spadic::FexWord<0x10> fw, std::uint32_t criid); + /** @brief Up to now we do not need this function for this algorithm */ bool setDerivedTsParameters(size_t /*itimeslice*/) { return true; } @@ -171,6 +181,11 @@ protected: */ bool unpack(const fles::Timeslice* ts, std::uint16_t icomp, UInt_t imslice); + bool unpackRaw(const fles::MicrosliceDescriptor msdesc, const size_t* mscontent); + + template<std::uint8_t sys_ver> + bool unpackFex(const fles::MicrosliceDescriptor msdesc, const size_t* mscontent); + // Parameter storage members /** @brief Counter for the ts_msb used to reconstruct the time */ @@ -196,7 +211,7 @@ protected: static const std::uint8_t fStreamsPerWord = 2; -private: + private: ClassDef(CbmTrdUnpackAlgoR, 2) };