diff --git a/reco/detectors/sts/CMakeLists.txt b/reco/detectors/sts/CMakeLists.txt
index 7c02555e7ac3c3ce843415e6c865da68e8aeeaf4..7b28844bb09c3232716bc95f5779809897a5f9b8 100644
--- a/reco/detectors/sts/CMakeLists.txt
+++ b/reco/detectors/sts/CMakeLists.txt
@@ -21,6 +21,7 @@ CbmStsRecoModule.cxx
 CbmStsTrackFinderIdeal.cxx
 
 unpack/CbmStsUnpackAlgo.cxx
+unpack/CbmStsUnpackAlgoLegacy.cxx
 unpack/CbmStsUnpackConfig.cxx
 unpack/CbmStsUnpackMonitor.cxx
 )
diff --git a/reco/detectors/sts/CbmRecoStsLinkDef.h b/reco/detectors/sts/CbmRecoStsLinkDef.h
index 1b139a204d796f83362a20e8f8a900738e9ab4d2..4ea941a18e7194fcb3e522a9a42f349a44b5b040 100644
--- a/reco/detectors/sts/CbmRecoStsLinkDef.h
+++ b/reco/detectors/sts/CbmRecoStsLinkDef.h
@@ -20,6 +20,7 @@
 #pragma link C++ class CbmStsTrackFinderIdeal + ;
 
 #pragma link C++ class CbmStsUnpackAlgo + ;
+#pragma link C++ class CbmStsUnpackAlgoLegacy + ;
 #pragma link C++ class CbmStsUnpackConfig + ;
 #pragma link C++ class CbmStsUnpackMonitor + ;
 
diff --git a/reco/detectors/sts/unpack/CbmStsUnpackAlgoLegacy.cxx b/reco/detectors/sts/unpack/CbmStsUnpackAlgoLegacy.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..cf90af171dc084793c901d02a728993993c60a31
--- /dev/null
+++ b/reco/detectors/sts/unpack/CbmStsUnpackAlgoLegacy.cxx
@@ -0,0 +1,777 @@
+// -----------------------------------------------------------------------------
+// -----                                                                   -----
+// -----                  CbmStsUnpackAlgoLegacy                                 -----
+// -----               Created 26.01.2019 by P.-A. Loizeau                 -----
+// -----                                                                   -----
+// -----------------------------------------------------------------------------
+
+#include "CbmStsUnpackAlgoLegacy.h"
+
+#include "CbmStsUnpackMonitor.h"
+//#include "CbmFormatMsHeaderPrintout.h"
+#include "CbmMcbm2018StsPar.h"
+
+#include <Logger.h>
+
+#include "TCanvas.h"
+#include "TH1.h"
+#include "TH2.h"
+#include "TList.h"
+#include "TProfile.h"
+#include "TROOT.h"
+#include "TString.h"
+
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+
+#include <stdint.h>
+
+// -------------------------------------------------------------------------
+
+CbmStsUnpackAlgoLegacy::CbmStsUnpackAlgoLegacy()
+  : CbmRecoUnpackAlgo("CbmStsUnpackAlgoLegacy")
+  ,
+  /// From the class itself
+  fbMonitorMode(false)
+  , fbDebugMonitorMode(false)
+  , fvbMaskedComponents()
+  , fUnpackPar(nullptr)
+  , fuNbFebs(0)
+  , fDpbIdIndexMap()
+  , fviFebType()
+  , fviFebAddress()
+  , fviFebSide()
+  , fvdFebAdcGain()
+  , fvdFebAdcOffs()
+  , fdTimeOffsetNs(0.0)
+  , fvdTimeOffsetNsAsics()
+  , fbUseChannelMask(false)
+  , fvvbMaskedChannels()
+  , fdAdcCut(0)
+  , fulCurrentMsIdx(0)
+  , fuCurrDpbIdx(0)
+  , fvulCurrentTsMsb()
+  , fdStartTime(0.0)
+  , fdStartTimeMsSz(-1.0)
+  , ftStartTimeUnix(std::chrono::steady_clock::now())
+  , fvmHitsInMs()
+  , fvvusLastTsChan()
+  , fvvusLastAdcChan()
+  , fvvusLastTsMsbChan()
+  , fvvusLastTsMsbCycleChan()
+{
+}
+
+CbmStsUnpackAlgoLegacy::~CbmStsUnpackAlgoLegacy()
+{
+  /// Clear buffers
+  fvmHitsInMs.clear();
+  if (nullptr != fUnpackPar) delete fUnpackPar;
+}
+
+// -------------------------------------------------------------------------
+bool CbmStsUnpackAlgoLegacy::init()
+{
+  LOG(info) << "Initializing mCBM STS 2019 unpacker algo";
+  return true;
+}
+
+// -------------------------------------------------------------------------
+void CbmStsUnpackAlgoLegacy::reset() {}
+
+// -------------------------------------------------------------------------
+void CbmStsUnpackAlgoLegacy::finish()
+{
+  /// Printout Goodbye message and stats
+  /// Write Output histos
+}
+
+// ---- initParSet(FairParGenericSet* parset) ----
+Bool_t CbmStsUnpackAlgoLegacy::initParSet(FairParGenericSet* parset)
+{
+  LOG(info) << fName << "::initParSet - for container " << parset->ClassName();
+  if (parset->IsA() == CbmMcbm2018StsPar::Class()) return initParSet(static_cast<CbmMcbm2018StsPar*>(parset));
+
+  // If we do not know the derived ParSet class we return false
+  LOG(error)
+    << fName << "::initParSet - for container " << parset->ClassName()
+    << " failed, since CbmStsUnpackAlgoLegacy::initParSet() does not know the derived ParSet and what to do with it!";
+  return kFALSE;
+}
+
+// ---- initParSet(CbmMcbm2018StsPar* parset) ----
+Bool_t CbmStsUnpackAlgoLegacy::initParSet(CbmMcbm2018StsPar* parset)
+{
+  fUnpackPar  = parset;
+  bool initOK = InitParameters();
+  return initOK;
+}
+
+// -------------------------------------------------------------------------
+bool CbmStsUnpackAlgoLegacy::InitParameters()
+{
+  //Type of each module: 0 for connectors on the right, 1 for connectors on the left
+  std::vector<int32_t> viModuleType;
+
+  // STS address for the first strip of each module
+  std::vector<int32_t> viModAddress;
+
+  // Idx of the STS module for each FEB, [ NbDpb ][ NbCrobPerDpb ][ NbFebsPerCrob ], -1 if inactive
+  std::vector<std::vector<std::vector<int32_t>>> viFebModuleIdx;
+
+  // Array to hold the active flag for all CROBs, [ NbDpb ][ NbCrobPerDpb ]
+  std::vector<std::vector<bool>> vbCrobActiveFlag;
+
+  //STS module side for each FEB, [ NbDpb ][ NbCrobPerDpb ][ NbFebsPerCrob ], 0 = P, 1 = N, -1 if inactive
+  std::vector<std::vector<std::vector<int32_t>>> viFebModuleSide;
+
+  // Total number of STS modules in the setup
+  const uint32_t uNbModules = fUnpackPar->GetNbOfModules();
+  LOG(info) << "Nr. of STS Modules:    " << uNbModules;
+
+  //Initialize temporary "per Feb" fields
+  InitTempVectors(&viModuleType, &viModAddress, &viFebModuleIdx, &vbCrobActiveFlag, &viFebModuleSide);
+
+  // Total number of STS DPBs in system
+  const uint32_t uNbOfDpbs = fUnpackPar->GetNrOfDpbs();
+  LOG(info) << "Nr. of STS DPBs:       " << uNbOfDpbs;
+
+  // Read dpb index map from parameter container
+  InitDpbIdIndexMap();
+
+  // Get Nr of Febs
+  fuNbFebs = fUnpackPar->GetNrOfFebs();
+  LOG(info) << "Nr. of FEBs:           " << fuNbFebs;
+
+  // Get Nr of Asics
+  const uint32_t uNbStsXyters = fUnpackPar->GetNrOfAsics();
+  LOG(info) << "Nr. of StsXyter ASICs: " << uNbStsXyters;
+
+  if (fvdTimeOffsetNsAsics.size() < uNbStsXyters) { fvdTimeOffsetNsAsics.resize(uNbStsXyters, 0.0); }
+
+  //Initialize class-wide "per Feb" fields
+  fviFebType.resize(uNbOfDpbs);
+
+  for (uint32_t uDpb = 0; uDpb < uNbOfDpbs; ++uDpb) {
+    fviFebType[uDpb].resize(fUnpackPar->GetNbCrobsPerDpb());
+    for (uint32_t uCrobIdx = 0; uCrobIdx < fUnpackPar->GetNbCrobsPerDpb(); ++uCrobIdx) {
+      fviFebType[uDpb][uCrobIdx].resize(fUnpackPar->GetNbFebsPerCrob(), -1);
+      for (uint32_t uFebIdx = 0; uFebIdx < fUnpackPar->GetNbFebsPerCrob(); ++uFebIdx) {
+        fvdFebAdcGain.push_back(fUnpackPar->GetFebAdcGain(uDpb, uCrobIdx, uFebIdx));
+        fvdFebAdcOffs.push_back(fUnpackPar->GetFebAdcOffset(uDpb, uCrobIdx, uFebIdx));
+
+        if (0 <= viFebModuleIdx[uDpb][uCrobIdx][uFebIdx]
+            && static_cast<uint32_t>(viFebModuleIdx[uDpb][uCrobIdx][uFebIdx]) < uNbModules
+            && 0 <= viFebModuleSide[uDpb][uCrobIdx][uFebIdx] && viFebModuleSide[uDpb][uCrobIdx][uFebIdx] < 2) {
+          switch (viModuleType[viFebModuleIdx[uDpb][uCrobIdx][uFebIdx]]) {
+            case 0:  // FEB-8-1 with ZIF connector on the right
+            {
+              // P side (0) has type A (0)
+              // N side (1) has type B (1)
+              fviFebType[uDpb][uCrobIdx][uFebIdx] = viFebModuleSide[uDpb][uCrobIdx][uFebIdx];
+
+              ///! FIXME: 1) Geometry is using front/back while we are using P/N !!!!
+              ///!            => Assuming that front facing modules have connectors on right side
+              ///!            +> Volker warns that the front side should be electrons one so N
+              ///!        2) No accessor/setter to change only the side field of an STS address
+              ///!            => hardcode the shift
+              ///!            +> The bit is unused in the current scheme: the side is encoded in the Digi channel
+              fviFebAddress.push_back(viModAddress[viFebModuleIdx[uDpb][uCrobIdx][uFebIdx]]
+                                      + (viFebModuleSide[uDpb][uCrobIdx][uFebIdx] << 25));
+              fviFebSide.push_back(viFebModuleSide[uDpb][uCrobIdx][uFebIdx]);
+              break;
+            }        // case 0: // FEB-8-1 with ZIF connector on the right
+            case 1:  // FEB-8-1 with ZIF connector on the left
+            {
+              // P side (0) has type B (1)
+              // N side (1) has type A (0)
+              fviFebType[uDpb][uCrobIdx][uFebIdx] = !(viFebModuleSide[uDpb][uCrobIdx][uFebIdx]);
+
+              ///! FIXME: 1) Geometry is using front/back while we are using P/N !!!!
+              ///!            => Assuming that front facing modules have connectors on right side
+              ///!            +> Volker warns that the front side should be electrons one so N
+              ///!        2) No accessor/setter to change only the side field of an STS address
+              ///!            => hardcode the shift
+              ///!            +> The bit is unused in the current scheme: the side is encoded in the Digi channel
+              fviFebAddress.push_back(viModAddress[viFebModuleIdx[uDpb][uCrobIdx][uFebIdx]]
+                                      + ((!viFebModuleSide[uDpb][uCrobIdx][uFebIdx]) << 25));
+              fviFebSide.push_back(viFebModuleSide[uDpb][uCrobIdx][uFebIdx]);
+              break;
+            }  // case 1: // FEB-8-1 with ZIF connector on the left
+            default:
+              LOG(fatal) << Form("Bad module type for DPB #%02u CROB #%u FEB %02u: %d", uDpb, uCrobIdx, uFebIdx,
+                                 viModuleType[viFebModuleIdx[uDpb][uCrobIdx][uFebIdx]]);
+              break;
+          }
+        }  // FEB active and module index OK
+        else if (-1 == viFebModuleIdx[uDpb][uCrobIdx][uFebIdx] || -1 == viFebModuleSide[uDpb][uCrobIdx][uFebIdx]) {
+          fviFebAddress.push_back(0);
+          fviFebSide.push_back(-1);
+        }  // Module index or type is set to inactive
+        else {
+          LOG(fatal) << Form("Bad module Index and/or Side for DPB #%02u CROB "
+                             "#%u FEB %02u: %d %d",
+                             uDpb, uCrobIdx, uFebIdx, viFebModuleIdx[uDpb][uCrobIdx][uFebIdx],
+                             viFebModuleSide[uDpb][uCrobIdx][uFebIdx]);
+        }  // Bad module index or type for this FEB
+      }
+    }
+  }
+
+  PrintActiveCrobs(vbCrobActiveFlag);
+  PrintAddressMaps(viFebModuleIdx, viFebModuleSide);
+
+  LOG(info) << "Unpacking data in bin sorter FW mode";
+  InitInternalStatus();
+
+  return true;
+}
+
+// -------------------------------------------------------------------------
+void CbmStsUnpackAlgoLegacy::InitDpbIdIndexMap()
+{
+  fDpbIdIndexMap.clear();
+  for (uint32_t uDpb = 0; uDpb < fUnpackPar->GetNrOfDpbs(); ++uDpb) {
+    fDpbIdIndexMap[fUnpackPar->GetDpbId(uDpb)] = uDpb;
+    LOG(info) << "Eq. ID for DPB #" << std::setw(2) << uDpb << " = 0x" << std::setw(4) << std::hex
+              << fUnpackPar->GetDpbId(uDpb) << std::dec << " => " << fDpbIdIndexMap[fUnpackPar->GetDpbId(uDpb)];
+  }
+}
+
+// -------------------------------------------------------------------------
+void CbmStsUnpackAlgoLegacy::InitTempVectors(std::vector<int32_t>* viModuleType, std::vector<int32_t>* viModAddress,
+                                             std::vector<std::vector<std::vector<int32_t>>>* viFebModuleIdx,
+                                             std::vector<std::vector<bool>>* vbCrobActiveFlag,
+                                             std::vector<std::vector<std::vector<int32_t>>>* viFebModuleSide)
+{
+  const uint32_t uNbModules = fUnpackPar->GetNbOfModules();
+  const uint32_t uNbOfDpbs  = fUnpackPar->GetNrOfDpbs();
+
+  viModuleType->resize(uNbModules);
+  viModAddress->resize(uNbModules);
+  for (uint32_t uModIdx = 0; uModIdx < uNbModules; ++uModIdx) {
+    (*viModuleType)[uModIdx] = fUnpackPar->GetModuleType(uModIdx);
+    (*viModAddress)[uModIdx] = fUnpackPar->GetModuleAddress(uModIdx);
+    LOG(info) << "Module #" << std::setw(2) << uModIdx << " Type " << std::setw(4) << (*viModuleType)[uModIdx]
+              << " Address 0x" << std::setw(8) << std::hex << (*viModAddress)[uModIdx] << std::dec;
+  }
+  vbCrobActiveFlag->resize(uNbOfDpbs);
+  viFebModuleIdx->resize(uNbOfDpbs);
+  viFebModuleSide->resize(uNbOfDpbs);
+
+  for (uint32_t uDpb = 0; uDpb < uNbOfDpbs; ++uDpb) {
+    (*vbCrobActiveFlag)[uDpb].resize(fUnpackPar->GetNbCrobsPerDpb());
+    (*viFebModuleIdx)[uDpb].resize(fUnpackPar->GetNbCrobsPerDpb());
+    (*viFebModuleSide)[uDpb].resize(fUnpackPar->GetNbCrobsPerDpb());
+    for (uint32_t uCrobIdx = 0; uCrobIdx < fUnpackPar->GetNbCrobsPerDpb(); ++uCrobIdx) {
+      (*vbCrobActiveFlag)[uDpb][uCrobIdx] = fUnpackPar->IsCrobActive(uDpb, uCrobIdx);
+      (*viFebModuleIdx)[uDpb][uCrobIdx].resize(fUnpackPar->GetNbFebsPerCrob());
+      (*viFebModuleSide)[uDpb][uCrobIdx].resize(fUnpackPar->GetNbFebsPerCrob());
+      for (uint32_t uFebIdx = 0; uFebIdx < fUnpackPar->GetNbFebsPerCrob(); ++uFebIdx) {
+        (*viFebModuleIdx)[uDpb][uCrobIdx][uFebIdx]  = fUnpackPar->GetFebModuleIdx(uDpb, uCrobIdx, uFebIdx);
+        (*viFebModuleSide)[uDpb][uCrobIdx][uFebIdx] = fUnpackPar->GetFebModuleSide(uDpb, uCrobIdx, uFebIdx);
+      }
+    }
+  }
+}
+
+// -------------------------------------------------------------------------
+void CbmStsUnpackAlgoLegacy::PrintActiveCrobs(const std::vector<std::vector<bool>>& vbCrobActiveFlag)
+{
+  for (uint32_t uDpb = 0; uDpb < fUnpackPar->GetNrOfDpbs(); ++uDpb) {
+    TString sPrintoutLine = Form("DPB #%02u CROB Active ?:       ", uDpb);
+    for (uint32_t uCrobIdx = 0; uCrobIdx < fUnpackPar->GetNbCrobsPerDpb(); ++uCrobIdx) {
+      sPrintoutLine += Form("%1u", (vbCrobActiveFlag[uDpb][uCrobIdx] == true));
+    }
+    LOG(info) << sPrintoutLine;
+  }
+}
+
+// -------------------------------------------------------------------------
+void CbmStsUnpackAlgoLegacy::PrintAddressMaps(const std::vector<std::vector<std::vector<int32_t>>>& viFebModuleIdx,
+                                              const std::vector<std::vector<std::vector<int32_t>>>& viFebModuleSide)
+{
+  uint32_t uGlobalFebIdx = 0;
+  for (uint32_t uDpb = 0; uDpb < fUnpackPar->GetNrOfDpbs(); ++uDpb) {
+    for (uint32_t uCrobIdx = 0; uCrobIdx < fUnpackPar->GetNbCrobsPerDpb(); ++uCrobIdx) {
+      LOG(info) << Form("DPB #%02u CROB #%u:       ", uDpb, uCrobIdx);
+      for (uint32_t uFebIdx = 0; uFebIdx < fUnpackPar->GetNbFebsPerCrob(); ++uFebIdx) {
+        if (0 <= viFebModuleIdx[uDpb][uCrobIdx][uFebIdx])
+          LOG(info) << Form("      FEB #%02u (%02u): Mod. Idx = %03d Side %c (%2d) Type %c "
+                            "(%2d) (Addr. 0x%08x) ADC gain %4.0f e- ADC Offs %5.0f e-",
+                            uFebIdx, uGlobalFebIdx, viFebModuleIdx[uDpb][uCrobIdx][uFebIdx],
+                            1 == viFebModuleSide[uDpb][uCrobIdx][uFebIdx] ? 'N' : 'P',
+                            viFebModuleSide[uDpb][uCrobIdx][uFebIdx],
+                            1 == fviFebType[uDpb][uCrobIdx][uFebIdx] ? 'B' : 'A', fviFebType[uDpb][uCrobIdx][uFebIdx],
+                            fviFebAddress[uGlobalFebIdx], fvdFebAdcGain[uGlobalFebIdx], fvdFebAdcOffs[uGlobalFebIdx]);
+        else
+          LOG(info) << Form("Disabled FEB #%02u (%02u): Mod. Idx = %03d Side %c (%2d) Type %c "
+                            "(%2d) (Addr. 0x%08x) ADC gain %4.0f e- ADC Offs %5.0f e-",
+                            uFebIdx, uGlobalFebIdx, viFebModuleIdx[uDpb][uCrobIdx][uFebIdx],
+                            1 == viFebModuleSide[uDpb][uCrobIdx][uFebIdx] ? 'N' : 'P',
+                            viFebModuleSide[uDpb][uCrobIdx][uFebIdx],
+                            1 == fviFebType[uDpb][uCrobIdx][uFebIdx] ? 'B' : 'A', fviFebType[uDpb][uCrobIdx][uFebIdx],
+                            fviFebAddress[uGlobalFebIdx], fvdFebAdcGain[uGlobalFebIdx], fvdFebAdcOffs[uGlobalFebIdx]);
+        uGlobalFebIdx++;
+      }
+    }
+  }
+}
+
+// -------------------------------------------------------------------------
+void CbmStsUnpackAlgoLegacy::InitInternalStatus()
+{
+  const uint32_t uNbOfDpbs    = fUnpackPar->GetNrOfDpbs();
+  const uint32_t uNbStsXyters = fUnpackPar->GetNrOfAsics();
+
+  fvulCurrentTsMsb.resize(uNbOfDpbs);
+  fvuCurrentTsMsbCycle.resize(uNbOfDpbs);
+  for (uint32_t uDpb = 0; uDpb < uNbOfDpbs; ++uDpb) {
+    fvulCurrentTsMsb[uDpb]     = 0;
+    fvuCurrentTsMsbCycle[uDpb] = 0;
+  }
+
+  fvvusLastTsChan.resize(uNbStsXyters);
+  fvvusLastAdcChan.resize(uNbStsXyters);
+  fvvusLastTsMsbChan.resize(uNbStsXyters);
+  fvvusLastTsMsbCycleChan.resize(uNbStsXyters);
+  for (uint32_t uAsicIdx = 0; uAsicIdx < uNbStsXyters; ++uAsicIdx) {
+    fvvusLastTsChan[uAsicIdx].resize(fUnpackPar->GetNbChanPerAsic(), 0);
+    fvvusLastAdcChan[uAsicIdx].resize(fUnpackPar->GetNbChanPerAsic(), 0);
+    fvvusLastTsMsbChan[uAsicIdx].resize(fUnpackPar->GetNbChanPerAsic(), 0);
+    fvvusLastTsMsbCycleChan[uAsicIdx].resize(fUnpackPar->GetNbChanPerAsic(), 0);
+  }
+}
+
+/*
+// -------------------------------------------------------------------------
+bool CbmStsUnpackAlgoLegacy::Unpack(const fles::Timeslice& ts, const uint32_t uMsComp)
+{
+  fTsIndex = ts.index();
+
+  /// Loop over core microslices (and overlap ones if chosen)
+  for (uint32_t uMsIndex = 0; uMsIndex < fuNbMsLoop; uMsIndex++) {
+    if (false == ProcessMs(ts, uMsComp, uMsIndex)) {
+      LOG(error) << "Failed to process ts " << fTsIndex << " MS " << uMsIndex << " for component " << uMsComp;
+      return false;
+    }
+  }
+  /// Sort the buffers of hits
+  /// => Commented out as for now problems at MS borders due to offsets
+  //      std::sort( fvmHitsInMs.begin(), fvmHitsInMs.end() );
+
+  /// Add the hits to the output buffer as Digis
+  AddHitsToDigiVect(&fvmHitsInMs, &fOutputVec);
+
+  /// Clear the buffer of hits
+  fvmHitsInMs.clear();
+
+  return true;
+}
+*/
+
+void CbmStsUnpackAlgoLegacy::AddHitsToDigiVect(std::vector<stsxyter::FinalHit>* vmHitsIn,
+                                               std::vector<CbmStsDigi>* vDigiVectOut)
+{
+  for (auto itHitIn = vmHitsIn->begin(); itHitIn < vmHitsIn->end(); ++itHitIn) {
+    const uint32_t uAsicIdx = itHitIn->GetAsic();
+    const uint32_t uFebIdx  = itHitIn->GetAsic() / fUnpackPar->GetNbAsicsPerFeb();
+    uint32_t uChanInMod =
+      itHitIn->GetChan() + fUnpackPar->GetNbChanPerAsic() * (itHitIn->GetAsic() % fUnpackPar->GetNbAsicsPerFeb());
+    /// FIXME: see issue #1549
+    /// N side: 0-1023 =>    0-1023
+    /// P side: 0-1023 => 2047-1024
+    if (0 == fviFebSide[uFebIdx])
+      uChanInMod = fUnpackPar->GetNbChanPerFeb() - uChanInMod - 1  // Invert channel order
+                   + fUnpackPar->GetNbChanPerFeb();                // Offset for P (back) side
+
+    double dTimeInNs = itHitIn->GetTs() * stsxyter::kdClockCycleNs - fdTimeOffsetNs;
+    if (uAsicIdx < fvdTimeOffsetNsAsics.size()) dTimeInNs -= fvdTimeOffsetNsAsics[uAsicIdx];
+
+    const uint64_t ulTimeInNs = static_cast<uint64_t>(dTimeInNs);
+    const double dCalAdc      = fvdFebAdcOffs[uFebIdx] + (itHitIn->GetAdc() - 1) * fvdFebAdcGain[uFebIdx];
+
+    if (0 == fviFebAddress[uFebIdx] || -1 == fviFebSide[uFebIdx]) {
+      LOG(error) << Form("Digi on disabled FEB %02u has address 0x%08x and side %d", uFebIdx, fviFebAddress[uFebIdx],
+                         fviFebSide[uFebIdx]);
+    }
+    vDigiVectOut->emplace_back(fviFebAddress[uFebIdx], uChanInMod, ulTimeInNs, dCalAdc);
+  }
+}
+
+bool CbmStsUnpackAlgoLegacy::unpack(const fles::Timeslice* ts, std::uint16_t uMsCompIdx, UInt_t uMsIdx)
+{
+  auto msDescriptor = ts->descriptor(uMsCompIdx, uMsIdx);
+
+  //Current equipment ID, tells from which DPB the current MS is originating
+  const uint32_t uCurrentEquipmentId = msDescriptor.eq_id;
+  const uint8_t* msContent           = reinterpret_cast<const uint8_t*>(ts->content(uMsCompIdx, uMsIdx));
+  const uint32_t uSize               = msDescriptor.size;
+
+  fulCurrentMsIdx = msDescriptor.idx;
+  LOG(debug) << "Microslice: " << fulCurrentMsIdx << " from EqId " << std::hex << uCurrentEquipmentId << std::dec
+             << " has size: " << uSize;
+
+  if (0 == fvbMaskedComponents.size()) fvbMaskedComponents.resize(ts->num_components(), false);
+
+  //Temp holder until current equipment ID is properly filled in MS
+  const uint32_t uCurrDpbId = static_cast<uint32_t>(uCurrentEquipmentId & 0xFFFF);
+
+  if (fbMonitorMode && fbDebugMonitorMode) {
+    const double dMsTime = (1e-9) * static_cast<double>(fulCurrentMsIdx);
+    if (uMsCompIdx < fUnpackMonitor->GetMaxNbFlibLinks()) {
+      if (fdStartTimeMsSz < 0) fdStartTimeMsSz = dMsTime;
+      fUnpackMonitor->FillMsSize(uMsCompIdx, uSize);
+      fUnpackMonitor->FillMsSizeTime(uMsCompIdx, dMsTime - fdStartTimeMsSz, uSize);
+    }
+  }
+
+  /// Check if this sDPB ID was declared in parameter file and stop there if not
+  auto it = fDpbIdIndexMap.find(uCurrDpbId);
+  if (it == fDpbIdIndexMap.end()) {
+    if (false == fvbMaskedComponents[uMsCompIdx]) {
+      LOG(info) << "---------------------------------------------------------------";
+      //LOG(info) << FormatMsHeaderPrintout(msDescriptor);
+      LOG(warning) << "Could not find the sDPB index for AFCK id 0x" << std::hex << uCurrDpbId << std::dec
+                   << " in timeslice " << fTsIndex << " in microslice " << uMsIdx << " component " << uMsCompIdx << "\n"
+                   << "If valid this index has to be added in the STS "
+                      "parameter file in the DbpIdArray field";
+      fvbMaskedComponents[uMsCompIdx] = true;
+
+      /// If first TS being analyzed, we are probably detecting STS/MUCH boards with same sysid
+      /// => Do not report the MS as bad, just ignore it
+      if (1 == fTsIndex) return true;
+    }
+    else
+      return true;
+
+    return false;
+  }
+  else
+    fuCurrDpbIdx = fDpbIdIndexMap[uCurrDpbId];
+
+  if (fbMonitorMode || fbDebugMonitorMode) fUnpackMonitor->FillMsCntEvo(fulCurrentMsIdx);
+
+  // Check the current TS_MSb cycle and correct it if wrong
+  RefreshTsMsbFields(uMsIdx);
+
+  //Reset internal monitor variables for debugging info
+  if (fbMonitorMode && fbDebugMonitorMode) { fUnpackMonitor->ResetDebugInfo(); }
+
+  //Main processing of MS content
+  LoopMsMessages(msContent, uSize, uMsIdx);
+
+  //Output debugging info
+  if (fbMonitorMode) {
+    if (fbDebugMonitorMode) { fUnpackMonitor->PrintDebugInfo(fulCurrentMsIdx, fTsIndex, msDescriptor.flags, uSize); }
+    for (auto itHit = fOutputVec.begin(); itHit != fOutputVec.end(); ++itHit) {
+      fUnpackMonitor->FillDigisTimeInRun(itHit->GetTime());  //check whether this does what it should
+    }
+    fUnpackMonitor->FillVectorSize(ts->index(), fOutputVec.size());  //check whether this does what it should
+    //fUnpackMonitor->DrawCanvases();
+  }
+
+  AddHitsToDigiVect(&fvmHitsInMs, &fOutputVec);
+
+  /// Clear the buffer of hits
+  fvmHitsInMs.clear();
+
+  return true;
+}
+
+// -------------------------------------------------------------------------
+void CbmStsUnpackAlgoLegacy::RefreshTsMsbFields(const size_t uMsIdx)
+{
+  const uint32_t uTsMsbCycleHeader =
+    std::floor(fulCurrentMsIdx / (stsxyter::kulTsCycleNbBinsBinning * stsxyter::kdClockCycleNs));
+
+  if (0 == uMsIdx) {
+    if (uTsMsbCycleHeader != fvuCurrentTsMsbCycle[fuCurrDpbIdx])
+      LOG(info) << " TS " << std::setw(12) << fTsIndex << " MS " << std::setw(12) << fulCurrentMsIdx << " MS Idx "
+                << std::setw(4) << uMsIdx << " Msg Idx " << std::setw(5) << 0 << " DPB " << std::setw(2) << fuCurrDpbIdx
+                << " Old TsMsb " << std::setw(5) << fvulCurrentTsMsb[fuCurrDpbIdx] << " Old MsbCy " << std::setw(5)
+                << fvuCurrentTsMsbCycle[fuCurrDpbIdx] << " New MsbCy " << uTsMsbCycleHeader;
+    fvuCurrentTsMsbCycle[fuCurrDpbIdx] = uTsMsbCycleHeader;
+    fvulCurrentTsMsb[fuCurrDpbIdx]     = 0;
+  }
+  else if (uTsMsbCycleHeader != fvuCurrentTsMsbCycle[fuCurrDpbIdx]) {
+    if (4194303 == fvulCurrentTsMsb[fuCurrDpbIdx]) {
+      LOG(info) << " TS " << std::setw(12) << fTsIndex << " MS " << std::setw(12) << fulCurrentMsIdx << " MS Idx "
+                << std::setw(4) << uMsIdx << " Msg Idx " << std::setw(5) << 0 << " DPB " << std::setw(2) << fuCurrDpbIdx
+                << " Old TsMsb " << std::setw(5) << fvulCurrentTsMsb[fuCurrDpbIdx] << " Old MsbCy " << std::setw(5)
+                << fvuCurrentTsMsbCycle[fuCurrDpbIdx] << " New MsbCy " << uTsMsbCycleHeader;
+    }
+    else {
+      LOG(warning) << "TS MSB cycle from MS header does not match current cycle from data "
+                   << "for TS " << std::setw(12) << fTsIndex << " MS " << std::setw(12) << fulCurrentMsIdx << " MsInTs "
+                   << std::setw(3) << uMsIdx << " ====> " << fvuCurrentTsMsbCycle[fuCurrDpbIdx] << " (cnt) VS "
+                   << uTsMsbCycleHeader << " (header)";
+    }
+    fvuCurrentTsMsbCycle[fuCurrDpbIdx] = uTsMsbCycleHeader;
+  }
+}
+
+// -------------------------------------------------------------------------
+void CbmStsUnpackAlgoLegacy::LoopMsMessages(const uint8_t* msContent, const uint32_t uSize, const size_t uMsIdx)
+{
+  // If not integer number of message in input buffer, print warning/error
+  if (0 != (uSize % sizeof(stsxyter::Message))) {
+    LOG(error) << "The input microslice buffer does NOT "
+               << "contain only complete sDPB messages!";
+  }
+  // Compute the number of complete messages in the input microslice buffer
+  const uint32_t uNbMessages = (uSize - (uSize % sizeof(stsxyter::Message))) / sizeof(stsxyter::Message);
+
+  // Prepare variables for the loop on contents
+  const stsxyter::Message* pMess = reinterpret_cast<const stsxyter::Message*>(msContent);
+
+  for (uint32_t uIdx = 0; uIdx < uNbMessages; uIdx++) {
+    /// Get message type
+    const stsxyter::MessType typeMess = pMess[uIdx].GetMessType();
+    if (fbMonitorMode && fbDebugMonitorMode) { fUnpackMonitor->ProcessDebugInfo(pMess[uIdx], fuCurrDpbIdx); }
+    switch (typeMess) {
+      case stsxyter::MessType::Hit: {
+        ProcessHitInfo(pMess[uIdx]);
+        break;
+      }
+      case stsxyter::MessType::TsMsb: {
+        ProcessTsMsbInfo(pMess[uIdx], uIdx, uMsIdx);
+        break;
+      }
+      case stsxyter::MessType::Epoch: {
+        ProcessEpochInfo(pMess[uIdx]);
+        if (0 < uIdx) {
+          LOG(info) << "CbmStsUnpackAlgoLegacy::DoUnpack => "
+                    << "EPOCH message at unexpected position in MS: message " << uIdx << " VS message 0 expected!";
+        }
+        break;
+      }
+      case stsxyter::MessType::Status: {
+        ProcessStatusInfo(pMess[uIdx], uIdx);
+        break;
+      }
+      case stsxyter::MessType::Empty: {
+        break;
+      }
+      case stsxyter::MessType::EndOfMs: {
+        ProcessErrorInfo(pMess[uIdx]);
+        break;
+      }
+      case stsxyter::MessType::Dummy: {
+        break;
+      }
+      default: {
+        LOG(fatal) << "CbmStsUnpackAlgoLegacy::DoUnpack => "
+                   << "Unknown message type, should never happen, stopping "
+                      "here! Type found was: "
+                   << static_cast<int>(typeMess);
+      }
+    }
+  }
+}
+
+// -------------------------------------------------------------------------
+void CbmStsUnpackAlgoLegacy::ProcessHitInfo(const stsxyter::Message& mess)
+{
+  const uint16_t usElinkIdx = mess.GetLinkIndexHitBinning();
+  const uint32_t uCrobIdx   = usElinkIdx / fUnpackPar->GetNbElinkPerCrob();
+  const int32_t uFebIdx     = fUnpackPar->ElinkIdxToFebIdx(usElinkIdx);
+  if (-1 == uFebIdx) {
+    LOG(warning) << "CbmStsUnpackAlgoLegacy::DoUnpack => "
+                 << "Wrong elink Idx! Elink raw " << Form("%d remap %d", usElinkIdx, uFebIdx);
+    return;
+  }
+  const uint32_t uAsicIdx =
+    (fuCurrDpbIdx * fUnpackPar->GetNbCrobsPerDpb() + uCrobIdx) * fUnpackPar->GetNbAsicsPerCrob()
+    + fUnpackPar->ElinkIdxToAsicIdx(1 == fviFebType[fuCurrDpbIdx][uCrobIdx][uFebIdx], usElinkIdx);
+  //LOG(info) << "Test " << uFebIdx << " " << uAsicIdx / fUnpackPar->GetNbAsicsPerFeb();
+  //const uint32_t uFebIdx    = uAsicIdx / fUnpackPar->GetNbAsicsPerFeb();  // delete this?
+
+  const uint16_t usChan     = mess.GetHitChannel();
+  const uint16_t usRawAdc   = mess.GetHitAdc();
+  const uint16_t usRawTs    = mess.GetHitTimeBinning();
+  const uint32_t uChanInFeb = usChan + fUnpackPar->GetNbChanPerAsic() * (uAsicIdx % fUnpackPar->GetNbAsicsPerFeb());
+
+  /// Duplicate hits rejection
+  if (usRawTs == fvvusLastTsChan[uAsicIdx][usChan] &&
+      //       usRawAdc                           == fvvusLastAdcChan[ uAsicIdx ][ usChan ] &&
+      fvulCurrentTsMsb[fuCurrDpbIdx] - fvvusLastTsMsbChan[uAsicIdx][usChan] < kuMaxTsMsbDiffDuplicates
+      && fvuCurrentTsMsbCycle[fuCurrDpbIdx] == fvvusLastTsMsbCycleChan[uAsicIdx][usChan]) {
+    /// FIXME: add plots to check what is done in this rejection
+    return;
+  }  // if SMX 2.0 DPB and same TS, ADC, TS MSB, TS MSB cycle!
+  fvvusLastTsChan[uAsicIdx][usChan]         = usRawTs;
+  fvvusLastAdcChan[uAsicIdx][usChan]        = usRawAdc;
+  fvvusLastTsMsbChan[uAsicIdx][usChan]      = fvulCurrentTsMsb[fuCurrDpbIdx];
+  fvvusLastTsMsbCycleChan[uAsicIdx][usChan] = fvuCurrentTsMsbCycle[fuCurrDpbIdx];
+
+  // Compute the Full time stamp
+  const int64_t ulHitTime = GetFullTimeStamp(usRawTs);
+
+  /// Store hit for output only if it is mapped to a module!!!
+  if (0 != fviFebAddress[uFebIdx] && fdAdcCut < usRawAdc) {
+    /// Store only if masking is disabled or if channeld is not masked
+    /// 2D vector is safe as always right size if masking enabled
+    if (false == fbUseChannelMask || false == fvvbMaskedChannels[uFebIdx][uChanInFeb])
+      fvmHitsInMs.push_back(stsxyter::FinalHit(ulHitTime, usRawAdc, uAsicIdx, usChan, fuCurrDpbIdx, uCrobIdx));
+  }
+
+  // Convert the Hit time in bins to Hit time in ns
+  const double dHitTimeNs = ulHitTime * stsxyter::kdClockCycleNs;
+
+  /// If EM flag ON, store a corresponding error message with the next flag after all other possible status flags set
+  if (mess.IsHitMissedEvts())
+    fOptOutAVec->push_back(
+      CbmErrorMessage(ECbmModuleId::kSts, dHitTimeNs, uAsicIdx, 1 << stsxyter::kusLenStatStatus, usChan));
+
+  if (fbMonitorMode) {
+    // Check Starting point of histos with time as X axis
+    if (-1 == fdStartTime) { fdStartTime = dHitTimeNs; }
+    if (fbDebugMonitorMode) {
+      fUnpackMonitor->FillHitDebugMonitoringHistos(uAsicIdx, usChan, usRawAdc, usRawTs, mess.IsHitMissedEvts());
+    }
+    const uint32_t uAsicInFeb       = uAsicIdx % fUnpackPar->GetNbAsicsPerFeb();
+    const double dTimeSinceStartSec = (dHitTimeNs - fdStartTime) * 1e-9;
+    const double dCalAdc            = fvdFebAdcOffs[uFebIdx] + (usRawAdc - 1) * fvdFebAdcGain[uFebIdx];
+    fUnpackMonitor->FillHitMonitoringHistos(uFebIdx, usChan, uChanInFeb, usRawAdc, dCalAdc, usRawTs,
+                                            mess.IsHitMissedEvts());
+    fUnpackMonitor->FillHitEvoMonitoringHistos(uFebIdx, uAsicIdx, uAsicInFeb, uChanInFeb, dTimeSinceStartSec,
+                                               mess.IsHitMissedEvts());
+  }
+}
+
+
+void CbmStsUnpackAlgoLegacy::ProcessTsMsbInfo(const stsxyter::Message& mess, uint32_t uMessIdx, uint32_t uMsIdx)
+{
+  const uint32_t uVal = mess.GetTsMsbValBinning();
+
+  // Update Status counters
+  if (uVal < fvulCurrentTsMsb[fuCurrDpbIdx]) {
+
+    LOG(info) << " TS " << std::setw(12) << fTsIndex << " MS " << std::setw(12) << fulCurrentMsIdx << " MS Idx "
+              << std::setw(4) << uMsIdx << " Msg Idx " << std::setw(5) << uMessIdx << " DPB " << std::setw(2)
+              << fuCurrDpbIdx << " Old TsMsb " << std::setw(5) << fvulCurrentTsMsb[fuCurrDpbIdx] << " Old MsbCy "
+              << std::setw(5) << fvuCurrentTsMsbCycle[fuCurrDpbIdx] << " new TsMsb " << std::setw(5) << uVal;
+
+    fvuCurrentTsMsbCycle[fuCurrDpbIdx]++;
+  }
+  if (
+    uVal != fvulCurrentTsMsb[fuCurrDpbIdx] + 1 && !(0 == uVal && 4194303 == fvulCurrentTsMsb[fuCurrDpbIdx])
+    &&                /// Case where we reach a normal cycle edge
+    1 != uMessIdx &&  /// First TS_MSB in MS may jump if TS dropped by DAQ
+    !(0 == uVal && 0 == fvulCurrentTsMsb[fuCurrDpbIdx] && 2 == uMessIdx) &&  /// case with cycle et edge of 2 MS
+    !(uVal == fvulCurrentTsMsb[fuCurrDpbIdx] && 2 == uMessIdx)
+    &&  /// Msg 1 and 2 will be same TS_MSB if data in 1st bin
+    uVal < fvulCurrentTsMsb
+        [fuCurrDpbIdx]  /// New FW introduced TS_MSB suppression + large TS_MSB => warning only if value not increasing
+  ) {
+    LOG(info) << "TS MSb Jump in "
+              << " TS " << std::setw(12) << fTsIndex << " MS " << std::setw(12) << fulCurrentMsIdx << " MS Idx "
+              << std::setw(4) << uMsIdx << " Msg Idx " << std::setw(5) << uMessIdx << " DPB " << std::setw(2)
+              << fuCurrDpbIdx << " => Old TsMsb " << std::setw(5) << fvulCurrentTsMsb[fuCurrDpbIdx] << " new TsMsb "
+              << std::setw(5) << uVal;
+  }
+
+  /// Catch case where previous MS ended up on a TS MSB cycle as it is then
+  /// already updated from the MS index
+  if (4194303 == uVal && 1 == uMessIdx) fvulCurrentTsMsb[fuCurrDpbIdx] = 0;
+  else
+    fvulCurrentTsMsb[fuCurrDpbIdx] = uVal;
+
+  if (fbMonitorMode && fbDebugMonitorMode) {  //also if( 1 < uMessIdx )?
+    fUnpackMonitor->FillStsDpbRawTsMsb(fuCurrDpbIdx, fvulCurrentTsMsb[fuCurrDpbIdx]);
+    fUnpackMonitor->FillStsDpbRawTsMsbSx(fuCurrDpbIdx, fvulCurrentTsMsb[fuCurrDpbIdx]);
+    fUnpackMonitor->FillStsDpbRawTsMsbDpb(fuCurrDpbIdx, fvulCurrentTsMsb[fuCurrDpbIdx]);
+  }
+}
+
+void CbmStsUnpackAlgoLegacy::ProcessEpochInfo(const stsxyter::Message& /*mess*/)
+{
+  //   Currently not used
+  //   uint32_t uVal    = mess.GetEpochVal();
+  //   uint32_t uCurrentCycle = uVal % stsxyter::kulTsCycleNbBins;
+}
+
+// -------------------------------------------------------------------------
+void CbmStsUnpackAlgoLegacy::ProcessStatusInfo(const stsxyter::Message& mess, uint32_t uIdx)
+{
+  if (fbMonitorMode && fbDebugMonitorMode) {
+    std::cout << Form("DPB %2u TS %12u MS %12u mess %5u ", fuCurrDpbIdx, fTsIndex, fulCurrentMsIdx, uIdx);
+    mess.PrintMess(std::cout, stsxyter::MessagePrintMask::msg_print_Human);
+  }
+
+  const uint16_t usElinkIdx = mess.GetStatusLink();
+  const uint32_t uCrobIdx   = usElinkIdx / fUnpackPar->GetNbElinkPerCrob();
+  const int32_t uFebIdx     = fUnpackPar->ElinkIdxToFebIdx(usElinkIdx);
+  if (-1 == uFebIdx) {
+    LOG(warning) << "CbmStsUnpackAlgoLegacy::DoUnpack => "
+                 << "Wrong elink Idx! Elink raw " << Form("%d remap %d", usElinkIdx, uFebIdx);
+    return;
+  }
+  const uint32_t uAsicIdx =
+    (fuCurrDpbIdx * fUnpackPar->GetNbCrobsPerDpb() + uCrobIdx) * fUnpackPar->GetNbAsicsPerCrob()
+    + fUnpackPar->ElinkIdxToAsicIdx(1 == fviFebType[fuCurrDpbIdx][uCrobIdx][uFebIdx], usElinkIdx);
+
+  if (fbMonitorMode) {
+    const uint16_t usStatusField = mess.GetStatusStatus();
+    fUnpackMonitor->FillStsStatusMessType(uAsicIdx, usStatusField);
+  }
+  /// Compute the Full time stamp
+  const int64_t ulTime = GetFullTimeStamp(0);
+
+  /// Convert the time in bins to Hit time in ns
+  const double dTimeNs = ulTime * stsxyter::kdClockCycleNs;
+  fOptOutAVec->push_back(
+    CbmErrorMessage(ECbmModuleId::kSts, dTimeNs, uAsicIdx, mess.GetStatusStatus(), mess.GetData()));
+}
+
+// -------------------------------------------------------------------------
+int64_t CbmStsUnpackAlgoLegacy::GetFullTimeStamp(const uint16_t usRawTs)
+{
+  // Use TS w/o overlap bits as they will anyway come from the TS_MSB
+  const int64_t ulTime =
+    usRawTs
+    + static_cast<uint64_t>(stsxyter::kuHitNbTsBinsBinning) * static_cast<uint64_t>(fvulCurrentTsMsb[fuCurrDpbIdx])
+    + static_cast<uint64_t>(stsxyter::kulTsCycleNbBinsBinning)
+        * static_cast<uint64_t>(fvuCurrentTsMsbCycle[fuCurrDpbIdx]);
+
+  return ulTime;
+}
+
+// -------------------------------------------------------------------------
+void CbmStsUnpackAlgoLegacy::ProcessErrorInfo(const stsxyter::Message& mess)
+{
+  if (mess.IsMsErrorFlagOn()) {
+    if (fbMonitorMode || fbDebugMonitorMode) {
+      fUnpackMonitor->FillMsErrorsEvo(fulCurrentMsIdx, mess.GetMsErrorType());
+    }
+    fOptOutAVec->push_back(
+      CbmErrorMessage(ECbmModuleId::kSts, fulCurrentMsIdx, fuCurrDpbIdx, 0x20, mess.GetMsErrorType()));
+  }
+}
+
+// -------------------------------------------------------------------------
+void CbmStsUnpackAlgoLegacy::SetTimeOffsetNsAsic(const uint32_t uAsicIdx, const double dOffsetIn)
+{
+  if (uAsicIdx >= fvdTimeOffsetNsAsics.size()) { fvdTimeOffsetNsAsics.resize(uAsicIdx + 1, 0.0); }
+  fvdTimeOffsetNsAsics[uAsicIdx] = dOffsetIn;
+}
+
+// -------------------------------------------------------------------------
+void CbmStsUnpackAlgoLegacy::MaskNoisyChannel(const uint32_t uFeb, const uint32_t uChan, const bool bMasked)
+{
+  if (false == fbUseChannelMask) {
+    fbUseChannelMask = true;
+    fvvbMaskedChannels.resize(fuNbFebs);
+    for (uint32_t uFebIdx = 0; uFebIdx < fuNbFebs; ++uFebIdx) {
+      fvvbMaskedChannels[uFebIdx].resize(fUnpackPar->GetNbChanPerFeb(), false);
+    }
+  }
+  if (uFeb < fuNbFebs && uChan < fUnpackPar->GetNbChanPerFeb()) fvvbMaskedChannels[uFeb][uChan] = bMasked;
+  else
+    LOG(fatal) << "CbmStsUnpackAlgoLegacy::MaskNoisyChannel => Invalid FEB "
+                  "and/or CHAN index:"
+               << Form(" %u vs %u and %u vs %u", uFeb, fuNbFebs, uChan, fUnpackPar->GetNbChanPerFeb());
+}
+// -------------------------------------------------------------------------
diff --git a/reco/detectors/sts/unpack/CbmStsUnpackAlgoLegacy.h b/reco/detectors/sts/unpack/CbmStsUnpackAlgoLegacy.h
new file mode 100644
index 0000000000000000000000000000000000000000..d097121527a90d6c185cbc7d2b780e7246ec0b59
--- /dev/null
+++ b/reco/detectors/sts/unpack/CbmStsUnpackAlgoLegacy.h
@@ -0,0 +1,178 @@
+// -----------------------------------------------------------------------------
+// -----                                                                   -----
+// -----                  CbmStsUnpackAlgoLegacy                       -----
+// -----               Created 26.01.2019 by P.-A. Loizeau                 -----
+// -----                                                                   -----
+// -----------------------------------------------------------------------------
+
+#ifndef CbmStsUnpackAlgoLegacy_H
+#define CbmStsUnpackAlgoLegacy_H
+
+#include "CbmErrorMessage.h"  // REMARK see remark in CbmStsUnpackConfig
+#include "CbmRecoUnpackAlgo.tmpl"
+
+// Data
+#include "CbmStsDigi.h"
+
+#include "StsXyterFinalHit.h"
+#include "StsXyterMessage.h"
+
+// CbmRoot
+
+// C++11
+#include <chrono>
+
+// C/C++
+#include <map>
+#include <vector>
+
+class CbmMcbm2018StsPar;
+class CbmStsUnpackMonitor;
+
+class CbmStsUnpackAlgoLegacy : public CbmRecoUnpackAlgo<CbmStsDigi, CbmErrorMessage> {
+public:
+  CbmStsUnpackAlgoLegacy();
+  ~CbmStsUnpackAlgoLegacy();
+
+  /** @brief Copy constructor - not implemented **/
+  CbmStsUnpackAlgoLegacy(const CbmStsUnpackAlgoLegacy&) = delete;
+
+  /** @brief Assignment operator - not implemented **/
+  CbmStsUnpackAlgoLegacy& operator=(const CbmStsUnpackAlgoLegacy&) = delete;
+
+  virtual bool init();
+  virtual void reset();
+  virtual void finish();
+
+  bool InitParameters();
+
+  //virtual bool Unpack(const fles::Timeslice& ts, const uint32_t uMsComp);
+
+  inline void SetMonitorMode(bool bFlagIn = true) { fbMonitorMode = bFlagIn; }
+  inline void SetDebugMonitorMode(bool bFlagIn = true) { fbDebugMonitorMode = bFlagIn; }
+  inline void SetTimeOffsetNs(double dOffsetIn = 0.0) { fdTimeOffsetNs = dOffsetIn; }
+  void SetTimeOffsetNsAsic(const uint32_t uAsicIdx, const double dOffsetIn = 0.0);
+  void MaskNoisyChannel(const uint32_t uFeb, const uint32_t uChan, const bool bMasked = true);
+  void SetMinAdcCut(uint32_t uAdc) { fdAdcCut = uAdc; }
+
+  void SetUnpackStsMonitor(CbmStsUnpackMonitor* inMonitor) { fUnpackMonitor = inMonitor; }
+
+protected:
+  /**
+   * @brief Unpack a given microslice. To be implemented in the derived unpacker algos.
+   *
+   * @param ts timeslice pointer
+   * @param icomp index to the component to be unpacked
+   * @param imslice index of the microslice to be unpacked
+   * @return true
+   * @return false
+   *
+   * @remark The content of the µslice can only be accessed via the timeslice. Hence, we need to pass the pointer to the full timeslice
+  */
+  bool unpack(const fles::Timeslice* ts, std::uint16_t icomp, UInt_t imslice);
+
+private:
+  /// Control flags
+  bool fbMonitorMode;       //! Switch ON the filling of a minimal set of histograms
+  bool fbDebugMonitorMode;  //! Switch ON the filling of a additional set of histograms
+  std::vector<bool> fvbMaskedComponents;
+
+  /// Storage of monitoring histograms
+  CbmStsUnpackMonitor* fUnpackMonitor = nullptr;
+
+  /// Settings from parameter file
+  CbmMcbm2018StsPar* fUnpackPar;                //!
+                                                /// Readout chain dimensions and mapping
+  uint32_t fuNbFebs;                            //! Number of FEBs with StsXyter ASICs
+  std::map<uint32_t, uint32_t> fDpbIdIndexMap;  //! Map of DPB Identifier to DPB index
+  void InitDpbIdIndexMap();
+
+  std::vector<std::vector<std::vector<int32_t>>>
+    fviFebType;  //! FEB type, [ NbDpb ][ NbCrobPerDpb ][ NbFebsPerCrob ], 0 = A, 1 = B, -1 if inactive
+  std::vector<int32_t> fviFebAddress;  //! STS address for each FEB, [ NbDpb * NbCrobPerDpb * NbFebsPerCrob ]
+  std::vector<int32_t> fviFebSide;     //! Module side for each FEB, [ NbDpb * NbCrobPerDpb * NbFebsPerCrob ]
+  std::vector<double> fvdFebAdcGain;   //! ADC gain in e-/b, [ NbDpb * NbCrobPerDpb * NbFebsPerCrob ]
+  std::vector<double> fvdFebAdcOffs;   //! ADC offset in e-, [ NbDpb * NbCrobPerDpb * NbFebsPerCrob ]
+
+  /**
+   * @brief Handles the distribution of the hidden derived classes to their explicit functions.
+   *
+   * @param parset
+   * @return Bool_t initOk
+  */
+  Bool_t initParSet(FairParGenericSet* parset);
+
+  /**
+   * @brief Initialize the parameters from CbmMcbm2018StsPar.
+   *
+   * @param parset
+   * @return Bool_t initOk
+  */
+  Bool_t initParSet(CbmMcbm2018StsPar* parset);
+
+  void InitInternalStatus();
+  void InitTempVectors(std::vector<int32_t>* viModuleType, std::vector<int32_t>* viModAddress,
+                       std::vector<std::vector<std::vector<int32_t>>>* viFebModuleIdx,
+                       std::vector<std::vector<bool>>* vbCrobActiveFlag,
+                       std::vector<std::vector<std::vector<int32_t>>>* viFebModuleSide);
+
+  void PrintActiveCrobs(const std::vector<std::vector<bool>>& vbCrobActiveFlag);
+  void PrintAddressMaps(const std::vector<std::vector<std::vector<int32_t>>>& viFebModuleIdx,
+                        const std::vector<std::vector<std::vector<int32_t>>>& viFebModuleSide);
+
+  /// Add the hits to the output buffer as Digis
+  void AddHitsToDigiVect(std::vector<stsxyter::FinalHit>* vmHitsIn, std::vector<CbmStsDigi>* vDigiVectOut);
+
+  /// Get full time stamp from raw time stamp
+  int64_t GetFullTimeStamp(const uint16_t usRawTs);
+
+  /// User settings: Data correction parameters
+  double fdTimeOffsetNs;
+  std::vector<double> fvdTimeOffsetNsAsics;
+  bool fbUseChannelMask;
+  std::vector<std::vector<bool>>
+    fvvbMaskedChannels;  //! Vector of channel masks, [ NbFeb ][ NbCHanInFeb ], used only if fbUseChannelMask is true
+  uint32_t fdAdcCut;
+
+  /// Running indices
+  /// TS/MS info
+  uint64_t fulCurrentMsIdx;
+
+  /// Current data properties
+  uint32_t fuCurrDpbIdx;                       //! Index of the DPB from which the MS currently unpacked is coming
+                                               /// Data format control
+  std::vector<uint64_t> fvulCurrentTsMsb;      //! Current TS MSB for each DPB
+  std::vector<uint32_t> fvuCurrentTsMsbCycle;  //! Current TS MSB cycle for DPB
+                                               /// Starting state book-keeping
+  double fdStartTime;     /** Time of first valid hit (TS_MSB available), used as reference for evolution plots**/
+  double fdStartTimeMsSz; /** Time of first microslice, used as reference for evolution plots**/
+  std::chrono::steady_clock::time_point
+    ftStartTimeUnix; /** Time of run Start from UNIX system, used as reference for long evolution plots against reception time **/
+
+  /// Hits time-sorting
+  std::vector<stsxyter::FinalHit>
+    fvmHitsInMs;  //! All hits (time in bins, ADC in bins, asic, channel) in last MS, sorted with "<" operator
+
+  /// Duplicate hits suppression
+  static const uint32_t kuMaxTsMsbDiffDuplicates = 8;
+  std::vector<std::vector<uint16_t>> fvvusLastTsChan;  //! TS of last hit message for each channel, [ AsicIdx ][ Chan ]
+  std::vector<std::vector<uint16_t>>
+    fvvusLastAdcChan;  //! ADC of last hit message for each channel, [ AsicIdx ][ Chan ]
+  std::vector<std::vector<uint16_t>>
+    fvvusLastTsMsbChan;  //! TS MSB of last hit message for each channel, [ AsicIdx ][ Chan ]
+  std::vector<std::vector<uint16_t>>
+    fvvusLastTsMsbCycleChan;  //! TS MSB cycle of last hit message for each channel, [ AsicIdx ][ Chan ]
+
+  void ProcessHitInfo(const stsxyter::Message& mess);
+  void ProcessTsMsbInfo(const stsxyter::Message& mess, uint32_t uMessIdx = 0, uint32_t uMsIdx = 0);
+  void ProcessEpochInfo(const stsxyter::Message& mess);
+  void ProcessStatusInfo(const stsxyter::Message& mess, uint32_t uIdx);
+  void ProcessErrorInfo(const stsxyter::Message& mess);
+
+  void RefreshTsMsbFields(const size_t uMsIdx);
+  void LoopMsMessages(const uint8_t* msContent, const uint32_t uSize, const size_t uMsIdx);
+
+  ClassDef(CbmStsUnpackAlgoLegacy, 1)
+};
+
+#endif