diff --git a/algo/detectors/trd2d/ReadoutConfig.cxx b/algo/detectors/trd2d/ReadoutConfig.cxx index 3aaa79b1c208c9bcd6078d5c090b2561702f6eb2..675b8084ac96dc690a5e6fac2b9d3c26e5dbfacc 100644 --- a/algo/detectors/trd2d/ReadoutConfig.cxx +++ b/algo/detectors/trd2d/ReadoutConfig.cxx @@ -1,10 +1,11 @@ -/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt +/* Copyright (C) 2023-2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt SPDX-License-Identifier: GPL-3.0-only - Authors: Volker Friese, Dominik Smith [committer] */ + Authors: Volker Friese, Dominik Smith [committer], Alex Bercuci */ #include "ReadoutConfig.h" //#include "CbmTrdAddress.h" +#include "AlgoFairloggerCompat.h" #include <cassert> #include <iomanip> @@ -51,6 +52,16 @@ namespace cbm::algo::trd2d } // ------------------------------------------------------------------------------------ + // --- List of ASICs registered to the ROB --------------------- + std::vector<uint8_t> ReadoutConfig::GetAsicList(uint16_t equipmentId) + { + std::vector<uint8_t> result; + for (auto& entry : fChannelMap[equipmentId]) + result.push_back(entry.first); + return result; + } + // ------------------------------------------------------------------------------------ + // --- Number of Channels for a component / equipment, asic pair --------------------- size_t ReadoutConfig::GetNumChans(uint16_t equipmentId, uint16_t asicId) @@ -58,8 +69,10 @@ namespace cbm::algo::trd2d size_t result = 0; auto it = fChannelMap.find(equipmentId); if (it != fChannelMap.end()) { - if (asicId < fChannelMap[equipmentId].size()) { - result = fChannelMap[equipmentId][asicId].size(); + auto fiberMap = fChannelMap[equipmentId]; + auto jt = fiberMap.find(asicId); + if (jt != fiberMap.end()) { + result = fiberMap[asicId].size(); } } return result; @@ -67,16 +80,17 @@ namespace cbm::algo::trd2d // ------------------------------------------------------------------------------------ // --- Initialise the component mapping structure ---------------------------------- - void ReadoutConfig::InitComponentMap(const std::map<uint32_t, uint16_t[NCROBMOD]>& map) + void ReadoutConfig::InitComponentMap(const std::map<uint32_t, std::vector<uint16_t>>& map) { // Receive map (moduleId, crobId) -> (equipId) // Invert to obtain component map (equipId) -> (module iq, crob id) for (auto& entry : map) { uint16_t mod_id = entry.first; - for (uint8_t crob_id = 0; crob_id < NCROBMOD; crob_id++) { - uint16_t eq_id = entry.second[crob_id]; - if (!eq_id) continue; - fReadoutMap[eq_id] = {mod_id, crob_id}; + //for (uint8_t eq_id = 0; eq_id < NROBMOD * NELINKROB; eq_id++) { + uint8_t eq_id = 0; + for (const auto& eq_add : entry.second) { + //uint16_t eq_id = entry.second[elink_id]; + fReadoutMap[eq_add] = {mod_id, eq_id++}; } } } @@ -84,22 +98,22 @@ namespace cbm::algo::trd2d // --- Initialise the mapping structure -------------------------------------------- void ReadoutConfig::InitChannelMap( - const std::map<size_t, std::map<size_t, std::map<size_t, std::tuple<int32_t, bool, uint64_t>>>>& channelMap) + const std::map<size_t, std::map<size_t, std::map<size_t, std::tuple<int32_t, bool, uint8_t, uint16_t>>>>& + channelMap) { // Constructing the map (equipId, asicId, chanId) -> (pad address, mask flag, daq offset) for (auto compMap : channelMap) { uint16_t equipmentId = compMap.first; - uint16_t numAsics = compMap.second.size(); - fChannelMap[equipmentId].resize(numAsics); - + // uint16_t numAsics = compMap.second.size(); for (auto asicMap : compMap.second) { uint16_t asicId = asicMap.first; - uint16_t numChans = asicMap.second.size(); - fChannelMap[equipmentId][asicId].resize(numChans); + // uint16_t numChans = asicMap.second.size(); + fChannelMap[equipmentId][asicId].resize(16); for (auto chanMap : asicMap.second) { uint16_t chanId = chanMap.first; - std::tuple<int32_t, bool, uint64_t> chanPars = chanMap.second; - ChanMapping entry = {std::get<0>(chanPars), std::get<1>(chanPars), std::get<2>(chanPars)}; + std::tuple<int32_t, bool, uint8_t, uint16_t> chanPars = chanMap.second; + const ChanMapping entry = {std::get<0>(chanPars), std::get<1>(chanPars), std::get<2>(chanPars), + std::get<3>(chanPars)}; fChannelMap[equipmentId][asicId][chanId] = entry; } } @@ -109,14 +123,17 @@ namespace cbm::algo::trd2d // --- Mapping (equimentId, asicId, channel) -> (pad address, mask flag, daq offset) ----- - ReadoutConfig::ChanMapping ReadoutConfig::ChanMap(uint16_t equipId, uint16_t asic, uint16_t chan) + ReadoutConfig::ChanMapping ReadoutConfig::ChanMap(uint16_t equipId, uint16_t asicId, uint16_t chanId) { - ChanMapping result = {-1, false, 0}; + ChanMapping result = {-1, false, 0, 0}; auto it = fChannelMap.find(equipId); if (it != fChannelMap.end()) { - if (asic < fChannelMap[equipId].size()) { - if (chan < fChannelMap[equipId][asic].size()) { - result = fChannelMap[equipId][asic][chan]; + auto fiberMap = fChannelMap[equipId]; + auto jt = fiberMap.find(asicId); + if (jt != fiberMap.end()) { + auto asic = fiberMap[asicId]; + if (chanId < asic.size()) { + result = asic[chanId]; } } } @@ -146,27 +163,33 @@ namespace cbm::algo::trd2d uint16_t equipmentId = comp.first; auto value = comp.second; uint16_t moduleId = value.moduleId; - uint16_t crobId = value.crobId; - ss << "Equipment " << equipmentId << " Module " << moduleId << " Crob " << crobId << "\n"; + uint16_t fiberId = value.fiberId; + ss << "Equipment 0x" << std::hex << (int) equipmentId << " Module " << moduleId << " fiberId " << fiberId << "\n"; } ss << "\n"; for (auto asicMap : fChannelMap) { uint16_t equipmentId = asicMap.first; uint16_t numAsics = asicMap.second.size(); - ss << "\n Equipment " << equipmentId << " nAsics " << numAsics; - for (size_t asicId = 0; asicId < numAsics; asicId++) { - - uint16_t numChans = asicMap.second.at(asicId).size(); - ss << "\n Equipment " << equipmentId << " AsicId " << asicId << " nChans " << numChans; + ss << "\n Equipment 0x" << std::hex << (int) equipmentId << " nAsics " << numAsics; + + int asicCnt(0); + auto asics = asicMap.second; + for (auto asic : asics) { + int asicId = asic.first; + auto asicChs = asic.second; + uint16_t numChans = asicChs.size(); + ss << "\n " << asicCnt << " AsicId " << asicId << " nChans " << numChans; for (size_t chanId = 0; chanId < numChans; chanId++) { - auto entry = asicMap.second.at(asicId).at(chanId); - int32_t address = entry.padAddress; - bool isMasked = entry.rPairingFlag; - uint64_t daqOffset = entry.daqOffset; - ss << "\n Equipment " << equipmentId << " AsicId " << asicId << " chanID " << chanId << " pad address " - << address << " mask " << isMasked << " daq offset " << daqOffset; + auto entry = asicChs.at(chanId); + int32_t address = entry.padAddress; + bool isMasked = entry.maskFlag; + uint8_t tOffset = entry.tOffset; + uint16_t thres = entry.lThreshold; + ss << "\n chanID " << chanId << " {pad " << address << " mask " << isMasked << " time offset[clk] " + << (int) tOffset << " threshold[" << (thres > 0 ? "on" : "off") << "]}"; } + asicCnt++; } } ss << "\n"; diff --git a/algo/detectors/trd2d/ReadoutConfig.h b/algo/detectors/trd2d/ReadoutConfig.h index 9d43ea1e5fdb222a38a0f01e4de870fe96e9c64c..ebd29530d0303cb60df43d4a1026f766b140354a 100644 --- a/algo/detectors/trd2d/ReadoutConfig.h +++ b/algo/detectors/trd2d/ReadoutConfig.h @@ -1,6 +1,6 @@ -/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt +/* Copyright (C) 2023-2025 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt SPDX-License-Identifier: GPL-3.0-only - Authors: Volker Friese, Dominik Smith [committer] */ + Authors: Volker Friese, Dominik Smith [committer], Alex Bercuci */ #pragma once @@ -34,22 +34,25 @@ namespace cbm::algo::trd2d public: struct CompMapping { uint16_t moduleId; - uint8_t crobId; + uint8_t fiberId; CBM_YAML_FORMAT(YAML::Flow); CBM_YAML_PROPERTIES(yaml::Property(&CompMapping::moduleId, "moduleId", "Module ID"), - yaml::Property(&CompMapping::crobId, "crobId", "CROB ID")); + yaml::Property(&CompMapping::fiberId, "fiberId", "Optical Fibre ID")); }; struct ChanMapping { - int32_t padAddress; - bool rPairingFlag; - uint64_t daqOffset; + int32_t padAddress; /// map pad and pairing to FASP channel + bool maskFlag; /// HW mask flag for channel + uint8_t tOffset; /// time correction in clk + uint16_t lThreshold; /// SW threshold for ringing channels CBM_YAML_FORMAT(YAML::Flow); - CBM_YAML_PROPERTIES(yaml::Property(&ChanMapping::padAddress, "padAddress", "Pad address"), - yaml::Property(&ChanMapping::rPairingFlag, "rPairingFlag", "R pairing flag"), - yaml::Property(&ChanMapping::daqOffset, "daqOffset", "DAQ offset")); + CBM_YAML_PROPERTIES( + yaml::Property(&ChanMapping::padAddress, "address", "Pad address"), + yaml::Property(&ChanMapping::maskFlag, "mask", "Channel masking flag"), + yaml::Property(&ChanMapping::tOffset, "toff", "Channel wise time offset"), + yaml::Property(&ChanMapping::lThreshold, "thres", "SW masking by threshold")); }; /** @brief Constructor **/ @@ -73,6 +76,13 @@ namespace cbm::algo::trd2d size_t GetNumAsics(uint16_t equipmentId); + /** @brief Number of ASICS of a component + ** @param Equipment ID + ** @return List of ASICS linked to the curent ROB + **/ + std::vector<uint8_t> GetAsicList(uint16_t equipmentId); + + /** @brief Number of channels of a component - ASIC pair ** @param Equipment ID ** @param ASIC ID @@ -102,11 +112,12 @@ namespace cbm::algo::trd2d std::string PrintReadoutMap(); /** @brief Initialisation of readout map **/ - void InitComponentMap(const std::map<uint32_t, uint16_t[NCROBMOD]>& crob_map); + void InitComponentMap(const std::map<uint32_t, std::vector<uint16_t>>& map); /** @brief Initialisation of channel map **/ void InitChannelMap( - const std::map<size_t, std::map<size_t, std::map<size_t, std::tuple<int32_t, bool, uint64_t>>>>& channelMap); + const std::map<size_t, std::map<size_t, std::map<size_t, std::tuple<int32_t, bool, uint8_t, uint16_t>>>>& + channelMap); /** @brief Get system time offset **/ int64_t GetSystemTimeOffset() { return fSystemTimeOffset; }; @@ -124,14 +135,14 @@ namespace cbm::algo::trd2d // --- TRD2D channel map // --- Map index: (equipment, asic, chan), map value: (pad address, mask flag, daq offset) - std::map<uint16_t, std::vector<std::vector<ChanMapping>>> fChannelMap = {}; //! - - CBM_YAML_PROPERTIES(yaml::Property(&ReadoutConfig::fSystemTimeOffset, "timeOffset", "System time offset for TRD2D"), - yaml::Property(&ReadoutConfig::fReadoutMap, "readoutMap", "Maps equipment to module and CROB ID", - YAML::Hex), - yaml::Property(&ReadoutConfig::fChannelMap, "channelMap", - "Maps equipment, ASIC and channel to pad address, R pairing flag and DAQ offset", - {}, YAML::Hex)); + std::map<uint16_t, std::map<uint8_t, std::vector<ChanMapping>>> fChannelMap = {}; //! + + CBM_YAML_PROPERTIES( + yaml::Property(&ReadoutConfig::fSystemTimeOffset, "timeOffset", "System time offset for TRD2D"), + yaml::Property(&ReadoutConfig::fReadoutMap, "readoutMap", "Maps equipment to module and Optical fibre Id", YAML::Hex), + yaml::Property(&ReadoutConfig::fChannelMap, "channelMap", + "Maps equipment, ASIC and channel to pad address, mask flag and DAQ offset", + YAML::Hex)); }; } // namespace cbm::algo::trd2d diff --git a/algo/detectors/trd2d/Unpack.cxx b/algo/detectors/trd2d/Unpack.cxx index ef628a177d65b674e0dd9979fb6eefc0d55787d8..f42c1851484cf6ce8822d42d2ab7ed72dcb7aaba 100644 --- a/algo/detectors/trd2d/Unpack.cxx +++ b/algo/detectors/trd2d/Unpack.cxx @@ -1,6 +1,6 @@ -/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main +/* Copyright (C) 2024-2025 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main SPDX-License-Identifier: GPL-3.0-only - Authors: Felix Weiglhofer [committer], Dominik Smith */ + Authors: Felix Weiglhofer [committer], Dominik Smith, Alex Bercuci */ #include "Unpack.h" @@ -11,7 +11,13 @@ using fles::Subsystem; Unpack::Unpack(const ReadoutConfig& readout) : fReadout(readout) { - constexpr u8 SystemVersion = 0x02; + /** Register the algorithm versions available for TRD2D. For the moment (25.01.14), there is + * no distinction between ALGO and MESSAGE version. The following mapping is + * assumed: + * eMessageVersion::kMessLegacy - refers to the version WITH digi buffering + * eMessageVersion::kMess24 - refers to the version WITHOUT digi buffering + */ + constexpr std::array<u8, 2> AlgoVersion = {(u8) eMessageVersion::kMessLegacy, (u8) eMessageVersion::kMess24}; // Create one algorithm per component for TRD and configure it with parameters auto equipIdsTrd2d = fReadout.GetEquipmentIds(); @@ -20,30 +26,53 @@ Unpack::Unpack(const ReadoutConfig& readout) : fReadout(readout) trd2d::UnpackPar par{}; const size_t numAsics = fReadout.GetNumAsics(equip); - for (size_t asic = 0; asic < numAsics; asic++) { + auto asics = fReadout.GetAsicList(equip); + for (auto asic : asics) { trd2d::UnpackAsicPar asicPar; const size_t numChans = fReadout.GetNumChans(equip, asic); for (size_t chan = 0; chan < numChans; chan++) { trd2d::UnpackChannelPar chanPar; - auto pars = fReadout.ChanMap(equip, asic, chan); - chanPar.fPadAddress = pars.padAddress; // Pad address for channel - chanPar.fMask = pars.rPairingFlag; // Flag channel mask - chanPar.fDaqOffset = pars.daqOffset; // Time calibration parameter + auto pars = fReadout.ChanMap(equip, asic, chan); + chanPar.fPadAddress = pars.padAddress; // Pad address for channel + chanPar.fMask = pars.maskFlag; // Flag channel mask + chanPar.fDaqOffset = pars.tOffset; // Time calibration parameter + chanPar.fSignalThres = pars.lThreshold; // Threshold cut asicPar.fChanParams.push_back(chanPar); } + L_(debug) << "--- Configured asic " << (int) asic << " with " << numChans << " channels"; auto comppars = fReadout.CompMap(equip); par.fSystemTimeOffset = fReadout.GetSystemTimeOffset(); par.fModId = comppars.moduleId; - par.fCrobId = comppars.crobId; - par.fAsicParams.push_back(asicPar); + par.fEqAdd = equip; + par.fEqId = comppars.fiberId; + par.fAsicParams[asic] = asicPar; } - auto algo = std::make_unique<UnpackMS>(par); - fAlgos[{equip, SystemVersion}] = std::move(algo); + L_(debug) << "--- Configured equipment 0x" << std::hex << (int) equip << " with " << std::dec << numAsics + << " asics"; - L_(debug) << "--- Configured equipment " << equip << " with " << numAsics << " asics"; + // build all algorithms defined for data unpacking ! Why ?? (AB 25.01.15) + std::unique_ptr<UnpackMSBase<CbmTrdDigi, UnpackMonitorData, UnpackAuxData>> algo; + for (auto ver : AlgoVersion) { + switch (ver) { + case (int) eMessageVersion::kMessLegacy: + algo = std::make_unique<UnpackMS<(u8) eMessageVersion::kMessLegacy>>(std::move(par)); + break; + case (int) eMessageVersion::kMess24: + algo = std::make_unique<UnpackMS<(u8) eMessageVersion::kMess24>>(std::move(par)); + break; + } + // register algorithm + L_(debug) << "Register algo for ver=" << (int) ver << " eqId=0x" << std::hex << (int) equip; + fAlgos[{equip, ver}] = std::move(algo); + } } L_(info) << "--- Configured " << fAlgos.size() << " unpacker algorithms for TRD2D."; + // for (const auto& [key, algo] : fAlgos) { + // L_(info) << "eq=0x" << std::hex << key.eqId << " ver=" << int(key.sysVer); + // if (key.sysVer ==2 ) continue; + // (dynamic_cast<const UnpackMS<3>&>(*algo)).DumpParameters(); + // } } Unpack::Result_t Unpack::operator()(const fles::Timeslice& ts) const { return DoUnpack(Subsystem::TRD2D, ts); } diff --git a/algo/detectors/trd2d/UnpackMS.cxx b/algo/detectors/trd2d/UnpackMS.cxx index 714f4c2e81b7066d5beb362fa116ec2bfa46684f..9184338d6ace3c0dbe2644a80edb0c29e24cccb6 100644 --- a/algo/detectors/trd2d/UnpackMS.cxx +++ b/algo/detectors/trd2d/UnpackMS.cxx @@ -8,6 +8,9 @@ #include <algorithm> #include <cassert> +#include <iomanip> +#include <iostream> +#include <sstream> #include <vector> using std::unique_ptr; @@ -15,23 +18,165 @@ using std::unique_ptr; namespace cbm::algo::trd2d { // ---- Fasp message constructor ---------------------------------------- - FaspMessage::FaspMessage(uint8_t c, uint8_t typ, uint8_t t, uint16_t d, uint8_t rob, uint8_t asic) + FaspMessage::FaspMessage(uint8_t c, uint8_t typ, uint8_t t, uint16_t d, uint8_t asic) : ch(c) - , type(typ) + , type(eMessageType::kNone) , tlab(t) , data(d) - , crob(rob) , fasp(asic) { + if (typ == uint8_t(eMessageType::kData)) + type = eMessageType::kData; + else if (typ == uint8_t(eMessageType::kEpoch)) + type = eMessageType::kEpoch; } - UnpackMS::UnpackMS(const UnpackPar& pars) : fParams(pars) {} - UnpackMS::~UnpackMS() = default; + std::string FaspMessage::print() const + { + std::stringstream ss; + switch (type) { + case eMessageType::kData: + ss << " DATA : fasp=" << std::setw(2) << (int) fasp << " ch=" << std::setw(2) << (int) ch + << " t=" << std::setw(3) << (int) tlab << " data=" << std::setw(4) << (int) data << std::endl; + break; + case eMessageType::kEpoch: ss << " EPOCH: ch=" << (int) ch << " epoch=" << (int) epoch << std::endl; break; + default: ss << " MTYPE: unknown" << std::endl; break; + } + + return ss.str(); + } + + // ---- Data type descriptor --------------------------------------------- + template<std::uint8_t mess_ver> + eMessageType FaspMessage::getType(uint32_t) + { + return eMessageType::kNone; + } + + template<> + eMessageType FaspMessage::getType<uint8_t(eMessageVersion::kMess24)>(uint32_t w) + { + /** Search the data type descriptor in a FASP word. Starting with message version kMess24*/ + + if ((w >> 31) & 0x1) return eMessageType::kEpoch; + return eMessageType::kData; + } + + // ---- Unpacking a DATA WORD --------------------------------------------- + template<std::uint8_t mess_ver> + void FaspMessage::readDW(uint32_t) + { + return; + } + + template<> + void FaspMessage::readDW<uint8_t(eMessageVersion::kMess24)>(uint32_t w) + { + /** Data Word unpacking starting with message version kMess24*/ + + uint8_t shift(0); + uint16_t adc_data = (w >> shift) & 0x3fff; + // TODO This data format version delivers the ADC value as bit_sgn + 13 significant bits + // TODO The CbmTrdDigi supports digi data with only 12bits unsigned. The first tests will + // TODO convert the measurement to the old format leaving the implementation of the new storage to // TODO later time. (AB 14.06.2024) + uint16_t sign = adc_data >> 13; // sign + int value_i; + if (!sign) + value_i = adc_data; + else + value_i = (-1) * ((adc_data ^ 0xffff) & 0x1fff); + // convert to 12bit unsigned + data = (value_i + 0x1fff) >> 2; + shift += uint8_t(eMessageLength::kMessData); + tlab = (w >> shift) & 0x7f; + shift += uint8_t(eMessageLength::kMessTlab); + ch = (w >> shift) & 0xf; + shift += uint8_t(eMessageLength::kMessCh); + fasp = ((w >> shift) & 0x3f); + shift += uint8_t(eMessageLength::kMessFasp); + type = eMessageType((w >> shift) & 0x1); + shift += uint8_t(eMessageLength::kMessType); + + // if (VERBOSE >= 2) { + // printf("v06.24Mess_readDW[%x] signed charge = %+d\n", w, value_i); + // print(); + // } + return; + } + + // ---- Unpacking an EPOCH WORD --------------------------------------------- + template<std::uint8_t mess_ver> + void FaspMessage::readEW(uint32_t) + { + return; + } + + template<> + void FaspMessage::readEW<uint8_t(eMessageVersion::kMess24)>(uint32_t w) + { + /** Epoch Word unpacking starting with message version kMess24*/ + + uint8_t shift(0); + epoch = (w >> shift) & 0x1fffff; + shift += uint8_t(eMessageLength::kMessEpoch); + ch = (w >> shift) & 0xf; + shift += uint8_t(eMessageLength::kMessCh); + fasp = (w >> shift) & 0x3f; + shift += uint8_t(eMessageLength::kMessFasp); + type = eMessageType((w >> shift) & 0x1); + shift += uint8_t(eMessageLength::kMessType); + + // if (VERBOSE >= 2) { + // printf("v06.24Mess_readEW[%x]\n", w); + // print(); + // } + return; + } + + void UnpackPar::dump() const + { + L_(debug) << "UnpackPar::dump()"; + L_(debug) << "mod=" << fModId << " elink[" << (int) fEqId << "]=0x" << std::hex << (int) fEqAdd + << " nAsics=" << std::dec << fAsicParams.size(); + for (const auto& [fasp, par] : fAsicParams) { + L_(debug) << " fasp=" << int(fasp) << " par=" << std::hex << ∥ + } + L_(debug) << "UnpackPar::dump(-----------------------)"; + } + + template<> + uint8_t UnpackPar::mapFaspId2Mod<uint8_t(eMessageVersion::kMessLegacy)>(uint8_t fasp_id) const + { + /** Use the mapping 36 fasp -> 1 optical fiber (equipment id) + * Applies to FASPRO/FW v1 (e.g. mCBM22) + */ + L_(debug) << "<vLegacy> Eq[" << (int) fEqId << "] = 0x" << std::hex << fEqAdd; + return fEqId * NFASPROB + fasp_id; + } + + template<> + uint8_t UnpackPar::mapFaspId2Mod<uint8_t(eMessageVersion::kMess24)>(uint8_t fasp_id) const + { + /** Use the mapping 36 fasp -> 2 optical fiber (equipment id) + * Applies to FASPRO/FW v2 (e.g. mCBM25) + */ + + int rob = fEqId / 2; // ROB on the current chamber + //L_(debug) << "<v24> ROB=" << rob << " Eq[" << (int)fEqId << "] = 0x" << std::hex << fEqAdd; + + return rob * NFASPROB + fasp_id; + } // ---- Algorithm execution --------------------------------------------- - UnpackMS::Result_t UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr, - const uint64_t tTimeslice) const + template<> + typename UnpackMS<uint8_t(eMessageVersion::kMessLegacy)>::Result_t + UnpackMS<uint8_t(eMessageVersion::kMessLegacy)>::operator()(const uint8_t* msContent, + const fles::MicrosliceDescriptor& msDescr, + const uint64_t tTimeslice) const { + /** Implementation of TRD2D unpacking for the 2021 - 2022 mCBM data taking + * The algorithm implements digi buffering due to a "feature" on the ADC read-out + */ // --- Output data Result_t result = {}; @@ -44,12 +189,13 @@ namespace cbm::algo::trd2d uint64_t time = uint64_t((msDescr.idx - tTimeslice - fParams.fSystemTimeOffset) / 12.5); // Get parameters for current eq id. - const uint8_t crob_id = fParams.fCrobId; + //const uint8_t crob_id = fParams.fEqId; // Get the number of complete words in the input MS buffer. const uint32_t nwords = msDescr.size / 4; - - // We have 32 bit spadic frames in this readout version + L_(debug) << "UnpackMS<kMessLegacy>::op() param.olink[" << (int) fParams.fEqId << "]=0x" << std::hex + << (int) fParams.fEqAdd << " data.rob=0x" << int(msDescr.eq_id) << " words=" << std::dec << nwords; + // We have 32 bit FASP frames in this readout version const uint32_t* wd = reinterpret_cast<const uint32_t*>(msContent); unsigned char lFaspOld(0xff); @@ -90,24 +236,29 @@ namespace cbm::algo::trd2d ctx.fMonitor.fNumSelfTriggeredData++; data &= 0x1fff; } - vMess.emplace_back(ch_id, kData, slice, data >> 1, crob_id, lFaspOld); + vMess.emplace_back(ch_id, (uint8_t) eMessageType::kData, slice, data >> 1, lFaspOld); } std::get<0>(result) = FinalizeComponent(ctx); //TO DO: Original (non-algo) version calls this after MS loop!! std::get<1>(result) = ctx.fMonitor; return result; } - //_________________________________________________________________________________ - bool UnpackMS::pushDigis(std::vector<FaspMessage> messes, const uint64_t time, MsContext& ctx) const + template<uint8_t sys_ver> + bool UnpackMS<sys_ver>::pushDigis(std::vector<FaspMessage> messes, const uint64_t time, MsContext& ctx) const { + constexpr uint8_t mLegacy = + uint8_t(eMessageVersion::kMessLegacy); // message versions compatible with the current algo specialization const uint16_t mod_id = fParams.fModId; - const UnpackAsicPar& asicPar = fParams.fAsicParams[messes[0].fasp]; - const uint64_t tdaqOffset = asicPar.fChanParams[messes[0].ch].fDaqOffset; + const uint8_t fasp_mod_id = fParams.mapFaspId2Mod<mLegacy>(messes[0].fasp); + const UnpackAsicPar& asicPar = fParams.fAsicParams.at(fasp_mod_id); for (auto imess : messes) { - const int32_t pad = std::abs(asicPar.fChanParams[imess.ch].fPadAddress); - const bool hasPairingR = bool(asicPar.fChanParams[imess.ch].fPadAddress > 0); + const UnpackChannelPar& chPar = asicPar.fChanParams[imess.ch]; + //std::cout << imess.print(); + const int32_t pad = std::abs(chPar.fPadAddress) / 2; + const bool hasPairingR = bool(chPar.fPadAddress > 0); + const uint8_t tdaqOffset = chPar.fDaqOffset; const uint64_t lTime = time + tdaqOffset + imess.tlab; const uint16_t lchR = hasPairingR ? imess.data : 0; const uint16_t lchT = hasPairingR ? 0 : imess.data; @@ -167,11 +318,12 @@ namespace cbm::algo::trd2d return true; } - std::vector<CbmTrdDigi> UnpackMS::FinalizeComponent(MsContext& ctx) const + template<uint8_t sys_ver> + std::vector<CbmTrdDigi> UnpackMS<sys_ver>::FinalizeComponent(MsContext& ctx) const { std::vector<CbmTrdDigi> outputDigis; - for (uint16_t ipad(0); ipad < NFASPMOD * NFASPCH; ipad++) { + for (uint16_t ipad(0); ipad < NFASPMOD * NFASPPAD; ipad++) { if (!ctx.fDigiBuffer[ipad].size()) continue; uint nIncomplete(0); for (auto id = ctx.fDigiBuffer[ipad].begin(); id != ctx.fDigiBuffer[ipad].end(); id++) { @@ -196,4 +348,156 @@ namespace cbm::algo::trd2d } return outputDigis; } + + // ------------- Specialization kMess24 -------------------------------- + typename UnpackMS<uint8_t(eMessageVersion::kMess24)>::Result_t + UnpackMS<uint8_t(eMessageVersion::kMess24)>::operator()(const uint8_t* msContent, + const fles::MicrosliceDescriptor& msDescr, + const uint64_t tTimeslice) const + { + /** Implementation of TRD2D unpacking for the 2024 - PRESENT mCBM data taking + * The algorithm implements the new message format starting with version kMess24 + */ + + constexpr uint8_t m24 = + uint8_t(eMessageVersion::kMess24); // message versions compatible with the current algo specialization + Result_t result = {}; + MsContext ctx = {}; + + // define time wrt start of time slice in TRD/FASP clks [80 MHz]. Contains: + // - relative offset of the MS wrt the TS + // - FASP epoch offset for current CROB + // - TRD2D system offset wrt to experiment time + uint64_t time = uint64_t((msDescr.idx - tTimeslice - fParams.fSystemTimeOffset) * fAsicClockFreq); + + // Get the number of complete words in the input MS buffer. + const uint32_t nwords = msDescr.size / 4; + L_(debug) << "UnpackMS<kMess24>::op() param.olink[" << (int) fParams.fEqId << "]=0x" << std::hex + << (int) fParams.fEqAdd << " data.rob=0x" << int(msDescr.eq_id) << " words=" << std::dec << nwords; + + // We have 32 bit FASP frames in this readout version + const uint32_t* wd = reinterpret_cast<const uint32_t*>(msContent); + + unsigned char lFaspOld(0xff); + std::vector<FaspMessage> vMess; + for (uint32_t j = 0; j < nwords; j++, wd++) { + uint32_t w = *wd; + // Select the appropriate conversion type of the word according to + // the current message version and type + switch (FaspMessage::getType<m24>(w)) { + case eMessageType::kData: ctx.fMess.readDW<m24>(w); break; + case eMessageType::kEpoch: ctx.fMess.readEW<m24>(w); break; + default: break; // no way to reach this line + } + + // PROCESS EPOCH MESSAGES + if (ctx.fMess.type == eMessageType::kEpoch) { + if (ctx.fMess.ch == 0) { // check word integrity + // clear buffer + if (vMess.size()) { + pushDigis(vMess, time, ctx); + } + vMess.clear(); + + lFaspOld = 0xff; + time += FASP_EPOCH_LENGTH; + } + else { + L_(error) << "FASP message[Epoch] with wrong signature."; + ctx.fMonitor.fNumErrEndBitSet++; + } + continue; + } + + // PROCESS DATA MESSAGES + // clear buffer when switching to other FASP + if (ctx.fMess.fasp != lFaspOld) { + if (vMess.size()) pushDigis(vMess, time, ctx); + vMess.clear(); + lFaspOld = ctx.fMess.fasp; + } + if (ctx.fMess.data & 0x2000) { // kept for backward compatibility TODO + ctx.fMonitor.fNumSelfTriggeredData++; + ctx.fMess.data &= 0x1fff; + } + vMess.emplace_back(ctx.fMess); + } + + // combine all digis from this ROB + std::vector<CbmTrdDigi> outputDigis; + for (uint16_t ipad(0); ipad < NFASPMOD * NFASPPAD; ipad++) { + if (!ctx.fRobDigi[ipad].size()) continue; + for (auto id : ctx.fRobDigi[ipad]) { + // L_(debug) << id.ToString(); + outputDigis.emplace_back(std::move(id)); + } + } + std::get<0>(result) = outputDigis; + std::get<1>(result) = ctx.fMonitor; + + return result; + } + bool UnpackMS<uint8_t(eMessageVersion::kMess24)>::pushDigis(std::vector<FaspMessage> messes, const uint64_t time, + MsContext& ctx) const + { + constexpr uint8_t m24 = + uint8_t(eMessageVersion::kMess24); // message versions compatible with the current algo specialization + const uint8_t fasp_mod_id = fParams.mapFaspId2Mod<m24>(messes[0].fasp); + L_(debug) << "pushDigis<v24> fasp=" << (int) messes[0].fasp << "/" << (int) fasp_mod_id; + if (fParams.fAsicParams.find(fasp_mod_id) == fParams.fAsicParams.end()) { + L_(error) << "pushDigis<v24> fasp=" << (int) messes[0].fasp << "/" << (int) fasp_mod_id + << " not mapped to param.olink[" << (int) fParams.fEqId << "]=0x" << std::hex << (int) fParams.fEqAdd; + return false; + } + const UnpackAsicPar& asicPar = fParams.fAsicParams.at(fasp_mod_id); + + for (auto imess : messes) { + const UnpackChannelPar& chPar = asicPar.fChanParams[imess.ch]; + // skip message if threshold set and signal under + if (chPar.fSignalThres && imess.data <= chPar.fSignalThres) continue; + const int32_t pad = std::abs(chPar.fPadAddress) / 2; + const bool hasPairingR = bool(chPar.fPadAddress > 0); + const uint64_t lTime = time + chPar.fDaqOffset + imess.tlab; + const uint16_t lchR = hasPairingR ? imess.data : 0; + const uint16_t lchT = hasPairingR ? 0 : imess.data; + std::vector<CbmTrdDigi>& digiBuffer = ctx.fRobDigi[pad]; + + // init pad position in array and build digi for message + if (digiBuffer.size() == 0) { + digiBuffer.emplace_back(pad, lchT, lchR, lTime); + digiBuffer.back().SetAddressModule(fParams.fModId); + continue; + } + + // check if last digi has both R/T message components. + // Update if not and is within time window + auto& id = digiBuffer.back(); // Should always be valid here. + // No need to extra check + double r, t; + int32_t dt; + const int32_t dtime = id.GetTimeDAQ() - lTime; + bool use(false); + if (abs(dtime) < 5) { // test message part of (last) digi + r = id.GetCharge(t, dt); + if (lchR && r < 0.1) { // set R charge on an empty slot + id.SetCharge(t, lchR, -dtime); + use = true; + } + else if (lchT && t < 0.1) { // set T charge on an empty slot + id.SetCharge(lchT, r, +dtime); + id.SetTimeDAQ(uint64_t(id.GetTimeDAQ() - dtime)); + use = true; + } + } + + // build digi for message when update failed + if (!use) { + digiBuffer.emplace_back(pad, lchT, lchR, lTime); + digiBuffer.back().SetAddressModule(fParams.fModId); + } + } + messes.clear(); + + return true; + } } // namespace cbm::algo::trd2d diff --git a/algo/detectors/trd2d/UnpackMS.h b/algo/detectors/trd2d/UnpackMS.h index 18a498eecc63f649d81486d9357a3b533bc1bb99..631bb4db6d247eb3386e5c34c0723642c246bd16 100644 --- a/algo/detectors/trd2d/UnpackMS.h +++ b/algo/detectors/trd2d/UnpackMS.h @@ -4,7 +4,6 @@ #pragma once #include "CbmTrdDigi.h" -#include "CbmTrdRawMessageSpadic.h" #include "MicrosliceDescriptor.hpp" #include "UnpackMSBase.h" @@ -13,49 +12,118 @@ #include <sstream> #define NFASPMOD 180 -#define NCROBMOD 5 -#define NFASPCROB NFASPMOD / NCROBMOD +#define NROBMOD 5 +#define NFASPROB NFASPMOD / NROBMOD #define NFASPCH 16 +#define NFASPPAD NFASPCH / 2 -#define FASP_EPOCH_LENGTH 128 +#define FASP_EPOCH_LENGTH 128 // the length in clks of FASP epoch [1600ns @ 40MHz] namespace cbm::algo::trd2d { + enum class eMessageLength : int + { + kMessCh = 4, + kMessType = 1, + kMessTlab = 7, + kMessData = 14, + kMessFasp = 6, + kMessEpoch = 21 + }; - enum FaspMessageType + enum class eMessageVersion : uint8_t { - kEpoch = 0, - kData + kMessLegacy = 2, /// unpacker version for 2-board FASPRO+GETS HW + kMess24 = 3, /// unpacker version for 1-board FASPRO HW first used 18.06.24 (mCBM) + }; + + enum class eMessageType : int + { + kData = 0, + kEpoch = 1, + kNone }; /** @brief Data structure for unpacking the FASP word */ + // Constants + /** @brief Bytes per FASP frame stored in the microslices (32 bits words) + * - DATA WORD - for legacy version + * ffff.ffdd dddd.dddd dddd.tttt ttta.cccc + * f - FASP id + * d - ADC signal + * t - time label inside epoch + * a - word type (1) + * c - channel id + * - EPOCH WORD - + * ffff.fftt tttt.tttt tttt.tttt ttta.cccc + * f - FASP id + * t - epoch index + * a - word type (0) + * c - channel id + * ===================================================== + * - DATA WORD - for 06.2024 version + * afff.fffc ccct.tttt ttdd.dddd dddd.dddd + * f - FASP id + * d - ADC signal + * t - time label inside epoch + * a - word type (1) + * c - channel id + * - EPOCH WORD - + * afff.fffc ccct.tttt tttt tttt tttt.tttt + * a - word type (0) + * f - FASP id + * t - epoch index + * c - channel id + */ struct FaspMessage { - FaspMessage(uint8_t c, uint8_t typ, uint8_t t, uint16_t d, uint8_t rob, uint8_t asic); - uint8_t ch = 0; ///< ch id in the FASP - uint8_t type = 0; ///< message type 0 = epoch, 1 = data (not used for the moment) - uint8_t tlab = 0; ///< time of the digi inside the epoch - uint16_t data = 0; ///< ADC value - uint32_t epoch = 0; ///< epoch id (not used for the moment) - uint32_t mod = 0; ///< full module address according to CbmTrdAddress - uint8_t crob = 0; ///< CROB id in the module - uint8_t fasp = 0; ///< FASP id in the module + FaspMessage() = default; + FaspMessage(const FaspMessage&) = default; + FaspMessage(uint8_t c, uint8_t typ, uint8_t t, uint16_t d, uint8_t asic); + + /** \brief Implementation of message type descriptor according to message version + * \param w the message word + */ + template<std::uint8_t mess_ver> + static eMessageType getType(uint32_t w); + + std::string print() const; + + /** \brief Read DATA WORD and store the content locally + * \param w the message word + */ + template<std::uint8_t mess_ver> + void readDW(uint32_t w); + + /** \brief Read EPOCH WORD and store the content locally + * \param w the message word + */ + template<std::uint8_t mess_ver> + void readEW(uint32_t w); + + uint8_t ch = 0; ///< ch id in the FASP + eMessageType type = eMessageType::kNone; ///< message type 0 = data, 1 = epoch (not used for the moment) + uint8_t tlab = 0; ///< time of the digi inside the epoch + uint16_t data = 0; ///< ADC value + uint32_t epoch = 0; ///< epoch id (not used for the moment) + uint8_t fasp = 0; ///< FASP id in the module }; /** @struct UnpackChannelPar ** @author Dominik Smith <d.smith@gsi.de> ** @since 31 January 2023 - ** @brief TRD Unpacking parameters for one Asic channel + ** @brief TRD2D Unpacking parameters for one Asic channel **/ struct UnpackChannelPar { int32_t fPadAddress; ///< Pad address for channel bool fMask; ///< Flag for channel masking - uint64_t fDaqOffset = 0; ///< Time calibration parameter + uint8_t fDaqOffset = 0; ///< Time calibration parameter + uint16_t fSignalThres = 0; ///< Signal threshold to remove ringing channels }; /** @struct UnpackAsicPar ** @author Dominik Smith <d.smith@gsi.de> ** @since 31 January 2023 - ** @brief TRD Unpacking parameters for one Asic + ** @brief TRD2D Unpacking parameters for one Asic **/ struct UnpackAsicPar { std::vector<UnpackChannelPar> fChanParams; ///< Parameters for different channels @@ -64,20 +132,32 @@ namespace cbm::algo::trd2d /** @struct UnpackPar ** @author Dominik Smith <d.smith@gsi.de> ** @since 31 January 2023 - ** @brief Parameters required for the TRD unpacking (specific to one component) + ** @brief Parameters required for the TRD2D unpacking (specific to one component) **/ struct UnpackPar { - int32_t fSystemTimeOffset = 0; ///< Time calibration parameter - uint16_t fModId = 0; ///< Module ID of component - uint8_t fCrobId = 0; ///< CROB ID of component - std::vector<UnpackAsicPar> fAsicParams = {}; ///< Parameters for each ASIC + int32_t fSystemTimeOffset = 0; ///< Time calibration parameter + uint16_t fModId = 0; ///< Module ID of component + uint16_t fEqAdd = 0; ///< Equipment (optical fiber) address [HEX] + uint8_t fEqId = 0xff; ///< Equipment (optical fiber) ID of component + std::map<uint8_t, UnpackAsicPar> fAsicParams = {}; ///< Parameters for each ASIC + + /** \brief Write to the debug stream the content of the current param object*/ + void dump() const; + + /** \brief Calculate the module wise FASP id from the FASP id provided at the level + * of equipment Id (optical fibre in TRD2D case). + * \param fasp_id index of fasp as written on the message + * \return fasp id on the module as it is used in the parameter file + */ + template<uint8_t ver> + uint8_t mapFaspId2Mod(uint8_t fasp_id) const; }; /** @struct UnpackMoni ** @author Dominik Smith <d.smith@gsi.de> ** @since 31 January 2023 - ** @brief Monitoring data for TRD unpacking + ** @brief Monitoring data for TRD2D unpacking **/ struct UnpackMonitorData { uint32_t fNumSelfTriggeredData = 0; ///< word fulfills data & 0x2000 @@ -101,27 +181,26 @@ namespace cbm::algo::trd2d /** @struct UnpackAux ** @author Dominik Smith <d.smith@gsi.de> ** @since 24 May 2024 - ** @brief Auxiliary data for BMON unpacking + ** @brief Auxiliary data for unpacking **/ struct UnpackAuxData { ///// TO BE FILLED }; /** @class UnpackMS - ** @author Dominik Smith <d.smith@gsi.de> + ** @author Dominik Smith <d.smith@gsi.de>, Alex Bercuci <abercuci@niham.nipne.ro> ** @since 31 January 2023 - ** @brief Unpack algorithm for TRD + ** @brief Unpack algorithm for TRD2D **/ + template<std::uint8_t sys_ver> class UnpackMS : public UnpackMSBase<CbmTrdDigi, UnpackMonitorData, UnpackAuxData> { public: /** @brief Construct from parameters **/ - UnpackMS(const UnpackPar& pars); - + UnpackMS(const UnpackPar& pars) : fParams(pars) {} /** @brief Destructor **/ - ~UnpackMS() override; - + ~UnpackMS() override = default; /** @brief Algorithm execution ** @param msContent Microslice payload @@ -152,25 +231,58 @@ namespace cbm::algo::trd2d /** @brief Finalize component (e.g. copy from temp buffers) */ std::vector<CbmTrdDigi> FinalizeComponent(MsContext& ctx) const; - - // Constants - /** @brief Bytes per FASP frame stored in the microslices (32 bits words) - * - DATA WORD - - * ffff.ffdd dddd.dddd dddd.tttt ttta.cccc - * f - FASP id - * d - ADC signal - * t - time label inside epoch - * a - word type (1) - * c - channel id - * - EPOCH WORD - - * ffff.fftt tttt.tttt tttt.tttt ttta.cccc - * f - FASP id - * t - epoch index - * a - word type (0) - * c - channel id - */ - static const std::uint8_t fBytesPerWord = 4; }; + /** @class UnpackMS<kMess24> + ** @author Alex Bercuci <abercuci@niham.nipne.ro> + ** @since 15 January 2025 + ** @brief Unpack algorithm specialization for TRD2D based on one-layered FEB design introduced in + * 06.2024 (https://indico.gsi.de/event/20885/attachments/49263/72236/TRD2D-CDR-FEB.pdf) + * - using different message format (\see \enum eMessageVersion) starting with kMess24 + * - remove time buffering of digi per channel as a new 32 channels ADC is used in the FEE + **/ + template<> + class UnpackMS<uint8_t(eMessageVersion::kMess24)> : + public UnpackMSBase<CbmTrdDigi, UnpackMonitorData, UnpackAuxData> { + + public: + /** @brief Construct from parameters **/ + UnpackMS(const UnpackPar& pars) : fParams(pars) {} + + /** @brief Destructor **/ + ~UnpackMS() override = default; + + + /** @brief Algorithm execution + ** @param msContent Microslice payload + ** @param msDescr Microslice descriptor + ** @param tTimeslice Unix start time of timeslice [ns] + ** @return TRD digi data + **/ + Result_t operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr, + const uint64_t tTimeslice) const override; + + /** @brief Set the parameter container + ** @param params Pointer to parameter container + **/ + void SetParams(std::unique_ptr<UnpackPar> params) { fParams = *(std::move(params)); } + + private: // Types + struct MsContext { + UnpackMonitorData fMonitor; ///< Container for monitoring data + std::array<std::vector<CbmTrdDigi>, NFASPMOD* NFASPPAD> fRobDigi = { + {}}; ///> Buffered digi for each pad in one Epoch-ROB component + FaspMessage fMess; ///< encapsulation of the FASP message. + }; + + private: // members + bool pushDigis(std::vector<FaspMessage> messages, const uint64_t time, MsContext& ctx) const; + + UnpackPar fParams = {}; ///< Parameter container + + /** @brief Clock frequency of FASP in 0.08 GHz. HW also supports 0.04 GHz*/ + static constexpr float fAsicClockFreq = 0.08; + }; + } // namespace cbm::algo::trd2d diff --git a/external/InstallParameter.cmake b/external/InstallParameter.cmake index 267991c336588df4892dd46f2713874df20fdba8..cf8bece02f0d33abacfd8befb3ca2d059474f63b 100644 --- a/external/InstallParameter.cmake +++ b/external/InstallParameter.cmake @@ -1,4 +1,4 @@ -set(PARAMETER_VERSION 46692530a94d76df4a6f13b5c7a34c20e862695f) # 2024-12-05 +set(PARAMETER_VERSION 6c2a42c01b2f21b02d65755ca2cc41319aacce15) # 2025-01-29 set(PARAMETER_SRC_URL "https://git.cbm.gsi.de/CbmSoft/cbmroot_parameter.git") download_project_if_needed(PROJECT Parameter_source diff --git a/reco/tasks/CbmTaskTrdUnpackParWrite.cxx b/reco/tasks/CbmTaskTrdUnpackParWrite.cxx index c7c3667f31426582748a8ec18bdf0a6f7c9447ea..aa85f8906c28250b3a10060be1e3be97e272b307 100644 --- a/reco/tasks/CbmTaskTrdUnpackParWrite.cxx +++ b/reco/tasks/CbmTaskTrdUnpackParWrite.cxx @@ -37,9 +37,9 @@ InitStatus CbmTaskTrdUnpackParWrite::Init() cbm::algo::trd2d::ReadoutConfig trd2dConfig; // Map (moduleId) -> (array of crobId) - std::map<uint32_t, uint16_t[NCROBMOD]> crobMap; + std::map<uint32_t, std::vector<uint16_t>> crobMap; // Map (equipId, asicId, chanId) -> (pad address, mask flag, daq offset [FASP clk]) - std::map<size_t, std::map<size_t, std::map<size_t, std::tuple<int32_t, bool, uint64_t>>>> channelMap; + std::map<size_t, std::map<size_t, std::map<size_t, std::tuple<int32_t, bool, uint8_t, uint16_t>>>> channelMap; // Loop through a list of module IDs from the .digi file (can in principle contradict crob_map). for (auto entry : digiparset.GetModuleMap()) { @@ -53,9 +53,12 @@ InitStatus CbmTaskTrdUnpackParWrite::Init() auto digipar = entry.second; const int* crobs = setDet->GetCrobAddresses(); - for (int icrob(0); icrob < NCROBMOD; icrob++) - crobMap[moduleId][icrob] = crobs[icrob]; - + for (int icrob(0); icrob < NCROBMOD; icrob++) { + crobMap[moduleId].emplace_back(crobs[icrob] & 0xffff); + // check if there is an extra fiber defined on this ROB (version 2025 -) + uint16_t eq_id = (crobs[icrob] >> 16) & 0xffff; + if (eq_id) crobMap[moduleId].emplace_back(eq_id); + } // Loop through ASICs for this module std::vector<int32_t> addresses; setDet->GetAsicAddresses(&addresses); @@ -74,9 +77,10 @@ InitStatus CbmTaskTrdUnpackParWrite::Init() const CbmTrdParFaspChannel* faspch = fasppar->GetChannel(chan); const int32_t pad = fasppar->GetPadAddress(chan) * (faspch->HasPairingR() ? 1 : -1); const bool isMasked = faspch->IsMasked(); - uint64_t daq_offset = 0; + uint8_t daq_offset = 0; + uint8_t thres = 0; if (((CbmTrdParModDigi*) digipar)->GetPadRow(pad) % 2 == 0) daq_offset = 3; - channelMap[eq_id][fasp_in_eq][chan] = std::make_tuple(pad, isMasked, daq_offset); + channelMap[eq_id][fasp_in_eq][chan] = std::make_tuple(pad, isMasked, daq_offset, thres); } } }