diff --git a/algo/detectors/bmon/Unpack.cxx b/algo/detectors/bmon/Unpack.cxx
index ed0313d552860a6148666aa07be53c8801587420..dc1bccb95fd9938f2ad34a1f991a4c4716807a72 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 aca19761f62113c3cc39ef3ac20c074b2581e696..9535c560ec72e0eefa8d1e1edf61caa923f21bfe 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 88204285120634d39396683c8a8cdb39b4e33a5e..da858f1519cce400adf0fee401a9f9146a0f50b3 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 58dfc4c7a1350d6fe0f5bdf4d1c946fbb0d188cd..af37710afa5982280724b017fa0a3a77c6159949 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 0e8797e1d6de6c6b8931d185f3d7d22ab8abfd60..45f78ba06f8f091fa0e648cc8e95ba063a3a9793 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 8721ea9b41d8d6f59f81d78769f95bf304ad4026..191d421f9639cab11a9f4c97080418bfc40ec1e6 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 f7e1cd3a31523b36caedb64a437bba15883dab7f..1274de56bdb434c74c51120b921fa0c9a2117049 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 8a3162514e6ffb2896c4deb511effe2748735a64..1f9e413f841596f1fc8eb24262a9970d82766af7 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 04fc255666c7c336e8dfdd64f72defb7c3a24dde..efbb1e7ca598ebc929687b76bbcf90c07b5a86b2 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 dbb7bd6b904c0fa4a0417b50e2efac70d70aa468..ec21c5d84757186dc5693abb7c7d6037f669ac12 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 b463e279c3aa7348a94a416a0d428d410f24fc4c..7460c6bfb915dd983819a7242529ec0c0fec274c 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 fc0897c88070609fcaf71de3b614e866bed7d877..f89b2f58cf8a07000fe2a9b6cd67562ce6e99fa7 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 34990d21afbdad145baec5b95b26d2d319d629e6..7cf95a1fb3515def8520e086d14b98dd93ef0319 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 0670fd8697b7a6e7f4188c7a82716457b503a865..8391e86dc68e397332bfafdc3862d2d5de6d3a72 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 250981bdf9b283b7d8a176316e034b58def747d8..e4caf5b730c079d2619a1ad9e99480368bcd12d8 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 6ae726b8795539608b1f999ae9eb0e67ddb07984..33cb29bc0d010e4fc3ef0a700b42a5da8f35c565 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 7764470e22284eb48d96e6b029fd6ee89581e637..7d566cfeb2066aa5ba288f462ab1e94b85c83362 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 d11e669f03d92c8c1be713efe223847954a00263..3b49776c291945f34aba2d04bbe5da3968caac43 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 bf011c43fe1d675b219a099fa81ae0ceb16fda40..4294e61c65648e158fa89326ee4fc3140a2360bc 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 4fb1295ce73b4b31c86840704be8c19d784e3689..c919418c59363ed2b3375105761c26699dd5c534 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 9beddb8e7cc6db978a61f457d11fbc67d3521800..88b2f9c3583f32732361a67b024345c90af8ccd0 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 b35c26b2304bfb7bde5ac65cc6a1f2303cce5fff..0791cd2f9cb756d24daf49cba923881f355cdbe4 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 01cdbdc10299b0fe7c62f4fe68f4b90c3ed4d15d..0ba70becd7dd1bf874a1c216f696bfa24c9609c7 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 c5918369a65019d5dc5d82379467b11a6d552a42..63eaa5e12a5c6aa5f012551b88516f1fe552faf9 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 16f82926fac58d225d5fefdcee4cc74370a45c85..e12ef68aee899ad3b398f78947ff8a9da5c13ff1 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 eac2415c06bef15862ac32599119d30e2798f5d8..710a90093c83240ba110346f41a179e1dcc23b6d 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 c0e447c6c45df3b447a91f1f3b6c4af7d83b9ae1..4a51f76db15e43117d47d47bd81146116e49d043 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 264b30ae44fd398c9c6ba72141a2ab286c14dc91..6a280e1a398827e3363e6a488b1fee3cba1a64ce 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 a55564b131cf8af8c7ff9b67b17b34435798e58c..6f0f871816f914cdf35c15e9a48db3d32581188d 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 35bf7fe552feac2bd3208116a774ae8161ec6ee3..a0fb3eb84b12905d18761f564c34c859e7ad7408 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 0000000000000000000000000000000000000000..d345eb05ef13f0678162724c3169f06c961e0f98
--- /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