From 37a02b42f53a2e11e800a77f179e39ae1eebf6ea Mon Sep 17 00:00:00 2001
From: Felix Weiglhofer <weiglhofer@fias.uni-frankfurt.de>
Date: Wed, 20 Mar 2024 10:11:47 +0000
Subject: [PATCH] algo: Instantiate unpack algos for equipment id and system
 version.

---
 algo/detectors/bmon/Unpack.cxx    | 15 ++++----
 algo/detectors/bmon/Unpack.h      |  2 +-
 algo/detectors/bmon/UnpackMS.cxx  |  9 +++--
 algo/detectors/bmon/UnpackMS.h    | 17 ++++----
 algo/detectors/much/Unpack.cxx    | 16 ++++----
 algo/detectors/much/Unpack.h      |  2 +-
 algo/detectors/much/UnpackMS.cxx  |  9 +++--
 algo/detectors/much/UnpackMS.h    | 21 ++++------
 algo/detectors/rich/Unpack.cxx    | 18 ++++-----
 algo/detectors/rich/Unpack.h      |  2 +-
 algo/detectors/rich/UnpackMS.cxx  |  7 +++-
 algo/detectors/rich/UnpackMS.h    | 17 ++++----
 algo/detectors/sts/Unpack.cxx     | 15 ++++----
 algo/detectors/sts/Unpack.h       |  2 +-
 algo/detectors/sts/UnpackMS.cxx   |  3 ++
 algo/detectors/sts/UnpackMS.h     | 12 +++---
 algo/detectors/tof/Unpack.cxx     | 14 +++----
 algo/detectors/tof/Unpack.h       |  2 +-
 algo/detectors/tof/UnpackMS.cxx   |  9 +++--
 algo/detectors/tof/UnpackMS.h     | 13 +++----
 algo/detectors/trd/Unpack.cxx     | 16 ++++----
 algo/detectors/trd/Unpack.h       |  2 +-
 algo/detectors/trd/UnpackMS.cxx   |  9 +++--
 algo/detectors/trd/UnpackMS.h     | 16 ++++----
 algo/detectors/trd2d/Unpack.cxx   | 21 +++++-----
 algo/detectors/trd2d/Unpack.h     |  2 +-
 algo/detectors/trd2d/UnpackMS.cxx |  9 +++--
 algo/detectors/trd2d/UnpackMS.h   | 16 ++++----
 algo/unpack/CommonUnpacker.cxx    | 15 +-------
 algo/unpack/CommonUnpacker.h      | 64 +++++++++++++++++++++++++------
 algo/unpack/UnpackMSBase.h        | 32 ++++++++++++++++
 31 files changed, 232 insertions(+), 175 deletions(-)
 create mode 100644 algo/unpack/UnpackMSBase.h

diff --git a/algo/detectors/bmon/Unpack.cxx b/algo/detectors/bmon/Unpack.cxx
index ed0313d552..dc1bccb95f 100644
--- a/algo/detectors/bmon/Unpack.cxx
+++ b/algo/detectors/bmon/Unpack.cxx
@@ -12,26 +12,25 @@ using fles::Subsystem;
 Unpack::Unpack(const ReadoutConfig& readout) : fReadout(readout)
 {
   constexpr i64 SystemTimeOffset = 0;
+  constexpr u8 SystemVersion     = 0x00;
 
   // Create one algorithm per component for Bmon and configure it with parameters
   auto equipIdsBmon = fReadout.GetEquipmentIds();
   for (auto& equip : equipIdsBmon) {
-    std::unique_ptr<bmon::UnpackPar> par(new bmon::UnpackPar());
+    bmon::UnpackPar par{};
     const size_t numElinks = fReadout.GetNumElinks(equip);
     for (size_t elink = 0; elink < numElinks; elink++) {
       bmon::UnpackElinkPar elinkPar;
       elinkPar.fChannelUId = fReadout.Map(equip, elink);  // Vector of Bmon addresses for this elink
       elinkPar.fTimeOffset = SystemTimeOffset;
-      par->fElinkParams.push_back(elinkPar);
+      par.fElinkParams.push_back(elinkPar);
     }
-    fAlgos[equip].SetParams(std::move(par));
+    auto algo                      = std::make_unique<UnpackMS>(par);
+    fAlgos[{equip, SystemVersion}] = std::move(algo);
+
     L_(debug) << "--- Configured equipment " << equip << " with " << numElinks << " elinks";
   }
   L_(info) << "--- Configured " << fAlgos.size() << " unpacker algorithms for Bmon.";
 }
 
-Unpack::Result_t Unpack::operator()(const fles::Timeslice& ts) const
-{
-  constexpr int SystemVersion = 0x00;
-  return DoUnpack(Subsystem::BMON, ts, SystemVersion);
-}
+Unpack::Result_t Unpack::operator()(const fles::Timeslice& ts) const { return DoUnpack(Subsystem::BMON, ts); }
diff --git a/algo/detectors/bmon/Unpack.h b/algo/detectors/bmon/Unpack.h
index aca19761f6..9535c560ec 100644
--- a/algo/detectors/bmon/Unpack.h
+++ b/algo/detectors/bmon/Unpack.h
@@ -13,7 +13,7 @@ namespace cbm::algo::bmon
 
   namespace detail
   {
-    using UnpackBase = CommonUnpacker<CbmBmonDigi, UnpackMS, UnpackMonitorData>;
+    using UnpackBase = CommonUnpacker<CbmBmonDigi, UnpackMonitorData>;
   }
 
   class Unpack : public detail::UnpackBase {
diff --git a/algo/detectors/bmon/UnpackMS.cxx b/algo/detectors/bmon/UnpackMS.cxx
index 8820428512..da858f1519 100644
--- a/algo/detectors/bmon/UnpackMS.cxx
+++ b/algo/detectors/bmon/UnpackMS.cxx
@@ -16,13 +16,16 @@ using std::vector;
 namespace cbm::algo::bmon
 {
 
+  UnpackMS::UnpackMS(const UnpackPar& pars) : fParams(pars) {}
+  UnpackMS::~UnpackMS() = default;
+
   // ----   Algorithm execution   ---------------------------------------------
-  UnpackMS::resultType UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
-                                            const uint64_t tTimeslice) const
+  UnpackMS::Result_t UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
+                                          const uint64_t tTimeslice) const
   {
 
     // --- Output data
-    resultType result = {};
+    Result_t result = {};
 
     // --- Number of messages in microslice
     auto msSize = msDescr.size;
diff --git a/algo/detectors/bmon/UnpackMS.h b/algo/detectors/bmon/UnpackMS.h
index 58dfc4c7a1..af37710afa 100644
--- a/algo/detectors/bmon/UnpackMS.h
+++ b/algo/detectors/bmon/UnpackMS.h
@@ -7,6 +7,7 @@
 #include "CriGet4Mess001.h"
 #include "MicrosliceDescriptor.hpp"
 #include "Timeslice.hpp"
+#include "UnpackMSBase.h"
 
 #include <cassert>
 #include <cstddef>
@@ -78,18 +79,14 @@ namespace cbm::algo::bmon
    ** @since 25 November 2021
    ** @brief Unpack algorithm for STS
    **/
-  class UnpackMS {
+  class UnpackMS : public UnpackMSBase<CbmBmonDigi, UnpackMonitorData> {
 
    public:
-    typedef std::pair<std::vector<CbmBmonDigi>, UnpackMonitorData> resultType;
-
-
-    /** @brief Default constructor **/
-    UnpackMS() = default;
-
+    /** @brief Construct from parameters **/
+    UnpackMS(const UnpackPar& pars);
 
     /** @brief Destructor **/
-    ~UnpackMS() = default;
+    ~UnpackMS() override;
 
 
     /** @brief Algorithm execution
@@ -98,8 +95,8 @@ namespace cbm::algo::bmon
      ** @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) const;
+    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
diff --git a/algo/detectors/much/Unpack.cxx b/algo/detectors/much/Unpack.cxx
index 0e8797e1d6..45f78ba06f 100644
--- a/algo/detectors/much/Unpack.cxx
+++ b/algo/detectors/much/Unpack.cxx
@@ -12,27 +12,25 @@ using fles::Subsystem;
 Unpack::Unpack(const ReadoutConfig& readout) : fReadout(readout)
 {
   constexpr i64 SystemTimeOffset = -980;
+  constexpr u8 SystemVersion     = 0x20;
 
-  // Create one algorithm per component for Bmon and configure it with parameters
+  // Create one algorithm per component for MUCH and configure it with parameters
   auto equipIdsMuch = fReadout.GetEquipmentIds();
   for (auto& equip : equipIdsMuch) {
-    std::unique_ptr<much::UnpackPar> par(new much::UnpackPar());
+    much::UnpackPar par{};
     const size_t numElinks = fReadout.GetNumElinks(equip);
     for (size_t elink = 0; elink < numElinks; elink++) {
       much::UnpackElinkPar elinkPar;
       elinkPar.fAddress    = fReadout.Map(equip, elink);  // Vector of MUCH addresses for this elink
       elinkPar.fTimeOffset = SystemTimeOffset;
       elinkPar.fChanMask   = fReadout.MaskMap(equip, elink);
-      par->fElinkParams.push_back(elinkPar);
+      par.fElinkParams.push_back(elinkPar);
     }
-    fAlgos[equip].SetParams(std::move(par));
+    auto algo                      = std::make_unique<UnpackMS>(par);
+    fAlgos[{equip, SystemVersion}] = std::move(algo);
     L_(debug) << "--- Configured equipment " << equip << " with " << numElinks << " elinks";
   }
   L_(info) << "--- Configured " << fAlgos.size() << " unpacker algorithms for MUCH.";
 }
 
-Unpack::Result_t Unpack::operator()(const fles::Timeslice& ts) const
-{
-  constexpr int SystemVersion = 0x20;
-  return DoUnpack(Subsystem::MUCH, ts, SystemVersion);
-}
+Unpack::Result_t Unpack::operator()(const fles::Timeslice& ts) const { return DoUnpack(Subsystem::MUCH, ts); }
diff --git a/algo/detectors/much/Unpack.h b/algo/detectors/much/Unpack.h
index 8721ea9b41..191d421f96 100644
--- a/algo/detectors/much/Unpack.h
+++ b/algo/detectors/much/Unpack.h
@@ -13,7 +13,7 @@ namespace cbm::algo::much
 
   namespace detail
   {
-    using UnpackBase = CommonUnpacker<CbmMuchDigi, UnpackMS, UnpackMonitorData>;
+    using UnpackBase = CommonUnpacker<CbmMuchDigi, UnpackMonitorData>;
   }
 
   class Unpack : public detail::UnpackBase {
diff --git a/algo/detectors/much/UnpackMS.cxx b/algo/detectors/much/UnpackMS.cxx
index f7e1cd3a31..1274de56bd 100644
--- a/algo/detectors/much/UnpackMS.cxx
+++ b/algo/detectors/much/UnpackMS.cxx
@@ -17,13 +17,16 @@ using std::vector;
 namespace cbm::algo::much
 {
 
+  UnpackMS::UnpackMS(const UnpackPar& pars) : fParams(pars) {}
+  UnpackMS::~UnpackMS() = default;
+
   // ----   Algorithm execution   ---------------------------------------------
-  UnpackMS::resultType UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
-                                            const uint64_t tTimeslice) const
+  UnpackMS::Result_t UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
+                                          const uint64_t tTimeslice) const
   {
 
     // --- Output data
-    resultType result = {};
+    Result_t result = {};
 
     TimeSpec time;
 
diff --git a/algo/detectors/much/UnpackMS.h b/algo/detectors/much/UnpackMS.h
index 8a3162514e..1f9e413f84 100644
--- a/algo/detectors/much/UnpackMS.h
+++ b/algo/detectors/much/UnpackMS.h
@@ -7,6 +7,7 @@
 #include "MicrosliceDescriptor.hpp"
 #include "StsXyterMessage.h"
 #include "Timeslice.hpp"
+#include "UnpackMSBase.h"
 
 #include <cassert>
 #include <cstddef>
@@ -74,17 +75,14 @@ namespace cbm::algo::much
    ** @since 25 November 2021
    ** @brief Unpack algorithm for STS
    **/
-  class UnpackMS {
+  class UnpackMS : public UnpackMSBase<CbmMuchDigi, UnpackMonitorData> {
 
    public:
-    typedef std::pair<std::vector<CbmMuchDigi>, UnpackMonitorData> resultType;
-
-
-    /** @brief Default constructor **/
-    UnpackMS() = default;
+    /** @brief Construct with parameters **/
+    UnpackMS(const UnpackPar& pars);
 
     /** @brief Destructor **/
-    ~UnpackMS() = default;
+    ~UnpackMS() override;
 
 
     /** @brief Algorithm execution
@@ -93,13 +91,8 @@ namespace cbm::algo::much
      ** @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) const;
-
-    /** @brief Set the parameter container
-     ** @param params Pointer to parameter container
-     **/
-    void SetParams(std::unique_ptr<UnpackPar> params) { fParams = *(std::move(params)); }
+    Result_t operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
+                        const uint64_t tTimeslice) const override;
 
    private:  // datatypes
     struct TimeSpec {
diff --git a/algo/detectors/rich/Unpack.cxx b/algo/detectors/rich/Unpack.cxx
index 04fc255666..efbb1e7ca5 100644
--- a/algo/detectors/rich/Unpack.cxx
+++ b/algo/detectors/rich/Unpack.cxx
@@ -12,25 +12,25 @@ using fles::Subsystem;
 Unpack::Unpack(const ReadoutConfig& readout) : fReadout(readout)
 {
   constexpr i64 SystemTimeOffset = 100;
+  constexpr u8 SystemVersion     = 0x03;
+
 
   // Create one algorithm per component for Bmon and configure it with parameters
   auto equipIdsRich = fReadout.GetEquipmentIds();
   for (auto& equip : equipIdsRich) {
-    std::unique_ptr<rich::UnpackPar> par(new rich::UnpackPar());
+    rich::UnpackPar par{};
     std::map<uint32_t, std::vector<double>> compMap = fReadout.Map(equip);
     for (auto const& val : compMap) {
       uint32_t address                       = val.first;
-      par->fElinkParams[address].fToTshift   = val.second;
-      par->fElinkParams[address].fTimeOffset = SystemTimeOffset;
+      par.fElinkParams[address].fToTshift    = val.second;
+      par.fElinkParams[address].fTimeOffset  = SystemTimeOffset;
     }
-    fAlgos[equip].SetParams(std::move(par));
+    auto algo                      = std::make_unique<UnpackMS>(par);
+    fAlgos[{equip, SystemVersion}] = std::move(algo);
+
     L_(info) << "--- Configured equipment " << equip << " with " << fReadout.GetNumElinks(equip) << " elinks";
   }
   L_(info) << "--- Configured " << fAlgos.size() << " unpacker algorithms for RICH.";
 }
 
-Unpack::Result_t Unpack::operator()(const fles::Timeslice& ts) const
-{
-  constexpr int SystemVersion = 0x03;
-  return DoUnpack(Subsystem::RICH, ts, SystemVersion);
-}
+Unpack::Result_t Unpack::operator()(const fles::Timeslice& ts) const { return DoUnpack(Subsystem::RICH, ts); }
diff --git a/algo/detectors/rich/Unpack.h b/algo/detectors/rich/Unpack.h
index dbb7bd6b90..ec21c5d847 100644
--- a/algo/detectors/rich/Unpack.h
+++ b/algo/detectors/rich/Unpack.h
@@ -13,7 +13,7 @@ namespace cbm::algo::rich
 
   namespace detail
   {
-    using UnpackBase = CommonUnpacker<CbmRichDigi, UnpackMS, UnpackMonitorData>;
+    using UnpackBase = CommonUnpacker<CbmRichDigi, UnpackMonitorData>;
   }
 
   class Unpack : public detail::UnpackBase {
diff --git a/algo/detectors/rich/UnpackMS.cxx b/algo/detectors/rich/UnpackMS.cxx
index b463e279c3..7460c6bfb9 100644
--- a/algo/detectors/rich/UnpackMS.cxx
+++ b/algo/detectors/rich/UnpackMS.cxx
@@ -10,9 +10,12 @@
 
 namespace cbm::algo::rich
 {
+  UnpackMS::UnpackMS(const UnpackPar& pars) : fParams(pars) {}
+  UnpackMS::~UnpackMS() = default;
+
   // ----   Algorithm execution   ---------------------------------------------
-  UnpackMS::resultType UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
-                                            const uint64_t tTimeslice) const
+  UnpackMS::Result_t UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
+                                          const uint64_t tTimeslice) const
   {
     MSContext ctx;
 
diff --git a/algo/detectors/rich/UnpackMS.h b/algo/detectors/rich/UnpackMS.h
index fc0897c880..f89b2f58cf 100644
--- a/algo/detectors/rich/UnpackMS.h
+++ b/algo/detectors/rich/UnpackMS.h
@@ -6,6 +6,7 @@
 #include "CbmRichDigi.h"
 #include "Definitions.h"
 #include "Timeslice.hpp"
+#include "UnpackMSBase.h"
 
 #include <cstddef>
 #include <cstdint>
@@ -96,17 +97,15 @@ namespace cbm::algo::rich
   };
 
 
-  class UnpackMS {
-   public:
-    typedef std::pair<std::vector<CbmRichDigi>, UnpackMonitorData> resultType;
-
+  class UnpackMS : public UnpackMSBase<CbmRichDigi, UnpackMonitorData> {
 
-    /** @brief Default constructor **/
-    UnpackMS() = default;
+   public:
+    /** @brief Construct from parameters **/
+    UnpackMS(const UnpackPar& pars);
 
 
     /** @brief Destructor **/
-    ~UnpackMS() = default;
+    ~UnpackMS() override;
 
 
     /** @brief Algorithm execution
@@ -115,8 +114,8 @@ namespace cbm::algo::rich
      ** @param  tTimeslice Unix start time of timeslice [ns]
      ** @return RICH digi data
      **/
-    resultType operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
-                          const uint64_t tTimeslice) const;
+    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
diff --git a/algo/detectors/sts/Unpack.cxx b/algo/detectors/sts/Unpack.cxx
index 34990d21af..7cf95a1fb3 100644
--- a/algo/detectors/sts/Unpack.cxx
+++ b/algo/detectors/sts/Unpack.cxx
@@ -15,12 +15,13 @@ Unpack::Unpack(const Config& config) : fConfig(config)
   uint32_t numAsicsPerModuleSts = 16;   // Number of ASICs per module for STS
 
   constexpr i64 SystemTimeOffset = -970;  // ns?
+  constexpr u8 SystemVersion     = 0x20;
 
   auto equipIdsSts = fConfig.readout.GetEquipmentIds();
   for (auto& equip : equipIdsSts) {
-    std::unique_ptr<sts::UnpackPar> par(new sts::UnpackPar());
-    par->fNumChansPerAsic   = numChansPerAsicSts;
-    par->fNumAsicsPerModule = numAsicsPerModuleSts;
+    sts::UnpackPar par{};
+    par.fNumChansPerAsic    = numChansPerAsicSts;
+    par.fNumAsicsPerModule  = numAsicsPerModuleSts;
     const size_t numElinks  = fConfig.readout.GetNumElinks(equip);
     for (size_t elink = 0; elink < numElinks; elink++) {
       sts::UnpackElinkPar elinkPar;
@@ -34,9 +35,10 @@ Unpack::Unpack(const Config& config) : fConfig(config)
       elinkPar.fWalk       = fConfig.walkMap.Get(elinkPar.fAddress, elinkPar.fAsicNr);
       elinkPar.fChanMask   = fConfig.readout.MaskMap(equip, elink);
       // TODO: Add parameters for time and ADC calibration
-      par->fElinkParams.push_back(elinkPar);
+      par.fElinkParams.push_back(elinkPar);
     }
-    fAlgos[equip].SetParams(std::move(par));
+    auto algo                      = std::make_unique<UnpackMS>(par);
+    fAlgos[{equip, SystemVersion}] = std::move(algo);
     L_(debug) << "--- Configured equipment " << equip << " with " << numElinks << " elinks";
   }  //# equipments
 
@@ -45,9 +47,8 @@ Unpack::Unpack(const Config& config) : fConfig(config)
 
 Unpack::Result_t Unpack::operator()(const fles::Timeslice& ts) const
 {
-  constexpr int SystemVersion = 0x20;
 
-  auto result = DoUnpack(Subsystem::STS, ts, SystemVersion);
+  auto result = DoUnpack(Subsystem::STS, ts);
   // PrintDigisPerModule(result.first);
   return result;
 }
diff --git a/algo/detectors/sts/Unpack.h b/algo/detectors/sts/Unpack.h
index 0670fd8697..8391e86dc6 100644
--- a/algo/detectors/sts/Unpack.h
+++ b/algo/detectors/sts/Unpack.h
@@ -14,7 +14,7 @@ namespace cbm::algo::sts
 
   namespace detail
   {
-    using UnpackBase = CommonUnpacker<CbmStsDigi, UnpackMS, UnpackMonitorData>;
+    using UnpackBase = CommonUnpacker<CbmStsDigi, UnpackMonitorData>;
   }
 
   class Unpack : public detail::UnpackBase {
diff --git a/algo/detectors/sts/UnpackMS.cxx b/algo/detectors/sts/UnpackMS.cxx
index 250981bdf9..e4caf5b730 100644
--- a/algo/detectors/sts/UnpackMS.cxx
+++ b/algo/detectors/sts/UnpackMS.cxx
@@ -18,6 +18,9 @@ using std::vector;
 namespace cbm::algo::sts
 {
 
+  UnpackMS::UnpackMS(const UnpackPar& pars) : fParams(pars) {}
+  UnpackMS::~UnpackMS() = default;
+
   // ----   Algorithm execution   ---------------------------------------------
   UnpackMS::Result_t UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
                                           const uint64_t tTimeslice) const
diff --git a/algo/detectors/sts/UnpackMS.h b/algo/detectors/sts/UnpackMS.h
index 6ae726b879..33cb29bc0d 100644
--- a/algo/detectors/sts/UnpackMS.h
+++ b/algo/detectors/sts/UnpackMS.h
@@ -7,6 +7,7 @@
 #include "Definitions.h"
 #include "MicrosliceDescriptor.hpp"
 #include "StsXyterMessage.h"
+#include "UnpackMSBase.h"
 
 #include <cassert>
 #include <cstddef>
@@ -78,18 +79,15 @@ namespace cbm::algo::sts
    ** @since 25 November 2021
    ** @brief Unpack algorithm for STS
    **/
-  class UnpackMS {
+  class UnpackMS : public UnpackMSBase<CbmStsDigi, UnpackMonitorData> {
 
    public:
-    using Result_t = std::pair<std::vector<CbmStsDigi>, UnpackMonitorData>;
-
-
     /** @brief Default constructor **/
-    UnpackMS() = default;
+    UnpackMS(const UnpackPar& pars);
 
 
     /** @brief Destructor **/
-    ~UnpackMS() = default;
+    ~UnpackMS() override;
 
 
     /** @brief Algorithm execution
@@ -99,7 +97,7 @@ namespace cbm::algo::sts
      ** @return STS digi data
      **/
     Result_t operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
-                        const uint64_t tTimeslice) const;
+                        const uint64_t tTimeslice) const override;
 
     /** @brief Set the parameter container
      ** @param params Pointer to parameter container
diff --git a/algo/detectors/tof/Unpack.cxx b/algo/detectors/tof/Unpack.cxx
index 7764470e22..7d566cfeb2 100644
--- a/algo/detectors/tof/Unpack.cxx
+++ b/algo/detectors/tof/Unpack.cxx
@@ -12,26 +12,24 @@ using fles::Subsystem;
 Unpack::Unpack(const ReadoutConfig& readout) : fReadout(readout)
 {
   constexpr i64 SystemTimeOffset = 40;
+  constexpr u8 SystemVersion     = 0x00;
 
   auto equipIdsTof = fReadout.GetEquipmentIds();
   for (auto& equip : equipIdsTof) {
-    std::unique_ptr<tof::UnpackPar> par(new tof::UnpackPar());
+    tof::UnpackPar par{};
     const size_t numElinks = fReadout.GetNumElinks(equip);
     for (size_t elink = 0; elink < numElinks; elink++) {
       tof::UnpackElinkPar elinkPar;
       elinkPar.fChannelUId = fReadout.Map(equip, elink);  // Vector of TOF addresses for this elink
       elinkPar.fTimeOffset = SystemTimeOffset;
-      par->fElinkParams.push_back(elinkPar);
+      par.fElinkParams.push_back(elinkPar);
     }
-    fAlgos[equip].SetParams(std::move(par));
+    auto algo                      = std::make_unique<UnpackMS>(std::move(par));
+    fAlgos[{equip, SystemVersion}] = std::move(algo);
     L_(debug) << "--- Configured equipment " << equip << " with " << numElinks << " elinks";
   }
 
   L_(info) << "--- Configured " << fAlgos.size() << " unpacker algorithms for TOF.";
 }
 
-Unpack::Result_t Unpack::operator()(const fles::Timeslice& ts) const
-{
-  constexpr int SystemVersion = 0x00;
-  return DoUnpack(Subsystem::TOF, ts, SystemVersion);
-}
+Unpack::Result_t Unpack::operator()(const fles::Timeslice& ts) const { return DoUnpack(Subsystem::TOF, ts); }
diff --git a/algo/detectors/tof/Unpack.h b/algo/detectors/tof/Unpack.h
index d11e669f03..3b49776c29 100644
--- a/algo/detectors/tof/Unpack.h
+++ b/algo/detectors/tof/Unpack.h
@@ -12,7 +12,7 @@ namespace cbm::algo::tof
 
   namespace detail
   {
-    using UnpackBase = CommonUnpacker<CbmTofDigi, UnpackMS, UnpackMonitorData>;
+    using UnpackBase = CommonUnpacker<CbmTofDigi, UnpackMonitorData>;
   }
 
   class Unpack : public detail::UnpackBase {
diff --git a/algo/detectors/tof/UnpackMS.cxx b/algo/detectors/tof/UnpackMS.cxx
index bf011c43fe..4294e61c65 100644
--- a/algo/detectors/tof/UnpackMS.cxx
+++ b/algo/detectors/tof/UnpackMS.cxx
@@ -15,13 +15,16 @@ using std::vector;
 namespace cbm::algo::tof
 {
 
+  UnpackMS::UnpackMS(const UnpackPar& pars) : fParams(pars) {}
+  UnpackMS::~UnpackMS() = default;
+
   // ----   Algorithm execution   ---------------------------------------------
-  UnpackMS::resultType UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
-                                            const uint64_t tTimeslice) const
+  UnpackMS::Result_t UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
+                                          const uint64_t tTimeslice) const
   {
 
     // --- Output data
-    resultType result = {};
+    Result_t result   = {};
     TimeSpec time     = {};
 
     // --- Current Timeslice start time in epoch units. Note that it is always a multiple of epochs
diff --git a/algo/detectors/tof/UnpackMS.h b/algo/detectors/tof/UnpackMS.h
index 4fb1295ce7..c919418c59 100644
--- a/algo/detectors/tof/UnpackMS.h
+++ b/algo/detectors/tof/UnpackMS.h
@@ -8,6 +8,7 @@
 #include "Definitions.h"
 #include "MicrosliceDescriptor.hpp"
 #include "Timeslice.hpp"
+#include "UnpackMSBase.h"
 
 #include <cassert>
 #include <cstddef>
@@ -74,16 +75,14 @@ namespace cbm::algo::tof
    ** @since 25 November 2021
    ** @brief Unpack algorithm for STS
    **/
-  class UnpackMS {
+  class UnpackMS : public UnpackMSBase<CbmTofDigi, UnpackMonitorData> {
 
    public:
-    typedef std::pair<std::vector<CbmTofDigi>, UnpackMonitorData> resultType;
-
     /** @brief Default constructor **/
-    UnpackMS() = default;
+    UnpackMS(const UnpackPar& pars);
 
     /** @brief Destructor **/
-    ~UnpackMS() = default;
+    ~UnpackMS() override;
 
     /** @brief Algorithm execution
      ** @param  msContent  Microslice payload
@@ -91,8 +90,8 @@ namespace cbm::algo::tof
      ** @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) const;
+    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
diff --git a/algo/detectors/trd/Unpack.cxx b/algo/detectors/trd/Unpack.cxx
index 9beddb8e7c..88b2f9c358 100644
--- a/algo/detectors/trd/Unpack.cxx
+++ b/algo/detectors/trd/Unpack.cxx
@@ -12,12 +12,12 @@ using fles::Subsystem;
 Unpack::Unpack(const ReadoutConfig& readout) : fReadout(readout)
 {
   constexpr i64 SystemTimeOffset = 1300;
+  constexpr u8 SystemVersion     = 0x01;
 
   // Create one algorithm per component for TRD and configure it with parameters
   auto equipIdsTrd = fReadout.GetEquipmentIds();
   for (auto& equip : equipIdsTrd) {
-
-    std::unique_ptr<trd::UnpackPar> par(new trd::UnpackPar());
+    trd::UnpackPar par{};
     const size_t numCrobs = fReadout.GetNumCrobs(equip);
 
     for (size_t crob = 0; crob < numCrobs; crob++) {
@@ -32,16 +32,14 @@ Unpack::Unpack(const ReadoutConfig& readout) : fReadout(readout)
         elinkPar.fTimeOffset  = SystemTimeOffset;
         crobPar.fElinkParams.push_back(elinkPar);
       }
-      par->fCrobParams.push_back(crobPar);
+      par.fCrobParams.push_back(crobPar);
     }
-    fAlgos[equip].SetParams(std::move(par));
+    auto algo                      = std::make_unique<UnpackMS>(std::move(par));
+    fAlgos[{equip, SystemVersion}] = std::move(algo);
+
     L_(debug) << "--- Configured equipment " << equip << " with " << numCrobs << " crobs";
   }
   L_(info) << "--- Configured " << fAlgos.size() << " unpacker algorithms for TRD.";
 }
 
-Unpack::Result_t Unpack::operator()(const fles::Timeslice& ts) const
-{
-  constexpr int SystemVersion = 0x01;
-  return DoUnpack(Subsystem::TRD, ts, SystemVersion);
-}
+Unpack::Result_t Unpack::operator()(const fles::Timeslice& ts) const { return DoUnpack(Subsystem::TRD, ts); }
diff --git a/algo/detectors/trd/Unpack.h b/algo/detectors/trd/Unpack.h
index b35c26b230..0791cd2f9c 100644
--- a/algo/detectors/trd/Unpack.h
+++ b/algo/detectors/trd/Unpack.h
@@ -13,7 +13,7 @@ namespace cbm::algo::trd
 
   namespace detail
   {
-    using UnpackBase = CommonUnpacker<CbmTrdDigi, UnpackMS, UnpackMonitorData>;
+    using UnpackBase = CommonUnpacker<CbmTrdDigi, UnpackMonitorData>;
   }
 
   class Unpack : public detail::UnpackBase {
diff --git a/algo/detectors/trd/UnpackMS.cxx b/algo/detectors/trd/UnpackMS.cxx
index 01cdbdc102..0ba70becd7 100644
--- a/algo/detectors/trd/UnpackMS.cxx
+++ b/algo/detectors/trd/UnpackMS.cxx
@@ -14,12 +14,15 @@ using std::unique_ptr;
 namespace cbm::algo::trd
 {
 
+  UnpackMS::UnpackMS(const UnpackPar& pars) : fParams(pars) {}
+  UnpackMS::~UnpackMS() = default;
+
   // ----   Algorithm execution   ---------------------------------------------
-  UnpackMS::resultType UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
-                                            const uint64_t tTimeslice) const
+  UnpackMS::Result_t UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
+                                          const uint64_t tTimeslice) const
   {
     // --- Output data
-    resultType result = {};
+    Result_t result = {};
 
     MsContext ctx = {};
 
diff --git a/algo/detectors/trd/UnpackMS.h b/algo/detectors/trd/UnpackMS.h
index c5918369a6..63eaa5e12a 100644
--- a/algo/detectors/trd/UnpackMS.h
+++ b/algo/detectors/trd/UnpackMS.h
@@ -8,6 +8,7 @@
 #include "CbmTrdRawMessageSpadic.h"
 #include "MicrosliceDescriptor.hpp"
 #include "Timeslice.hpp"
+#include "UnpackMSBase.h"
 
 #include <cmath>
 #include <memory>
@@ -96,18 +97,15 @@ namespace cbm::algo::trd
    ** @since 31 January 2023
    ** @brief Unpack algorithm for TRD
    **/
-  class UnpackMS {
+  class UnpackMS : public UnpackMSBase<CbmTrdDigi, UnpackMonitorData> {
 
    public:
-    typedef std::pair<std::vector<CbmTrdDigi>, UnpackMonitorData> resultType;
-
-
-    /** @brief Default constructor **/
-    UnpackMS() = default;
+    /** @brief Construct from parameters **/
+    UnpackMS(const UnpackPar& pars);
 
 
     /** @brief Destructor **/
-    ~UnpackMS() = default;
+    ~UnpackMS() override;
 
 
     /** @brief Algorithm execution
@@ -116,8 +114,8 @@ namespace cbm::algo::trd
      ** @param  tTimeslice Unix start time of timeslice [ns]
      ** @return TRD digi data
      **/
-    resultType operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
-                          const uint64_t tTimeslice) const;
+    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
diff --git a/algo/detectors/trd2d/Unpack.cxx b/algo/detectors/trd2d/Unpack.cxx
index 16f82926fa..e12ef68aee 100644
--- a/algo/detectors/trd2d/Unpack.cxx
+++ b/algo/detectors/trd2d/Unpack.cxx
@@ -12,12 +12,13 @@ using fles::Subsystem;
 Unpack::Unpack(const ReadoutConfig& readout) : fReadout(readout)
 {
   constexpr i64 SystemTimeOffset = -510;
+  constexpr u8 SystemVersion     = 0x02;
 
   // Create one algorithm per component for TRD and configure it with parameters
   auto equipIdsTrd2d = fReadout.GetEquipmentIds();
   for (auto& equip : equipIdsTrd2d) {
 
-    std::unique_ptr<trd2d::UnpackPar> par(new trd2d::UnpackPar());
+    trd2d::UnpackPar par{};
     const size_t numAsics = fReadout.GetNumAsics(equip);
 
     for (size_t asic = 0; asic < numAsics; asic++) {
@@ -33,19 +34,17 @@ Unpack::Unpack(const ReadoutConfig& readout) : fReadout(readout)
         asicPar.fChanParams.push_back(chanPar);
       }
       auto comppars          = fReadout.CompMap(equip);
-      par->fSystemTimeOffset = SystemTimeOffset;
-      par->fModId            = comppars.moduleId;
-      par->fCrobId           = comppars.crobId;
-      par->fAsicParams.push_back(asicPar);
+      par.fSystemTimeOffset  = SystemTimeOffset;
+      par.fModId             = comppars.moduleId;
+      par.fCrobId            = comppars.crobId;
+      par.fAsicParams.push_back(asicPar);
     }
-    fAlgos[equip].SetParams(std::move(par));
+    auto algo                      = std::make_unique<UnpackMS>(par);
+    fAlgos[{equip, SystemVersion}] = std::move(algo);
+
     L_(debug) << "--- Configured equipment " << equip << " with " << numAsics << " asics";
   }
   L_(info) << "--- Configured " << fAlgos.size() << " unpacker algorithms for TRD2D.";
 }
 
-Unpack::Result_t Unpack::operator()(const fles::Timeslice& ts) const
-{
-  constexpr int SystemVersion = 0x02;
-  return DoUnpack(Subsystem::TRD2D, ts, SystemVersion);
-}
+Unpack::Result_t Unpack::operator()(const fles::Timeslice& ts) const { return DoUnpack(Subsystem::TRD2D, ts); }
diff --git a/algo/detectors/trd2d/Unpack.h b/algo/detectors/trd2d/Unpack.h
index eac2415c06..710a90093c 100644
--- a/algo/detectors/trd2d/Unpack.h
+++ b/algo/detectors/trd2d/Unpack.h
@@ -13,7 +13,7 @@ namespace cbm::algo::trd2d
 
   namespace detail
   {
-    using UnpackBase = CommonUnpacker<CbmTrdDigi, UnpackMS, UnpackMonitorData>;
+    using UnpackBase = CommonUnpacker<CbmTrdDigi, UnpackMonitorData>;
   }
 
   class Unpack : public detail::UnpackBase {
diff --git a/algo/detectors/trd2d/UnpackMS.cxx b/algo/detectors/trd2d/UnpackMS.cxx
index c0e447c6c4..4a51f76db1 100644
--- a/algo/detectors/trd2d/UnpackMS.cxx
+++ b/algo/detectors/trd2d/UnpackMS.cxx
@@ -25,12 +25,15 @@ namespace cbm::algo::trd2d
   {
   }
 
+  UnpackMS::UnpackMS(const UnpackPar& pars) : fParams(pars) {}
+  UnpackMS::~UnpackMS() = default;
+
   // ----   Algorithm execution   ---------------------------------------------
-  UnpackMS::resultType UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
-                                            const uint64_t tTimeslice) const
+  UnpackMS::Result_t UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
+                                          const uint64_t tTimeslice) const
   {
     // --- Output data
-    resultType result = {};
+    Result_t result = {};
 
     MsContext ctx = {};
 
diff --git a/algo/detectors/trd2d/UnpackMS.h b/algo/detectors/trd2d/UnpackMS.h
index 264b30ae44..6a280e1a39 100644
--- a/algo/detectors/trd2d/UnpackMS.h
+++ b/algo/detectors/trd2d/UnpackMS.h
@@ -6,6 +6,7 @@
 #include "CbmTrdDigi.h"
 #include "CbmTrdRawMessageSpadic.h"
 #include "MicrosliceDescriptor.hpp"
+#include "UnpackMSBase.h"
 
 #include <array>
 #include <memory>
@@ -102,18 +103,15 @@ namespace cbm::algo::trd2d
    ** @since 31 January 2023
    ** @brief Unpack algorithm for TRD
    **/
-  class UnpackMS {
+  class UnpackMS : public UnpackMSBase<CbmTrdDigi, UnpackMonitorData> {
 
    public:
-    typedef std::pair<std::vector<CbmTrdDigi>, UnpackMonitorData> resultType;
-
-
-    /** @brief Default constructor **/
-    UnpackMS() = default;
+    /** @brief Construct from parameters **/
+    UnpackMS(const UnpackPar& pars);
 
 
     /** @brief Destructor **/
-    ~UnpackMS() = default;
+    ~UnpackMS() override;
 
 
     /** @brief Algorithm execution
@@ -122,8 +120,8 @@ namespace cbm::algo::trd2d
      ** @param  tTimeslice Unix start time of timeslice [ns]
      ** @return TRD digi data
      **/
-    resultType operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
-                          const uint64_t tTimeslice) const;
+    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
diff --git a/algo/unpack/CommonUnpacker.cxx b/algo/unpack/CommonUnpacker.cxx
index a55564b131..6f0f871816 100644
--- a/algo/unpack/CommonUnpacker.cxx
+++ b/algo/unpack/CommonUnpacker.cxx
@@ -7,7 +7,7 @@
 
 using namespace cbm::algo;
 
-detail::MSData::MSData(const fles::Timeslice& ts, fles::Subsystem subsystem, gsl::span<u16> legalEqIds, u8 sys_ver)
+detail::MSData::MSData(const fles::Timeslice& ts, fles::Subsystem subsystem, gsl::span<u16> legalEqIds)
 {
   monitor.system = subsystem;
 
@@ -18,21 +18,9 @@ detail::MSData::MSData(const fles::Timeslice& ts, fles::Subsystem subsystem, gsl
       continue;
     }
 
-    if (this_subsystem == fles::Subsystem::STS) {
-      L_(debug) << "Found STS component, eq_id: " << ts.descriptor(comp, 0).eq_id
-                << ", sys_ver: " << int{ts.descriptor(comp, 0).sys_ver};
-    }
-
     const u64 numMsInComp = ts.num_microslices(comp);
     const u16 componentId = ts.descriptor(comp, 0).eq_id;
 
-    if (ts.descriptor(comp, 0).sys_ver != sys_ver) {
-      L_(error) << "Invalid system version " << int{ts.descriptor(comp, 0).sys_ver} << " for subsystem "
-                << ToString(subsystem);
-      monitor.errInvalidSysVer++;
-      continue;
-    }
-
     if (std::find(legalEqIds.begin(), legalEqIds.end(), componentId) == legalEqIds.end()) {
       L_(error) << "Invalid equipment id " << componentId << " for subsystem " << ToString(subsystem);
       monitor.errInvalidEqId++;
@@ -43,7 +31,6 @@ detail::MSData::MSData(const fles::Timeslice& ts, fles::Subsystem subsystem, gsl
     monitor.sizeBytesIn += ts.size_component(comp);
     monitor.numMs += numMsInComp;
     for (u64 mslice = 0; mslice < numMsInComp; mslice++) {
-      msEqIds.push_back(componentId);
       msDesc.push_back(ts.descriptor(comp, mslice));
       msContent.push_back(ts.content(comp, mslice));
     }
diff --git a/algo/unpack/CommonUnpacker.h b/algo/unpack/CommonUnpacker.h
index 35bf7fe552..a0fb3eb84b 100644
--- a/algo/unpack/CommonUnpacker.h
+++ b/algo/unpack/CommonUnpacker.h
@@ -6,11 +6,14 @@
 #include "Definitions.h"
 #include "PODVector.h"
 #include "Timeslice.hpp"
+#include "UnpackMSBase.h"
 #include "compat/Algorithm.h"
 #include "compat/OpenMP.h"
+#include "util/StlUtils.h"
 
 #include <cstdint>
 #include <gsl/span>
+#include <log.hpp>
 #include <map>
 #include <vector>
 
@@ -40,13 +43,12 @@ namespace cbm::algo
      * @note Helper struct for CommonUnpacker. Moved out of class body to avoid code duplication from different template specializations.
      */
     struct MSData {
-      std::vector<u16> msEqIds;                        // equipment ids of microslices
       std::vector<fles::MicrosliceDescriptor> msDesc;  // microslice descriptors
       std::vector<const u8*> msContent;                // pointer to microslice contents
 
       UnpackMonitorBase monitor;  // monitoring data
 
-      MSData(const fles::Timeslice& ts, fles::Subsystem system, gsl::span<u16> legalEqIds, u8 sys_ver);
+      MSData(const fles::Timeslice& ts, fles::Subsystem system, gsl::span<u16> legalEqIds);
       ~MSData() = default;
     };
 
@@ -57,21 +59,35 @@ namespace cbm::algo
     std::vector<MSMonitor> msMonitor;  // monitoring data per microslice
   };
 
-  template<class Digi, class UnpackAlgo, class MSMonitor>
+  struct UnpackKey {
+    u16 eqId;
+    u8 sysVer;
+
+    UnpackKey(u16 eqId_, u8 sysVer_) : eqId(eqId_), sysVer(sysVer_) {}
+    UnpackKey(const fles::MicrosliceDescriptor& msDesc) : eqId(msDesc.eq_id), sysVer(msDesc.sys_ver) {}
+
+    bool operator<(const UnpackKey& other) const
+    {
+      return eqId < other.eqId || (eqId == other.eqId && sysVer < other.sysVer);
+    }
+  };
+
+  template<class Digi, class MSMonitor>
   class CommonUnpacker {
 
    protected:
     using Monitor_t = UnpackMonitor<MSMonitor>;
     using Result_t  = std::pair<PODVector<Digi>, Monitor_t>;
+    using Unpack_t  = UnpackMSBase<Digi, MSMonitor>;
 
-    std::map<u16, UnpackAlgo> fAlgos;  //< Equipment id to unpacker map. Filled by child class!
+    std::map<UnpackKey, std::unique_ptr<Unpack_t>> fAlgos;  //< Equipment id to unpacker map. Filled by child class!
 
-    Result_t DoUnpack(const fles::Subsystem subsystem, const fles::Timeslice& ts, u8 sys_ver) const
+    Result_t DoUnpack(const fles::Subsystem subsystem, const fles::Timeslice& ts) const
     {
       xpu::scoped_timer t_(fles::to_string(subsystem));
       auto legalEqIds = GetEqIds();
 
-      detail::MSData msData{ts, subsystem, gsl::make_span(legalEqIds), sys_ver};
+      detail::MSData msData{ts, subsystem, gsl::make_span(legalEqIds)};
       const size_t numMs = msData.monitor.numMs;
 
       Result_t out;
@@ -89,7 +105,22 @@ namespace cbm::algo
       xpu::t_add_bytes(msData.monitor.sizeBytesIn);
       CBM_PARALLEL_FOR(schedule(dynamic))
       for (size_t i = 0; i < numMs; i++) {
-        auto result             = fAlgos.at(msData.msEqIds[i])(msData.msContent[i], msData.msDesc[i], ts.start_time());
+        auto& msDesc = msData.msDesc[i];
+        auto algo    = fAlgos.find(UnpackKey{msDesc});
+
+        if (algo == fAlgos.end()) {
+          if (!Contains(legalEqIds, msDesc.eq_id)) {
+            L_(error) << "Invalid equip id " << int{msDesc.eq_id} << " for subsystem " << ToString(subsystem);
+            monitorOut.errInvalidEqId++;
+          }
+          else {
+            L_(error) << "Invalid system version " << int{msDesc.sys_ver} << " for subsystem " << ToString(subsystem);
+            monitorOut.errInvalidSysVer++;
+          }
+          continue;
+        }
+
+        auto result             = (*algo->second)(msData.msContent[i], msData.msDesc[i], ts.start_time());
         msDigis[i]              = std::move(result.first);
         monitorOut.msMonitor[i] = std::move(result.second);
       }
@@ -126,14 +157,25 @@ namespace cbm::algo
       Sort(digis.begin(), digis.end(), [](const Digi& a, const Digi& b) { return a.GetTime() < b.GetTime(); });
     }
 
-    std::vector<uint16_t> GetEqIds() const
+    std::vector<u16> GetEqIds() const
     {
-      std::vector<uint16_t> eqIds;
+      std::vector<u16> eqIds;
       eqIds.reserve(fAlgos.size());
-      for (const auto& [eqId, algo] : fAlgos) {
-        eqIds.push_back(eqId);
+      for (const auto& [key, algo] : fAlgos) {
+        eqIds.push_back(key.eqId);
       }
       return eqIds;
     }
+
+    std::vector<u8> GetSysVers(u16 eqId) const
+    {
+      std::vector<u8> sysVers;
+      for (const auto& [key, algo] : fAlgos) {
+        if (key.eqId == eqId) {
+          sysVers.push_back(key.sysVer);
+        }
+      }
+      return sysVers;
+    }
   };
 }  // namespace cbm::algo
diff --git a/algo/unpack/UnpackMSBase.h b/algo/unpack/UnpackMSBase.h
new file mode 100644
index 0000000000..d345eb05ef
--- /dev/null
+++ b/algo/unpack/UnpackMSBase.h
@@ -0,0 +1,32 @@
+/* Copyright (C) 2024 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Felix Weiglhofer [committer] */
+#pragma once
+
+#include <utility>
+#include <vector>
+
+namespace fles
+{
+  class MicrosliceDescriptor;
+}
+
+namespace cbm::algo
+{
+
+  template<typename D, typename M>
+  class UnpackMSBase {
+
+   public:
+    using Digi_t    = D;
+    using Monitor_t = M;
+
+    using Result_t = std::pair<std::vector<Digi_t>, Monitor_t>;
+
+    virtual ~UnpackMSBase() = default;
+
+    virtual Result_t operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
+                                const uint64_t tTimeslice) const = 0;
+  };
+
+}  // namespace cbm::algo
-- 
GitLab