From 368e7a5e58808f73773480cc2d61b245d47b5f35 Mon Sep 17 00:00:00 2001 From: Dominik Smith <d.smith@gsi.de> Date: Tue, 23 Aug 2022 12:34:51 +0200 Subject: [PATCH] Added TOF unpacker in algo namespace. Modified CMakeLists to compile new TOF and T0 unpackers. --- algo/CMakeLists.txt | 6 +- algo/detectors/tof/TofReadoutConfig.cxx | 445 ++++++++++++++++++++++++ algo/detectors/tof/TofReadoutConfig.h | 103 ++++++ algo/detectors/tof/UnpackTof.cxx | 165 +++++++++ algo/detectors/tof/UnpackTof.h | 121 +++++++ 5 files changed, 839 insertions(+), 1 deletion(-) create mode 100644 algo/detectors/tof/TofReadoutConfig.cxx create mode 100644 algo/detectors/tof/TofReadoutConfig.h create mode 100644 algo/detectors/tof/UnpackTof.cxx create mode 100644 algo/detectors/tof/UnpackTof.h diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt index 6e80b666e2..4f7e36be31 100644 --- a/algo/CMakeLists.txt +++ b/algo/CMakeLists.txt @@ -11,7 +11,11 @@ set(SRCS detectors/much/MuchReadoutConfig.cxx detectors/much/UnpackMuch.cxx detectors/tof/HitFinderTof.cxx -) + detectors/tof/TofReadoutConfig.cxx + detectors/tof/UnpackTof.cxx + detectors/t0/T0ReadoutConfig.cxx + detectors/t0/UnpackT0.cxx + ) add_library(Algo SHARED ${SRCS}) diff --git a/algo/detectors/tof/TofReadoutConfig.cxx b/algo/detectors/tof/TofReadoutConfig.cxx new file mode 100644 index 0000000000..ac108fa1a9 --- /dev/null +++ b/algo/detectors/tof/TofReadoutConfig.cxx @@ -0,0 +1,445 @@ +/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Dominik Smith [committer] */ + +#include "TofReadoutConfig.h" + +#include "CbmTofAddress.h" + +#include <Logger.h> + +#include <bitset> +#include <iomanip> + +#include "gDpbMessv100.h" + +using namespace std; + +namespace cbm::algo +{ + // --- Constructor ------------------------------------------------------------------ + TofReadoutConfig::TofReadoutConfig() { Init(); } + // ------------------------------------------------------------------------------------ + + // --- Destructor ----------------------------------------------------------------- + TofReadoutConfig::~TofReadoutConfig() {} + // ------------------------------------------------------------------------------------ + + // --- Equipment IDs -------------------------------------------------------------- + std::vector<uint16_t> TofReadoutConfig::GetEquipmentIds() + { + std::vector<uint16_t> result; + for (auto& entry : fReadoutMap) + result.push_back(entry.first); + return result; + } + // ------------------------------------------------------------------------------------ + + // --- Number of elinks for a component / equipment ------------------------------- + size_t TofReadoutConfig::GetNumElinks(uint16_t equipmentId) + { + size_t result = 0; + auto it = fReadoutMap.find(equipmentId); + if (it != fReadoutMap.end()) result = fReadoutMap[equipmentId].size(); + return result; + } + // ------------------------------------------------------------------------------------ + + + // --- Mapping (equimentId, elink) -> address[channel] ------------------------------ + std::vector<uint32_t> TofReadoutConfig::Map(uint16_t equipmentId, uint16_t elinkId) + { + std::vector<uint32_t> result; + auto equipIter = fReadoutMap.find(equipmentId); + if (equipIter != fReadoutMap.end()) { + if (elinkId < equipIter->second.size()) { result = equipIter->second.at(elinkId); } + } + return result; + } + // ------------------------------------------------------------------------------------ + + void TofReadoutConfig::Init() + { + // This here refers to the mCBM 2022 setup. + // Taken from CbmMcbm2018TofPar in combination with macro/beamtime/mcbm2022/mTofCriParNickel.par + + // Array to hold the unique IDs (equipment ID) for all TOF DPBs + uint16_t eqId[numComp] = {0xabc0, 0xabc1, 0xabc2, 0xabc3, 0xabc4, 0xabc5, 0xabc6, 0xabc7}; + + // Constructing the map (equipmentId, eLink, channel) -> (TOF address) + const uint32_t numChanPerComp = numChanPerAsic * numElinksPerComp; + + // Constructs the fviRpcChUId array + BuildChannelsUidMap(); + + for (uint16_t comp = 0; comp < numComp; comp++) { + + uint16_t equipment = eqId[comp]; + fReadoutMap[equipment].resize(numElinksPerComp); + + for (uint16_t elink = 0; elink < numElinksPerComp; elink++) { + fReadoutMap[equipment][elink].resize(numChanPerAsic); + const uint32_t asicId = ElinkIdxToGet4Idx(elink); + + for (uint16_t channel = 0; channel < numChanPerAsic; channel++) { + const uint32_t febId = (asicId / numAsicsPerFeb); + const uint32_t chanInFeb = (asicId % numAsicsPerFeb) * numChanPerAsic + channel; + const uint32_t remappedChan = comp * numChanPerComp + febId * numChanPerFeb + Get4ChanToPadiChan(chanInFeb); + const uint32_t chanUId = fviRpcChUId[remappedChan]; + fReadoutMap[equipment][elink][channel] = chanUId; + } //# channel + } //# elink + } //# component + } + + int32_t TofReadoutConfig::ElinkIdxToGet4Idx(uint32_t elink) + { + if (gdpbv100::kuChipIdMergedEpoch == elink) return elink; + else if (elink < numElinksPerComp) + return elink2Asic[elink % numElinksPerCrob] + numElinksPerCrob * (elink / numElinksPerCrob); + else { + LOG(fatal) << "CbmMcbm2018TofPar::ElinkIdxToGet4Idx => Index out of bound, " << elink << " vs " + << static_cast<uint32_t>(numElinksPerComp) << ", returning crazy value!"; + return -1; + } + } + // ------------------------------------------------------------------------- + + + // ------------------------------------------------------------------------- + int32_t TofReadoutConfig::Get4ChanToPadiChan(uint32_t channelInFee) + { + if (channelInFee < numChanPerFeb) return asic2PadI[channelInFee]; + else { + LOG(fatal) << "CbmMcbm2018TofPar::Get4ChanToPadiChan => Index out of bound, " << channelInFee << " vs " + << static_cast<uint32_t>(numChanPerFeb) << ", returning crazy value!"; + return -1; + } + } + // ------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- + void TofReadoutConfig::BuildChannelsUidMap() + { + uint32_t uNrOfGet4 = numComp * numFebsPerComp * numAsicsPerFeb; + uint32_t uNrOfChannels = uNrOfGet4 * numChanPerAsic; + fviRpcChUId.resize(uNrOfChannels); + + uint32_t uCh = 0; + for (uint32_t uGbtx = 0; uGbtx < numCrob; ++uGbtx) { + uint32_t uCh0 = uCh; + switch (rpcType[uGbtx]) { + case 2: // intended fall-through + case 0: { + // CBM modules + BuildChannelsUidMapCbm(uCh, uGbtx); + break; + } + case 1: { + // STAR eTOF modules + BuildChannelsUidMapStar(uCh, uGbtx); + break; + } + case 78: { + // cern-20-gap + ceramic module + BuildChannelsUidMapCern(uCh, uGbtx); + } + [[fallthrough]]; // fall through is intended + case 8: // ceramics + { + BuildChannelsUidMapCera(uCh, uGbtx); + break; + } + case 69: + case 6: // Buc box + { + BuildChannelsUidMapBuc(uCh, uGbtx); + if (rpcType[uGbtx] == 6) break; + } + [[fallthrough]]; + case 4: // intended fallthrough + [[fallthrough]]; + case 7: [[fallthrough]]; + case 9: // Star2 boxes + { + if (rpcType[uGbtx] == 69) uCh -= 80; + BuildChannelsUidMapStar2(uCh, uGbtx); + if (rpcType[uGbtx] == 69) uCh -= 80; + break; + } + + case -1: { + LOG(info) << " Found unused GBTX link at uCh = " << uCh; + uCh += 160; + break; + } + default: { + LOG(error) << "Invalid Tof Type specifier for GBTx " << std::setw(2) << uGbtx << ": " << rpcType[uGbtx]; + } + } // switch (rpcType[uGbtx]) + if ((int32_t)(uCh - uCh0) != numFebsPerComp * numAsicsPerFeb * numChanPerAsic / 2) { + LOG(fatal) << "Tof mapping error for Gbtx " << uGbtx << ", diff = " << uCh - uCh0 << ", type " + << rpcType[uGbtx]; + } + } // for (UInt_t uGbtx = 0; uGbtx < numCrob; ++uGbtx) + } + // ------------------------------------------------------------------------- + + + // ------------------------------------------------------------------------- + void TofReadoutConfig::BuildChannelsUidMapCbm(uint32_t& uCh, uint32_t uGbtx) + { + LOG(info) << " Map mTof box " << moduleId[uGbtx] << " at GBTX " << uGbtx << " - uCh = " << uCh; + if (rpcSide[uGbtx] < 2) { // mTof modules + LOG(debug) << " Map mTof box " << moduleId[uGbtx] << " at GBTX - uCh = " << uCh; + const int32_t RpcMap[5] = {4, 2, 0, 3, 1}; + for (int32_t iRpc = 0; iRpc < numRpc[uGbtx]; iRpc++) { + int32_t iStrMax = 32; + uint32_t uChNext = 1; + + for (int32_t iStr = 0; iStr < iStrMax; iStr++) { + int32_t iStrMap = iStr; + int32_t iRpcMap = RpcMap[iRpc]; + + if (rpcSide[uGbtx] == 0) iStrMap = 31 - iStr; + if (moduleId[uGbtx] > -1) + fviRpcChUId[uCh] = + CbmTofAddress::GetUniqueAddress(moduleId[uGbtx], iRpcMap, iStrMap, rpcSide[uGbtx], rpcType[uGbtx]); + else + fviRpcChUId[uCh] = 0; + uCh += uChNext; + } // for (int32_t iStr = 0; iStr < iStrMax; iStr++) + } // for (int32_t iRpc = 0; iRpc < numRpc[uGbtx]; iRpc++) + } // if (rpcSide[uGbtx] < 2) + } + + + // ------------------------------------------------------------------------- + void TofReadoutConfig::BuildChannelsUidMapStar(uint32_t& uCh, uint32_t uGbtx) + { + if (rpcSide[uGbtx] < 2) { + // mTof modules + LOG(info) << "Start eTOF module side " << rpcSide[uGbtx] << " at " << uCh; + const int32_t RpcMap[3] = {0, 1, 2}; + for (int32_t iRpc = 0; iRpc < numRpc[uGbtx]; iRpc++) { + int32_t iStrMax = 32; + int32_t uChNext = 1; + + for (int32_t iStr = 0; iStr < iStrMax; iStr++) { + int32_t iStrMap = iStr; + int32_t iRpcMap = RpcMap[iRpc]; + + if (rpcSide[uGbtx] == 0) iStrMap = 31 - iStr; + if (moduleId[uGbtx] > -1) + fviRpcChUId[uCh] = + CbmTofAddress::GetUniqueAddress(moduleId[uGbtx], iRpcMap, iStrMap, rpcSide[uGbtx], rpcType[uGbtx]); + else + fviRpcChUId[uCh] = 0; + uCh += uChNext; + } + } + } + uCh += 64; + } + + // ------------------------------------------------------------------------- + void TofReadoutConfig::BuildChannelsUidMapCern(uint32_t& uCh, uint32_t) + { + LOG(info) << " Map CERN 20 gap at GBTX - uCh = " << uCh; + // clang-format off + const int32_t StrMap[32] = {0, 1, 2, 3, 4, 31, 5, 6, 7, 30, 8, + 9, 10, 29, 11, 12, 13, 14, 28, 15, 16, 17, + 18, 27, 26, 25, 24, 23, 22, 21, 20, 19}; + // clang-format on + int32_t iModuleId = 0; + int32_t iModuleType = 7; + int32_t iRpcMap = 0; + for (int32_t iFeet = 0; iFeet < 2; iFeet++) { + for (int32_t iStr = 0; iStr < 32; iStr++) { + int32_t iStrMap = 31 - 12 - StrMap[iStr]; + int32_t iSideMap = iFeet; + if (iStrMap < 20) + fviRpcChUId[uCh] = CbmTofAddress::GetUniqueAddress(iModuleId, iRpcMap, iStrMap, iSideMap, iModuleType); + else + fviRpcChUId[uCh] = 0; + uCh++; + } + } + LOG(info) << " Map end CERN 20 gap at GBTX - uCh = " << uCh; + } + + // ------------------------------------------------------------------------- + void TofReadoutConfig::BuildChannelsUidMapCera(uint32_t& uCh, uint32_t) + { + int32_t iModuleId = 0; + int32_t iModuleType = 8; + for (int32_t iRpc = 0; iRpc < 8; iRpc++) { + fviRpcChUId[uCh] = CbmTofAddress::GetUniqueAddress(iModuleId, 7 - iRpc, 0, 0, iModuleType); + uCh++; + } + uCh += (24 + 2 * 32); + LOG(info) << " Map end ceramics box at GBTX - uCh = " << uCh; + } + + + // ------------------------------------------------------------------------- + void TofReadoutConfig::BuildChannelsUidMapStar2(uint32_t& uCh, uint32_t uGbtx) + { + LOG(info) << " Map Star2 box " << moduleId[uGbtx] << " at GBTX " << uGbtx << " - uCh = " << uCh; + const int32_t iRpc[5] = {1, -1, 1, 0, 0}; + const int32_t iSide[5] = {1, -1, 0, 1, 0}; + for (int32_t iFeet = 0; iFeet < 5; iFeet++) { + for (int32_t iStr = 0; iStr < 32; iStr++) { + int32_t iStrMap = iStr; + int32_t iRpcMap = iRpc[iFeet]; + int32_t iSideMap = iSide[iFeet]; + if (iSideMap == 0) iStrMap = 31 - iStr; + switch (rpcSide[uGbtx]) { + case 0:; break; + case 1:; + iRpcMap = 1 - iRpcMap; // swap counters + break; + case 2: + switch (iFeet) { + case 1: + iRpcMap = iRpc[4]; + iSideMap = iSide[4]; + iStrMap = 31 - iStrMap; + break; + case 4: + iRpcMap = iRpc[1]; + iSideMap = iSide[1]; + break; + default:; + } + break; + case 3: // direct beam 20210524 + switch (iFeet) { + case 0: + iRpcMap = 0; + iSideMap = 0; + iStrMap = iStr; + break; + case 1: + iRpcMap = 0; + iSideMap = 1; + iStrMap = 31 - iStr; + break; + default: iSideMap = -1; + } + break; + } + if (iSideMap > -1) + fviRpcChUId[uCh] = + CbmTofAddress::GetUniqueAddress(moduleId[uGbtx], iRpcMap, iStrMap, iSideMap, rpcType[uGbtx]); + else + fviRpcChUId[uCh] = 0; + uCh++; + } + } + } + + + // ------------------------------------------------------------------------- + void TofReadoutConfig::BuildChannelsUidMapBuc(uint32_t& uCh, uint32_t uGbtx) + { + LOG(info) << " Map Buc box " << moduleId[uGbtx] << " at GBTX " << uGbtx << " - uCh = " << uCh; + + int32_t iModuleIdMap = moduleId[uGbtx]; + const int32_t iRpc[5] = {0, -1, 0, 1, 1}; + const int32_t iSide[5] = {1, -1, 0, 1, 0}; + for (int32_t iFeet = 0; iFeet < 5; iFeet++) { + for (int32_t iStr = 0; iStr < 32; iStr++) { + int32_t iStrMap = iStr; + int32_t iRpcMap = iRpc[iFeet]; + int32_t iSideMap = iSide[iFeet]; + switch (rpcSide[uGbtx]) { + case 0:; break; + case 1: // HD cosmic 2019, Buc2018, v18n + iStrMap = 31 - iStr; + iRpcMap = 1 - iRpcMap; + break; + case 2: // v18m_cosmicHD + // iStrMap=31-iStr; + iSideMap = 1 - iSideMap; + break; + case 3: + iStrMap = 31 - iStr; + iRpcMap = 1 - iRpcMap; + iSideMap = 1 - iSideMap; + break; + case 4: // HD cosmic 2019, Buc2018, v18o + iRpcMap = 1 - iRpcMap; + break; + case 5: // HD cosmic 2020, Buc2018, v20a + iStrMap = 31 - iStr; + break; + case 6: //BUC special + { + switch (moduleId[uGbtx]) { + case 0: iRpcMap = 0; break; + case 1: iRpcMap = 1; break; + } + if (iFeet % 2 == 1) iModuleIdMap = 1; + else + iModuleIdMap = 0; + + switch (iFeet) { + case 0: + case 3: iSideMap = 0; break; + case 1: + case 2: iSideMap = 1; break; + } + } break; + + case 7: { + // clang-format off + const int32_t iChMap[160]={ + 124, 125, 126, 127, 12, 13, 14, 15, 4, 5, 6, 7, 28, 29, 30, 31, 120, 121, 122, 123, 8, 9, 10, 11, 104, 105, 106, 107, 108, 109, 110, 111, + 36, 37, 38, 39, 52, 53, 54, 55, 60, 61, 62, 63, 128, 129, 130, 131, 40, 41, 42, 43, 148, 149, 150, 151, 56, 57, 58, 59, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, 96, 97, 98, 99, 64, 65, 66, 67, 100, 101, 102, 103, 84, 85, 86, 87, 152, 153, 154, 155, 68, 69, 70, 71, + 156, 157, 158, 159, 144, 145, 146, 147, 44, 45, 46, 47, 76, 77, 78, 79, 48, 49, 50, 51, 20, 21, 22, 23, 32, 33, 34, 35, 116, 117, 118, 119, + 75, 74, 73, 72, 92, 93, 94, 95, 16, 17, 18, 19, 80, 81, 82, 83, 115, 114, 113, 112, 24, 25, 26, 27, 88, 89, 90, 91, 0, 1, 2, 3 + }; + // clang-format on + int32_t iInd = iFeet * 32 + iStr; + int32_t i = 0; + for (; i < 160; i++) + if (iInd == iChMap[i]) break; + iStrMap = i % 32; + int32_t iFeetInd = (i - iStrMap) / 32; + switch (iFeetInd) { + case 0: + iRpcMap = 0; + iSideMap = 1; + break; + case 1: + iRpcMap = 1; + iSideMap = 1; + break; + case 2: + iRpcMap = 1; + iSideMap = 0; + break; + case 3: + iRpcMap = 0; + iSideMap = 0; + break; + case 4: iSideMap = -1; break; + } + iModuleIdMap = moduleId[uGbtx]; + } break; + default:; + } // switch (rpcSide[uGbtx]) + if (iSideMap > -1) + fviRpcChUId[uCh] = CbmTofAddress::GetUniqueAddress(iModuleIdMap, iRpcMap, iStrMap, iSideMap, rpcType[uGbtx]); + else + fviRpcChUId[uCh] = 0; + + uCh++; + } // for (int32_t iStr = 0; iStr < 32; iStr++) + } // for (int32_t iFeet = 0; iFeet < 5; iFeet++) + } + // ------------------------------------------------------------------------- + +} /* namespace cbm::algo */ diff --git a/algo/detectors/tof/TofReadoutConfig.h b/algo/detectors/tof/TofReadoutConfig.h new file mode 100644 index 0000000000..30b40104fe --- /dev/null +++ b/algo/detectors/tof/TofReadoutConfig.h @@ -0,0 +1,103 @@ +/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Dominik Smith [committer] */ + +#ifndef ALGO_DETECTORS_TOF_TOFREADOUTCONFIG_H +#define ALGO_DETECTORS_TOF_TOFREADOUTCONFIG_H + +#include <cstdint> +#include <map> +#include <vector> + +namespace cbm::algo +{ + class TofReadoutConfig { + + public: + /** @brief Constructor **/ + TofReadoutConfig(); + + /** @brief Destructor **/ + virtual ~TofReadoutConfig(); + + /** @brief Equipment in the configuration + ** @return Vector of equipment IDs + **/ + std::vector<uint16_t> GetEquipmentIds(); + + /** @brief Number of elinks of a component + ** @param Equipment ID + ** @return Number of elinks + **/ + size_t GetNumElinks(uint16_t equipmentId); + + /** @brief API: Mapping from component and elink to addresses per channel + ** @param equipId Equipment identifier (component) + ** @param elink Elink number within component + ** @return Vector of TOF addresses, indexed via channel number + */ + std::vector<uint32_t> Map(uint16_t equipId, uint16_t elink); + + private: + // --- TOF readout map + // --- Map index: (equipment, elink, channel), map value: (TOF address) + std::map<uint16_t, std::vector<std::vector<uint32_t>>> fReadoutMap = {}; + + /** @brief Initialisation of readout map **/ + void Init(); + + /// Mapping to eLink to ASIC number within DPB. Mapping is the same for each DPB. + int32_t ElinkIdxToGet4Idx(uint32_t elink); + int32_t Get4ChanToPadiChan(uint32_t channelInFee); + + /// Constants + + /// Taken from mTofCriParNickel_withBmon.par + static const uint16_t numComp = 8; // Total number of TOF DPBs in system + static const uint32_t numFebsPerComp = 10; // Number of FEEs which are connected to one GDPB + static const uint32_t numAsicsPerFeb = 8; // Number of ASICs connected in each FEB for TOF + static const uint32_t numChanPerAsic = 4; // Number of channels in each ASIC + static const uint32_t numCrob = 16; // Total number of Gbtx links + + // Module Identifier connected to Gbtx link, has to match geometry + const int32_t moduleId[numCrob] = {0, 0, 1, 1, 0, 0, 2, 2, 3, 3, 4, 4, 0 - 1, 0, 0}; + + // type of Rpcs connected to Gbtx link + const int32_t rpcType[numCrob] = {0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 9, 9, 6, 9}; + + // side of Rpcs connected to Gbtx link, i.e. 0 or 1 + const int32_t rpcSide[numCrob] = {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 8, 0}; + + // number of Rpcs connected to Gbtx link, i.e. 3 or 5 + const int32_t numRpc[numCrob] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; + + //// Taken from CbmMcbm2018TofPar.h (fixed numCrobPerComp) + static const uint32_t numCrobPerComp = 2; // Number of CROBs possible per DPB + static const uint32_t numFebsPerCrob = 5; // Number of FEBs connected to each CROB for mTof 2019 + static const uint32_t numChanPerFeb = numChanPerAsic * numAsicsPerFeb; + static const uint32_t numElinksPerCrob = numAsicsPerFeb * numFebsPerCrob; + static const uint32_t numElinksPerComp = numElinksPerCrob * numCrobPerComp; + + // Mapping to eLink to ASIC number within CROB. Mapping is the same for each CROB. + const uint32_t elink2Asic[numElinksPerCrob] = {27, 2, 7, 3, 31, 26, 30, 1, 33, 37, 32, 13, 9, 14, + 10, 15, 17, 21, 16, 35, 34, 38, 25, 24, 0, 6, 20, 23, + 18, 22, 28, 4, 29, 5, 19, 36, 39, 8, 12, 11}; + // Mapping in Readout chain PCBs + const uint32_t asic2PadI[numChanPerFeb] = { + 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12, + 19, 18, 17, 16, 23, 22, 21, 20, 27, 26, 25, 24, 31, 30, 29, 28}; //! Map from GET4 channel to PADI channel + + std::vector<int32_t> fviRpcChUId = {}; // UID/address for each channel, build from type, side and module + + void BuildChannelsUidMap(); + void BuildChannelsUidMapCbm(uint32_t& uCh, uint32_t uGbtx); + void BuildChannelsUidMapStar(uint32_t& uCh, uint32_t uGbtx); + void BuildChannelsUidMapCern(uint32_t& uCh, uint32_t uGbtx); + void BuildChannelsUidMapCera(uint32_t& uCh, uint32_t uGbtx); + void BuildChannelsUidMapStar2(uint32_t& uCh, uint32_t uGbtx); + void BuildChannelsUidMapBuc(uint32_t& uCh, uint32_t uGbtx); + }; + +} /* namespace cbm::algo */ + +#endif //ALGO_DETECTORS_TOF_TOFREADOUTCONFIG_H diff --git a/algo/detectors/tof/UnpackTof.cxx b/algo/detectors/tof/UnpackTof.cxx new file mode 100644 index 0000000000..fa12645f2e --- /dev/null +++ b/algo/detectors/tof/UnpackTof.cxx @@ -0,0 +1,165 @@ +/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Dominik Smith [committer] */ + +#include "UnpackTof.h" + +#include <cassert> +#include <utility> +#include <vector> + +#include <cmath> + +using std::unique_ptr; +using std::vector; + +namespace cbm::algo +{ + + // ---- Algorithm execution --------------------------------------------- + UnpackTof::resultType UnpackTof::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr, + const uint64_t tTimeslice) + { + + // --- Output data + resultType result = {}; + + // --- Current Timeslice start time in epoch units. Note that it is always a multiple of epochs + // --- and the epoch is a multiple of ns. + fCurrentTsTime = static_cast<uint64_t>(tTimeslice / critof001::kuEpochInNs) % critof001::kulEpochCycleEp; + + // ---Â Number of messages in microslice + auto msSize = msDescr.size; + if (msSize % sizeof(critof001::Message) != 0) { + result.second.fNumErrInvalidMsSize++; + return result; + } + const uint32_t numMessages = msSize / sizeof(critof001::Message); + if (numMessages < 2) { + result.second.fNumErrInvalidMsSize++; + return result; + } + + // --- Interpret MS content as sequence of Critof messages + auto message = reinterpret_cast<const critof001::Message*>(msContent); + + // --- The first message in the MS is expected to be of type EPOCH. + if (message[0].getMessageType() != critof001::MSG_EPOCH) { + result.second.fNumErrInvalidFirstMessage++; + return result; + } + + { // --- Check that first epoch matches with the microslice index + const uint64_t msStartEpoch = + static_cast<uint64_t>(msDescr.idx / critof001::kuEpochInNs) % critof001::kulEpochCycleEp; + if (message[0].getGdpbEpEpochNb() != msStartEpoch) { + result.second.fNumErrInvalidStartEpoch++; + return result; + } + } + + // --- The last message in the MS is expected to be EndOfMs. + if (!message[numMessages - 1].isEndOfMs()) { + result.second.fNumErrInvalidLastMessage++; + return result; + } + // Check if last message is "EndOfMs"!! Maybe loop to messageNr < numMessages - 1 + + // --- Message loop + for (uint32_t messageNr = 0; messageNr < numMessages; messageNr++) { + + // --- Action depending on message type + switch (message[messageNr].getMessageType()) { + + case critof001::MSG_HIT: { + ProcessHitMessage(message[messageNr], result.first, result.second); + break; + } + case critof001::MSG_EPOCH: { + ProcessEpochMessage(message[messageNr]); + break; + } + case critof001::MSG_SLOWC: { + // Fill error + break; + } + case critof001::MSG_SYST: { + // Fill error + break; + } + default: { + result.second.fNumNonHitOrTsbMessage++; + break; + } + } //? Message type + } //# Messages + + return result; + } + // -------------------------------------------------------------------------- + + + // ----- Process hit message -------------------------------------------- + inline void UnpackTof::ProcessHitMessage(const critof001::Message& message, vector<CbmTofDigi>& digiVec, + UnpackTofMonitorData& monitor) const + { + // --- Check eLink and get parameters + const uint32_t elink = message.getGet4Idx(); + if (elink >= fParams.fElinkParams.size()) { + monitor.fNumErrElinkOutOfRange++; + return; + } + const UnpackTofElinkPar& elinkPar = fParams.fElinkParams.at(elink); + + const uint32_t channel = message.getGdpbHitChanId(); + const uint32_t channelUId = (elinkPar.fChannelUId)[channel]; + + double messageTime = message.getMsgFullTimeD(fCurrentEpochInTs) - elinkPar.fTimeOffset; + const double charge = (double) message.getGdpbHit32Tot(); //cast from uint32_t + + { // weird address hack (probably should not be in final version) + std::unique_ptr<CbmTofDigi> digi(new CbmTofDigi(channelUId, messageTime, charge)); + int iSmType = 8; + int iSm = -1; + int iRpc = 0; + int iDetId = 0; + if (digi->GetType() == 6 && digi->GetRpc() == 1) { + switch ((int) (digi->GetChannel() * 2 + digi->GetSide())) { + case 62: //800 + iSm = 0; + break; + case 46: //810 + iSm = 1; + break; + default:; + } + if (iSm > -1) { + iDetId = CbmTofAddress::GetUniqueAddress(iSm, iRpc, 0, 0, iSmType); + digi->SetAddress(iDetId); + } + } + if (digi) digiVec.emplace_back(*std::move(digi)); + } //special remapping end + + // --- Create output digi + //digiVec.emplace_back(channelUId, messageTime, charge); ((restore this)) + } + // -------------------------------------------------------------------------- + + + // ----- Process an epoch message --------------------------------------- + inline void UnpackTof::ProcessEpochMessage(const critof001::Message& message) + { + const uint64_t epoch = message.getGdpbEpEpochNb(); + + // --- Calculate epoch relative to timeslice start time; correct for epoch cycles + if (fCurrentTsTime <= epoch) { fCurrentEpochInTs = epoch - fCurrentTsTime; } + else { + fCurrentEpochInTs = epoch + critof001::kulEpochCycleEp - fCurrentTsTime; + } + //Problem if MS spans multiple epoch cycles? + } + // -------------------------------------------------------------------------- + + +} /* namespace cbm::algo */ diff --git a/algo/detectors/tof/UnpackTof.h b/algo/detectors/tof/UnpackTof.h new file mode 100644 index 0000000000..2710dd8619 --- /dev/null +++ b/algo/detectors/tof/UnpackTof.h @@ -0,0 +1,121 @@ +/* Copyright (C) 2022 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt + SPDX-License-Identifier: GPL-3.0-only + Authors: Dominik Smith [committer] */ + +#ifndef CBM_ALGO_UNPACKTOF_H +#define CBM_ALGO_UNPACKTOF_H 1 + + +#include "CbmTofDigi.h" + +#include "MicrosliceDescriptor.hpp" +#include "Timeslice.hpp" + +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <memory> +#include <vector> + +#include "CriGet4Mess001.h" + +namespace cbm::algo +{ + + /** @struct UnpackTofElinkPar + ** @author Volker Friese <v.friese@gsi.de> + ** @since 25 November 2021 + ** @brief TOF Unpacking parameters for one eLink / ASIC + **/ + struct UnpackTofElinkPar { + std::vector<uint32_t> fChannelUId; ///< CbmTofAddress for different channels + uint64_t fTimeOffset = 0.; ///< Time calibration parameter + }; + + /** @struct UnpackTofPar + ** @author Volker Friese <v.friese@gsi.de> + ** @since 25 November 2021 + ** @brief Parameters required for the STS unpacking (specific to one component) + **/ + struct UnpackTofPar { + uint32_t fNumChansPerAsic = 0; ///< Number of channels per ASIC + uint32_t fNumAsicsPerModule = 0; ///< Number of ASICS per module + std::vector<UnpackTofElinkPar> fElinkParams = {}; ///< Parameters for each eLink + }; + + /** @struct UnpackTofMoni + ** @author Volker Friese <v.friese@gsi.de> + ** @since 2 December 2021 + ** @brief Monitoring data for STS unpacking + **/ + struct UnpackTofMonitorData { + uint32_t fNumNonHitOrTsbMessage = 0; + uint32_t fNumErrElinkOutOfRange = 0; ///< Elink not contained in parameters + uint32_t fNumErrInvalidFirstMessage = 0; ///< First message is not EPOCH + uint32_t fNumErrInvalidLastMessage = 0; ///< Last message is not EndOfMs + uint32_t fNumErrInvalidMsSize = 0; ///< Microslice size is not multiple of message size + uint32_t fNumErrTimestampOverflow = 0; ///< Overflow in 64 bit time stamp + uint32_t fNumErrInvalidStartEpoch = 0; ///< Microslice index doesn't match first epoch + bool HasErrors() + { + uint32_t numErrors = fNumNonHitOrTsbMessage + fNumErrElinkOutOfRange + fNumErrInvalidFirstMessage + + fNumErrInvalidLastMessage + fNumErrInvalidMsSize + fNumErrTimestampOverflow + + fNumErrInvalidStartEpoch; + return (numErrors > 0 ? true : false); + } + }; + + /** @class UnpackTof + ** @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 UnpackTof { + + public: + typedef std::pair<std::vector<CbmTofDigi>, UnpackTofMonitorData> resultType; + + /** @brief Default constructor **/ + UnpackTof() {}; + + /** @brief Destructor **/ + ~UnpackTof() {}; + + /** @brief Algorithm execution + ** @param msContent Microslice payload + ** @param msDescr Microslice descriptor + ** @param tTimeslice Unix start time of timeslice [ns] + ** @return STS digi data + **/ + 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<UnpackTofPar> params) { fParams = *(std::move(params)); } + + private: // methods + /** @brief Process a hit message + ** @param message SMX message (32-bit word) + ** @param digiVec Vector to append the created digi to + ** @param monitor Reference to monitor object + **/ + void ProcessHitMessage(const critof001::Message& message, std::vector<CbmTofDigi>& digiVec, + UnpackTofMonitorData& monitor) const; + + /** @brief Process an epoch message + ** @param message SMX message (32-bit word) + **/ + void ProcessEpochMessage(const critof001::Message& message); + + private: // members + uint64_t fCurrentTsTime = 0; ///< Unix time of timeslice in units of epoch length + uint32_t fCurrentEpochInTs = 0; ///< Current epoch number relative to timeslice start epoch + UnpackTofPar fParams = {}; ///< Parameter container + }; + +} /* namespace cbm::algo */ + +#endif /* CBM_ALGO_UNPACKTOF_H */ -- GitLab