From bffd070a30de02186de7b6afd8a61d1dce0317c2 Mon Sep 17 00:00:00 2001
From: P-A Loizeau <p.-a.loizeau@gsi.de>
Date: Mon, 18 Oct 2021 19:01:23 +0200
Subject: [PATCH] [MQ] Add new algo based unpacker device + related changes

- Split the InitUnpacker method of the UnpackConfig template into
  - InitOutput
  - RegisterOutput (Framework bound, to be replaced by method in Task class CbmRecoUnpack)
  - SetAlgo
  - initParContainer, moved to the Task Class CbmRecoUnpack
  - InitAlgo
- Move to the template version of these methods all blocks common to all derived config classes
- Whenever necessary, overload these methods in the derived config classes (including the common parts, no base method call)
- Bump Config classes version number
- Adapt the Sts Unpack algo classes to initialize the monitor classes
- Adapt the CbmRecoUnpack
- Adapt the CbmUnpackDevice to use the standard Unpack Config classes (compiles with full functionality but untested)
---
 MQ/mcbm/CMakeLists.txt                        |  41 +
 MQ/mcbm/CbmDeviceMcbmUnpack.cxx               |  12 +-
 MQ/mcbm/CbmDeviceUnpack.cxx                   | 862 ++++++++++++++++++
 MQ/mcbm/CbmDeviceUnpack.h                     | 276 ++++++
 MQ/mcbm/runUnpack.cxx                         |  32 +
 core/data/CbmTsEventHeader.h                  |   4 +
 reco/base/CbmRecoUnpackConfig.tmpl            | 204 +++--
 .../psd/unpack/CbmPsdUnpackConfig.cxx         |  26 +-
 .../detectors/psd/unpack/CbmPsdUnpackConfig.h |  28 +-
 .../rich/unpack/CbmRichUnpackConfig.cxx       |  27 +-
 .../rich/unpack/CbmRichUnpackConfig.h         |  30 +-
 .../detectors/sts/unpack/CbmStsUnpackAlgo.cxx |   2 +
 .../sts/unpack/CbmStsUnpackAlgoLegacy.cxx     |   3 +
 .../sts/unpack/CbmStsUnpackConfig.cxx         |  42 +-
 .../detectors/sts/unpack/CbmStsUnpackConfig.h |  14 +-
 .../tof/unpack/CbmTofUnpackConfig.cxx         |  26 +-
 .../detectors/tof/unpack/CbmTofUnpackConfig.h |  12 -
 .../trd/unpack/CbmTrdUnpackConfig.cxx         |  15 +-
 .../detectors/trd/unpack/CbmTrdUnpackConfig.h |  37 +-
 .../trd/unpack/CbmTrdUnpackConfigFasp2D.cxx   |  26 +-
 .../trd/unpack/CbmTrdUnpackConfigFasp2D.h     |  28 +-
 reco/steer/CMakeLists.txt                     |   1 +
 reco/steer/CbmRecoUnpack.cxx                  |  55 +-
 reco/steer/CbmRecoUnpack.h                    |  56 ++
 24 files changed, 1524 insertions(+), 335 deletions(-)
 create mode 100644 MQ/mcbm/CbmDeviceUnpack.cxx
 create mode 100644 MQ/mcbm/CbmDeviceUnpack.h
 create mode 100644 MQ/mcbm/runUnpack.cxx

diff --git a/MQ/mcbm/CMakeLists.txt b/MQ/mcbm/CMakeLists.txt
index 6671f55ab5..e11e1daafa 100644
--- a/MQ/mcbm/CMakeLists.txt
+++ b/MQ/mcbm/CMakeLists.txt
@@ -12,6 +12,13 @@ set(INCLUDE_DIRECTORIES
     ${CBMROOT_SOURCE_DIR}/fles/mcbm2018/commonMQ
     ${CBMROOT_SOURCE_DIR}/fles/flestools
     ${CBMROOT_SOURCE_DIR}/reco/eventbuilder/digis
+    ${CBMROOT_SOURCE_DIR}/reco/base/
+    ${CBMROOT_SOURCE_DIR}/reco/detectors/psd/unpack
+    ${CBMROOT_SOURCE_DIR}/reco/detectors/sts/unpack
+    ${CBMROOT_SOURCE_DIR}/reco/detectors/tof/unpack
+    ${CBMROOT_SOURCE_DIR}/reco/detectors/trd/unpack
+    ${CBMROOT_SOURCE_DIR}/reco/detectors/trd/rawToDigiMethods
+    ${CBMROOT_SOURCE_DIR}/reco/detectors/rich/unpack
     ${CBMDATA_DIR}
     ${CBMDATA_DIR}/global
     ${CBMDATA_DIR}/raw
@@ -23,8 +30,13 @@ set(INCLUDE_DIRECTORIES
     ${CBMDATA_DIR}/trd
     ${CBMDATA_DIR}/mvd # Feint to avoid crash of DigiManager due to missing source pointer
     ${CBMBASE_DIR}
+    ${CBMROOT_SOURCE_DIR}/sim/transport/steer # For CbmSetup.h!
+    ${CBMROOT_SOURCE_DIR}/sim/transport/geosetup # For CbmGeoSetupDbProvider.h, needed by CbmSetup
 
+    ${CBMDETECTORBASE_DIR}/sts # required for parameter handling of the sts
     ${CBMDETECTORBASE_DIR}/trd # required for parameter handling of the trd
+    ${CBMDETECTORBASE_DIR}/tof # required for parameter handling of the tof
+    ${CBMDETECTORBASE_DIR}/rich # required for parameter handling of the rich
     ${CBMDETECTORBASE_DIR}/psd # required for fitting tools of the psd
 )
 
@@ -191,3 +203,32 @@ set(DEPENDENCIES
 #GENERATE_LIBRARY()
 GENERATE_EXECUTABLE()
 
+
+set(EXE_NAME MqUnpack)
+set(SRCS CbmDeviceUnpack.cxx runUnpack.cxx)
+
+set(DEPENDENCIES
+  ${DEPENDENCIES}
+  ${FAIR_LIBS}
+  ParBase
+  ${BOOST_LIBS}
+  fles_ipc
+  CbmFlibMcbm2018
+  CbmFlibFlesTools
+  CbmBase
+  CbmRecoBase
+  CbmPsdReco
+  CbmRichReco
+  CbmRecoSts
+  CbmTofReco
+  CbmTrdReco
+  CbmData
+  CbmSimSteer # for CbmSetup!
+  Core
+  RIO
+  Net
+  Hist
+  RHTTP
+)
+GENERATE_EXECUTABLE()
+
diff --git a/MQ/mcbm/CbmDeviceMcbmUnpack.cxx b/MQ/mcbm/CbmDeviceMcbmUnpack.cxx
index f73a825c82..d72d85b1ae 100644
--- a/MQ/mcbm/CbmDeviceMcbmUnpack.cxx
+++ b/MQ/mcbm/CbmDeviceMcbmUnpack.cxx
@@ -475,32 +475,32 @@ Bool_t CbmDeviceMcbmUnpack::DoUnpack(const fles::Timeslice& ts, size_t /*compone
 
   if (kFALSE == fUnpAlgoSts->ProcessTs(ts)) {
     LOG(error) << "Failed processing TS " << ts.index() << " in STS unpacker algorithm class";
-    return kTRUE;
+    return kFALSE;
   }  // if( kFALSE == fUnpAlgoSts->ProcessTs( ts ) )
 
   if (kFALSE == fUnpAlgoMuch->ProcessTs(ts)) {
     LOG(error) << "Failed processing TS " << ts.index() << " in MUCH unpacker algorithm class";
-    return kTRUE;
+    return kFALSE;
   }  // if( kFALSE == fUnpAlgoMuch->ProcessTs( ts ) )
 
   if (kFALSE == fUnpAlgoTrd->ProcessTs(ts)) {
     LOG(error) << "Failed processing TS " << ts.index() << " in TRD unpacker algorithm class";
-    return kTRUE;
+    return kFALSE;
   }  // if( kFALSE == fUnpAlgoTrd->ProcessTs( ts ) )
 
   if (kFALSE == fUnpAlgoTof->ProcessTs(ts)) {
     LOG(error) << "Failed processing TS " << ts.index() << " in TOF unpacker algorithm class";
-    return kTRUE;
+    return kFALSE;
   }  // if( kFALSE == fUnpAlgoTof->ProcessTs( ts ) )
 
   if (kFALSE == fUnpAlgoRich->ProcessTs(ts)) {
     LOG(error) << "Failed processing TS " << ts.index() << " in RICH unpacker algorithm class";
-    return kTRUE;
+    return kFALSE;
   }  // if( kFALSE == fUnpAlgoRich->ProcessTs( ts ) )
 
   if (kFALSE == fUnpAlgoPsd->ProcessTs(ts)) {
     LOG(error) << "Failed processing TS " << ts.index() << " in PSD unpacker algorithm class";
-    return kTRUE;
+    return kFALSE;
   }  // if( kFALSE == fUnpAlgoPsd->ProcessTs( ts ) )
 
 
diff --git a/MQ/mcbm/CbmDeviceUnpack.cxx b/MQ/mcbm/CbmDeviceUnpack.cxx
new file mode 100644
index 0000000000..cd895deaaf
--- /dev/null
+++ b/MQ/mcbm/CbmDeviceUnpack.cxx
@@ -0,0 +1,862 @@
+/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Pierre-Alain Loizeau [committer] */
+
+/**
+ * CbmDeviceUnpack.cxx
+ *
+ * @since 2020-05-04
+ * @author P.-A. Loizeau
+ */
+
+#include "CbmDeviceUnpack.h"
+
+#include "CbmFlesCanvasTools.h"
+#include "CbmMQDefs.h"
+#include "CbmMuchDigi.h"
+#include "CbmPsdUnpackConfig.h"
+#include "CbmRichUnpackConfig.h"
+#include "CbmSetup.h"
+#include "CbmStsUnpackConfig.h"
+#include "CbmTofUnpackConfig.h"
+#include "CbmTrdUnpackConfig.h"
+#include "CbmTrdUnpackConfigFasp2D.h"
+
+#include "StorableTimeslice.hpp"
+#include "TimesliceMetaData.h"
+
+#include "FairMQLogger.h"
+#include "FairMQProgOptions.h"  // device->fConfig
+#include "FairParGenericSet.h"
+
+#include "TCanvas.h"
+#include "TFile.h"
+#include "TH1.h"
+#include "TList.h"
+#include "TNamed.h"
+
+#include "BoostSerializer.h"
+#include <boost/archive/binary_iarchive.hpp>
+#include <boost/serialization/utility.hpp>
+
+#include <array>
+#include <iomanip>
+#include <stdexcept>
+#include <string>
+#include <utility>
+
+#include "RootSerializer.h"
+struct InitTaskError : std::runtime_error {
+  using std::runtime_error::runtime_error;
+};
+
+using namespace std;
+
+//Bool_t bMcbm2018MonitorTaskT0ResetHistos = kFALSE;
+
+CbmDeviceUnpack::CbmDeviceUnpack() {}
+
+void CbmDeviceUnpack::InitTask()
+try {
+  /// Read options from executable
+  LOG(info) << "Init options for CbmDeviceUnpack.";
+  fsSetupName             = fConfig->GetValue<std::string>("Setup");
+  fuRunId                 = fConfig->GetValue<uint32_t>("RunId");
+  fbIgnoreOverlapMs       = fConfig->GetValue<bool>("IgnOverMs");
+  fbOutputFullTimeSorting = fConfig->GetValue<bool>("FullTimeSort");
+  fvsSetTimeOffs          = fConfig->GetValue<std::vector<std::string>>("SetTimeOffs");
+  fsChannelNameDataInput  = fConfig->GetValue<std::string>("TsNameIn");
+  fsChannelNameDataOutput = fConfig->GetValue<std::string>("TsNameOut");
+  /// TODO: option to set fuDigiMaskedIdT0 !!!!
+  fsAllowedChannels[0] = fsChannelNameDataInput;
+
+  // Get the information about created channels from the device
+  // Check if the defined channels from the topology (by name)
+  // are in the list of channels which are possible/allowed
+  // for the device
+  // The idea is to check at initilization if the devices are
+  // properly connected. For the time beeing this is done with a
+  // nameing convention. It is not avoided that someone sends other
+  // data on this channel.
+  //logger::SetLogLevel("INFO");
+
+  int noChannel = fChannels.size();
+  LOG(info) << "Number of defined channels: " << noChannel;
+  for (auto const& entry : fChannels) {
+    LOG(info) << "Channel name: " << entry.first;
+    if (std::string::npos != entry.first.find(fsChannelNameDataInput)) {
+      if (!IsChannelNameAllowed(entry.first)) throw InitTaskError("Channel name does not match.");
+      OnData(entry.first, &CbmDeviceUnpack::HandleData);
+    }  // if( entry.first.find( "ts" )
+  }    // for( auto const &entry : fChannels )
+  InitContainers();
+}
+catch (InitTaskError& e) {
+  LOG(error) << e.what();
+  // Wrapper defined in CbmMQDefs.h to support different FairMQ versions
+  cbm::mq::ChangeState(this, cbm::mq::Transition::ErrorFound);
+}
+
+bool CbmDeviceUnpack::IsChannelNameAllowed(std::string channelName)
+{
+
+  for (auto const& entry : fsAllowedChannels) {
+    std::size_t pos1 = channelName.find(entry);
+    if (pos1 != std::string::npos) {
+      const vector<std::string>::const_iterator pos =
+        std::find(fsAllowedChannels.begin(), fsAllowedChannels.end(), entry);
+      const vector<std::string>::size_type idx = pos - fsAllowedChannels.begin();
+      LOG(info) << "Found " << entry << " in " << channelName;
+      LOG(info) << "Channel name " << channelName << " found in list of allowed channel names at position " << idx;
+      return true;
+    }  // if (pos1!=std::string::npos)
+  }    // for(auto const &entry : fsAllowedChannels)
+  LOG(info) << "Channel name " << channelName << " not found in list of allowed channel names.";
+  LOG(error) << "Stop device.";
+
+  return false;
+}
+
+Bool_t CbmDeviceUnpack::InitContainers()
+{
+  LOG(info) << "Init parameter containers for CbmDeviceUnpack.";
+
+  // ----- FIXME: Environment settings? or binary option?
+  TString srcDir = std::getenv("VMCWORKDIR");  // top source directory, standard C++ library
+  //  TString srcDir = gSystem->Getenv("VMCWORKDIR");  // top source directory
+
+  // -----   CbmSetup   -----------------------------------------------------
+  auto cbmsetup = CbmSetup::Instance();
+  cbmsetup->LoadSetup(fsSetupName.data());  //nh - accesses file system! FIXME
+  // ------------------------------------------------------------------------
+
+  /// Initialize the UnpackerConfigs objects and their "user options"
+  // ---- STS ----
+  std::shared_ptr<CbmStsUnpackConfig> stsconfig = nullptr;
+  TString stsSetupTag                           = "";
+  cbmsetup->GetGeoTag(ECbmModuleId::kSts, stsSetupTag);
+  if ("" != stsSetupTag) {
+    stsconfig = std::make_shared<CbmStsUnpackConfig>(std::string(fsSetupName), fuRunId);
+    if (stsconfig) {
+      // stsconfig->SetDebugState();
+      stsconfig->SetDoWriteOutput();
+      stsconfig->SetDoWriteOptOutA("StsDigiPulser");
+      std::string parfilesbasepathSts = Form("%s/macro/beamtime/mcbm2021/", srcDir.Data());
+      stsconfig->SetParFilesBasePath(parfilesbasepathSts);
+      /// Enable duplicates rejection, Ignores the ADC for duplicates check
+      stsconfig->SetDuplicatesRejection(true, true);
+      /// Enable Monitor plots
+      //      stsconfig->SetMonitor(GetStsMonitor(outfilename, true)); // FIXME: Unsupported for now
+      stsconfig->SetSystemTimeOffset(-2221);  // [ns] value to be updated
+
+      stsconfig->SetMinAdcCut(1, 1);
+      stsconfig->SetMinAdcCut(2, 1);
+      stsconfig->SetMinAdcCut(3, 1);
+      stsconfig->SetMinAdcCut(4, 1);
+
+      stsconfig->MaskNoisyChannel(7, 715);
+      stsconfig->MaskNoisyChannel(7, 162);
+      stsconfig->MaskNoisyChannel(7, 159);
+      stsconfig->MaskNoisyChannel(7, 158);
+      stsconfig->MaskNoisyChannel(7, 125);
+      stsconfig->MaskNoisyChannel(7, 124);
+      stsconfig->MaskNoisyChannel(7, 123);
+      stsconfig->MaskNoisyChannel(12, 119);
+      stsconfig->MaskNoisyChannel(3, 85);
+      stsconfig->MaskNoisyChannel(3, 79);
+      stsconfig->MaskNoisyChannel(3, 75);
+      stsconfig->MaskNoisyChannel(3, 56);
+      stsconfig->MaskNoisyChannel(9, 709);
+    }
+  }  // if ("" != stsSetupTag)
+  // -------------
+  // ---- TRD ----
+  std::shared_ptr<CbmTrdUnpackConfig> trd1Dconfig = nullptr;
+  TString trdsetuptag                             = "";
+  cbmsetup->GetGeoTag(ECbmModuleId::kTrd, trdsetuptag);
+  if ("" != trdsetuptag) {
+    // trd1Dconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data(), fuRunId);
+    trd1Dconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data(), 3);
+    if (trd1Dconfig) {
+      trd1Dconfig->SetDoWriteOutput();
+      // Activate the line below to write Trd1D digis to a separate "TrdSpadicDigi" branch. Can be used to separate between Fasp and Spadic digis
+      // trd1Dconfig->SetOutputBranchName("TrdSpadicDigi");
+      // trd1Dconfig->SetDoWriteOptOutA(CbmTrdRawMessageSpadic::GetBranchName());
+      // trd1Dconfig->SetDoWriteOptOutB("SpadicInfoMessages"); // SpadicInfoMessages
+
+      std::string parfilesbasepathTrd = Form("%s/parameters/trd", srcDir.Data());
+      trd1Dconfig->SetParFilesBasePath(parfilesbasepathTrd);
+      // trd1Dconfig->SetMonitor(GetTrdMonitor(outfilename));  // FIXME: Unsupported for now
+      // Get the spadic configuration true = avg baseline active / false plain sample 0
+      trd1Dconfig->SetSpadicObject(GetTrdSpadic(true));
+      trd1Dconfig->SetSystemTimeOffset(0);  // [ns] value to be updated
+    }
+  }  // if ("" != trdsetuptag)
+  // -------------
+  // ---- TRDFASP2D ----
+  std::shared_ptr<CbmTrdUnpackConfigFasp2D> trdfasp2dconfig = nullptr;
+  if ("" != trdsetuptag) {
+    trdfasp2dconfig = std::make_shared<CbmTrdUnpackConfigFasp2D>(trdsetuptag.Data(), 3);
+    if (trdfasp2dconfig) {
+      // trdfasp2dconfig->SetDebugState();
+      trdfasp2dconfig->SetDoWriteOutput();
+      // Activate the line below to write Trd1D digis to a separate "TrdFaspDigi" branch. Can be used to separate between Fasp and Spadic digis
+      trdfasp2dconfig->SetOutputBranchName("TrdFaspDigi");
+      std::string parfilesbasepathTrdfasp2d = Form("%s/parameters/trd", srcDir.Data());
+      trdfasp2dconfig->SetParFilesBasePath(parfilesbasepathTrdfasp2d);
+      trdfasp2dconfig->SetSystemTimeOffset(-1800);  // [ns] value to be updated
+    }
+  }  // if ("" != trdsetuptag)
+  // -------------
+  // ---- TOF ----
+  std::shared_ptr<CbmTofUnpackConfig> tofconfig = nullptr;
+  TString tofSetupTag                           = "";
+  cbmsetup->GetGeoTag(ECbmModuleId::kTof, tofSetupTag);
+  if ("" != tofSetupTag) {
+    tofconfig = std::make_shared<CbmTofUnpackConfig>("", fuRunId);
+    if (tofconfig) {
+      // tofconfig->SetDebugState();
+      tofconfig->SetDoWriteOutput();
+      // tofconfig->SetDoWriteOptOutA("CbmTofErrors");
+      std::string parfilesbasepathTof = Form("%s/macro/beamtime/mcbm2021/", srcDir.Data());
+      tofconfig->SetParFilesBasePath(parfilesbasepathTof);
+      tofconfig->SetSystemTimeOffset(-1220);  // [ns] value to be updated
+    }
+  }  // if ("" != tofSetupTag)
+  // -------------
+  // ---- RICH ----
+  std::shared_ptr<CbmRichUnpackConfig> richconfig = nullptr;
+  TString richSetupTag                            = "";
+  cbmsetup->GetGeoTag(ECbmModuleId::kRich, richSetupTag);
+  if ("" != richSetupTag) {
+    richconfig = std::make_shared<CbmRichUnpackConfig>("", fuRunId);
+    if (richconfig) {
+      richconfig->SetDebugState();
+      richconfig->SetDoWriteOutput();
+      std::string parfilesbasepathRich = Form("%s/macro/beamtime/mcbm2021/", srcDir.Data());
+      richconfig->SetParFilesBasePath(parfilesbasepathRich);
+      richconfig->SetSystemTimeOffset(256000 - 1200);  // [ns] 1 MS and additional correction
+      if (1588 == fuRunId) richconfig->MaskDiRICH(0x7150);
+    }
+  }  // if ("" != richSetupTag)
+  // -------------
+  // ---- PSD ----
+  std::shared_ptr<CbmPsdUnpackConfig> psdconfig = nullptr;
+  TString psdSetupTag                           = "";
+  cbmsetup->GetGeoTag(ECbmModuleId::kPsd, psdSetupTag);
+  if ("" != psdSetupTag) {
+    psdconfig = std::make_shared<CbmPsdUnpackConfig>("", fuRunId);
+    if (psdconfig) {
+      // psdconfig->SetDebugState();
+      psdconfig->SetDoWriteOutput();
+      // psdconfig->SetDoWriteOptOutA("CbmPsdDsp");
+      std::string parfilesbasepathPsd = Form("%s/macro/beamtime/mcbm2021/", srcDir.Data());
+      psdconfig->SetParFilesBasePath(parfilesbasepathPsd);
+      psdconfig->SetSystemTimeOffset(0);  // [ns] value to be updated
+    }
+  }  // if ("" != psdSetupTag)
+  // -------------
+
+  /// Enable full time sorting instead of time sorting per FLIM link
+  if (stsconfig) SetUnpackConfig(stsconfig);
+  if (trd1Dconfig) SetUnpackConfig(trd1Dconfig);
+  if (trdfasp2dconfig) SetUnpackConfig(trdfasp2dconfig);
+  if (tofconfig) SetUnpackConfig(tofconfig);
+  if (richconfig) SetUnpackConfig(richconfig);
+  if (psdconfig) SetUnpackConfig(psdconfig);
+
+  /// Load time offsets
+  for (std::vector<std::string>::iterator itStrOffs = fvsSetTimeOffs.begin(); itStrOffs != fvsSetTimeOffs.end();
+       ++itStrOffs) {
+    size_t charPosDel = (*itStrOffs).find(',');
+    if (std::string::npos == charPosDel) {
+      LOG(info) << "CbmDeviceUnpack::InitContainers => "
+                << "Trying to set trigger window with invalid option pattern, ignored! "
+                << " (Should be ECbmModuleId,dWinBeg,dWinEnd but instead found " << (*itStrOffs) << " )";
+    }  // if( std::string::npos == charPosDel )
+
+    /// Detector Enum Tag
+    std::string sSelDet = (*itStrOffs).substr(0, charPosDel);
+    /// Min number
+    charPosDel++;
+    int32_t iOffset = std::stoi((*itStrOffs).substr(charPosDel));
+
+    if ("kSTS" == sSelDet && fStsConfig) {  //
+      fStsConfig->SetSystemTimeOffset(iOffset);
+
+      fStsConfig->SetMinAdcCut(1, 1);
+      fStsConfig->SetMinAdcCut(2, 1);
+      fStsConfig->SetMinAdcCut(3, 1);
+      fStsConfig->SetMinAdcCut(4, 1);
+
+      fStsConfig->MaskNoisyChannel(7, 715);
+      fStsConfig->MaskNoisyChannel(7, 162);
+      fStsConfig->MaskNoisyChannel(7, 159);
+      fStsConfig->MaskNoisyChannel(7, 158);
+      fStsConfig->MaskNoisyChannel(7, 125);
+      fStsConfig->MaskNoisyChannel(7, 124);
+      fStsConfig->MaskNoisyChannel(7, 123);
+      fStsConfig->MaskNoisyChannel(12, 119);
+      fStsConfig->MaskNoisyChannel(3, 85);
+      fStsConfig->MaskNoisyChannel(3, 79);
+      fStsConfig->MaskNoisyChannel(3, 75);
+      fStsConfig->MaskNoisyChannel(3, 56);
+      fStsConfig->MaskNoisyChannel(9, 709);
+
+      // Time OffSet
+      // U2 MOD1
+      fStsConfig->SetAsicTimeOffset(104, 0.235097);
+      fStsConfig->SetAsicTimeOffset(105, -0.919854);
+      fStsConfig->SetAsicTimeOffset(106, 0.470871);
+      fStsConfig->SetAsicTimeOffset(107, -0.302136);
+      fStsConfig->SetAsicTimeOffset(108, 0.0538701);
+      fStsConfig->SetAsicTimeOffset(109, -0.726945);
+      fStsConfig->SetAsicTimeOffset(110, -0.474958);
+      fStsConfig->SetAsicTimeOffset(111, -0.426105);
+      fStsConfig->SetAsicTimeOffset(112, -0.642128);
+      fStsConfig->SetAsicTimeOffset(113, 3.90217);
+      fStsConfig->SetAsicTimeOffset(114, 4.50206);
+      fStsConfig->SetAsicTimeOffset(115, 4.16447);
+      fStsConfig->SetAsicTimeOffset(116, 5.00525);
+      fStsConfig->SetAsicTimeOffset(117, 4.2554);
+      fStsConfig->SetAsicTimeOffset(118, 5.51313);
+      fStsConfig->SetAsicTimeOffset(119, 3.38058);
+      // U2 MOD0
+      fStsConfig->SetAsicTimeOffset(88, 5.32785);
+      fStsConfig->SetAsicTimeOffset(89, 5.10337);
+      fStsConfig->SetAsicTimeOffset(90, 6.63223);
+      fStsConfig->SetAsicTimeOffset(91, 4.44318);
+      fStsConfig->SetAsicTimeOffset(92, 6.5406);
+      fStsConfig->SetAsicTimeOffset(93, 3.82063);
+      fStsConfig->SetAsicTimeOffset(94, 5.8673);
+      fStsConfig->SetAsicTimeOffset(95, 4.41679);
+      fStsConfig->SetAsicTimeOffset(96, 0.917994);
+      fStsConfig->SetAsicTimeOffset(97, 2.7819);
+      fStsConfig->SetAsicTimeOffset(98, 5.61836);
+      fStsConfig->SetAsicTimeOffset(99, 5.9533);
+      fStsConfig->SetAsicTimeOffset(100, 5.9789);
+      fStsConfig->SetAsicTimeOffset(101, 5.24167);
+      fStsConfig->SetAsicTimeOffset(102, 7.14848);
+      fStsConfig->SetAsicTimeOffset(103, 6.12267);
+      // U1 MOD1
+      fStsConfig->SetAsicTimeOffset(64, 6.94614);
+      fStsConfig->SetAsicTimeOffset(65, 6.79433);
+      fStsConfig->SetAsicTimeOffset(66, 5.57188);
+      fStsConfig->SetAsicTimeOffset(67, 4.78256);
+      fStsConfig->SetAsicTimeOffset(68, 4.47773);
+      fStsConfig->SetAsicTimeOffset(69, 3.70702);
+      fStsConfig->SetAsicTimeOffset(70, 4.02281);
+      fStsConfig->SetAsicTimeOffset(71, 4.74402);
+      fStsConfig->SetAsicTimeOffset(72, 2.13448);
+      fStsConfig->SetAsicTimeOffset(73, 3.28798);
+      fStsConfig->SetAsicTimeOffset(74, 4.13604);
+      fStsConfig->SetAsicTimeOffset(76, 5.02552);
+      fStsConfig->SetAsicTimeOffset(77, 3.55128);
+      fStsConfig->SetAsicTimeOffset(78, 4.66596);
+      fStsConfig->SetAsicTimeOffset(79, 3.76298);
+      // U1 MOD0
+      fStsConfig->SetAsicTimeOffset(48, 10.0742);
+      fStsConfig->SetAsicTimeOffset(49, 9.31221);
+      fStsConfig->SetAsicTimeOffset(50, 6.09788);
+      fStsConfig->SetAsicTimeOffset(51, 2.85866);
+      fStsConfig->SetAsicTimeOffset(52, 5.45111);
+      fStsConfig->SetAsicTimeOffset(53, 3.18376);
+      fStsConfig->SetAsicTimeOffset(54, 4.77448);
+      fStsConfig->SetAsicTimeOffset(55, 3.20388);
+      fStsConfig->SetAsicTimeOffset(56, 3.37812);
+      fStsConfig->SetAsicTimeOffset(57, 4.08165);
+      fStsConfig->SetAsicTimeOffset(58, 5.06481);
+      fStsConfig->SetAsicTimeOffset(59, 4.39388);
+      fStsConfig->SetAsicTimeOffset(60, 5.63931);
+      fStsConfig->SetAsicTimeOffset(61, 4.15354);
+      fStsConfig->SetAsicTimeOffset(62, 6.67062);
+      fStsConfig->SetAsicTimeOffset(63, 6.33579);
+      // U0 MOD1
+      fStsConfig->SetAsicTimeOffset(24, 5.01505);
+      fStsConfig->SetAsicTimeOffset(25, 3.84039);
+      fStsConfig->SetAsicTimeOffset(26, 5.36344);
+      fStsConfig->SetAsicTimeOffset(27, 2.96807);
+      fStsConfig->SetAsicTimeOffset(28, 4.14668);
+      fStsConfig->SetAsicTimeOffset(29, 2.4282);
+      fStsConfig->SetAsicTimeOffset(30, 4.02055);
+      fStsConfig->SetAsicTimeOffset(31, 4.13309);
+      fStsConfig->SetAsicTimeOffset(32, 1.2073);
+      fStsConfig->SetAsicTimeOffset(33, 4.02747);
+      fStsConfig->SetAsicTimeOffset(34, 5.03306);
+      fStsConfig->SetAsicTimeOffset(35, 3.5234);
+      fStsConfig->SetAsicTimeOffset(36, 5.41946);
+      fStsConfig->SetAsicTimeOffset(37, 4.82807);
+      fStsConfig->SetAsicTimeOffset(38, 6.33436);
+      fStsConfig->SetAsicTimeOffset(39, 4.71413);
+      // U0 MOD0
+      fStsConfig->SetAsicTimeOffset(8, 8.15031);
+      fStsConfig->SetAsicTimeOffset(9, 6.99897);
+      fStsConfig->SetAsicTimeOffset(10, 8.14826);
+      fStsConfig->SetAsicTimeOffset(11, 3.29095);
+      fStsConfig->SetAsicTimeOffset(12, 3.04337);
+      fStsConfig->SetAsicTimeOffset(14, 3.71628);
+      fStsConfig->SetAsicTimeOffset(15, 3.82512);
+      fStsConfig->SetAsicTimeOffset(16, 4.05862);
+      fStsConfig->SetAsicTimeOffset(17, 4.53291);
+      fStsConfig->SetAsicTimeOffset(18, 5.22825);
+      fStsConfig->SetAsicTimeOffset(19, 4.93144);
+      fStsConfig->SetAsicTimeOffset(20, 6.33821);
+      fStsConfig->SetAsicTimeOffset(21, 5.66979);
+      fStsConfig->SetAsicTimeOffset(22, 9.33802);
+      fStsConfig->SetAsicTimeOffset(23, 7.41302);
+    }  // if( "kSTS"  == sSelDet && fStsConfig)
+       /*
+    else if ("kMUCH" == sSelDet) {
+      fUnpAlgoMuch->SetSystemTimeOffset(iOffset);
+    }  // else if( "kMUCH" == sSelDet )
+*/
+    else if ("kTRD" == sSelDet && fTrd1DConfig) {
+      fTrd1DConfig->SetSystemTimeOffset(iOffset);
+    }  // else if( "kTRD"  == sSelDet && fTrd2DConfig )
+    else if ("kTRD2D" == sSelDet && fTrd2DConfig) {
+      fTrd2DConfig->SetSystemTimeOffset(iOffset);
+    }  // else if( "kTRD"  == sSelDet && fTrd2DConfig )
+    else if ("kTOF" == sSelDet && fTofConfig) {
+      fTofConfig->SetSystemTimeOffset(iOffset);
+    }  // else if( "kTOF"  == sSelDet && fTofConfig)
+    else if ("kRICH" == sSelDet && fRichConfig) {
+      fRichConfig->SetSystemTimeOffset(iOffset);
+    }  // else if( "kRICH" == sSelDet && fRichConfig)
+    else if ("kPSD" == sSelDet && fPsdConfig) {
+      fPsdConfig->SetSystemTimeOffset(iOffset);
+    }  // else if( "kPSD"  == sSelDet )
+    else {
+      LOG(info) << "CbmDeviceUnpack::InitContainers => Trying to set time "
+                   "offset for unsupported detector, ignored! "
+                << (sSelDet);
+      continue;
+    }  // else of detector enum detection
+  }  // for( std::vector< std::string >::iterator itStrAdd = fvsAddDet.begin(); itStrAdd != fvsAddDet.end(); ++itStrAdd )
+
+  Bool_t initOK = kTRUE;
+  // --- Sts
+  if (fStsConfig) {
+    fStsConfig->InitOutput();
+    //    RegisterOutputs( ioman, fStsConfig ); /// Framework bound work = kept in this Task
+    fStsConfig->SetDoIgnoreOverlappMs(fbIgnoreOverlapMs);
+    fStsConfig->SetAlgo();
+    initOK &= InitParameters(fStsConfig->GetParContainerRequest());  /// Framework bound work = kept in this Device
+    fStsConfig->InitAlgo();
+    //    initPerformanceMaps(fkFlesSts, "STS");
+  }
+  // --- Tof
+  if (fTofConfig) {
+    fTofConfig->InitOutput();
+    //    RegisterOutputs( ioman, fTofConfig ); /// Framework bound work = kept in this Task
+    fTofConfig->SetDoIgnoreOverlappMs(fbIgnoreOverlapMs);
+    fTofConfig->SetAlgo();
+    initOK &= InitParameters(fTofConfig->GetParContainerRequest());  /// Framework bound work = kept in this Device
+    LOG(info) << "TOF call InitAlgo()";
+    fTofConfig->InitAlgo();
+    //    initPerformanceMaps(fkFlesTof, "TOF");
+  }
+  // --- Trd
+  if (fTrd1DConfig) {
+    fTrd1DConfig->InitOutput();
+    //    RegisterOutputs( ioman, fTrd1DConfig ); /// Framework bound work = kept in this Task
+    fTrd1DConfig->SetDoIgnoreOverlappMs(fbIgnoreOverlapMs);
+    fTrd1DConfig->SetAlgo();
+    initOK &= InitParameters(fTrd1DConfig->GetParContainerRequest());  /// Framework bound work = kept in this Device
+    fTrd1DConfig->InitAlgo();
+    //    initPerformanceMaps(fkFlesTrd, "TRD1D");
+  }
+  // --- TRD2D
+  if (fTrd2DConfig) {
+    if (fTrd1DConfig && (fTrd2DConfig->GetOutputBranchName() == fTrd1DConfig->GetOutputBranchName())) {
+      LOG(info) << fTrd2DConfig->GetName() << "::Init() ---------------------------------";
+      fTrd2DConfig->SetOutputVec(fTrd1DConfig->GetOutputVec());
+    }
+    else {
+      fTrd2DConfig->InitOutput();
+      //      RegisterOutputs( ioman, fTrd2DConfig ); /// Framework bound work = kept in this Task
+    }
+    fTrd2DConfig->SetDoIgnoreOverlappMs(fbIgnoreOverlapMs);
+    fTrd2DConfig->SetAlgo();
+    initOK &= InitParameters(fTrd2DConfig->GetParContainerRequest());  /// Framework bound work = kept in this Device
+    fTrd2DConfig->InitAlgo();
+    //    initPerformanceMaps(fkFlesTrd2D, "TRD2D");
+  }
+  // This is an ugly work around, because the TRD and TRD2D want to access the same vector and there is no
+  // function to retrieve a writeable vector<obj> from the FairRootManager, especially before the branches
+  // are created, as far as I am aware.
+  // The second option workaround is in in Init() to look for the fasp config and create a separate branch
+  // for fasp created CbmTrdDigis PR 072021
+  // --- Rich
+  if (fRichConfig) {
+    fRichConfig->InitOutput();
+    //    RegisterOutputs( ioman, fRichConfig ); /// Framework bound work = kept in this Task
+    fRichConfig->SetDoIgnoreOverlappMs(fbIgnoreOverlapMs);
+    fRichConfig->SetAlgo();
+    initOK &= InitParameters(fRichConfig->GetParContainerRequest());  /// Framework bound work = kept in this Device
+    fRichConfig->InitAlgo();
+    //    initPerformanceMaps(fkFlesRich, "RICH");
+  }
+  // --- Psd
+  if (fPsdConfig) {
+    fPsdConfig->InitOutput();
+    //    RegisterOutputs( ioman, fPsdConfig ); /// Framework bound work = kept in this Task
+    fPsdConfig->SetDoIgnoreOverlappMs(fbIgnoreOverlapMs);
+    fPsdConfig->SetAlgo();
+    initOK &= InitParameters(fPsdConfig->GetParContainerRequest());  /// Framework bound work = kept in this Device
+    fPsdConfig->InitAlgo();
+    //    initPerformanceMaps(fkFlesPsd, "PSD");
+  }
+
+  /// Event header object
+  fCbmTsEventHeader = new CbmTsEventHeader();
+
+  return initOK;
+}
+
+Bool_t
+CbmDeviceUnpack::InitParameters(std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>* reqparvec)
+{
+  LOG(info) << "CbmDeviceUnpack::InitParameters";
+  if (!reqparvec) {
+    LOG(info) << "CbmDeviceUnpack::InitParameters - empty requirements vector no parameters initialized.";
+    return kTRUE;
+  }
+
+  // Now get the actual ascii files and init the containers with the asciiIo
+  for (auto& pair : *reqparvec) {
+    /*
+    auto filepath = pair.first;
+    auto parset   = pair.second;
+    FairParAsciiFileIo asciiInput;
+    if (!filepath.empty()) {
+      if (asciiInput.open(filepath.data())) { parset->init(&asciiInput); }
+    }
+    * */
+    std::string paramName {pair.second->GetName()};
+    // NewSimpleMessage creates a copy of the data and takes care of its destruction (after the transfer takes place).
+    // Should only be used for small data because of the cost of an additional copy
+
+    // Here must come the proper Runid
+    std::string message = paramName + ",111";
+    LOG(info) << "Requesting parameter container " << paramName << ", sending message: " << message;
+
+    FairMQMessagePtr req(NewSimpleMessage(message));
+    FairMQMessagePtr rep(NewMessage());
+
+    FairParGenericSet* newObj = nullptr;
+
+    if (Send(req, "parameters") > 0) {
+      if (Receive(rep, "parameters") >= 0) {
+        if (0 != rep->GetSize()) {
+          CbmMqTMessage tmsg(rep->GetData(), rep->GetSize());
+          newObj = static_cast<FairParGenericSet*>(tmsg.ReadObject(tmsg.GetClass()));
+          LOG(info) << "Received unpack parameter from the server: " << newObj->GetName();
+          newObj->print();
+        }  // if( 0 !=  rep->GetSize() )
+        else {
+          LOG(error) << "Received empty reply. Parameter not available";
+          return kFALSE;
+        }                       // else of if( 0 !=  rep->GetSize() )
+      }                         // if( Receive( rep, "parameters" ) >= 0)
+    }                           // if( Send(req, "parameters") > 0 )
+    pair.second.reset(newObj);  /// Potentially unsafe reasignment of raw pointer to the shared pointer?
+    //delete newObj;
+  }
+  return kTRUE;
+}
+
+// handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0)
+bool CbmDeviceUnpack::HandleData(FairMQMessagePtr& msg, int /*index*/)
+{
+  fulNumMessages++;
+  LOG(debug) << "Received message number " << fulNumMessages << " with size " << msg->GetSize();
+
+  if (0 == fulNumMessages % 10000) LOG(info) << "Received " << fulNumMessages << " messages";
+
+  std::string msgStr(static_cast<char*>(msg->GetData()), msg->GetSize());
+  std::istringstream iss(msgStr);
+  boost::archive::binary_iarchive inputArchive(iss);
+
+  /// Create an empty TS and fill it with the incoming message
+  fles::StorableTimeslice ts {0};
+  inputArchive >> ts;
+
+  /// On first TS, extract the TS parameters from header (by definition stable over time)
+  if (-1.0 == fdTsCoreSizeInNs) {
+    fuNbCoreMsPerTs  = ts.num_core_microslices();
+    fuNbOverMsPerTs  = ts.num_microslices(0) - ts.num_core_microslices();
+    fdMsSizeInNs     = (ts.descriptor(0, fuNbCoreMsPerTs).idx - ts.descriptor(0, 0).idx) / fuNbCoreMsPerTs;
+    fdTsCoreSizeInNs = fdMsSizeInNs * (fuNbCoreMsPerTs);
+    fdTsOverSizeInNs = fdMsSizeInNs * (fuNbOverMsPerTs);
+    fdTsFullSizeInNs = fdTsCoreSizeInNs + fdTsOverSizeInNs;
+    LOG(info) << "Timeslice parameters: each TS has " << fuNbCoreMsPerTs << " Core MS and " << fuNbOverMsPerTs
+              << " Overlap MS, for a MS duration of " << fdMsSizeInNs << " ns, a core duration of " << fdTsCoreSizeInNs
+              << " ns and a full duration of " << fdTsFullSizeInNs << " ns";
+    fTsMetaData = new TimesliceMetaData(ts.descriptor(0, 0).idx, fdTsCoreSizeInNs, fdTsOverSizeInNs, ts.index());
+  }  // if( -1.0 == fdTsCoreSizeInNs )
+  else {
+    /// Update only the fields changing from TS to TS
+    fTsMetaData->SetStartTime(ts.descriptor(0, 0).idx);
+    fTsMetaData->SetIndex(ts.index());
+  }
+
+  /// Process the Timeslice
+  DoUnpack(ts, 0);
+
+  /// Send digi vectors to ouput
+  if (!SendUnpData()) return false;
+
+  // Reset the event header for a new timeslice
+  fCbmTsEventHeader->Reset();
+
+  // Reset the unpackers for a new timeslice, e.g. clear the output vectors
+  // ---- Sts ----
+  if (fStsConfig) fStsConfig->Reset();
+  // ---- Tof ----
+  if (fTofConfig) fTofConfig->Reset();
+  // ---- Trd ----
+  if (fTrd1DConfig) fTrd1DConfig->Reset();
+  // ---- Trd2D ----
+  if (fTrd2DConfig) fTrd2DConfig->Reset();
+  // ---- Rich ----
+  if (fRichConfig) fRichConfig->Reset();
+  // ---- Psd ----
+  if (fPsdConfig) fPsdConfig->Reset();
+
+  return true;
+}
+
+bool CbmDeviceUnpack::SendUnpData()
+{
+  FairMQParts parts;
+
+  /// Prepare serialized versions of the TS Event header
+  FairMQMessagePtr messTsHeader(NewMessage());
+  Serialize<RootSerializer>(*messTsHeader, fCbmTsEventHeader);
+  parts.AddPart(std::move(messTsHeader));
+
+  // ---- T0 ----
+  std::stringstream ossT0;
+  boost::archive::binary_oarchive oaT0(ossT0);
+  //  oaT0 << fUnpAlgoTof->GetOptOutAVec();
+  oaT0 << (std::vector<CbmTofDigi>());
+  std::string* strMsgT0 = new std::string(ossT0.str());
+
+  parts.AddPart(NewMessage(
+    const_cast<char*>(strMsgT0->c_str()),  // data
+    strMsgT0->length(),                    // size
+    [](void*, void* object) { delete static_cast<std::string*>(object); },
+    strMsgT0));  // object that manages the data
+
+  // ---- Sts ----
+  std::stringstream ossSts;
+  boost::archive::binary_oarchive oaSts(ossSts);
+  if (fStsConfig) {  //
+    oaSts << *(fStsConfig->GetOutputVec());
+  }
+  std::string* strMsgSts = new std::string(ossSts.str());
+
+  parts.AddPart(NewMessage(
+    const_cast<char*>(strMsgSts->c_str()),  // data
+    strMsgSts->length(),                    // size
+    [](void*, void* object) { delete static_cast<std::string*>(object); },
+    strMsgSts));  // object that manages the data
+
+  // ---- Much ----
+  std::stringstream ossMuch;
+  boost::archive::binary_oarchive oaMuch(ossMuch);
+  //  oaMuch << fUnpAlgoMuch->GetVector();
+  oaMuch << (std::vector<CbmMuchDigi>());
+  std::string* strMsgMuch = new std::string(ossMuch.str());
+
+  parts.AddPart(NewMessage(
+    const_cast<char*>(strMsgMuch->c_str()),  // data
+    strMsgMuch->length(),                    // size
+    [](void*, void* object) { delete static_cast<std::string*>(object); },
+    strMsgMuch));  // object that manages the data
+
+
+  // ---- Trd ----
+  std::stringstream ossTrd;
+  boost::archive::binary_oarchive oaTrd(ossTrd);
+  if (fTrd1DConfig || fTrd2DConfig) {  //
+    oaTrd << *(fTrd1DConfig ? fTrd1DConfig->GetOutputVec() : fTrd2DConfig->GetOutputVec());
+  }
+  std::string* strMsgTrd = new std::string(ossTrd.str());
+
+  parts.AddPart(NewMessage(
+    const_cast<char*>(strMsgTrd->c_str()),  // data
+    strMsgTrd->length(),                    // size
+    [](void*, void* object) { delete static_cast<std::string*>(object); },
+    strMsgTrd));  // object that manages the data
+
+  // ---- Tof ----
+  std::stringstream ossTof;
+  boost::archive::binary_oarchive oaTof(ossTof);
+  if (fTofConfig) {  //
+    oaTof << *(fTofConfig->GetOutputVec());
+  }
+  std::string* strMsgTof = new std::string(ossTof.str());
+
+  parts.AddPart(NewMessage(
+    const_cast<char*>(strMsgTof->c_str()),  // data
+    strMsgTof->length(),                    // size
+    [](void*, void* object) { delete static_cast<std::string*>(object); },
+    strMsgTof));  // object that manages the data
+
+  // ---- Rich ----
+  std::stringstream ossRich;
+  boost::archive::binary_oarchive oaRich(ossRich);
+  if (fRichConfig) {  //
+    oaRich << *(fRichConfig->GetOutputVec());
+  }
+  std::string* strMsgRich = new std::string(ossRich.str());
+
+  parts.AddPart(NewMessage(
+    const_cast<char*>(strMsgRich->c_str()),  // data
+    strMsgRich->length(),                    // size
+    [](void*, void* object) { delete static_cast<std::string*>(object); },
+    strMsgRich));  // object that manages the data
+
+  // ---- Psd ----
+  std::stringstream ossPsd;
+  boost::archive::binary_oarchive oaPsd(ossPsd);
+  if (fPsdConfig) {  //
+    oaPsd << *(fPsdConfig->GetOutputVec());
+  }
+  std::string* strMsgPsd = new std::string(ossPsd.str());
+
+  parts.AddPart(NewMessage(
+    const_cast<char*>(strMsgPsd->c_str()),  // data
+    strMsgPsd->length(),                    // size
+    [](void*, void* object) { delete static_cast<std::string*>(object); },
+    strMsgPsd));  // object that manages the data
+
+  /// Prepare serialized versions of the TS Meta
+  /// FIXME: only for TS duration and overlap, should be sent to parameter service instead as stable values in run
+  ///        Index and start time are already included in the TsHeader object!
+  FairMQMessagePtr messTsMeta(NewMessage());
+  Serialize<RootSerializer>(*messTsMeta, fTsMetaData);
+  parts.AddPart(std::move(messTsMeta));
+
+  if (Send(parts, fsChannelNameDataOutput) < 0) {
+    LOG(error) << "Problem sending data to " << fsChannelNameDataOutput;
+    return false;
+  }
+
+  return true;
+}
+
+
+CbmDeviceUnpack::~CbmDeviceUnpack()
+{
+  if (fStsConfig) fStsConfig->GetUnpacker()->Finish();
+  if (fTofConfig) fTofConfig->GetUnpacker()->Finish();
+  if (fTrd1DConfig) fTrd1DConfig->GetUnpacker()->Finish();
+  if (fTrd2DConfig) fTrd2DConfig->GetUnpacker()->Finish();
+  if (fRichConfig) fRichConfig->GetUnpacker()->Finish();
+  if (fPsdConfig) fPsdConfig->GetUnpacker()->Finish();
+}
+
+Bool_t CbmDeviceUnpack::DoUnpack(const fles::Timeslice& ts, size_t /*component*/)
+{
+  fulTsCounter++;
+  // Prepare timeslice
+  //  const fles::Timeslice& timeslice = *ts;
+
+  fCbmTsEventHeader->SetTsIndex(ts.index());
+  fCbmTsEventHeader->SetTsStartTime(ts.start_time());
+
+  uint64_t nComponents = ts.num_components();
+  // if (fDoDebugPrints) LOG(info) << "Unpack: TS index " << ts.index() << " components " << nComponents;
+  LOG(info) << "Unpack: TS index " << ts.index() << " components " << nComponents;
+
+  for (uint64_t component = 0; component < nComponents; component++) {
+    auto systemId = static_cast<std::uint16_t>(ts.descriptor(component, 0).sys_id);
+
+    switch (systemId) {
+      case fkFlesSts: {
+        if (fStsConfig) {
+          fCbmTsEventHeader->AddNDigisSts(
+            unpack(systemId, &ts, component, fStsConfig, fStsConfig->GetOptOutAVec(), fStsConfig->GetOptOutBVec()));
+        }
+        break;
+      }
+      case fkFlesTof: {
+        if (fTofConfig) {
+          fCbmTsEventHeader->AddNDigisTof(
+            unpack(systemId, &ts, component, fTofConfig, fTofConfig->GetOptOutAVec(), fTofConfig->GetOptOutBVec()));
+        }
+        break;
+      }
+      case fkFlesTrd: {
+        if (fTrd1DConfig) {
+          fCbmTsEventHeader->AddNDigisTrd1D(unpack(systemId, &ts, component, fTrd1DConfig,
+                                                   fTrd1DConfig->GetOptOutAVec(), fTrd1DConfig->GetOptOutBVec()));
+        }
+        break;
+      }
+      case fkFlesTrd2D: {
+        if (fTrd2DConfig) {
+          fCbmTsEventHeader->AddNDigisTrd2D(unpack(systemId, &ts, component, fTrd2DConfig,
+                                                   fTrd2DConfig->GetOptOutAVec(), fTrd2DConfig->GetOptOutBVec()));
+        }
+        break;
+      }
+      case fkFlesRich: {
+        if (fRichConfig) {
+          fCbmTsEventHeader->AddNDigisRich(
+            unpack(systemId, &ts, component, fRichConfig, fRichConfig->GetOptOutAVec(), fRichConfig->GetOptOutBVec()));
+        }
+        break;
+      }
+      case fkFlesPsd: {
+        if (fPsdConfig) {
+          fCbmTsEventHeader->AddNDigisPsd(
+            unpack(systemId, &ts, component, fPsdConfig, fPsdConfig->GetOptOutAVec(), fPsdConfig->GetOptOutBVec()));
+        }
+        break;
+      }
+      default: {
+        if (fDoDebugPrints) LOG(error) << "Unpack: Unknown system ID " << systemId << " for component " << component;
+        break;
+      }
+    }
+  }
+
+  if (fbOutputFullTimeSorting) {
+    /// Time sort the output vectors of all unpackers present
+    if (fStsConfig && fStsConfig->GetOutputVec()) { timesort(fStsConfig->GetOutputVec()); }
+    if (fTofConfig && fTofConfig->GetOutputVec()) { timesort(fTofConfig->GetOutputVec()); }
+    if (fTrd1DConfig && fTrd1DConfig->GetOutputVec()) { timesort(fTrd1DConfig->GetOutputVec()); }
+    if (fTrd2DConfig && fTrd2DConfig->GetOutputVec()) { timesort(fTrd2DConfig->GetOutputVec()); }
+    if (fRichConfig && fRichConfig->GetOutputVec()) { timesort(fRichConfig->GetOutputVec()); }
+    if (fPsdConfig && fPsdConfig->GetOutputVec()) { timesort(fPsdConfig->GetOutputVec()); }
+
+    /// Time sort the output vectors of all unpackers present
+    if (fStsConfig && fStsConfig->GetOptOutAVec()) { timesort(fStsConfig->GetOptOutAVec()); }
+    if (fTofConfig && fTofConfig->GetOptOutAVec()) { timesort(fTofConfig->GetOptOutAVec()); }
+    if (fTrd1DConfig && fTrd1DConfig->GetOptOutAVec()) { timesort(fTrd1DConfig->GetOptOutAVec()); }
+    if (fTrd2DConfig && fTrd2DConfig->GetOptOutAVec()) { timesort(fTrd2DConfig->GetOptOutAVec()); }
+    if (fRichConfig && fRichConfig->GetOptOutAVec()) { timesort(fRichConfig->GetOptOutAVec()); }
+    if (fPsdConfig && fPsdConfig->GetOptOutAVec()) { timesort(fPsdConfig->GetOptOutAVec()); }
+  }
+
+  if (0 == fulTsCounter % 10000) LOG(info) << "Processed " << fulTsCounter << " time slices";
+
+  return kTRUE;
+}
+/**
+ * @brief Get the Trd Spadic
+ * @return std::shared_ptr<CbmTrdSpadic>
+*/
+std::shared_ptr<CbmTrdSpadic> CbmDeviceUnpack::GetTrdSpadic(bool useAvgBaseline)
+{
+  auto spadic = std::make_shared<CbmTrdSpadic>();
+  spadic->SetUseBaselineAverage(useAvgBaseline);
+  spadic->SetMaxAdcToEnergyCal(1.0);
+
+  return spadic;
+}
+
+void CbmDeviceUnpack::Finish() {}
diff --git a/MQ/mcbm/CbmDeviceUnpack.h b/MQ/mcbm/CbmDeviceUnpack.h
new file mode 100644
index 0000000000..1eb6ad1a00
--- /dev/null
+++ b/MQ/mcbm/CbmDeviceUnpack.h
@@ -0,0 +1,276 @@
+/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Pierre-Alain Loizeau [committer] */
+
+/**
+ * CbmDeviceUnpack.h
+ *
+ * @since 2020-05-04
+ * @author P.-A. Loizeau
+ */
+
+#ifndef CBMDEVICEUNPACK_H_
+#define CBMDEVICEUNPACK_H_
+
+#include "CbmMqTMessage.h"
+#include "CbmTsEventHeader.h"
+
+#include "Timeslice.hpp"
+
+#include "FairMQDevice.h"
+#include "FairParGenericSet.h"
+
+#include "Rtypes.h"
+#include "TObjArray.h"
+
+#include <map>
+#include <vector>
+
+class TList;
+class CbmPsdUnpackConfig;
+class CbmRichUnpackConfig;
+class CbmStsUnpackConfig;
+class CbmTofUnpackConfig;
+class CbmTrdUnpackConfigFasp2D;
+class CbmTrdUnpackConfig;
+
+class TimesliceMetaData;
+
+class CbmTrdSpadic;
+
+class CbmDeviceUnpack : public FairMQDevice {
+public:
+  CbmDeviceUnpack();
+  virtual ~CbmDeviceUnpack();
+
+protected:
+  virtual void InitTask();
+  bool HandleData(FairMQMessagePtr&, int);
+  bool HandleCommand(FairMQMessagePtr&, int);
+
+  /** @brief Set the Sts Unpack Config @param config */
+  void SetUnpackConfig(std::shared_ptr<CbmStsUnpackConfig> config) { fStsConfig = config; }
+
+  // /** @brief Set the Tof Unpack Config @param config */
+  void SetUnpackConfig(std::shared_ptr<CbmTofUnpackConfig> config) { fTofConfig = config; }
+
+  /** @brief Set the Trd Unpack Config @param config */
+  void SetUnpackConfig(std::shared_ptr<CbmTrdUnpackConfig> config) { fTrd1DConfig = config; }
+
+  /** @brief Set the Trd2D Unpack Config @param config */
+  void SetUnpackConfig(std::shared_ptr<CbmTrdUnpackConfigFasp2D> config) { fTrd2DConfig = config; }
+
+  /** @brief Set the Rich Unpack Config @param config */
+  void SetUnpackConfig(std::shared_ptr<CbmRichUnpackConfig> config) { fRichConfig = config; }
+
+  /** @brief Set the Psd Unpack Config @param config */
+  void SetUnpackConfig(std::shared_ptr<CbmPsdUnpackConfig> config) { fPsdConfig = config; }
+
+private:
+  /// Constants
+  static const uint16_t kusSysIdSts  = 0x10;
+  static const uint16_t kusSysIdMuch = 0x50;
+  static const uint16_t kusSysIdTrd  = 0x40;
+  static const uint16_t kusSysIdTof  = 0x60;
+  static const uint16_t kusSysIdT0   = 0x90;
+  static const uint16_t kusSysIdRich = 0x30;
+  static const uint16_t kusSysIdPsd  = 0x80;
+
+  static constexpr std::uint16_t fkFlesMvd   = static_cast<std::uint16_t>(fles::SubsystemIdentifier::MVD);
+  static constexpr std::uint16_t fkFlesSts   = static_cast<std::uint16_t>(fles::SubsystemIdentifier::STS);
+  static constexpr std::uint16_t fkFlesMuch  = static_cast<std::uint16_t>(fles::SubsystemIdentifier::MUCH);
+  static constexpr std::uint16_t fkFlesTrd   = static_cast<std::uint16_t>(fles::SubsystemIdentifier::TRD);
+  static constexpr std::uint16_t fkFlesTrd2D = static_cast<std::uint16_t>(fles::SubsystemIdentifier::TRD2D);
+  static constexpr std::uint16_t fkFlesTof   = static_cast<std::uint16_t>(fles::SubsystemIdentifier::RPC);
+  static constexpr std::uint16_t fkFlesRich  = static_cast<std::uint16_t>(fles::SubsystemIdentifier::RICH);
+  static constexpr std::uint16_t fkFlesPsd   = static_cast<std::uint16_t>(fles::SubsystemIdentifier::PSD);
+
+
+  /// Control flags
+  Bool_t fbIgnoreOverlapMs       = false;  //! Ignore Overlap Ms: all fuOverlapMsNb MS at the end of timeslice
+  Bool_t fbComponentsAddedToList = kFALSE;
+
+  /** @brief Flag if extended debug output is to be printed or not*/
+  bool fDoDebugPrints = false;  //!
+  /** @brief Flag if performance profiling should be activated or not.*/
+  bool fDoPerfProf = false;  //!
+  /** @brief Flag to Enable/disable a full time sorting. If off, time sorting happens per link/FLIM source */
+  bool fbOutputFullTimeSorting = false;
+
+  /// User settings parameters
+  std::string fsSetupName             = "mcbm_beam_2021_07";
+  uint32_t fuRunId                    = 1588;
+  std::string fsChannelNameDataInput  = "fullts";
+  std::string fsChannelNameDataOutput = "unpts_0";
+  std::string fsChannelNameCommands   = "commands";
+  UInt_t fuDigiMaskedIdT0             = 0x00005006;
+  UInt_t fuDigiMaskId                 = 0x0001FFFF;
+
+  /// List of MQ channels names
+  std::vector<std::string> fsAllowedChannels = {fsChannelNameDataInput};
+
+  /// Parameters management
+  //      TList* fParCList = nullptr;
+  Bool_t InitParameters(std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>* reqparvec);
+
+  /// Statistics & first TS rejection
+  uint64_t fulNumMessages = 0;
+  uint64_t fulTsCounter   = 0;
+  /** @brief Map to store a name for the unpackers and the processed amount of digis, key = fkFlesId*/
+  std::map<std::uint16_t, std::pair<std::string, size_t>> fNameMap = {};  //!
+  /** @brief Map to store the cpu and wall time, key = fkFlesId*/
+  std::map<std::uint16_t, std::pair<double, double>> fTimeMap = {};  //!
+  /** @brief Map to store the in and out data amount, key = fkFlesId*/
+  std::map<std::uint16_t, std::pair<double, double>> fDataSizeMap = {};  //!
+
+  /// Configuration of the unpackers. Provides the configured algorithm
+  std::shared_ptr<CbmStsUnpackConfig> fStsConfig         = nullptr;
+  std::shared_ptr<CbmTrdUnpackConfigFasp2D> fTrd2DConfig = nullptr;
+  std::shared_ptr<CbmTrdUnpackConfig> fTrd1DConfig       = nullptr;
+  std::shared_ptr<CbmTofUnpackConfig> fTofConfig         = nullptr;
+  std::shared_ptr<CbmRichUnpackConfig> fRichConfig       = nullptr;
+  std::shared_ptr<CbmPsdUnpackConfig> fPsdConfig         = nullptr;
+
+  /// Pointer to the Timeslice header conatining start time and index
+  CbmTsEventHeader* fCbmTsEventHeader = nullptr;
+
+  /// Time offsets
+  std::vector<std::string> fvsSetTimeOffs = {};
+
+  /// TS MetaData storage: stable so should be moved somehow to parameters handling (not transmitted with each TS
+  size_t fuNbCoreMsPerTs    = 0;     //!
+  size_t fuNbOverMsPerTs    = 0;     //!
+  Double_t fdMsSizeInNs     = 0;     //! Size of a single MS, [nanoseconds]
+  Double_t fdTsCoreSizeInNs = -1.0;  //! Total size of the core MS in a TS, [nanoseconds]
+  Double_t fdTsOverSizeInNs = -1.0;  //! Total size of the overlap MS in a TS, [nanoseconds]
+  Double_t fdTsFullSizeInNs = -1.0;  //! Total size of all MS in a TS, [nanoseconds]
+  TimesliceMetaData* fTsMetaData;
+
+  bool IsChannelNameAllowed(std::string channelName);
+  Bool_t InitContainers();
+  Bool_t DoUnpack(const fles::Timeslice& ts, size_t component);
+  void Finish();
+  bool SendUnpData();
+
+  std::shared_ptr<CbmTrdSpadic> GetTrdSpadic(bool useAvgBaseline);
+
+  /** @brief Sort a vector timewise vector type has to provide GetTime() */
+  template<typename TVecobj>
+  typename std::enable_if<std::is_same<TVecobj, std::nullptr_t>::value == true, void>::type
+  timesort(std::vector<TVecobj>* /*vec = nullptr*/)
+  {
+    LOG(debug) << "CbmDeviceUnpack::timesort() got an object that has no member function GetTime(). Hence, we can and "
+                  "will not timesort it!";
+  }
+
+  template<typename TVecobj>
+  typename std::enable_if<!std::is_member_function_pointer<decltype(&TVecobj::GetTime)>::value, void>::type
+  timesort(std::vector<TVecobj>* /*vec = nullptr*/)
+  {
+    LOG(debug) << "CbmDeviceUnpack::timesort() " << TVecobj::Class_Name()
+               << "is  an object that has no member function GetTime(). Hence, we can and "
+                  "will not timesort it!";
+  }
+
+  template<typename TVecobj>
+  typename std::enable_if<std::is_member_function_pointer<decltype(&TVecobj::GetTime)>::value, void>::type
+  timesort(std::vector<TVecobj>* vec = nullptr)
+  {
+    if (vec == nullptr) return;
+    std::sort(vec->begin(), vec->end(),
+              [](const TVecobj& a, const TVecobj& b) -> bool { return a.GetTime() < b.GetTime(); });
+  }
+
+  /**
+   * @brief Template for the unpacking call of a given algorithm.
+   *
+   * @tparam TAlgo Algorithm to be called
+   * @tparam TOutput Output element types
+   * @tparam TOptoutputs Optional output element types
+   * @param ts Timeslice
+   * @param icomp Component number
+   * @param algo Algorithm to be used for this component
+   * @param outtargetvec Target vector for the output elements
+   * @param optoutputvecs Target vectors for optional outputs
+   * @return std::pair<ndigis, std::pair<cputime, walltime>>
+  */
+  template<class TConfig, class TOptOutA = std::nullptr_t, class TOptOutB = std::nullptr_t>
+  size_t unpack(const std::uint16_t subsysid, const fles::Timeslice* ts, std::uint16_t icomp, TConfig config,
+                std::vector<TOptOutA>* optouttargetvecA = nullptr, std::vector<TOptOutB>* optouttargetvecB = nullptr)
+  {
+
+    auto wallstarttime        = std::chrono::high_resolution_clock::now();
+    std::clock_t cpustarttime = std::clock();
+
+    auto algo                        = config->GetUnpacker();
+    std::vector<TOptOutA> optoutAvec = {};
+    std::vector<TOptOutB> optoutBvec = {};
+    if (optouttargetvecA) { algo->SetOptOutAVec(&optoutAvec); }
+    if (optouttargetvecB) { algo->SetOptOutBVec(&optoutBvec); }
+
+    // Set the start time of the current TS for this algorithm
+    algo->SetTsStartTime(ts->start_time());
+
+    // Run the actual unpacking
+    auto digivec = algo->Unpack(ts, icomp);
+
+    // Check if we want to write the output to somewhere (in pure online monitoring mode for example this can/would/should be skipped)
+    if (config->GetOutputVec()) {
+      // Lets do some time-sorting if we are not doing it later
+      if (!fbOutputFullTimeSorting) timesort(&digivec);
+
+      // Transfer the data from the timeslice vector to the target branch vector
+      // Digis/default output retrieved as offered by the algorithm
+      for (auto digi : digivec)
+        config->GetOutputVec()->emplace_back(digi);
+    }
+    if (optouttargetvecA) {
+      // Lets do some timesorting
+      if (!fbOutputFullTimeSorting) timesort(&optoutAvec);
+      // Transfer the data from the timeslice vector to the target branch vector
+      for (auto optoutA : optoutAvec)
+        optouttargetvecA->emplace_back(optoutA);
+    }
+    if (optouttargetvecB) {
+      // Second opt output is not time sorted to allow non GetTime data container.
+      // Lets do some timesorting
+      timesort(&optoutAvec);
+      // Transfer the data from the timeslice vector to the target branch vector
+      for (auto optoutB : optoutBvec)
+        optouttargetvecB->emplace_back(optoutB);
+    }
+
+    std::clock_t cpuendtime = std::clock();
+    auto wallendtime        = std::chrono::high_resolution_clock::now();
+
+    // Cpu time in [µs]
+    auto cputime = 1e6 * (cpuendtime - cpustarttime) / CLOCKS_PER_SEC;
+    algo->AddCpuTime(cputime);
+    // Real time in [µs]
+    auto walltime = std::chrono::duration<double, std::micro>(wallendtime - wallstarttime).count();
+    algo->AddWallTime(walltime);
+
+
+    // Check some numbers from this timeslice
+    size_t nDigis = digivec.size();
+    LOG(debug) << "Component " << icomp << " connected to config " << config->GetName() << "   n-Digis " << nDigis
+               << " processed in walltime(cputime) = " << walltime << "(" << cputime << cputime << ") µs"
+               << "this timeslice.";
+
+    if (fDoPerfProf) {
+      auto timeit = fTimeMap.find(subsysid);
+      timeit->second.first += cputime;
+      timeit->second.second += walltime;
+
+      auto datait = fDataSizeMap.find(subsysid);
+      datait->second.first += ts->size_component(icomp) / 1.0e6;
+      datait->second.second += nDigis * algo->GetOutputObjSize() / 1.0e6;
+
+      fNameMap.find(subsysid)->second.second += nDigis;
+    }
+
+    return nDigis;
+  }
+};
+
+#endif /* CBMDEVICEMCBMUNPACK_H_ */
diff --git a/MQ/mcbm/runUnpack.cxx b/MQ/mcbm/runUnpack.cxx
new file mode 100644
index 0000000000..2eba9e3a9a
--- /dev/null
+++ b/MQ/mcbm/runUnpack.cxx
@@ -0,0 +1,32 @@
+/* Copyright (C) 2021 Facility for Antiproton and Ion Research in Europe, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Pierre-Alain Loizeau [committer] */
+
+#include "CbmDeviceUnpack.h"
+
+#include <iomanip>
+#include <string>
+
+#include "runFairMQDevice.h"
+
+namespace bpo = boost::program_options;
+using namespace std;
+
+void addCustomOptions(bpo::options_description& options)
+{
+  options.add_options()("Setup", bpo::value<std::string>()->default_value("mcbm_beam_2021_07_surveyed"),
+                        "Name/tag of the geomatry setup");
+  options.add_options()("RunId", bpo::value<uint32_t>()->default_value(1588), "Run ID");
+  options.add_options()("IgnOverMs", bpo::value<bool>()->default_value(true), "Ignore overlap MS if true");
+  options.add_options()("FullTimeSort", bpo::value<bool>()->default_value(true),
+                        "Full time sorting per detector before sending output array");
+  options.add_options()("SetTimeOffs", bpo::value<std::vector<std::string>>()->multitoken()->composing(),
+                        "Set time offset in ns for selected detector, use string matching "
+                        "ECbmModuleId,dOffs e.g. kTof,-35.2");
+  options.add_options()("TsNameIn", bpo::value<std::string>()->default_value("fullts"),
+                        "MQ channel name for raw TS data");
+  options.add_options()("TsNameOut", bpo::value<std::string>()->default_value("unpts_0"),
+                        "MQ channel name for unpacked TS data");
+}
+
+FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) { return new CbmDeviceUnpack(); }
diff --git a/core/data/CbmTsEventHeader.h b/core/data/CbmTsEventHeader.h
index 932e2c8d0e..32e1a72c62 100644
--- a/core/data/CbmTsEventHeader.h
+++ b/core/data/CbmTsEventHeader.h
@@ -71,6 +71,10 @@ public:
   /** @brief Set the Ts Start Time @param value Start time of the TS */
   void SetTsStartTime(uint64_t value) { fTsStartTime = value; }
 
+
+  CbmTsEventHeader(const CbmTsEventHeader&) = default;
+  CbmTsEventHeader& operator=(const CbmTsEventHeader&) = default;
+
 protected:
   /** Timeslice index */
   uint64_t fTsIndex = 0;
diff --git a/reco/base/CbmRecoUnpackConfig.tmpl b/reco/base/CbmRecoUnpackConfig.tmpl
index 421c709ec8..5ebb830407 100644
--- a/reco/base/CbmRecoUnpackConfig.tmpl
+++ b/reco/base/CbmRecoUnpackConfig.tmpl
@@ -8,15 +8,12 @@
  * @brief Configuration class for an unpacker algorithm
  * @version 0.1
  * @date 2021-04-21
- * 
+ *
  * @copyright Copyright (c) 2021
- * 
- * This is the common steering task to run unpacking processes in a FairRun for the 
- * CbmTrd.
- * 
- * 
- * 
- * 
+ *
+ * This is the common steering task to run unpacking processes in a FairRun for the
+ * CBM detectors.
+ *
 */
 
 #ifndef CbmRecoUnpackConfig_tmpl
@@ -25,7 +22,7 @@
 #include "CbmRecoUnpackAlgo.tmpl"
 
 #include <FairLogger.h>
-#include <FairParAsciiFileIo.h>
+//#include <FairParAsciiFileIo.h>
 #include <FairRootManager.h>
 #include <Logger.h>
 
@@ -43,11 +40,14 @@ public:
   /**
    * @brief Create a Cbm Reco Unpack Config object
   */
-  CbmRecoUnpackConfig(std::string name) : fName(name) {};
+  CbmRecoUnpackConfig(std::string name, std::string detGeoSetupTag, UInt_t runid) :
+    fName(name)
+    , fGeoSetupTag(detGeoSetupTag)
+    , fRunId(runid) {};
 
   /**
    * @brief Destroy the Cbm Trd Unpack Task object
-   * 
+   *
   */
   virtual ~CbmRecoUnpackConfig() {};
 
@@ -86,6 +86,12 @@ protected:
   /** @brief Name of the (derived) class for debugging statements */
   std::string fName = "";
 
+  /** @brief Geometry setup tag for the given detector as used by CbmSetup objects */
+  std::string fGeoSetupTag = "";
+
+  /** @brief RunId of the current run, if not known 0 is a valid runtime case. Used runId based parameter loading. */
+  UInt_t fRunId = 0;
+
   /** @brief Do debug printouts. Call SetDebugState() to activate*/
   bool fDoLog = false;
 
@@ -107,6 +113,9 @@ protected:
   */
   int32_t fSystemTimeOffset = 0;
 
+  /** @brief Flag to control whether the unpacker algo ignores the overlapp microslices (if true).*/
+  bool fDoIgnoreOverlappMs = true;
+
   /** @brief Use this function to implement additional actions to be called once per TS, e.g. needed if more than the default output vector is used. */
   virtual void reset() { return; };
 
@@ -115,85 +124,158 @@ public:
   // Getters
   /**
    * @brief Get the Output Branch Name
-   * 
-   * @return std::string 
+   *
+   * @return std::string
   */
   std::string GetOutputBranchName() { return fOutputBranchName.empty() ? TOutput::GetBranchName() : fOutputBranchName; }
 
+  /**
+   * @brief Get the Output Branch Name
+   *
+   * @return std::string
+  */
+  std::string GetOutputBranchNameOptA() { return fOptoutABranchName; }
+
+  /**
+   * @brief Get the Output Branch Name
+   *
+   * @return std::string
+  */
+  std::string GetOutputBranchNameOptB() { return fOptoutBBranchName; }
+
   /** @brief Get the name of the given derived config */
   std::string GetName() { return fName; }
 
   /**
    * @brief Get a given output vector connected to the tree, if called after calling InitUnpacker().
-   * 
-   * @return std::vector<TOutput>* 
+   *
+   * @return std::vector<TOutput>*
   */
   std::vector<TOutput>* GetOutputVec() { return fOutputVec; }
 
   /**
    * @brief Get a given output vector connected to the tree, if called after calling InitUnpacker().
-   * 
-   * @return std::vector<TOptOutA>* 
+   *
+   * @return std::vector<TOptOutA>*
   */
   std::vector<TOptOutA>* GetOptOutAVec() { return fOptOutAVec; }
 
   /**
    * @brief Get a given output vector connected to the tree, if called after calling InitUnpacker().
-   * 
-   * @return std::vector<TOptOutA>* 
+   *
+   * @return std::vector<TOptOutA>*
   */
   std::vector<TOptOutB>* GetOptOutBVec() { return fOptOutBVec; }
 
   /**
    * @brief Get the ready to run Unpacker. To be defined in the derived classes.
    * In this function also all initialization steps of the unpacker algorithms have to happen.
-   * @return std::shared_ptr<CbmRecoUnpackAlgo> 
+   * @return std::shared_ptr<CbmRecoUnpackAlgo>
   */
   std::shared_ptr<CbmRecoUnpackAlgo<TOutput, TOptOutA, TOptOutB>> GetUnpacker() { return fAlgo; };
 
+  /**
+   * @brief Get the requested parameter containers from the Algo.
+   * Return the required parameter containers together with the paths to the ascii
+   * files to.
+   * @return fParContVec
+  */
+  virtual std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>*
+    GetParContainerRequest()
+  {
+    if(fAlgo) return fAlgo->GetParContainerRequest(fGeoSetupTag, fRunId);
+    else return {};
+  }
+
   /**
    * @brief Init function of the configs to be called by CbmRecoUnpack()
    * Initializes the output branches and calls InitUnpacker()
    * @param ioman Pointer to the FairRootManager instance
    * @param branchname by default TOutput::GetBranchName() is used for the first output. If branchname is not empty that branchname is used.
   */
-  void Init(FairRootManager* ioman)
+  void InitOutput()
   {
     LOG(info) << fName << "::Init() ---------------------------------";
 
     if (fDoWriteOutput) {
-
       fOutputVec = new std::vector<TOutput>();
-      ioman->RegisterAny(GetOutputBranchName().data(), fOutputVec, kTRUE);
-      LOG(info) << fName << "::registerBranchToTree(" << GetOutputBranchName().data() << ")";
+      LOG(info) << fName << "::InitOutput(" << GetOutputBranchName().data() << ")";
     }
 
     /** @todo for the optional outputs it is more complicated to check if they exist. Needs exceptions for the std::nullptr_t. Should be added at some point in time. */
     if (fDoWriteOptOutA) {
       if (!fOptOutAVec) {
         fOptOutAVec = new std::vector<TOptOutA>();
-        ioman->RegisterAny(fOptoutABranchName.data(), fOptOutAVec, kTRUE);
-        LOG(info) << fName << "::registerBranchToTree(" << fOptoutABranchName.data() << ")";
+        LOG(info) << fName << "::InitOutput(" << fOptoutABranchName.data() << ")";
       }
     }
 
     if (fDoWriteOptOutB) {
       fOptOutBVec = new std::vector<TOptOutB>();
+      LOG(info) << fName << "::InitOutput(" << fOptoutBBranchName.data() << ")";
+    }
+  }
+
+  /**
+   * @brief Register the output vectors (if needed) to the FairRoot Manager)
+   * FIXME: To be removed with the Manager include whenever the similar code in the CbmRecoUnpack task work as expected
+   *
+  */
+  void RegisterOutput(FairRootManager* ioman)
+  {
+    if (fDoWriteOutput && fOutputVec) {
+      ioman->RegisterAny(GetOutputBranchName().data(), fOutputVec, kTRUE);
+      LOG(info) << fName << "::registerBranchToTree(" << GetOutputBranchName().data() << ")";
+    }
+
+    /** @todo for the optional outputs it is more complicated to check if they exist. Needs exceptions for the std::nullptr_t. Should be added at some point in time. */
+    if (fDoWriteOptOutA && fOptOutAVec) {
+      ioman->RegisterAny(fOptoutABranchName.data(), fOptOutAVec, kTRUE);
+      LOG(info) << fName << "::registerBranchToTree(" << fOptoutABranchName.data() << ")";
+    }
+
+    if (fDoWriteOptOutB && fOptOutBVec) {
       ioman->RegisterAny(fOptoutBBranchName.data(), fOptOutBVec, kTRUE);
       LOG(info) << fName << "::registerBranchToTree(" << fOptoutBBranchName.data() << ")";
     }
+  }
 
-    // Init the unpacker
-    InitUnpacker();
+  /**
+   * @brief Setup the derived unpacker algorithm to be used for the DAQ output to Digi translation.
+   * Can be re-implemented in the derived classes if more than the Algo choice and path setting needs to be done before getting the Parameters
+   *
+  */
+  virtual void SetAlgo()
+  {
+    LOG(info) << fName << "::SetAlgo -";
+
+    // First choose the derived unpacking algorithm to be used
+    // TODO: To avoid having to check if the pointer is assigned nultiples times, an exception
+    // should be thrown in case of failure
+    fAlgo = chooseAlgo();
+
+    if (fDoLog) LOG(info) << fName << "::SetAlgo - SetParFilesBasePath";
+    fAlgo->SetParFilesBasePath(fParFilesBasePath);
 
     // Set the global system time offset
-    if (fAlgo) fAlgo->SetSystemTimeOffset(fSystemTimeOffset);
+    if (fDoLog) LOG(info) << fName << "::SetAlgo - SetSystemTimeOffset";
+    fAlgo->SetSystemTimeOffset(fSystemTimeOffset);
 
-    LOG(info) << fName << " succesful initialized -----------------\n";
+    // Set the flag controlling the overlap ignore
+    if (fDoLog) LOG(info) << fName << "::SetAlgo - SetDoIgnoreOverlappMs";
+    fAlgo->SetDoIgnoreOverlappMs(fDoIgnoreOverlappMs);
   }
 
-  /** @brief Prepare the Unpacker algorithm for the run, to be implemented in the derived classes. */
-  virtual void InitUnpacker() {};
+  /**
+   * @brief Initialize the algorithm, should include all steps needing te parameter objects to be present.
+   * To be re-implemented in the derived classes if not all settings in parameter classes.
+   *
+  */
+  virtual void InitAlgo()
+  {
+    // Now we have all information required to initialise the algorithm
+    fAlgo->Init();
+  }
 
   /** @brief Reset called once per ReadEvent() */
   void Reset()
@@ -215,16 +297,16 @@ public:
 
   /**
    * @brief Set the Output Branch Name
-   * By default TOutput::GetBranchName() is used. Set this if you want to use a 
+   * By default TOutput::GetBranchName() is used. Set this if you want to use a
    * different output name
-   * @param value 
+   * @param value
   */
   void SetOutputBranchName(std::string value) { fOutputBranchName = value; }
 
   /**
    * @brief Set the Do Write OptOutput A flag, without activation the opt out is not written to the sink
-   * @param branchname name of the branch in the output tree 
-   * @param value bool 
+   * @param branchname name of the branch in the output tree
+   * @param value bool
    */
   void SetDoWriteOptOutA(std::string branchname, bool value = true)
   {
@@ -234,8 +316,8 @@ public:
 
   /**
    * @brief Set the Do Write OptOutput B flag, without activation the opt out is not written to the sink
-   * @param branchname name of the branch in the output tree 
-   * @param value bool 
+   * @param branchname name of the branch in the output tree
+   * @param value bool
    */
   void SetDoWriteOptOutB(std::string branchname, bool value = true)
   {
@@ -245,61 +327,47 @@ public:
 
   /**
    * @brief Set the Debug State, influences the log messages.
-   * 
-   * @param value 
+   *
+   * @param value
   */
   void SetDebugState(bool value = true) { fDoLog = value; }
 
   /**
    * @brief Set the is MC flag. Activates the Match branch.
-   * 
+   *
    * @param value
   */
   void SetIsMC(bool value = true) { fIsMC = value; }
 
   /**
    * @brief Set the Output Vec
-   * 
-   * @tparam Output 
-   * @param value 
+   *
+   * @tparam Output
+   * @param value
   */
   void SetOutputVec(std::vector<TOutput>* value) { fOutputVec = value; }
 
   /**
    * @brief Set the Par Files Base Path (absolute directory path were the files are stored)
-   * 
-   * @param value 
+   *
+   * @param value
   */
   void SetParFilesBasePath(std::string value) { fParFilesBasePath = value; }
 
   /** @brief Set the global system time offset @remark in princible this should go to parameters */
   void SetSystemTimeOffset(int32_t value) { fSystemTimeOffset = value; }
 
+  /** @brief Set the value of the flag to ignore the overlap microslices @remark in princible this should go to parameters */
+  void SetDoIgnoreOverlappMs(bool value = false) { fDoIgnoreOverlappMs = value; }
+
 protected:
   /**
-   * @brief Initialise the parameter containers requested by the algorithm
-   * 
-   * @return Bool_t initOk 
+   * @brief Choose the derived unpacker algorithm to be used for the DAQ output to Digi translation. If algo was already set manually by the user this algorithm is used.
+   * To be implemented in the derived classes
+   *
+   * @return std::shared_ptr<TAlgo>
   */
-  virtual Bool_t initParContainers(std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>* reqparvec)
-  {
-    if (fDoLog) LOG(info) << GetName() << "::Init - initParContainers";
-    if (!reqparvec) {
-      LOG(info) << GetName() << "::Init - initParContainers - empty requirements vector no parameters initialized.";
-      return kTRUE;
-    }
-
-    // Now get the actual ascii files and init the containers with the asciiIo
-    for (auto& pair : *reqparvec) {
-      auto filepath = pair.first;
-      auto parset   = pair.second;
-      FairParAsciiFileIo asciiInput;
-      if (!filepath.empty()) {
-        if (asciiInput.open(filepath.data())) { parset->init(&asciiInput); }
-      }
-    }
-    return kTRUE;
-  }
+  virtual std::shared_ptr<TAlgo> chooseAlgo() = 0;
 };
 
 
diff --git a/reco/detectors/psd/unpack/CbmPsdUnpackConfig.cxx b/reco/detectors/psd/unpack/CbmPsdUnpackConfig.cxx
index 8407d4fccc..4c6a90fd52 100644
--- a/reco/detectors/psd/unpack/CbmPsdUnpackConfig.cxx
+++ b/reco/detectors/psd/unpack/CbmPsdUnpackConfig.cxx
@@ -15,37 +15,13 @@
 #include <vector>
 
 CbmPsdUnpackConfig::CbmPsdUnpackConfig(std::string detGeoSetupTag, UInt_t runid)
-  : CbmRecoUnpackConfig("CbmPsdUnpackConfig")
-  , fGeoSetupTag(detGeoSetupTag)
-  , fRunId(runid)
+  : CbmRecoUnpackConfig("CbmPsdUnpackConfig", detGeoSetupTag, runid)
 {
 }
 
 CbmPsdUnpackConfig::~CbmPsdUnpackConfig() {}
 
 // ---- Init ----
-void CbmPsdUnpackConfig::InitUnpacker()
-{
-  LOG(info) << fName << "::Init -";
-
-  auto initOk = kTRUE;
-
-  // First choose the derived unpacking algorithm to be used and pass the raw to digi method
-  auto algo = chooseAlgo();
-
-  if (fDoLog) LOG(info) << fName << "::Init - SetParFilesBasePath";
-  algo->SetParFilesBasePath(fParFilesBasePath);
-
-  // Initialise the parameter containers required by the unpacker algo. Includes loading the corresponding ascii files
-  auto reqparvec = algo->GetParContainerRequest(fGeoSetupTag, fRunId);
-  initOk &= initParContainers(reqparvec);
-
-  // Now we have all information required to initialise the algorithm
-  algo->Init();
-
-  // Pass the algo to its member in the base class
-  fAlgo = algo;
-}
 
 // ---- chooseAlgo ----
 std::shared_ptr<CbmPsdUnpackAlgo> CbmPsdUnpackConfig::chooseAlgo()
diff --git a/reco/detectors/psd/unpack/CbmPsdUnpackConfig.h b/reco/detectors/psd/unpack/CbmPsdUnpackConfig.h
index 34fcac3e26..19fcf86072 100644
--- a/reco/detectors/psd/unpack/CbmPsdUnpackConfig.h
+++ b/reco/detectors/psd/unpack/CbmPsdUnpackConfig.h
@@ -8,11 +8,11 @@
  * @brief Configuration class for an unpacker algorithm
  * @version 0.1
  * @date 2021-04-21
- * 
+ *
  * @copyright Copyright (c) 2021
- * 
+ *
  * This is the common configuration class for unpacking algorithms
- * 
+ *
 */
 
 #ifndef CbmPsdUnpackConfig_H
@@ -38,7 +38,7 @@ class CbmPsdUnpackConfig : public CbmRecoUnpackConfig<CbmPsdUnpackAlgo, CbmPsdDi
 public:
   /**
    * @brief Create the Cbm Trd Unpack Task object
-   * 
+   *
    * @param geoSetupTag Geometry setup tag for the given detector as used by CbmSetup objects
    * @param runid set if unpacker is rerun on a special run with special parameters
    *@remark We use the string instead of CbmSetup here, to not having to link against sim/steer...
@@ -47,7 +47,7 @@ public:
 
   /**
    * @brief Destroy the Cbm Trd Unpack Task object
-   * 
+   *
   */
   virtual ~CbmPsdUnpackConfig();
 
@@ -60,30 +60,18 @@ public:
   // Getters
 
 
-  /**
-   * @brief Prepare the unpacker to be ready to run.
-   * In this function all initialization steps of the unpacker algorithms happen.
-  */
-  void InitUnpacker();
-
   // Setters
 
 protected:
   /**
    * @brief Choose the derived unpacker algorithm to be used for the DAQ output to Digi translation. If algo was already set manually by the user this algorithm is used.
-   * 
-   * @return Bool_t initOk 
+   *
+   * @return Bool_t initOk
   */
   virtual std::shared_ptr<CbmPsdUnpackAlgo> chooseAlgo();
 
-  /** @brief Geometry setup tag for the given detector as used by CbmSetup objects */
-  std::string fGeoSetupTag = "";
-
-  /** @brief RunId of the current run, if not known 0 is a valid runtime case. Used runId based parameter loading. */
-  UInt_t fRunId = 0;
-
 private:
-  ClassDef(CbmPsdUnpackConfig, 2)
+  ClassDef(CbmPsdUnpackConfig, 3)
 };
 
 #endif  // CbmPsdUnpackConfig_H
diff --git a/reco/detectors/rich/unpack/CbmRichUnpackConfig.cxx b/reco/detectors/rich/unpack/CbmRichUnpackConfig.cxx
index 94e8df82a3..a2d2700dcf 100644
--- a/reco/detectors/rich/unpack/CbmRichUnpackConfig.cxx
+++ b/reco/detectors/rich/unpack/CbmRichUnpackConfig.cxx
@@ -15,39 +15,20 @@
 #include <vector>
 
 CbmRichUnpackConfig::CbmRichUnpackConfig(std::string detGeoSetupTag, UInt_t runid)
-  : CbmRecoUnpackConfig("CbmRichUnpackConfig")
-  , fGeoSetupTag(detGeoSetupTag)
-  , fRunId(runid)
+  : CbmRecoUnpackConfig("CbmRichUnpackConfig", detGeoSetupTag, runid)
 {
 }
 
 CbmRichUnpackConfig::~CbmRichUnpackConfig() {}
 
 // ---- Init ----
-void CbmRichUnpackConfig::InitUnpacker()
+void CbmRichUnpackConfig::InitAlgo()
 {
-  LOG(info) << fName << "::Init -";
-
-  auto initOk = kTRUE;
-
-  // First choose the derived unpacking algorithm to be used and pass the raw to digi method
-  auto algo = chooseAlgo();
-
-  if (fDoLog) LOG(info) << fName << "::Init - SetParFilesBasePath";
-  algo->SetParFilesBasePath(fParFilesBasePath);
-
   if (fDoLog) LOG(info) << fName << "::Init - SetMaskedDiRICHes";
-  algo->SetMaskedDiRICHes(&fMaskedDiRICHes);
-
-  // Initialise the parameter containers required by the unpacker algo. Includes loading the corresponding ascii files
-  auto reqparvec = algo->GetParContainerRequest(fGeoSetupTag, fRunId);
-  initOk &= initParContainers(reqparvec);
+  fAlgo->SetMaskedDiRICHes(&fMaskedDiRICHes);
 
   // Now we have all information required to initialise the algorithm
-  algo->Init();
-
-  // Pass the algo to its member in the base class
-  fAlgo = algo;
+  fAlgo->Init();
 }
 
 // ---- chooseAlgo ----
diff --git a/reco/detectors/rich/unpack/CbmRichUnpackConfig.h b/reco/detectors/rich/unpack/CbmRichUnpackConfig.h
index 0f57445a5c..f73bd36f95 100644
--- a/reco/detectors/rich/unpack/CbmRichUnpackConfig.h
+++ b/reco/detectors/rich/unpack/CbmRichUnpackConfig.h
@@ -8,11 +8,11 @@
  * @brief Configuration class for an unpacker algorithm
  * @version 0.1
  * @date 2021-04-21
- * 
+ *
  * @copyright Copyright (c) 2021
- * 
+ *
  * This is the common configuration class for unpacking algorithms
- * 
+ *
 */
 
 #ifndef CbmRichUnpackConfig_H
@@ -38,7 +38,7 @@ class CbmRichUnpackConfig : public CbmRecoUnpackConfig<CbmRichUnpackAlgo, CbmRic
 public:
   /**
    * @brief Create the Cbm Trd Unpack Task object
-   * 
+   *
    * @param geoSetupTag Geometry setup tag for the given detector as used by CbmSetup objects
    * @param runid set if unpacker is rerun on a special run with special parameters
    *@remark We use the string instead of CbmSetup here, to not having to link against sim/steer...
@@ -47,7 +47,7 @@ public:
 
   /**
    * @brief Destroy the Cbm Trd Unpack Task object
-   * 
+   *
   */
   virtual ~CbmRichUnpackConfig();
 
@@ -61,10 +61,10 @@ public:
 
 
   /**
-   * @brief Prepare the unpacker to be ready to run.
-   * In this function all initialization steps of the unpacker algorithms happen.
+   * @brief Initialize the algorithm, should include all steps needing te parameter objects to be present.
+   * In this function most initialization steps of the unpacker algorithms happen.
   */
-  void InitUnpacker();
+  void InitAlgo();
 
   // Setters
 
@@ -73,21 +73,15 @@ public:
 protected:
   /**
    * @brief Choose the derived unpacker algorithm to be used for the DAQ output to Digi translation. If algo was already set manually by the user this algorithm is used.
-   * 
-   * @return Bool_t initOk 
+   *
+   * @return Bool_t initOk
   */
   virtual std::shared_ptr<CbmRichUnpackAlgo> chooseAlgo();
 
-  /** @brief Geometry setup tag for the given detector as used by CbmSetup objects */
-  std::string fGeoSetupTag = "";
-
-  /** @brief RunId of the current run, if not known 0 is a valid runtime case. Used runId based parameter loading. */
-  UInt_t fRunId = 0;
-
-  std::vector<Int_t> fMaskedDiRICHes;
+  std::vector<Int_t> fMaskedDiRICHes = {};
 
 private:
-  ClassDef(CbmRichUnpackConfig, 2)
+  ClassDef(CbmRichUnpackConfig, 3)
 };
 
 #endif  // CbmRichUnpackConfig_H
diff --git a/reco/detectors/sts/unpack/CbmStsUnpackAlgo.cxx b/reco/detectors/sts/unpack/CbmStsUnpackAlgo.cxx
index 27f212776a..4a0f00e707 100644
--- a/reco/detectors/sts/unpack/CbmStsUnpackAlgo.cxx
+++ b/reco/detectors/sts/unpack/CbmStsUnpackAlgo.cxx
@@ -231,6 +231,8 @@ Bool_t CbmStsUnpackAlgo::initParSet(CbmMcbm2018StsPar* parset)
   LOG(debug) << "Unpacking data in bin sorter FW mode";
   initInternalStatus(parset);
 
+  if (fMonitor) fMonitor->Init(parset);
+
   return kTRUE;
 }
 
diff --git a/reco/detectors/sts/unpack/CbmStsUnpackAlgoLegacy.cxx b/reco/detectors/sts/unpack/CbmStsUnpackAlgoLegacy.cxx
index 097ceecedd..20c411571a 100644
--- a/reco/detectors/sts/unpack/CbmStsUnpackAlgoLegacy.cxx
+++ b/reco/detectors/sts/unpack/CbmStsUnpackAlgoLegacy.cxx
@@ -93,6 +93,9 @@ Bool_t CbmStsUnpackAlgoLegacy::initParSet(CbmMcbm2018StsPar* parset)
 {
   fUnpackPar  = parset;
   bool initOK = InitParameters();
+
+  if (fMonitor) initOK &= fMonitor->Init(parset);
+
   return initOK;
 }
 
diff --git a/reco/detectors/sts/unpack/CbmStsUnpackConfig.cxx b/reco/detectors/sts/unpack/CbmStsUnpackConfig.cxx
index e2ce1e5526..b6c7be4c22 100644
--- a/reco/detectors/sts/unpack/CbmStsUnpackConfig.cxx
+++ b/reco/detectors/sts/unpack/CbmStsUnpackConfig.cxx
@@ -16,59 +16,37 @@
 #include <vector>
 
 CbmStsUnpackConfig::CbmStsUnpackConfig(std::string detGeoSetupTag, UInt_t runid)
-  : CbmRecoUnpackConfig("CbmStsUnpackConfig")
-  , fGeoSetupTag(detGeoSetupTag)
-  , fRunId(runid)
+  : CbmRecoUnpackConfig("CbmStsUnpackConfig", detGeoSetupTag, runid)
 {
 }
 
 CbmStsUnpackConfig::~CbmStsUnpackConfig() {}
 
 // ---- Init ----
-void CbmStsUnpackConfig::InitUnpacker()
+void CbmStsUnpackConfig::InitAlgo()
 {
-  LOG(info) << fName << "::Init -";
-
-  auto initOk = kTRUE;
-
-  // First choose the derived unpacking algorithm to be used and pass the raw to digi method
-  auto algo = chooseAlgo();
-
-  if (fDoLog) LOG(info) << fName << "::Init - SetParFilesBasePath";
-  algo->SetParFilesBasePath(fParFilesBasePath);
-
-  // Initialise the parameter containers required by the unpacker algo. Includes loading the corresponding ascii files
-  auto reqparvec = algo->GetParContainerRequest(fGeoSetupTag, fRunId);
-  initOk &= initParContainers(reqparvec);
-
   // Set the minimum adc cut
-  algo->SetMinAdcCut(fdAdcCut);
+  fAlgo->SetMinAdcCut(fdAdcCut);
 
   // Set the minimum adc cut Feb independent
   for (auto cut = fdAdcCut_perFeb.begin(); cut != fdAdcCut_perFeb.end(); cut++) {
-    algo->SetMinAdcCut(cut->first, cut->second);
+    fAlgo->SetMinAdcCut(cut->first, cut->second);
   }
 
   // Set the single asics time offsets
-  algo->SetAsicTimeOffsetVec(fvdTimeOffsetNsAsics);
+  fAlgo->SetAsicTimeOffsetVec(fvdTimeOffsetNsAsics);
 
   // Set the flags for duplicate digis rejections
-  algo->SetDuplicatesRejection(fbRejectDuplicateDigis, fbDupliWithoutAdc);
+  fAlgo->SetDuplicatesRejection(fbRejectDuplicateDigis, fbDupliWithoutAdc);
+
+  if (fMonitor) { fAlgo->SetMonitor(fMonitor); }
 
   // Now we have all information required to initialise the algorithm
-  algo->Init();
+  fAlgo->Init();
 
   // Mask the noisy channels set by the user
   for (auto chmask : fvChanMasks)
-    algo->MaskNoisyChannel(chmask.uFeb, chmask.uChan, chmask.bMasked);
-
-  if (fMonitor) {
-    fMonitor->Init(static_cast<CbmMcbm2018StsPar*>(reqparvec->at(0).second.get()));
-    algo->SetMonitor(fMonitor);
-  }
-
-  // Pass the algo to its member in the base class
-  fAlgo = algo;
+    fAlgo->MaskNoisyChannel(chmask.uFeb, chmask.uChan, chmask.bMasked);
 }
 
 // ---- chooseAlgo ----
diff --git a/reco/detectors/sts/unpack/CbmStsUnpackConfig.h b/reco/detectors/sts/unpack/CbmStsUnpackConfig.h
index d116e3f23d..d71c152a64 100644
--- a/reco/detectors/sts/unpack/CbmStsUnpackConfig.h
+++ b/reco/detectors/sts/unpack/CbmStsUnpackConfig.h
@@ -70,10 +70,10 @@ public:
   std::shared_ptr<CbmStsUnpackMonitor> GetMonitor() { return fMonitor; }
 
   /**
-   * @brief Prepare the unpacker to be ready to run.
-   * In this function all initialization steps of the unpacker algorithms happen.
+   * @brief Initialize the algorithm, should include all steps needing te parameter objects to be present.
+   * In this function most initialization steps of the unpacker algorithms happen.
   */
-  void InitUnpacker();
+  void InitAlgo();
 
   void MaskNoisyChannel(UInt_t uFeb, UInt_t uChan, Bool_t bMasked = kTRUE)
   {
@@ -138,14 +138,8 @@ protected:
   /// Temporary storage of user parameters
   std::vector<FebChanMaskReco> fvChanMasks = {};
 
-  /** @brief Geometry setup tag for the given detector as used by CbmSetup objects */
-  std::string fGeoSetupTag = "";
-
-  /** @brief RunId of the current run, if not known 0 is a valid runtime case. Used runId based parameter loading. */
-  UInt_t fRunId = 0;
-
 private:
-  ClassDef(CbmStsUnpackConfig, 2)
+  ClassDef(CbmStsUnpackConfig, 3)
 };
 
 #endif  // CbmStsUnpackConfig_H
diff --git a/reco/detectors/tof/unpack/CbmTofUnpackConfig.cxx b/reco/detectors/tof/unpack/CbmTofUnpackConfig.cxx
index 1bb23b5d92..a2a4d239c6 100644
--- a/reco/detectors/tof/unpack/CbmTofUnpackConfig.cxx
+++ b/reco/detectors/tof/unpack/CbmTofUnpackConfig.cxx
@@ -15,37 +15,13 @@
 #include <vector>
 
 CbmTofUnpackConfig::CbmTofUnpackConfig(std::string detGeoSetupTag, UInt_t runid)
-  : CbmRecoUnpackConfig("CbmTofUnpackConfig")
-  , fGeoSetupTag(detGeoSetupTag)
-  , fRunId(runid)
+  : CbmRecoUnpackConfig("CbmTofUnpackConfig", detGeoSetupTag, runid)
 {
 }
 
 CbmTofUnpackConfig::~CbmTofUnpackConfig() {}
 
 // ---- Init ----
-void CbmTofUnpackConfig::InitUnpacker()
-{
-  LOG(info) << fName << "::Init -";
-
-  auto initOk = kTRUE;
-
-  // First choose the derived unpacking algorithm to be used and pass the raw to digi method
-  auto algo = chooseAlgo();
-
-  if (fDoLog) LOG(info) << fName << "::Init - SetParFilesBasePath";
-  algo->SetParFilesBasePath(fParFilesBasePath);
-
-  // Initialise the parameter containers required by the unpacker algo. Includes loading the corresponding ascii files
-  auto reqparvec = algo->GetParContainerRequest(fGeoSetupTag, fRunId);
-  initOk &= initParContainers(reqparvec);
-
-  // Now we have all information required to initialise the algorithm
-  algo->Init();
-
-  // Pass the algo to its member in the base class
-  fAlgo = algo;
-}
 
 // ---- chooseAlgo ----
 std::shared_ptr<CbmTofUnpackAlgo> CbmTofUnpackConfig::chooseAlgo()
diff --git a/reco/detectors/tof/unpack/CbmTofUnpackConfig.h b/reco/detectors/tof/unpack/CbmTofUnpackConfig.h
index fae84af847..4589a7bf8f 100644
--- a/reco/detectors/tof/unpack/CbmTofUnpackConfig.h
+++ b/reco/detectors/tof/unpack/CbmTofUnpackConfig.h
@@ -61,12 +61,6 @@ public:
   // Getters
 
 
-  /**
-   * @brief Prepare the unpacker to be ready to run.
-   * In this function all initialization steps of the unpacker algorithms happen.
-  */
-  void InitUnpacker();
-
   // Setters
 
 protected:
@@ -77,12 +71,6 @@ protected:
   */
   virtual std::shared_ptr<CbmTofUnpackAlgo> chooseAlgo();
 
-  /** @brief Geometry setup tag for the given detector as used by CbmSetup objects */
-  std::string fGeoSetupTag = "";
-
-  /** @brief RunId of the current run, if not known 0 is a valid runtime case. Used runId based parameter loading. */
-  UInt_t fRunId = 0;
-
 private:
   ClassDef(CbmTofUnpackConfig, 1)
 };
diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackConfig.cxx b/reco/detectors/trd/unpack/CbmTrdUnpackConfig.cxx
index ef89941f4d..2048fff829 100644
--- a/reco/detectors/trd/unpack/CbmTrdUnpackConfig.cxx
+++ b/reco/detectors/trd/unpack/CbmTrdUnpackConfig.cxx
@@ -16,21 +16,17 @@
 #include <vector>
 
 CbmTrdUnpackConfig::CbmTrdUnpackConfig(std::string detGeoSetupTag, UInt_t runid)
-  : CbmRecoUnpackConfig("CbmTrdUnpackConfig")
-  , fGeoSetupTag(detGeoSetupTag)
-  , fRunId(runid)
+  : CbmRecoUnpackConfig("CbmTrdUnpackConfig", detGeoSetupTag, runid)
 {
 }
 
 CbmTrdUnpackConfig::~CbmTrdUnpackConfig() {}
 
 // ---- Init ----
-void CbmTrdUnpackConfig::InitUnpacker()
+void CbmTrdUnpackConfig::SetAlgo()
 {
   LOG(info) << fName << "::Init -";
 
-  auto initOk = kTRUE;
-
   // First choose the derived unpacking algorithm to be used and pass the raw to digi method
   auto algo = chooseAlgo();
 
@@ -49,13 +45,6 @@ void CbmTrdUnpackConfig::InitUnpacker()
   // If we have a monitor in the config add it to the algo
   if (fMonitor) algo->SetMonitor(fMonitor);
 
-  // Initialise the parameter containers required by the unpacker algo. Includes loading the corresponding ascii files
-  auto reqparvec = algo->GetParContainerRequest(fGeoSetupTag, fRunId);
-  initOk &= initParContainers(reqparvec);
-
-  // Now we have all information required to initialise the algorithm
-  algo->Init();
-
   // Pass the algo to its member in the base class
   fAlgo = algo;
 }
diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackConfig.h b/reco/detectors/trd/unpack/CbmTrdUnpackConfig.h
index a17e5c289d..0a8e96d553 100644
--- a/reco/detectors/trd/unpack/CbmTrdUnpackConfig.h
+++ b/reco/detectors/trd/unpack/CbmTrdUnpackConfig.h
@@ -8,11 +8,11 @@
  * @brief Configuration class for an unpacker algorithm
  * @version 0.1
  * @date 2021-04-21
- * 
+ *
  * @copyright Copyright (c) 2021
- * 
+ *
  * This is the common configuration class for unpacking algorithms
- * 
+ *
 */
 
 #ifndef CbmTrdUnpackConfig_H
@@ -42,7 +42,7 @@ class CbmTrdUnpackConfig :
 public:
   /**
    * @brief Create the Cbm Trd Unpack Task object
-   * 
+   *
    * @param geoSetupTag Geometry setup tag for the given detector as used by CbmSetup objects
    * @param runid set if unpacker is rerun on a special run with special parameters
    *@remark We use the string instead of CbmSetup here, to not having to link against sim/steer...
@@ -51,7 +51,7 @@ public:
 
   /**
    * @brief Destroy the Cbm Trd Unpack Task object
-   * 
+   *
   */
   virtual ~CbmTrdUnpackConfig();
 
@@ -69,10 +69,11 @@ public:
   std::shared_ptr<CbmTrdSpadic> GetSpadicObject() { return fSpadic; }
 
   /**
-   * @brief Prepare the unpacker to be ready to run.
-   * In this function all initialization steps of the unpacker algorithms happen.
+   * @brief Setup the derived unpacker algorithm to be used for the DAQ output to Digi translation.
+   * Re-implementing because the Monitor has to be set before requesting parameter objects
+   *
   */
-  void InitUnpacker();
+  void SetAlgo();
 
   // Setters
 
@@ -81,23 +82,23 @@ public:
 
   /**
    * @brief Set the raw to digi method
-   * 
-   * @param value 
+   *
+   * @param value
   */
   void SetRawToDigiMethod(std::shared_ptr<CbmTrdRawToDigiBaseR> value) { fRTDMethod = value; }
 
   /**
    * @brief Set the Spadic Object
-   * 
-   * @param value 
+   *
+   * @param value
   */
   void SetSpadicObject(std::shared_ptr<CbmTrdSpadic> value) { fSpadic = value; }
 
 protected:
   /**
    * @brief Choose the derived unpacker algorithm to be used for the DAQ output to Digi translation. If algo was already set manually by the user this algorithm is used.
-   * 
-   * @return Bool_t initOk 
+   *
+   * @return Bool_t initOk
   */
   virtual std::shared_ptr<CbmTrdUnpackAlgoBaseR> chooseAlgo();
 
@@ -110,14 +111,8 @@ protected:
   /** @brief pointer to the monitor object */
   std::shared_ptr<CbmTrdUnpackMonitor> fMonitor = nullptr;
 
-  /** @brief Geometry setup tag for the given detector as used by CbmSetup objects */
-  std::string fGeoSetupTag = "";
-
-  /** @brief RunId of the current run, if not known 0 is a valid runtime case. Used runId based parameter loading. */
-  UInt_t fRunId = 0;
-
 private:
-  ClassDef(CbmTrdUnpackConfig, 2)
+  ClassDef(CbmTrdUnpackConfig, 3)
 };
 
 #endif  // CbmTrdUnpackConfig_H
diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackConfigFasp2D.cxx b/reco/detectors/trd/unpack/CbmTrdUnpackConfigFasp2D.cxx
index d5a0333032..2fe94bfb04 100644
--- a/reco/detectors/trd/unpack/CbmTrdUnpackConfigFasp2D.cxx
+++ b/reco/detectors/trd/unpack/CbmTrdUnpackConfigFasp2D.cxx
@@ -15,37 +15,13 @@
 #include <vector>
 
 CbmTrdUnpackConfigFasp2D::CbmTrdUnpackConfigFasp2D(std::string detGeoSetupTag, UInt_t runid)
-  : CbmRecoUnpackConfig("CbmTrdUnpackConfigFasp2D")
-  , fGeoSetupTag(detGeoSetupTag)
-  , fRunId(runid)
+  : CbmRecoUnpackConfig("CbmTrdUnpackConfigFasp2D", detGeoSetupTag, runid)
 {
 }
 
 CbmTrdUnpackConfigFasp2D::~CbmTrdUnpackConfigFasp2D() {}
 
 // ---- Init ----
-void CbmTrdUnpackConfigFasp2D::InitUnpacker()
-{
-  LOG(info) << fName << "::Init -";
-
-  auto initOk = kTRUE;
-
-  // First choose the derived unpacking algorithm to be used and pass the raw to digi method
-  auto algo = chooseAlgo();
-
-  if (fDoLog) LOG(info) << fName << "::Init - SetParFilesBasePath";
-  algo->SetParFilesBasePath(fParFilesBasePath);
-
-  // Initialise the parameter containers required by the unpacker algo. Includes loading the corresponding ascii files
-  auto reqparvec = algo->GetParContainerRequest(fGeoSetupTag, fRunId);
-  initOk &= initParContainers(reqparvec);
-
-  // Now we have all information required to initialise the algorithm
-  algo->Init();
-
-  // Pass the algo to its member in the base class
-  fAlgo = algo;
-}
 
 // ---- chooseAlgo ----
 std::shared_ptr<CbmTrdUnpackAlgoFasp2D> CbmTrdUnpackConfigFasp2D::chooseAlgo()
diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackConfigFasp2D.h b/reco/detectors/trd/unpack/CbmTrdUnpackConfigFasp2D.h
index ac03873b64..79c15828e2 100644
--- a/reco/detectors/trd/unpack/CbmTrdUnpackConfigFasp2D.h
+++ b/reco/detectors/trd/unpack/CbmTrdUnpackConfigFasp2D.h
@@ -8,11 +8,11 @@
  * @brief Configuration class for an unpacker algorithm
  * @version 0.1
  * @date 2021-04-21
- * 
+ *
  * @copyright Copyright (c) 2021
- * 
+ *
  * This is the common configuration class for unpacking algorithms
- * 
+ *
 */
 
 #ifndef CbmTrdUnpackConfigFasp2D_H
@@ -39,7 +39,7 @@ class CbmTrdUnpackConfigFasp2D : public CbmRecoUnpackConfig<CbmTrdUnpackAlgoFasp
 public:
   /**
    * @brief Create the Cbm Trd Unpack Task object
-   * 
+   *
    * @param geoSetupTag Geometry setup tag for the given detector as used by CbmSetup objects
    * @param runid set if unpacker is rerun on a special run with special parameters
    *@remark We use the string instead of CbmSetup here, to not having to link against sim/steer...
@@ -48,7 +48,7 @@ public:
 
   /**
    * @brief Destroy the Cbm Trd Unpack Task object
-   * 
+   *
   */
   virtual ~CbmTrdUnpackConfigFasp2D();
 
@@ -58,28 +58,16 @@ public:
   /** @brief Assignment operator - not implemented **/
   CbmTrdUnpackConfigFasp2D& operator=(const CbmTrdUnpackConfigFasp2D&) = delete;
 
-  /**
-   * @brief Prepare the unpacker to be ready to run.
-   * In this function all initialization steps of the unpacker algorithms happen.
-  */
-  void InitUnpacker();
-
 protected:
   /**
    * @brief Choose the derived unpacker algorithm to be used for the DAQ output to Digi translation. If algo was already set manually by the user this algorithm is used.
-   * 
-   * @return Bool_t initOk 
+   *
+   * @return Bool_t initOk
   */
   virtual std::shared_ptr<CbmTrdUnpackAlgoFasp2D> chooseAlgo();
 
-  /** @brief Geometry setup tag for the given detector as used by CbmSetup objects */
-  std::string fGeoSetupTag = "";
-
-  /** @brief RunId of the current run, if not known 0 is a valid runtime case. Used runId based parameter loading. */
-  UInt_t fRunId = 0;
-
 private:
-  ClassDef(CbmTrdUnpackConfigFasp2D, 2)
+  ClassDef(CbmTrdUnpackConfigFasp2D, 3)
 };
 
 #endif  // CbmTrdUnpackConfigFasp2D_H
diff --git a/reco/steer/CMakeLists.txt b/reco/steer/CMakeLists.txt
index e020938e05..ecfbb7e297 100644
--- a/reco/steer/CMakeLists.txt
+++ b/reco/steer/CMakeLists.txt
@@ -81,6 +81,7 @@ CbmPsdReco
 CbmRichReco
 CbmRecoSts
 CbmTofBase
+CbmTofReco
 CbmTrdReco
 CbmData
 KF
diff --git a/reco/steer/CbmRecoUnpack.cxx b/reco/steer/CbmRecoUnpack.cxx
index 589aeede05..f63fbb4e81 100644
--- a/reco/steer/CbmRecoUnpack.cxx
+++ b/reco/steer/CbmRecoUnpack.cxx
@@ -70,49 +70,70 @@ Bool_t CbmRecoUnpack::Init()
 
   // --- Psd
   if (fPsdConfig) {
-    fPsdConfig->Init(ioman);
+    fPsdConfig->InitOutput();
+    RegisterOutputs(ioman, fPsdConfig);  /// Framework bound work = kept in this Task
+    fPsdConfig->SetAlgo();
+    initParContainers(fPsdConfig->GetParContainerRequest());  /// Framework bound work = kept in this Task
+    fPsdConfig->InitAlgo();
     initPerformanceMaps(fkFlesPsd, "PSD");
   }
   // --- Rich
   if (fRichConfig) {
-    fRichConfig->Init(ioman);
+    fRichConfig->InitOutput();
+    RegisterOutputs(ioman, fRichConfig);  /// Framework bound work = kept in this Task
+    fRichConfig->SetAlgo();
+    initParContainers(fRichConfig->GetParContainerRequest());  /// Framework bound work = kept in this Task
+    fRichConfig->InitAlgo();
     initPerformanceMaps(fkFlesRich, "RICH");
   }
 
   // --- Sts
   if (fStsConfig) {
-    fStsConfig->Init(ioman);
+    fStsConfig->InitOutput();
+    RegisterOutputs(ioman, fStsConfig);  /// Framework bound work = kept in this Task
+    fStsConfig->SetAlgo();
+    initParContainers(fStsConfig->GetParContainerRequest());  /// Framework bound work = kept in this Task
+    fStsConfig->InitAlgo();
     initPerformanceMaps(fkFlesSts, "STS");
   }
   // --- Tof
   if (fTofConfig) {
-    fTofConfig->Init(ioman);
+    fTofConfig->InitOutput();
+    RegisterOutputs(ioman, fTofConfig);  /// Framework bound work = kept in this Task
+    fTofConfig->SetAlgo();
+    initParContainers(fTofConfig->GetParContainerRequest());  /// Framework bound work = kept in this Task
+    fTofConfig->InitAlgo();
     initPerformanceMaps(fkFlesTof, "TOF");
   }
   // --- Trd
   if (fTrd1DConfig) {
-    fTrd1DConfig->Init(ioman);
+    fTrd1DConfig->InitOutput();
+    RegisterOutputs(ioman, fTrd1DConfig);  /// Framework bound work = kept in this Task
+    fTrd1DConfig->SetAlgo();
+    initParContainers(fTrd1DConfig->GetParContainerRequest());  /// Framework bound work = kept in this Task
+    fTrd1DConfig->InitAlgo();
     initPerformanceMaps(fkFlesTrd, "TRD1D");
   }
   // --- TRD2D
   if (fTrd2DConfig) {
-    if (fTrd1DConfig) {
-      if (fTrd2DConfig->GetOutputBranchName() == fTrd1DConfig->GetOutputBranchName()) {
-        LOG(info) << fTrd2DConfig->GetName() << "::Init() ---------------------------------";
-        fTrd2DConfig->SetOutputVec(fTrd1DConfig->GetOutputVec());
-        fTrd2DConfig->InitUnpacker();
-        LOG(info) << fTrd2DConfig->GetName() << " succesful initialized -----------------\n";
-      }
-      else {
-        fTrd2DConfig->Init(ioman);
-      }
+    if (fTrd1DConfig && (fTrd2DConfig->GetOutputBranchName() == fTrd1DConfig->GetOutputBranchName())) {
+      LOG(info) << fTrd2DConfig->GetName() << "::Init() ---------------------------------";
+      fTrd2DConfig->SetOutputVec(fTrd1DConfig->GetOutputVec());
     }
     else {
-      fTrd2DConfig->Init(ioman);
+      fTrd2DConfig->InitOutput();
+      RegisterOutputs(ioman, fTrd2DConfig);  /// Framework bound work = kept in this Task
     }
+    fTrd2DConfig->SetAlgo();
+    initParContainers(fTrd2DConfig->GetParContainerRequest());  /// Framework bound work = kept in this Task
+    fTrd2DConfig->InitAlgo();
     initPerformanceMaps(fkFlesTrd2D, "TRD2D");
   }
-  // This is an ugly work around, because the TRD and TRD2D want to access the same vector and there is no function to retrieve a writeable vector<obj> from the FairRootManager, especially before the branches are created, as far as I am aware. The second option workaround is in in Init() to look for the fasp config and create a separate branch for fasp created CbmTrdDigis PR 072021
+  // This is an ugly work around, because the TRD and TRD2D want to access the same vector and there is no
+  // function to retrieve a writeable vector<obj> from the FairRootManager, especially before the branches
+  // are created, as far as I am aware.
+  // The second option workaround is in in Init() to look for the fasp config and create a separate branch
+  // for fasp created CbmTrdDigis PR 072021
 
   return kTRUE;
 }
diff --git a/reco/steer/CbmRecoUnpack.h b/reco/steer/CbmRecoUnpack.h
index 5e131a4b2e..0ae07e4257 100644
--- a/reco/steer/CbmRecoUnpack.h
+++ b/reco/steer/CbmRecoUnpack.h
@@ -23,6 +23,9 @@
 #include <MicrosliceDescriptor.hpp>
 #include <Timeslice.hpp>
 
+#include <FairParAsciiFileIo.h>
+#include <FairRootManager.h>
+
 #include <RtypesCore.h>
 #include <THnSparse.h>
 #include <TObject.h>
@@ -159,6 +162,59 @@ private:
   */
   void initPerformanceMaps(std::uint16_t subsysid, std::string name);
 
+
+  template<class TConfig>
+  void RegisterOutputs(FairRootManager* ioman, std::shared_ptr<TConfig> config)
+  {
+    /*
+ * FIXME: Compiling but leading to a segfault at runtime
+    auto pOutVect = config->GetOutputVec();
+    if (pOutVect) {
+      ioman->RegisterAny(config->GetOutputBranchName().data(), pOutVect, kTRUE);
+      LOG(info) << "CbmRecoUnpack::RegisterOutputs() " << config->GetOutputBranchName() << " at " << pOutVect;
+    }
+
+    auto pOutVectOptA = config->GetOptOutAVec();
+    if (pOutVectOptA) {
+      ioman->RegisterAny(config->GetOutputBranchNameOptA().data(), pOutVectOptA, kTRUE);
+      LOG(info) << "CbmRecoUnpack::RegisterOutputs() " << config->GetOutputBranchNameOptA() << " at " << pOutVectOptA;
+    }
+
+    auto pOutVectOptB = config->GetOptOutBVec();
+    if (pOutVectOptB) {
+      ioman->RegisterAny(config->GetOutputBranchNameOptB().data(), pOutVectOptB, kTRUE);
+      LOG(info) << "CbmRecoUnpack::RegisterOutputs() " << config->GetOutputBranchNameOptB() << " at " << pOutVectOptB;
+    }
+*/
+    /// Alternative which compiles and run but forces to keep a Fairroot dependency in the Config template
+    config->RegisterOutput(ioman);
+  }
+
+  /**
+   * @brief Initialise the parameter containers requested by the algorithm
+   *
+   * @return Bool_t initOk
+  */
+  virtual Bool_t initParContainers(std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>* reqparvec)
+  {
+    LOG(debug) << GetName() << "::Init - initParContainers";
+    if (!reqparvec) {
+      LOG(info) << GetName() << "::Init - initParContainers - empty requirements vector no parameters initialized.";
+      return kTRUE;
+    }
+
+    // Now get the actual ascii files and init the containers with the asciiIo
+    for (auto& pair : *reqparvec) {
+      auto filepath = pair.first;
+      auto parset   = pair.second;
+      FairParAsciiFileIo asciiInput;
+      if (!filepath.empty()) {
+        if (asciiInput.open(filepath.data())) { parset->init(&asciiInput); }
+      }
+    }
+    return kTRUE;
+  }
+
   /** @brief Sort a vector timewise vector type has to provide GetTime() */
   template<typename TVecobj>
   typename std::enable_if<std::is_same<TVecobj, std::nullptr_t>::value == true, void>::type
-- 
GitLab