From cd2fb561aab3fca111fac6c7dabcfc10129368d9 Mon Sep 17 00:00:00 2001
From: Felix Weiglhofer <weiglhofer@fias.uni-frankfurt.de>
Date: Wed, 20 Mar 2024 20:03:29 +0000
Subject: [PATCH] online: Seperate readout parameters from ReadoutConfig in
 TOF.

---
 algo/CMakeLists.txt                           |   1 +
 algo/detectors/tof/ReadoutConfig.cxx          | 156 +++++++++---------
 algo/detectors/tof/ReadoutConfig.h            |  68 +++-----
 algo/detectors/tof/config/ReadoutPars.h       |  52 ++++++
 .../tof/config/ReadoutPars_mCBM2022.cxx       |  51 ++++++
 algo/global/Reco.cxx                          |   3 +-
 reco/tasks/CbmTaskUnpack.cxx                  |   4 +-
 7 files changed, 203 insertions(+), 132 deletions(-)
 create mode 100644 algo/detectors/tof/config/ReadoutPars.h
 create mode 100644 algo/detectors/tof/config/ReadoutPars_mCBM2022.cxx

diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt
index 79552f5987..32adb41db8 100644
--- a/algo/CMakeLists.txt
+++ b/algo/CMakeLists.txt
@@ -107,6 +107,7 @@ set(SRCS
   detectors/tof/Hitfind.cxx
   detectors/tof/HitfinderChain.cxx
   detectors/tof/CalibratorChain.cxx
+  detectors/tof/config/ReadoutPars_mCBM2022.cxx
   detectors/bmon/ReadoutConfig.cxx
   detectors/bmon/Unpack.cxx
   detectors/bmon/UnpackMS.cxx
diff --git a/algo/detectors/tof/ReadoutConfig.cxx b/algo/detectors/tof/ReadoutConfig.cxx
index ebda65c42f..6234bbead9 100644
--- a/algo/detectors/tof/ReadoutConfig.cxx
+++ b/algo/detectors/tof/ReadoutConfig.cxx
@@ -6,6 +6,7 @@
 
 #include "CbmTofAddress.h"
 #include "Exceptions.h"
+#include "config/ReadoutPars.h"
 #include "gDpbMessv100.h"
 
 #include <bitset>
@@ -17,7 +18,7 @@ using namespace std;
 namespace cbm::algo::tof
 {
   // ---  Constructor  ------------------------------------------------------------------
-  ReadoutConfig::ReadoutConfig() { Init(); }
+  ReadoutConfig::ReadoutConfig(const config::ReadoutPars& pars) { Init(pars); }
   // ------------------------------------------------------------------------------------
 
   // ---   Destructor   -----------------------------------------------------------------
@@ -59,33 +60,28 @@ namespace cbm::algo::tof
   }
   // ------------------------------------------------------------------------------------
 
-  void ReadoutConfig::Init()
+  void ReadoutConfig::Init(const config::ReadoutPars& pars)
   {
-    // 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;
+    const uint32_t numChanPerComp = pars.NChansPerComponent();
 
     // Constructs the fviRpcChUId array
-    BuildChannelsUidMap();
+    BuildChannelsUidMap(pars);
 
-    for (uint16_t comp = 0; comp < numComp; comp++) {
+    for (uint16_t comp = 0; comp < pars.NComponents(); comp++) {
 
-      uint16_t equipment = eqId[comp];
-      fReadoutMap[equipment].resize(numElinksPerComp);
+      uint16_t equipment = pars.eqIds.at(comp);
+      fReadoutMap[equipment].resize(pars.NElinksPerComponent());
 
-      for (uint16_t elink = 0; elink < numElinksPerComp; elink++) {
-        fReadoutMap[equipment][elink].resize(numChanPerAsic);
-        const uint32_t asicId = ElinkIdxToGet4Idx(elink);
+      for (uint16_t elink = 0; elink < pars.NElinksPerComponent(); elink++) {
+        fReadoutMap[equipment][elink].resize(pars.nChannelsPerAsic);
+        const uint32_t asicId = ElinkIdxToGet4Idx(elink, pars);
 
-        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);
+        for (uint16_t channel = 0; channel < pars.nChannelsPerAsic; channel++) {
+          const uint32_t febId     = (asicId / pars.nAsicsPerFeb);
+          const uint32_t chanInFeb = (asicId % pars.nAsicsPerFeb) * pars.nChannelsPerAsic + channel;
+          const uint32_t remappedChan =
+            comp * numChanPerComp + febId * pars.NChansPerFeb() + Get4ChanToPadiChan(chanInFeb, pars);
           const uint32_t chanUId      = fviRpcChUId[remappedChan];
           fReadoutMap[equipment][elink][channel] = chanUId;
         }  //# channel
@@ -93,62 +89,66 @@ namespace cbm::algo::tof
     }      //# component
   }
 
-  int32_t ReadoutConfig::ElinkIdxToGet4Idx(uint32_t elink)
+  int32_t ReadoutConfig::ElinkIdxToGet4Idx(uint32_t elink, const config::ReadoutPars& pars)
   {
-    if (gdpbv100::kuChipIdMergedEpoch == elink)
+    if (gdpbv100::kuChipIdMergedEpoch == elink) {
       return elink;
-    else if (elink < numElinksPerComp)
-      return elink2Asic[elink % numElinksPerCrob] + numElinksPerCrob * (elink / numElinksPerCrob);
+    }
+    else if (elink < pars.NElinksPerComponent()) {
+      return pars.elink2Asic[elink % pars.NElinksPerCrob()] + pars.NElinksPerCrob() * (elink / pars.NElinksPerCrob());
+    }
     else {
       throw FatalError("CbmMcbm2018TofPar::ElinkIdxToGet4Idx => Index out of bound, {} vs {}, returning crazy value!",
-                       elink, static_cast<uint32_t>(numElinksPerComp));
+                       elink, static_cast<uint32_t>(pars.NElinksPerComponent()));
     }
   }
   // -------------------------------------------------------------------------
 
 
   // -------------------------------------------------------------------------
-  int32_t ReadoutConfig::Get4ChanToPadiChan(uint32_t channelInFee)
+  int32_t ReadoutConfig::Get4ChanToPadiChan(uint32_t channelInFee, const config::ReadoutPars& pars)
   {
-    if (channelInFee < numChanPerFeb)
-      return asic2PadI[channelInFee];
+    if (channelInFee < pars.NChansPerFeb()) {
+      return pars.asic2PadI[channelInFee];
+    }
     else {
       throw FatalError("CbmMcbm2018TofPar::Get4ChanToPadiChan => Index out of bound, {} vs {}, returning crazy value!",
-                       channelInFee, static_cast<uint32_t>(numChanPerFeb));
+                       channelInFee, static_cast<uint32_t>(pars.NChansPerFeb()));
     }
   }
   // -------------------------------------------------------------------------
 
   // -------------------------------------------------------------------------
-  void ReadoutConfig::BuildChannelsUidMap()
+  void ReadoutConfig::BuildChannelsUidMap(const config::ReadoutPars& pars)
   {
-    uint32_t uNrOfGet4     = numComp * numFebsPerComp * numAsicsPerFeb;
-    uint32_t uNrOfChannels = uNrOfGet4 * numChanPerAsic;
+    uint32_t uNrOfGet4     = pars.NComponents() * pars.nFebsPerComponent * pars.nAsicsPerFeb;
+    uint32_t uNrOfChannels = uNrOfGet4 * pars.nChannelsPerAsic;
     fviRpcChUId.resize(uNrOfChannels);
 
     uint32_t uCh = 0;
-    for (uint32_t uGbtx = 0; uGbtx < numCrob; ++uGbtx) {
+    for (uint32_t uGbtx = 0; uGbtx < pars.NCROBs(); ++uGbtx) {
       uint32_t uCh0 = uCh;
-      switch (rpcType[uGbtx]) {
+      const auto& crob = pars.crobs.at(uGbtx);
+      switch (crob.rpcType) {
         case 2:  // intended fall-through
         case 0: {
           // CBM modules
-          BuildChannelsUidMapCbm(uCh, uGbtx);
+          BuildChannelsUidMapCbm(uCh, crob);
           break;
         }
         case 1: {
           // STAR eTOF  modules
-          BuildChannelsUidMapStar(uCh, uGbtx);
+          BuildChannelsUidMapStar(uCh, crob);
           break;
         }
         case 78: {
           // cern-20-gap + ceramic module
-          BuildChannelsUidMapCern(uCh, uGbtx);
+          BuildChannelsUidMapCern(uCh, crob);
         }
           [[fallthrough]];  // fall through is intended
         case 8:             // ceramics
         {
-          BuildChannelsUidMapCera(uCh, uGbtx);
+          BuildChannelsUidMapCera(uCh, crob);
           break;
         }
         case 4:  // intended fallthrough
@@ -156,20 +156,20 @@ namespace cbm::algo::tof
         case 7: [[fallthrough]];
         case 9:  // Star2 boxes
         {
-          BuildChannelsUidMapStar2(uCh, uGbtx);
+          BuildChannelsUidMapStar2(uCh, crob);
           break;
         }
         case 6:  // Buc box
         {
-          BuildChannelsUidMapBuc(uCh, uGbtx);
+          BuildChannelsUidMapBuc(uCh, crob);
           break;
         }
         case 69: {
           /// 2022 case: 69 is followed by 4 and 9
-          BuildChannelsUidMapBuc(uCh, uGbtx);
+          BuildChannelsUidMapBuc(uCh, crob);
           /// Map also 4 and 9 (equivalent to fallthrough to 4 then 9 but without changing past behaviors)
           uCh -= 80;  // PAL, 2022/03/17: ?!?
-          BuildChannelsUidMapStar2(uCh, uGbtx);
+          BuildChannelsUidMapStar2(uCh, crob);
           uCh -= 80;  // PAL, 2022/03/17: ?!?
           break;
         }
@@ -179,11 +179,11 @@ namespace cbm::algo::tof
           break;
         }
         default: {
-          L_(error) << "Invalid Tof Type specifier for GBTx " << std::setw(2) << uGbtx << ": " << rpcType[uGbtx];
+          L_(error) << "Invalid Tof Type specifier for GBTx " << std::setw(2) << uGbtx << ": " << crob.rpcType;
         }
-      }  // switch (rpcType[uGbtx])
-      if ((int32_t)(uCh - uCh0) != numFebsPerComp * numAsicsPerFeb * numChanPerAsic / 2) {
-        throw FatalError("Tof mapping error for Gbtx {},  diff = {}, type {}", uGbtx, uCh - uCh0, rpcType[uGbtx]);
+      }  // switch (crob.rpcType)
+      if (int32_t(uCh - uCh0) != pars.nFebsPerComponent * pars.nAsicsPerFeb * pars.nChannelsPerAsic / 2) {
+        throw FatalError("Tof mapping error for Gbtx {},  diff = {}, type {}", uGbtx, uCh - uCh0, crob.rpcType);
       }
     }  // for (UInt_t uGbtx = 0; uGbtx < numCrob; ++uGbtx)
   }
@@ -191,13 +191,11 @@ namespace cbm::algo::tof
 
 
   // -------------------------------------------------------------------------
-  void ReadoutConfig::BuildChannelsUidMapCbm(uint32_t& uCh, uint32_t uGbtx)
+  void ReadoutConfig::BuildChannelsUidMapCbm(uint32_t& uCh, const config::CROB& crob)
   {
-    L_(debug) << " Map mTof box " << moduleId[uGbtx] << " at GBTX " << uGbtx << " -  uCh = " << uCh;
-    if (rpcSide[uGbtx] < 2) {  // mTof modules
-      L_(debug) << " Map mTof box " << moduleId[uGbtx] << " at GBTX  -  uCh = " << uCh;
+    if (crob.rpcSide < 2) {  // mTof modules
       const int32_t RpcMap[5] = {4, 2, 0, 3, 1};
-      for (int32_t iRpc = 0; iRpc < numRpc[uGbtx]; iRpc++) {
+      for (int32_t iRpc = 0; iRpc < crob.nRPC; iRpc++) {
         int32_t iStrMax  = 32;
         uint32_t uChNext = 1;
 
@@ -205,27 +203,27 @@ namespace cbm::algo::tof
           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]);
+          if (crob.rpcSide == 0) iStrMap = 31 - iStr;
+          if (crob.moduleId > -1)
+            fviRpcChUId.at(uCh) =
+              CbmTofAddress::GetUniqueAddress(crob.moduleId, iRpcMap, iStrMap, crob.rpcSide, crob.rpcType);
           else
-            fviRpcChUId[uCh] = 0;
+            fviRpcChUId.at(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)
+      }    // for (int32_t iRpc = 0; iRpc < crob.nRPC; iRpc++)
+    }      // if (crob.rpcSide < 2)
   }
 
 
   // -------------------------------------------------------------------------
-  void ReadoutConfig::BuildChannelsUidMapStar(uint32_t& uCh, uint32_t uGbtx)
+  void ReadoutConfig::BuildChannelsUidMapStar(uint32_t& uCh, const config::CROB& crob)
   {
-    if (rpcSide[uGbtx] < 2) {
+    if (crob.rpcSide < 2) {
       // mTof modules
-      L_(debug) << "Start eTOF module side " << rpcSide[uGbtx] << " at " << uCh;
+      L_(debug) << "Start eTOF module side " << crob.rpcSide << " at " << uCh;
       const int32_t RpcMap[3] = {0, 1, 2};
-      for (int32_t iRpc = 0; iRpc < numRpc[uGbtx]; iRpc++) {
+      for (int32_t iRpc = 0; iRpc < crob.nRPC; iRpc++) {
         int32_t iStrMax = 32;
         int32_t uChNext = 1;
 
@@ -233,10 +231,10 @@ namespace cbm::algo::tof
           int32_t iStrMap = iStr;
           int32_t iRpcMap = RpcMap[iRpc];
 
-          if (rpcSide[uGbtx] == 0) iStrMap = 31 - iStr;
-          if (moduleId[uGbtx] > -1)
+          if (crob.rpcSide == 0) iStrMap = 31 - iStr;
+          if (crob.moduleId > -1)
             fviRpcChUId[uCh] =
-              CbmTofAddress::GetUniqueAddress(moduleId[uGbtx], iRpcMap, iStrMap, rpcSide[uGbtx], rpcType[uGbtx]);
+              CbmTofAddress::GetUniqueAddress(crob.moduleId, iRpcMap, iStrMap, crob.rpcSide, crob.rpcType);
           else
             fviRpcChUId[uCh] = 0;
           uCh += uChNext;
@@ -247,7 +245,7 @@ namespace cbm::algo::tof
   }
 
   // -------------------------------------------------------------------------
-  void ReadoutConfig::BuildChannelsUidMapCern(uint32_t& uCh, uint32_t)
+  void ReadoutConfig::BuildChannelsUidMapCern(uint32_t& uCh, const config::CROB&)
   {
     L_(debug) << " Map CERN 20 gap  at GBTX  -  uCh = " << uCh;
     // clang-format off
@@ -273,7 +271,7 @@ namespace cbm::algo::tof
   }
 
   // -------------------------------------------------------------------------
-  void ReadoutConfig::BuildChannelsUidMapCera(uint32_t& uCh, uint32_t)
+  void ReadoutConfig::BuildChannelsUidMapCera(uint32_t& uCh, const config::CROB&)
   {
     int32_t iModuleId   = 0;
     int32_t iModuleType = 8;
@@ -287,9 +285,8 @@ namespace cbm::algo::tof
 
 
   // -------------------------------------------------------------------------
-  void ReadoutConfig::BuildChannelsUidMapStar2(uint32_t& uCh, uint32_t uGbtx)
+  void ReadoutConfig::BuildChannelsUidMapStar2(uint32_t& uCh, const config::CROB& crob)
   {
-    L_(debug) << " 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++) {
@@ -298,7 +295,7 @@ namespace cbm::algo::tof
         int32_t iRpcMap  = iRpc[iFeet];
         int32_t iSideMap = iSide[iFeet];
         if (iSideMap == 0) iStrMap = 31 - iStr;
-        switch (rpcSide[uGbtx]) {
+        switch (crob.rpcSide) {
           case 0:; break;
           case 1:;
             iRpcMap = 1 - iRpcMap;  // swap counters
@@ -334,8 +331,7 @@ namespace cbm::algo::tof
             break;
         }
         if (iSideMap > -1)
-          fviRpcChUId[uCh] =
-            CbmTofAddress::GetUniqueAddress(moduleId[uGbtx], iRpcMap, iStrMap, iSideMap, rpcType[uGbtx]);
+          fviRpcChUId[uCh] = CbmTofAddress::GetUniqueAddress(crob.moduleId, iRpcMap, iStrMap, iSideMap, crob.rpcType);
         else
           fviRpcChUId[uCh] = 0;
         uCh++;
@@ -345,11 +341,9 @@ namespace cbm::algo::tof
 
 
   // -------------------------------------------------------------------------
-  void ReadoutConfig::BuildChannelsUidMapBuc(uint32_t& uCh, uint32_t uGbtx)
+  void ReadoutConfig::BuildChannelsUidMapBuc(uint32_t& uCh, const config::CROB& crob)
   {
-    L_(debug) << " Map Buc box " << moduleId[uGbtx] << " at GBTX " << uGbtx << " -  uCh = " << uCh;
-
-    int32_t iModuleIdMap   = moduleId[uGbtx];
+    int32_t iModuleIdMap   = crob.moduleId;
     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++) {
@@ -357,7 +351,7 @@ namespace cbm::algo::tof
         int32_t iStrMap  = iStr;
         int32_t iRpcMap  = iRpc[iFeet];
         int32_t iSideMap = iSide[iFeet];
-        switch (rpcSide[uGbtx]) {
+        switch (crob.rpcSide) {
           case 0:; break;
           case 1:  // HD cosmic 2019, Buc2018, v18n
             iStrMap = 31 - iStr;
@@ -380,7 +374,7 @@ namespace cbm::algo::tof
             break;
           case 6:  //BUC special
           {
-            switch (moduleId[uGbtx]) {
+            switch (crob.moduleId) {
               case 0: iRpcMap = 0; break;
               case 1: iRpcMap = 1; break;
             }
@@ -450,12 +444,12 @@ namespace cbm::algo::tof
                 break;
               case 4: iSideMap = -1; break;
             }
-            iModuleIdMap = moduleId[uGbtx];
+            iModuleIdMap = crob.moduleId;
           } break;
           default:;
-        }  // switch (rpcSide[uGbtx])
+        }  // switch (crob.rpcSide)
         if (iSideMap > -1)
-          fviRpcChUId[uCh] = CbmTofAddress::GetUniqueAddress(iModuleIdMap, iRpcMap, iStrMap, iSideMap, rpcType[uGbtx]);
+          fviRpcChUId[uCh] = CbmTofAddress::GetUniqueAddress(iModuleIdMap, iRpcMap, iStrMap, iSideMap, crob.rpcType);
         else
           fviRpcChUId[uCh] = 0;
 
diff --git a/algo/detectors/tof/ReadoutConfig.h b/algo/detectors/tof/ReadoutConfig.h
index 48f2575c6a..0959c48b26 100644
--- a/algo/detectors/tof/ReadoutConfig.h
+++ b/algo/detectors/tof/ReadoutConfig.h
@@ -10,16 +10,23 @@
 #include <map>
 #include <vector>
 
+namespace cbm::algo::tof::config
+{
+  struct CROB;
+  struct ReadoutPars;
+}  // namespace cbm::algo::tof::config
+
 namespace cbm::algo::tof
 {
+
   class ReadoutConfig {
 
    public:
     /** @brief Constructor **/
-    ReadoutConfig();
+    ReadoutConfig(const config::ReadoutPars& pars);
 
     /** @brief Destructor **/
-    virtual ~ReadoutConfig();
+    ~ReadoutConfig();
 
     /** @brief Equipment in the configuration
      ** @return Vector of equipment IDs
@@ -45,58 +52,21 @@ namespace cbm::algo::tof
     std::map<uint16_t, std::vector<std::vector<uint32_t>>> fReadoutMap = {};
 
     /** @brief Initialisation of readout map **/
-    void Init();
+    void Init(const config::ReadoutPars& pars);
 
     /// 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
+    int32_t ElinkIdxToGet4Idx(uint32_t elink, const config::ReadoutPars& pars);
+    int32_t Get4ChanToPadiChan(uint32_t channelInFee, const config::ReadoutPars& pars);
 
     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);
+    void BuildChannelsUidMap(const config::ReadoutPars& pars);
+    void BuildChannelsUidMapCbm(uint32_t& uCh, const config::CROB& crob);
+    void BuildChannelsUidMapStar(uint32_t& uCh, const config::CROB& crob);
+    void BuildChannelsUidMapCern(uint32_t& uCh, const config::CROB& crob);
+    void BuildChannelsUidMapCera(uint32_t& uCh, const config::CROB& crob);
+    void BuildChannelsUidMapStar2(uint32_t& uCh, const config::CROB& crob);
+    void BuildChannelsUidMapBuc(uint32_t& uCh, const config::CROB& crob);
   };
 
 }  // namespace cbm::algo::tof
diff --git a/algo/detectors/tof/config/ReadoutPars.h b/algo/detectors/tof/config/ReadoutPars.h
new file mode 100644
index 0000000000..bac8282523
--- /dev/null
+++ b/algo/detectors/tof/config/ReadoutPars.h
@@ -0,0 +1,52 @@
+/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Felix Weiglhofer [committer], Dominik Smith */
+#pragma once
+
+#include "Definitions.h"
+
+#include <vector>
+
+namespace cbm::algo::tof::config
+{
+
+  struct CROB {
+    i32 moduleId;
+    i32 rpcType;
+    i32 rpcSide;
+    i32 nRPC;
+  };
+
+  struct ReadoutPars {
+
+    static ReadoutPars MakeMCBM2022();
+
+    i32 nFebsPerComponent;
+    i32 nAsicsPerFeb;
+    i32 nChannelsPerAsic;
+    i32 nCrobPerComponent;
+
+    std::vector<CROB> crobs;
+    size_t NCROBs() const { return crobs.size(); }
+
+    // Array to hold the unique IDs (equipment ID) for all TOF DPBs
+    std::vector<u16> eqIds;
+    size_t NComponents() const { return eqIds.size(); }
+
+
+    // Mapping to eLink to ASIC number within CROB. Mapping is the same for each CROB. (size: nElinksPerCrob)
+    std::vector<i32> elink2Asic;
+
+    // Mapping in Readout chain PCBs
+    // Map from GET4 channel to PADI channel
+    // (size: nChansPerFeb)
+    std::vector<i32> asic2PadI;
+
+    i32 NFebsPerCrob() const { return nFebsPerComponent / nCrobPerComponent; }
+    i32 NChansPerFeb() const { return nAsicsPerFeb * nChannelsPerAsic; }
+    i32 NChansPerComponent() const { return nChannelsPerAsic * NElinksPerComponent(); }
+    i32 NElinksPerCrob() const { return nAsicsPerFeb * NFebsPerCrob(); }
+    i32 NElinksPerComponent() const { return NElinksPerCrob() * nCrobPerComponent; }
+  };
+
+}  // namespace cbm::algo::tof::config
diff --git a/algo/detectors/tof/config/ReadoutPars_mCBM2022.cxx b/algo/detectors/tof/config/ReadoutPars_mCBM2022.cxx
new file mode 100644
index 0000000000..34713a4207
--- /dev/null
+++ b/algo/detectors/tof/config/ReadoutPars_mCBM2022.cxx
@@ -0,0 +1,51 @@
+/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Felix Weiglhofer [committer], Dominik Smith */
+#include "ReadoutPars.h"
+
+using namespace cbm::algo::tof::config;
+
+ReadoutPars ReadoutPars::MakeMCBM2022()
+{
+  // This here refers to the mCBM 2022 setup.
+  // Taken from CbmMcbm2018TofPar in combination with macro/beamtime/mcbm2022/mTofCriParNickel.par
+  // and mTofCriParNickel_withBmon.par (?)
+
+  ReadoutPars pars;
+
+  pars.nFebsPerComponent = 10;
+  pars.nAsicsPerFeb      = 8;
+  pars.nChannelsPerAsic  = 4;
+  pars.nCrobPerComponent = 2;
+
+  constexpr int NumCrob = 16;
+
+  // 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};
+
+  for (int i = 0; i < NumCrob; ++i) {
+    pars.crobs.push_back({moduleId[i], rpcType[i], rpcSide[i], numRpc[i]});
+  }
+
+  pars.eqIds = {0xabc0, 0xabc1, 0xabc2, 0xabc3, 0xabc4, 0xabc5, 0xabc6, 0xabc7};
+
+  pars.elink2Asic = {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
+  pars.asic2PadI = {
+    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
+
+
+  return pars;
+}
diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx
index 5da292f47d..d61d7f7553 100644
--- a/algo/global/Reco.cxx
+++ b/algo/global/Reco.cxx
@@ -22,6 +22,7 @@
 #include "tof/CalibratorChain.h"
 #include "tof/HitfinderChain.h"
 #include "tof/Unpack.h"
+#include "tof/config/ReadoutPars.h"
 #include "trd/Unpack.h"
 #include "trd2d/Unpack.h"
 #include "util/TimingsFormat.h"
@@ -124,7 +125,7 @@ void Reco::Init(const Options& opts)
   }
 
   if (Opts().Has(Subsystem::TOF) && Opts().Has(Step::Unpack)) {
-    tof::ReadoutConfig cfg{};
+    tof::ReadoutConfig cfg{tof::config::ReadoutPars::MakeMCBM2022()};
     fTofUnpack = std::make_unique<tof::Unpack>(cfg);
   }
 
diff --git a/reco/tasks/CbmTaskUnpack.cxx b/reco/tasks/CbmTaskUnpack.cxx
index 5cae447460..f0caef8188 100644
--- a/reco/tasks/CbmTaskUnpack.cxx
+++ b/reco/tasks/CbmTaskUnpack.cxx
@@ -19,6 +19,7 @@
 #include "CbmTrdParSpadic.h"
 #include "MicrosliceDescriptor.hpp"
 #include "System.hpp"
+#include "tof/config/ReadoutPars.h"
 #include "yaml/Yaml.h"
 
 #include <FairParAsciiFileIo.h>
@@ -171,7 +172,8 @@ InitStatus CbmTaskUnpack::Init()
   auto stsReadout = sts::ReadoutConfig::MakeMCBM2022();
   auto stsWalkMap = sts::WalkMap::MakeMCBM2022();
   fStsUnpack      = std::make_unique<sts::Unpack>(sts::Unpack::Config{stsReadout, stsWalkMap});
-  fTofUnpack      = std::make_unique<tof::Unpack>(tof::ReadoutConfig{});
+  auto tofReadoutPars = tof::config::ReadoutPars::MakeMCBM2022();
+  fTofUnpack          = std::make_unique<tof::Unpack>(tof::ReadoutConfig{tofReadoutPars});
   fTrdUnpack      = std::make_unique<trd::Unpack>(InitTrdReadoutConfig());
   fTrd2dUnpack    = std::make_unique<trd2d::Unpack>(InitTrd2dReadoutConfig());
 
-- 
GitLab