diff --git a/reco/detectors/rich/CMakeLists.txt b/reco/detectors/rich/CMakeLists.txt
index c766bcf688acf0c56cc1da382582458ef6ff11de..b1defbaef25ea164664355f3e3226a2b57f75f6d 100644
--- a/reco/detectors/rich/CMakeLists.txt
+++ b/reco/detectors/rich/CMakeLists.txt
@@ -84,6 +84,8 @@ qa/CbmRichGeoTestOpt.cxx
 qa/CbmRichRecoQa.cxx
 
 unpack/CbmRichUnpackAlgo.cxx
+unpack/CbmRichUnpackAlgo2022.cxx
+unpack/CbmRichUnpackAlgoBase.cxx
 unpack/CbmRichUnpackConfig.cxx
 )
 
diff --git a/reco/detectors/rich/CbmRichRecoLinkDef.h b/reco/detectors/rich/CbmRichRecoLinkDef.h
index 80a8254f47b1769bfc1ff8dc2244eb7a41f7edbb..667b0bf5d4eb63129c81bc1d0ccd7cb4a84796b7 100644
--- a/reco/detectors/rich/CbmRichRecoLinkDef.h
+++ b/reco/detectors/rich/CbmRichRecoLinkDef.h
@@ -34,6 +34,8 @@
 
 //unpack
 #pragma link C++ class CbmRichUnpackAlgo + ;
+#pragma link C++ class CbmRichUnpackAlgo2022 + ;
+#pragma link C++ class CbmRichUnpackAlgoBase + ;
 #pragma link C++ class CbmRichUnpackConfig + ;
 
 
diff --git a/reco/detectors/rich/unpack/CbmRichUnpackAlgo.cxx b/reco/detectors/rich/unpack/CbmRichUnpackAlgo.cxx
index 2a997dc41180b756d2688d2354208f963476e94f..3d0e08f8f50bd925e51a7b221da034c5ce009262 100644
--- a/reco/detectors/rich/unpack/CbmRichUnpackAlgo.cxx
+++ b/reco/detectors/rich/unpack/CbmRichUnpackAlgo.cxx
@@ -14,75 +14,10 @@
 #include <cstdint>
 
 
-CbmRichUnpackAlgo::CbmRichUnpackAlgo() : CbmRecoUnpackAlgo("CbmRichUnpackAlgo") {}
+CbmRichUnpackAlgo::CbmRichUnpackAlgo() : CbmRichUnpackAlgoBase("CbmRichUnpackAlgo") {}
 
 CbmRichUnpackAlgo::~CbmRichUnpackAlgo() {}
 
-// ---- GetParContainerRequest ----
-std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>*
-  CbmRichUnpackAlgo::GetParContainerRequest(std::string /*geoTag*/, std::uint32_t /*runId*/)
-{
-  // Basepath for default Trd parameter sets (those connected to a geoTag)
-  std::string basepath = Form("%s", fParFilesBasePath.data());
-  std::string temppath = "";
-
-  // // Get parameter container
-  temppath = basepath + "mRichPar_70.par";
-
-  fParContVec.emplace_back(std::make_pair(temppath, std::make_shared<CbmMcbm2018RichPar>()));
-
-  return &fParContVec;
-}
-
-// ---- calculateTime
-double CbmRichUnpackAlgo::calculateTime(uint32_t epoch, uint32_t coarse, uint32_t fine)
-{
-  return ((double) epoch) * 2048. * 5. + ((double) coarse) * 5. - ((double) fine) * 0.005;
-}
-
-// ---- getLogHeader
-std::string CbmRichUnpackAlgo::getLogHeader(CbmRichUnpackAlgoMicrosliceReader& reader)
-{
-  std::stringstream stream;
-  stream << "[" << fNrProcessedTs << "-" << reader.GetWordCounter() << "/" << reader.GetSize() / 4 << " "
-         << reader.GetWordAsHexString(reader.GetCurWord()) << "] ";
-  return stream.str();
-}
-
-// ---- init
-Bool_t CbmRichUnpackAlgo::init() { return kTRUE; }
-
-// ---- initParSet(FairParGenericSet* parset) ----
-Bool_t CbmRichUnpackAlgo::initParSet(FairParGenericSet* parset)
-{
-  LOG(info) << fName << "::initParSet - for container " << parset->ClassName();
-  if (parset->IsA() == CbmMcbm2018RichPar::Class()) return initParSet(static_cast<CbmMcbm2018RichPar*>(parset));
-
-  // If we do not know the derived ParSet class we return false
-  LOG(error) << fName << "::initParSet - for container " << parset->ClassName() << " failed, since" << fName
-             << "::initParSet() does not know the derived ParSet and what to do with it!";
-  return kFALSE;
-}
-
-// ---- initParSet(CbmTrdParSetAsic* parset) ----
-Bool_t CbmRichUnpackAlgo::initParSet(CbmMcbm2018RichPar* parset)
-{
-  LOG(debug) << fName << "::initParSetAsic - ";
-  fUnpackPar = *parset;
-  fUnpackPar.Print();
-
-  LOG(info) << fName << "::initParSetRichMcbm2018 - Successfully initialized RICH unpacking parameters";
-
-  return kTRUE;
-}
-
-// ---- isLog ----
-bool CbmRichUnpackAlgo::isLog()
-{
-  //if (fTsCounter == 25215) return true;
-  return false;
-}
-
 // ---- unpack
 bool CbmRichUnpackAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp, UInt_t imslice)
 {
@@ -440,13 +375,5 @@ void CbmRichUnpackAlgo::writeOutputDigi(Int_t fpgaID, Int_t channel, Double_t ti
   */
 }
 
-bool CbmRichUnpackAlgo::checkMaskedDiRICH(Int_t subSubEventId)
-{
-  for (unsigned int i = 0; i < fMaskedDiRICHes->size(); ++i) {
-    if (fMaskedDiRICHes->at(i) == subSubEventId) return true;
-  }
-
-  return false;
-}
 
 ClassImp(CbmRichUnpackAlgo)
diff --git a/reco/detectors/rich/unpack/CbmRichUnpackAlgo.h b/reco/detectors/rich/unpack/CbmRichUnpackAlgo.h
index 489fd43ac7e668eada28a4f847cb6de0401faf0d..2e5503cb462dd376c4a45246da97216f07a28b4a 100644
--- a/reco/detectors/rich/unpack/CbmRichUnpackAlgo.h
+++ b/reco/detectors/rich/unpack/CbmRichUnpackAlgo.h
@@ -24,6 +24,7 @@
 #include "CbmMcbm2018RichPar.h"
 #include "CbmRecoUnpackAlgo.tmpl"
 #include "CbmRichDigi.h"
+#include "CbmRichUnpackAlgoBase.h"
 
 #include "Timeslice.hpp"  // timeslice
 
@@ -36,164 +37,8 @@
 #include <memory>
 #include <utility>
 
-enum class CbmRichUnpackAlgoErrorType
-{
-  mtsError,
-  tdcHeader,
-  tdcTrailer,
-  ctsHeader,
-  ctsTrailer,
-  subEventError
-};
-
-enum class CbmRichUnpackAlgoTdcWordType
-{
-  TimeData,
-  Header,
-  Epoch,
-  Trailer,
-  Debug,
-  Error
-};
-
-class CbmRichUnpackAlgoTdcTimeData {
-public:
-  uint32_t fCoarse  = 0;  // 11 bits
-  uint32_t fEdge    = 0;  // 1 bit
-  uint32_t fFine    = 0;  // 10 bits
-  uint32_t fChannel = 0;  // 7 bits
-
-  std::string ToString()
-  {
-    std::stringstream stream;
-    stream << "channel:" << fChannel << " coarse:" << fCoarse << " fine:" << fFine
-           << " edge:" << ((fEdge == 1) ? "R" : "F");
-    return stream.str();
-  }
-
-  bool IsRisingEdge() { return (fEdge == 1); }
-};
-
-class CbmRichUnpackAlgoTdcWordReader {
-public:
-  static CbmRichUnpackAlgoTdcWordType GetTdcWordType(uint32_t tdcWord)
-  {
-    uint32_t tdcTimeDataMarker = (tdcWord >> 31) & 0x1;  // 1 bit
-    uint32_t tdcMarker         = (tdcWord >> 29) & 0x7;  // 3 bits
-
-    if (tdcTimeDataMarker == 0x1) {
-      // TODO: I also include tdcMarker == 0x5, some tdc time data words have this marker. Is it correct?
-      if (tdcMarker == 0x4 || tdcMarker == 0x5) { return CbmRichUnpackAlgoTdcWordType::TimeData; }
-      else {
-        return CbmRichUnpackAlgoTdcWordType::Error;
-      }
-    }
-
-    if (tdcMarker == 0x0) return CbmRichUnpackAlgoTdcWordType::Trailer;
-    if (tdcMarker == 0x1) return CbmRichUnpackAlgoTdcWordType::Header;
-    if (tdcMarker == 0x2) return CbmRichUnpackAlgoTdcWordType::Debug;
-    if (tdcMarker == 0x3) return CbmRichUnpackAlgoTdcWordType::Epoch;
-
-    return CbmRichUnpackAlgoTdcWordType::Error;
-  }
-
-  static void ProcessTimeData(uint32_t tdcWord, CbmRichUnpackAlgoTdcTimeData& outData)
-  {
-    outData.fCoarse  = static_cast<uint32_t>(tdcWord & 0x7ff);          // 11 bits
-    outData.fEdge    = static_cast<uint32_t>((tdcWord >> 11) & 0x1);    // 1 bit
-    outData.fFine    = static_cast<uint32_t>((tdcWord >> 12) & 0x3ff);  // 10 bits
-    outData.fChannel = static_cast<uint32_t>((tdcWord >> 22) & 0x7f);   // 7 bits
-  }
-
-  static uint32_t ProcessEpoch(uint32_t tdcWord) { return static_cast<uint32_t>(tdcWord & 0xfffffff); }
-
-  static uint16_t ProcessHeader(uint32_t tdcWord)
-  {
-    // for the moment just extract error bits
-    return static_cast<uint16_t>(tdcWord & 0xff);  //8 bits
-  }
-
-  static uint16_t ProcessTrailer(uint32_t tdcWord)
-  {
-    // for the moment just extract error bits
-    return static_cast<uint16_t>(tdcWord & 0xffff);
-  }
-
-  static void ProcessDebug(uint32_t tdcWord)
-  {
-    LOG(debug4) << "ProcessDebug is not implemented. tdcWord:0x" << std::hex << tdcWord << std::dec;
-    // for the moment do nothing
-  }
-};
-
-class CbmRichUnpackAlgoMicrosliceReader {
-private:
-  const uint8_t* fData = nullptr;
-  size_t fSize         = 0;
-  size_t fOffset       = 0;  // offset in bytes
-  size_t fWordCounter  = 0;
-  uint32_t fCurWord;
-
-public:
-  void SetData(const uint8_t* data, size_t size)
-  {
-    fData        = data;
-    fSize        = size;
-    fOffset      = 0;
-    fWordCounter = 0;
-    fCurWord     = 0;
-  }
-
-  const uint8_t* GetData() { return fData; }
-
-  size_t GetSize() { return fSize; }
-
-  size_t GetOffset() { return fOffset; }
-
-  size_t GetWordCounter() { return fWordCounter; }
-
-  uint32_t GetCurWord() { return fCurWord; }
-
-  std::string GetWordAsHexString(uint32_t word)
-  {
-    std::stringstream stream;
-    stream << "0x" << std::setfill('0') << std::setw(sizeof(uint32_t) * 2) << std::hex << word;
-    return stream.str();
-  }
-
-  uint32_t NextWord()
-  {
-    //mRichSupport::SwapBytes(4, fData + fOffset);
-    //Int_t* dataPtr = (Int_t*) (fData + fOffset);
-    uint32_t i = ((uint32_t*) (fData + fOffset))[0];
-    //swap bytes
-    i = (i >> 24) | ((i << 8) & 0x00FF0000) | ((i >> 8) & 0x0000FF00) | (i << 24);
-    //i = ((i&0xFF)<<24) | (((i>>8)&0xFF)<<16) |   (((i>>16)&0xFF)<<8) | (((i>>24)&0xFF)<<0);
-
-    fOffset += 4;
-    fWordCounter++;
-    fCurWord = i;
-    //return (Int_t)(dataPtr[0]);
-    return i;
-  }
-
-  bool IsNextPadding()
-  {
-    uint32_t nextWord = ((uint32_t*) (fData + fOffset))[0];
-    if (nextWord == 0xffffffff) return true;
-    return false;
-  }
 
-  bool IsLastSubSubEvent(uint32_t subSubEventSize)
-  {
-    uint32_t i = ((uint32_t*) (fData + fOffset + 4 * subSubEventSize))[0];
-    i          = (i >> 24) | ((i << 8) & 0x00ff0000) | ((i >> 8) & 0x0000ff00) | (i << 24);
-    if (i == 0x00015555) return true;
-    return false;
-  }
-};
-
-class CbmRichUnpackAlgo : public CbmRecoUnpackAlgo<CbmRichDigi> {
+class CbmRichUnpackAlgo : public CbmRichUnpackAlgoBase {
 public:
   /** @brief Create the Cbm Trd Unpack AlgoBase object */
   CbmRichUnpackAlgo();
@@ -207,67 +52,8 @@ public:
   /** @brief Assignment operator - not implemented **/
   CbmRichUnpackAlgo& operator=(const CbmRichUnpackAlgo&) = delete;
 
-  /**
-   * @brief Get the requested parameter containers. To be defined in the derived classes!
-   * Return the required parameter containers together with the paths to the ascii 
-   * files to.
-   *  
-   * @param[in] std::string geoTag as used in CbmSetup
-   * @param[in] std::uint32_t runId for runwise defined parameters
-   * @return fParContVec
-  */
-  virtual std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>*
-  GetParContainerRequest(std::string geoTag, std::uint32_t runId);
-
-  void SetMaskedDiRICHes(std::vector<Int_t>* maskedDiRICHes) { fMaskedDiRICHes = maskedDiRICHes; }
 
 protected:
-  double calculateTime(uint32_t epoch, uint32_t coarse, uint32_t fine);
-
-  /** @brief Finish function for this algorithm base clase */
-  void finish()
-  {
-    finishDerived();
-    // Finish the monitor if we have one
-    // if (fMonitor) fMonitor->Finish();
-  }
-
-  /** @brief Function that allows special calls during Finish in the derived algos */
-  virtual void finishDerived() { return; }
-
-  std::string getLogHeader(CbmRichUnpackAlgoMicrosliceReader& reader);
-
-  Int_t getPixelUID(Int_t fpgaID, Int_t ch) const
-  {
-    // First 16 bits are used for the FPGA ID, then
-    // 8 bits unused and then 8 bits are used for the channel
-    return ((fpgaID << 16) | (ch & 0x00FF));
-  }
-
-  /**
-   * @brief Intialisation at begin of run. Special inits of the derived algos.
-   * 
-   * @retval Bool_t initOk
-  */
-  Bool_t init();
-
-  /**
-   * @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 Handles the distribution of the hidden derived classes to their explicit functions.
-   * 
-   * @param parset 
-   * @return Bool_t initOk 
-  */
-  Bool_t initParSet(CbmMcbm2018RichPar* parset);
-
-  bool isLog();
 
   void processTrbPacket(CbmRichUnpackAlgoMicrosliceReader& reader);
 
@@ -288,16 +74,6 @@ protected:
 	 */
   void writeOutputDigi(Int_t fpgaID, Int_t channel, Double_t time, Double_t tot);
 
-  /**
-   * @brief Set the Derived Ts Parameters
-   * 
-   * In this function parameters required by the explicit algo connected to the timeslice can be set.
-   * 
-   * @param itimeslice 
-   * @return true 
-   * @return false 
-  */
-  bool setDerivedTsParameters(size_t /*itimeslice*/) { return true; }
 
   /**
    * @brief Unpack a given microslice. To be implemented in the derived unpacker algos.
@@ -312,25 +88,13 @@ protected:
   */
   bool unpack(const fles::Timeslice* ts, std::uint16_t icomp, UInt_t imslice);
 
-  bool checkMaskedDiRICH(Int_t subSubEventId);
-
-  /** @brief Parameters for the unpacking */
-  CbmMcbm2018RichPar fUnpackPar;
-
-  std::vector<Int_t>* fMaskedDiRICHes = nullptr;
 
   double fMbsPrevTimeCh0 = 0.;
   double fMbsPrevTimeCh1 = 0.;
 
-  size_t fMsRefTime = 0;
-
-  double fToTMin = -20.;
-  double fToTMax = 100.;
-
   std::map<uint32_t, double> fLastCh0ReTime;      //key:TDC ID, value:Full time of last rising edge from ch 0
   std::map<uint32_t, double> fPrevLastCh0ReTime;  // key:TDC ID, value:Full time of previous last rising edge from ch 0
 
-  Bool_t fbDoToTCorr = true;  // kTRUE activates ToT correction from Parameterfile
 
 private:
   ClassDef(CbmRichUnpackAlgo, 2)
diff --git a/reco/detectors/rich/unpack/CbmRichUnpackAlgo2022.cxx b/reco/detectors/rich/unpack/CbmRichUnpackAlgo2022.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..2b91a3a958ed30e12087f36679415db8143e4a7f
--- /dev/null
+++ b/reco/detectors/rich/unpack/CbmRichUnpackAlgo2022.cxx
@@ -0,0 +1,407 @@
+/* Copyright (C) 2021 Goethe-University Frankfurt, Frankfurt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Pascal Raisig [committer] */
+
+#include "CbmRichUnpackAlgo2022.h"
+
+#include <FairParGenericSet.h>
+#include <FairTask.h>
+#include <Logger.h>
+
+#include <Rtypes.h>
+#include <RtypesCore.h>
+
+#include <cstdint>
+
+
+CbmRichUnpackAlgo2022::CbmRichUnpackAlgo2022() : CbmRichUnpackAlgoBase("CbmRichUnpackAlgo2022") {}
+
+CbmRichUnpackAlgo2022::~CbmRichUnpackAlgo2022() {}
+
+// ---- unpack
+bool CbmRichUnpackAlgo2022::unpack(const fles::Timeslice* ts, std::uint16_t icomp, UInt_t imslice)
+{
+
+  const fles::MicrosliceView mv            = ts->get_microslice(icomp, imslice);
+  const fles::MicrosliceDescriptor& msDesc = mv.desc();
+  //std::cout<< "startMS"<<std::endl;
+  CbmRichUnpackAlgoMicrosliceReader reader;
+  reader.SetData(mv.content(), msDesc.size);
+
+  auto mstime = msDesc.idx;
+  fMsRefTime  = mstime - fTsStartTime;
+  //std::cout<< fMsRefTime <<"  "<< fTsStartTime << std::endl;
+  // There are a lot of MS  with 8 bytes size
+  // Does one need these MS?
+  if (reader.GetSize() <= 8) return true;
+
+  while (true) {
+    processTrbPacket(reader);
+    // -4*2 for 2 last words which contain microslice index
+    if (reader.GetOffset() >= reader.GetSize() - 8) break;
+    // -4*3 for 0xffffffff padding and 2 last words which contain microslice index
+    if (reader.IsNextPadding() && reader.GetOffset() >= reader.GetSize() - 12) break;
+  }
+
+  uint32_t msIndexWord1 = reader.NextWord();
+  if (isLog()) LOG(DEBUG4) << getLogHeader(reader) << "Microslice Index 1:" << reader.GetWordAsHexString(msIndexWord1);
+
+  uint32_t msIndexWord2 = reader.NextWord();
+  if (isLog()) LOG(DEBUG4) << getLogHeader(reader) << "Microslice Index 2:" << reader.GetWordAsHexString(msIndexWord2);
+
+
+  return true;
+}
+
+void CbmRichUnpackAlgo2022::processHubBlock(CbmRichUnpackAlgoMicrosliceReader& reader)
+{
+  uint32_t word    = reader.NextWord();
+  uint32_t hubId   = word & 0xffff;          // 16 bits
+  uint32_t hubSize = (word >> 16) & 0xffff;  // 16 bits
+  if (isLog())
+    LOG(debug4) << getLogHeader(reader) << "hubId:0x" << std::hex << hubId << std::dec << " hubSize:" << hubSize;
+
+  //if ((HubId == 0xc001) || (HubId == 0xc000)) //CTS subevent?
+  //if (HubId == 0x5555)
+  //if (((HubId >> 8) & 0xff) == 0x82) // TRB subevent? // TODO: check if it starts from 0x82
+
+  // if true then it is CTS sub-sub-event
+  bool isLast         = false;
+  size_t counter      = 0;
+  size_t totalSize    = 0;
+  fCurrentSubSubEvent = 1;
+  while (!isLast) {
+    word                     = reader.NextWord();
+    uint32_t subSubEventId   = word & 0xffff;                              // 16 bits
+    uint32_t subSubEventSize = (word >> 16) & 0xffff;                      // 16 bits
+    isLast                   = reader.IsLastSubSubEvent(subSubEventSize);  // if true then it is CTS sub-sub-event
+    counter++;
+    totalSize += (1 + subSubEventSize);
+
+    if (isLog())
+      LOG(debug4) << getLogHeader(reader) << counter << ((isLast) ? " CTS" : " DiRICH") << " subSubEventId:0x"
+                  << std::hex << subSubEventId << std::dec << " subSubEventSize:" << subSubEventSize;
+
+    if (!isLast) {  // DiRICH event
+      // check correctness of subsub event, for safety reasons
+      if (((subSubEventId >> 12) & 0xF) != 0x7) {
+        LOG(error) << getLogHeader(reader) << "ERROR: subSubEventId has strange value:0x" << std::hex << subSubEventId
+                   << std::dec;
+      }
+      processSubSubEvent(reader, subSubEventSize, subSubEventId);
+    }
+    else {  // CTS event
+      fCurrentSubSubEvent = 0;
+      processCtsSubSubEvent(reader, subSubEventSize, subSubEventId);
+    }
+
+    //  if (fbDebugMonitorMode) {
+    //    //This address calculation is just for mCBM; will be a problem when using full CBM RICH acceptance
+    //    uint16_t histAddr = ((subSubEventId >> 8) & 0xF) * 18 + ((subSubEventId >> 4) & 0xF) * 2 + (subSubEventId & 0xF);
+    //    fhSubSubEventSize->Fill(histAddr, subSubEventSize);  // Words in a DiRICH
+    //  }
+
+    if ((totalSize == hubSize && !isLast) || (totalSize != hubSize && isLast)) {
+      if (isLog()) LOG(error) << "ERROR: totalSize OR isLast is wrong";
+    }
+
+    if (totalSize >= hubSize || isLast) break;
+
+    fCurrentSubSubEvent++;
+  }
+
+  // read last words
+  int lastWordsCounter = 0;
+  while (true) {
+    lastWordsCounter++;
+    word = reader.NextWord();
+    if (isLog()) LOG(debug4) << getLogHeader(reader);
+    if (word == 0x600dda7a) {
+      if (reader.IsNextPadding()) word = reader.NextWord();
+      break;
+    }
+    if (lastWordsCounter >= 7) {
+      LOG(error) << getLogHeader(reader)
+                 << "CbmMcbm2018UnpackerAlgoRich::ProcessHubBlock() ERROR: No word == 0x600dda7a";
+    }
+  }
+}
+
+void CbmRichUnpackAlgo2022::processCtsSubSubEvent(CbmRichUnpackAlgoMicrosliceReader& reader, uint32_t subSubEventSize,
+                                                  uint32_t subSubEventId)
+{
+  uint32_t word         = reader.NextWord();
+  uint32_t ctsState     = word & 0xffff;                                                                   // 16 bits
+  uint32_t nofInputs    = (word >> 16) & 0xf;                                                              // 4 bits
+  uint32_t nofTrigCh    = (word >> 20) & 0x1f;                                                             // 5 bits
+  uint32_t inclLastIdle = (word >> 25) & 0x1;                                                              // 1 bit
+  uint32_t inclTrigInfo = (word >> 26) & 0x1;                                                              // 1 bit
+  uint32_t inclTime     = (word >> 27) & 0x1;                                                              // 1 bit
+  uint32_t ETM          = (word >> 28) & 0x3;                                                              // 2 bits
+  uint32_t ctsInfoSize  = 2 * nofInputs + 2 * nofTrigCh + 2 * inclLastIdle + 3 * inclTrigInfo + inclTime;  // in words
+  switch (ETM) {
+    case 0: break;
+    case 1: ctsInfoSize += 1; break;
+    case 2: ctsInfoSize += 4; break;
+    case 3: break;
+  }
+  if (isLog()) LOG(debug4) << getLogHeader(reader) << "CTS ctsState:" << ctsState << " ctsInfoSize:" << ctsInfoSize;
+  for (uint32_t i = 0; i < ctsInfoSize; i++) {
+    word = reader.NextWord();  // do nothing?
+    if (isLog()) LOG(debug4) << getLogHeader(reader) << "CTS info words";
+  }
+  int nofTimeWords = subSubEventSize - ctsInfoSize - 1;
+  processSubSubEvent(reader, nofTimeWords, subSubEventId);
+}
+
+void CbmRichUnpackAlgo2022::processSubSubEvent(CbmRichUnpackAlgoMicrosliceReader& reader, int nofTimeWords,
+                                               uint32_t subSubEventId)
+{
+  // Store if a certain TDC word type was analysed,
+  // later one can check if the order is correct
+  bool wasHeader   = false;
+  bool wasEpoch    = false;
+  bool wasTime     = false;
+  bool wasTrailer  = false;
+  uint32_t epoch   = 0;  // store last epoch obtained in sub-sub-event
+  bool errorInData = false;
+
+  // Store last raising edge time for each channel or -1. if no time
+  // this array is used to match raising and falling edges
+  std::vector<double> raisingTime(33, -1.);
+
+  // check if DiRICH (SubSubEvId) is masked
+  bool DiRICH_masked = false;
+  if (checkMaskedDiRICH(subSubEventId)) { DiRICH_masked = true; }
+
+  for (int i = 0; i < nofTimeWords; i++) {
+    uint32_t word = reader.NextWord();
+    if (DiRICH_masked) continue;
+    CbmRichUnpackAlgoTdcWordType type = CbmRichUnpackAlgoTdcWordReader::GetTdcWordType(word);
+
+    if (type == CbmRichUnpackAlgoTdcWordType::TimeData) {
+      if (!wasHeader || !wasEpoch || wasTrailer) {
+        LOG(error) << getLogHeader(reader) << "DiRICH 0x" << std::hex << subSubEventId << std::dec
+                   << ": illegal position of TDC Time (before header/epoch or after trailer)";
+        errorInData = true;
+        continue;
+      }
+      wasTime = true;
+      processTimeDataWord(reader, i, epoch, word, subSubEventId, raisingTime);
+    }
+    else if (type == CbmRichUnpackAlgoTdcWordType::Epoch) {
+      if (!wasHeader || wasTrailer) {
+        LOG(error) << getLogHeader(reader) << "DiRICH 0x" << std::hex << subSubEventId << std::dec
+                   << ": illegal position of TDC Epoch (before header or after trailer)";
+        errorInData = true;
+        continue;
+      }
+      wasEpoch = true;
+      epoch    = CbmRichUnpackAlgoTdcWordReader::ProcessEpoch(word);
+      if (isLog()) LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << i << "] epoch:" << epoch;
+    }
+    else if (type == CbmRichUnpackAlgoTdcWordType::Header) {
+      if (wasEpoch || wasTime || wasTrailer) {
+        LOG(error) << getLogHeader(reader) << "DiRICH 0x" << std::hex << subSubEventId << std::dec
+                   << ": illegal position of TDC Header (after time/epoch/trailer)";
+        errorInData = true;
+        continue;
+      }
+      wasHeader = true;
+      // uint16_t errorBits = CbmRichUnpackAlgoTdcWordReader::ProcessHeader(word);
+      // ErrorMsg(errorBits, CbmRichUnpackAlgoErrorType::tdcHeader, subSubEventId);
+      if (isLog()) LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << i << "] header";
+    }
+    else if (type == CbmRichUnpackAlgoTdcWordType::Trailer) {
+      if (!wasEpoch || !wasTime || !wasHeader) {
+        LOG(error) << getLogHeader(reader) << "DiRICH 0x" << std::hex << subSubEventId << std::dec
+                   << ": illegal position of TDC Trailer (before time/epoch/header)";
+        errorInData = true;
+        continue;
+      }
+      wasTrailer = true;
+      // uint16_t errorBits = CbmRichUnpackAlgoTdcWordReader::ProcessTrailer(word);
+      // ErrorMsg(errorBits, CbmRichUnpackAlgoErrorType::tdcTrailer, subSubEventId);
+      if (isLog()) LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << i << "] trailer";
+    }
+    else if (type == CbmRichUnpackAlgoTdcWordType::Debug) {
+      // for the moment do nothing
+    }
+    else if (type == CbmRichUnpackAlgoTdcWordType::Error) {
+      LOG(error) << getLogHeader(reader) << "Wrong TDC word!!! marker:" << ((word >> 29) & 0x7);
+      errorInData = true;
+    }
+  }
+
+  if (errorInData) {
+    //TODO:
+  }
+}
+
+void CbmRichUnpackAlgo2022::processTrbPacket(CbmRichUnpackAlgoMicrosliceReader& reader)
+{
+  processCBMtime(reader);
+  uint32_t trigNum_this = reader.NextWord() & 0xFFFFFF;
+  for (auto l = 0; l < 5; ++l)
+    reader.NextWord();
+
+  //prev CBM time (64bit)
+  uint32_t cbmtime0           = reader.NextWord();  // CBM 63:32
+  uint32_t cbmtime1           = reader.NextWord();  // CBM 31: 0
+  uint64_t CbmTimePacket_prev = (uint64_t) cbmtime0 << 32 | cbmtime1;
+
+  uint32_t trigNum_prevMes = reader.NextWord() & 0xFFFFFF;
+
+  reader.NextWord();  // reserved
+  //std::cout<<"trigNum:  "<<std::hex<< trigNum_this <<std::dec  << "    trigNum_prev:  " <<std::hex<< trigNum_prevMes <<std::dec<<std::endl;
+  //std::cout<<"CBM time: "<<std::hex<< fCbmTimePacket <<std::dec<< "    CBM time prev: " <<std::hex<< CbmTimePacket_prev <<std::dec<<std::endl;
+  for (auto l = 0; l < 14; ++l) {
+    uint32_t wordEpoch = reader.NextWord();
+    uint32_t epoch     = CbmRichUnpackAlgoTdcWordReader::ProcessEpoch(wordEpoch);
+    uint32_t wordTime  = reader.NextWord();
+    CbmRichUnpackAlgoTdcTimeData td;
+    CbmRichUnpackAlgoTdcWordReader::ProcessTimeData(wordTime, td);
+
+    double fullTime = calculateTime(epoch, td.fCoarse, td.fFine);
+
+    if (l == 0) {
+      fMbsPrevTimeCh0       = fullTime;
+      fPrevLastCh0ReTime[0] = fullTime;
+    }
+    if (l == 1) fMbsPrevTimeCh1 = fullTime;
+    if (l > 1) fPrevLastCh0ReTime[l - 1] = fullTime;
+  }
+  //processMbs(reader, false);  // Current MBS
+  //processMbs(reader, true);   // Previous MBS
+
+  uint32_t trbNum = reader.NextWord();  // TRB trigger number
+  if (isLog()) LOG(debug4) << getLogHeader(reader) << "TRB Num:" << reader.GetWordAsHexString(trbNum);
+
+  processHubBlock(reader);
+}
+
+void CbmRichUnpackAlgo2022::processCBMtime(CbmRichUnpackAlgoMicrosliceReader& reader)
+{
+  uint32_t word_MSB = reader.NextWord();  // CBM 63:32
+  uint32_t word_LSB = reader.NextWord();  // CBM 31: 0
+  //fCbmTimePacket = 0;
+  //fCbmTimePacket = (uint64_t) word_MSB<<32 | word_LSB;
+}
+
+void CbmRichUnpackAlgo2022::processMbs(CbmRichUnpackAlgoMicrosliceReader& reader, bool isPrev)
+{
+  uint32_t word     = reader.NextWord();
+  uint32_t mbsNum   = word & 0xffffff;      //24 bits
+  uint32_t nofCtsCh = (word >> 24) & 0xff;  // 8 bits
+  if (isLog())
+    LOG(debug4) << getLogHeader(reader) << "MBS mbsNum:0x" << std::hex << mbsNum << std::dec
+                << " nofCtsCh:" << nofCtsCh;
+
+  for (uint32_t i = 0; i < nofCtsCh; i++) {
+    uint32_t wordEpoch = reader.NextWord();
+    uint32_t epoch     = CbmRichUnpackAlgoTdcWordReader::ProcessEpoch(wordEpoch);
+    if (isLog()) LOG(debug4) << getLogHeader(reader) << "MBS ch:" << i << " epoch:" << epoch;
+
+    uint32_t wordTime = reader.NextWord();
+    CbmRichUnpackAlgoTdcTimeData td;
+    CbmRichUnpackAlgoTdcWordReader::ProcessTimeData(wordTime, td);
+    if (isLog()) LOG(debug4) << getLogHeader(reader) << "MBS ch:" << i << " " << td.ToString();
+
+    double fullTime = calculateTime(epoch, td.fCoarse, td.fFine);
+
+    if (isPrev && td.fChannel == 0) fMbsPrevTimeCh0 = fullTime;
+    if (isPrev && td.fChannel == 1) fMbsPrevTimeCh1 = fullTime;
+  }
+
+  double mbsCorr = fMbsPrevTimeCh1 - fMbsPrevTimeCh0;
+  if (isLog())
+    LOG(debug4) << getLogHeader(reader) << "MBS Prev ch1:" << std::setprecision(15) << fMbsPrevTimeCh1
+                << " ch0:" << fMbsPrevTimeCh0 << " corr:" << mbsCorr;
+}
+
+// ---- processTimeDataWord ----
+void CbmRichUnpackAlgo2022::processTimeDataWord(CbmRichUnpackAlgoMicrosliceReader& reader, int iTdc, uint32_t epoch,
+                                                uint32_t tdcWord, uint32_t subSubEventId,
+                                                std::vector<double>& raisingTime)
+{
+  CbmRichUnpackAlgoTdcTimeData td;
+  CbmRichUnpackAlgoTdcWordReader::ProcessTimeData(tdcWord, td);
+  double fullTime = calculateTime(epoch, td.fCoarse, td.fFine);
+
+
+  if (td.fChannel == 0) {
+    if (td.IsRisingEdge()) {
+      if (isLog())
+        LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << iTdc << "] " << td.ToString()
+                    << " CH0 Last:" << std::setprecision(15) << fullTime
+                    << " PrevLast:" << fPrevLastCh0ReTime[fCurrentSubSubEvent]
+                    << " diff:" << fullTime - fPrevLastCh0ReTime[fCurrentSubSubEvent];
+    }
+  }
+  else {
+    double dT           = fullTime - fPrevLastCh0ReTime[fCurrentSubSubEvent];
+    double mbsCorr      = fMbsPrevTimeCh1 - fMbsPrevTimeCh0;
+    double fullTimeCorr = dT - mbsCorr;
+
+    // std::cout<< dT <<"  "
+    //          << fullTimeCorr <<"  "<< std::setprecision(15)
+    //          << fullTime <<"  "
+    //          << fPrevLastCh0ReTime[fCurrentSubSubEvent] <<"  "
+    //          << mbsCorr <<"  "
+    //          << fCurrentSubSubEvent <<"  " <<std::hex
+    //          << subSubEventId << std::dec <<std::endl;
+    if (isLog())
+      LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << iTdc << "] " << td.ToString()
+                  << " time:" << std::setprecision(15) << fullTime << " fullTimeCorr:" << fullTimeCorr;
+
+    if (td.fChannel < 1 || td.fChannel >= raisingTime.size()) {
+      LOG(error) << "ERROR: channel number is out of limit. Channel:" << td.fChannel;
+    }
+
+    if (td.IsRisingEdge()) {
+      // always store the latest raising edge. It means that in case RRFF situation only middle RF will be matched.
+      raisingTime[td.fChannel] = fullTimeCorr;
+    }
+    else {
+      if (raisingTime[td.fChannel] == -1.) {
+        //No raising channel was found before. Skip this falling edge time.
+        if (isLog())
+          LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << iTdc << "] "
+                      << "No raising channel was found before. Skip this falling edge time.";
+      }
+      else {
+        // Matching was found, calculate ToT, if tot is in a good range -> create digi
+        double ToT = fullTimeCorr - raisingTime[td.fChannel];
+        if (isLog())
+          LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << iTdc << "] "
+                      << "ToT:" << ToT;
+        if (ToT >= fToTMin && ToT <= fToTMax) {
+          //  if (fbMonitorMode) {
+          //    TH1D* h = GetTotH1(subSubEventId, td.fChannel);
+          //    if (h != nullptr) h->Fill(ToT);
+
+          //    TH2D* h2 = GetTotH2(subSubEventId);
+          //    if (h2 != nullptr) h2->Fill(td.fChannel, ToT);
+          //  }
+          if (fullTimeCorr >= 0.0) { writeOutputDigi(subSubEventId, td.fChannel, raisingTime[td.fChannel], ToT); }
+        }
+        // pair was created, set raising edge to -1.
+        raisingTime[td.fChannel] = -1.;
+      }
+    }
+  }
+}
+
+void CbmRichUnpackAlgo2022::writeOutputDigi(Int_t fpgaID, Int_t channel, Double_t time, Double_t tot)
+{
+  Double_t ToTcorr = fbDoToTCorr ? fUnpackPar.GetToTshift(fpgaID, channel) : 0.;
+  Int_t pixelUID   = this->getPixelUID(fpgaID, channel);
+  //check ordering
+  Double_t finalTime = time + (Double_t) fMsRefTime - fSystemTimeOffset;
+  //printf("time: %.3f  %.3f %d\n",finalTime, time, fSystemTimeOffset);
+  //   Double_t finalTime = time - fSystemTimeOffset - fTsStartTime;
+
+  fOutputVec.emplace_back(pixelUID, finalTime, tot - ToTcorr);
+}
+
+ClassImp(CbmRichUnpackAlgo2022)
diff --git a/reco/detectors/rich/unpack/CbmRichUnpackAlgo2022.h b/reco/detectors/rich/unpack/CbmRichUnpackAlgo2022.h
new file mode 100644
index 0000000000000000000000000000000000000000..7eaaa8ef7e48fa8bbc0987909406bc6bd20697f2
--- /dev/null
+++ b/reco/detectors/rich/unpack/CbmRichUnpackAlgo2022.h
@@ -0,0 +1,117 @@
+/* Copyright (C) 2021 Goethe-University Frankfurt, Frankfurt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Pascal Raisig [committer] */
+
+/**
+ * @file CbmRichUnpackAlgo.h
+ * @author Pascal Raisig (praisig@ikf.uni-frankfurt.de)
+ * @brief Baseclass for the TrdR unpacker algorithms
+ * @version 0.1
+ * @date 2021-04-21
+ * 
+ * @copyright Copyright (c) 2021
+ * 
+ * This is the base class for the algorithmic part of the tsa data unpacking 
+ * processes of the CbmTrd.
+ * The actual translation from tsa to digi happens in the derived classes. 
+ * 
+ * 
+*/
+
+#ifndef CbmRichUnpackAlgo2022_H
+#define CbmRichUnpackAlgo2022_H
+
+#include "CbmMcbm2018RichPar.h"
+#include "CbmRecoUnpackAlgo.tmpl"
+#include "CbmRichDigi.h"
+#include "CbmRichUnpackAlgoBase.h"
+
+#include "Timeslice.hpp"  // timeslice
+
+#include <Rtypes.h>  // for types
+#include <RtypesCore.h>
+
+#include <cstddef>
+#include <cstdint>
+#include <iomanip>
+#include <memory>
+#include <utility>
+
+class CbmRichUnpackAlgo2022 : public CbmRichUnpackAlgoBase {
+public:
+  /** @brief Create the Cbm Trd Unpack AlgoBase object */
+  CbmRichUnpackAlgo2022();
+
+  /** @brief Destroy the Cbm Trd Unpack Task object */
+  virtual ~CbmRichUnpackAlgo2022();
+
+  /** @brief Copy constructor - not implemented **/
+  CbmRichUnpackAlgo2022(const CbmRichUnpackAlgo2022&) = delete;
+
+  /** @brief Assignment operator - not implemented **/
+  CbmRichUnpackAlgo2022& operator=(const CbmRichUnpackAlgo2022&) = delete;
+
+
+protected:
+  void processCBMtime(CbmRichUnpackAlgoMicrosliceReader& reader);
+
+  void processTrbPacket(CbmRichUnpackAlgoMicrosliceReader& reader);
+
+  void processMbs(CbmRichUnpackAlgoMicrosliceReader& reader, bool isPrev);
+
+  void processHubBlock(CbmRichUnpackAlgoMicrosliceReader& reader);
+
+  void processCtsSubSubEvent(CbmRichUnpackAlgoMicrosliceReader& reader, uint32_t subSubEventSize,
+                             uint32_t subSubEventId);
+
+  void processSubSubEvent(CbmRichUnpackAlgoMicrosliceReader& reader, int nofTimeWords, uint32_t subSubEventId);
+
+  void processTimeDataWord(CbmRichUnpackAlgoMicrosliceReader& reader, int iTdc, uint32_t epoch, uint32_t tdcWord,
+                           uint32_t subSubEventId, std::vector<double>& raisingTime);
+
+  /**
+	 * Write a gidi object into the output collection
+	 */
+  void writeOutputDigi(Int_t fpgaID, Int_t channel, Double_t time, Double_t tot);
+
+
+  /**
+   * @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);
+
+  //bool checkMaskedDiRICH(Int_t subSubEventId);
+
+  /** @brief Parameters for the unpacking */
+  //CbmMcbm2018RichPar fUnpackPar;
+
+  //std::vector<Int_t>* fMaskedDiRICHes = nullptr;
+
+  double fMbsPrevTimeCh0 = 0.;
+  double fMbsPrevTimeCh1 = 0.;
+
+  //size_t fMsRefTime = 0;
+
+  //double fToTMin = -20.;
+  //double fToTMax = 100.;
+
+  //uint64_t fCbmTimePacket = 0;
+
+  double fPrevLastCh0ReTime[13];  // 12 DiRICHes chnl0 + 1 CTS chnl0
+  int fCurrentSubSubEvent = 0;
+
+  //Bool_t fbDoToTCorr = true;  // kTRUE activates ToT correction from Parameterfile
+
+private:
+  ClassDef(CbmRichUnpackAlgo2022, 2)
+};
+
+#endif  // CbmRichUnpackAlgo2022_H
diff --git a/reco/detectors/rich/unpack/CbmRichUnpackAlgoBase.cxx b/reco/detectors/rich/unpack/CbmRichUnpackAlgoBase.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..fd057ba80b71bfae8a78ca43f3c5692e4bdea325
--- /dev/null
+++ b/reco/detectors/rich/unpack/CbmRichUnpackAlgoBase.cxx
@@ -0,0 +1,96 @@
+/* Copyright (C) 2021 Goethe-University Frankfurt, Frankfurt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Pascal Raisig [committer] */
+
+#include "CbmRichUnpackAlgoBase.h"
+
+#include <FairParGenericSet.h>
+#include <FairTask.h>
+#include <Logger.h>
+
+#include <Rtypes.h>
+#include <RtypesCore.h>
+
+#include <cstdint>
+
+
+CbmRichUnpackAlgoBase::CbmRichUnpackAlgoBase(std::string name) : CbmRecoUnpackAlgo(name) {}
+
+CbmRichUnpackAlgoBase::~CbmRichUnpackAlgoBase() {}
+
+// ---- GetParContainerRequest ----
+std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>*
+  CbmRichUnpackAlgoBase::GetParContainerRequest(std::string /*geoTag*/, std::uint32_t /*runId*/)
+{
+  // Basepath for default Trd parameter sets (those connected to a geoTag)
+  std::string basepath = Form("%s", fParFilesBasePath.data());
+  std::string temppath = "";
+
+  // // Get parameter container
+  temppath = basepath + "mRichPar_70.par";
+
+  fParContVec.emplace_back(std::make_pair(temppath, std::make_shared<CbmMcbm2018RichPar>()));
+
+  return &fParContVec;
+}
+
+// ---- calculateTime
+double CbmRichUnpackAlgoBase::calculateTime(uint32_t epoch, uint32_t coarse, uint32_t fine)
+{
+  return ((double) epoch) * 2048. * 5. + ((double) coarse) * 5. - ((double) fine) * 0.005;
+}
+
+// ---- getLogHeader
+std::string CbmRichUnpackAlgoBase::getLogHeader(CbmRichUnpackAlgoMicrosliceReader& reader)
+{
+  std::stringstream stream;
+  stream << "[" << fNrProcessedTs << "-" << reader.GetWordCounter() << "/" << reader.GetSize() / 4 << " "
+         << reader.GetWordAsHexString(reader.GetCurWord()) << "] ";
+  return stream.str();
+}
+
+// ---- init
+Bool_t CbmRichUnpackAlgoBase::init() { return kTRUE; }
+
+// ---- initParSet(FairParGenericSet* parset) ----
+Bool_t CbmRichUnpackAlgoBase::initParSet(FairParGenericSet* parset)
+{
+  LOG(info) << fName << "::initParSet - for container " << parset->ClassName();
+  if (parset->IsA() == CbmMcbm2018RichPar::Class()) return initParSet(static_cast<CbmMcbm2018RichPar*>(parset));
+
+  // If we do not know the derived ParSet class we return false
+  LOG(error) << fName << "::initParSet - for container " << parset->ClassName() << " failed, since" << fName
+             << "::initParSet() does not know the derived ParSet and what to do with it!";
+  return kFALSE;
+}
+
+// ---- initParSet(CbmTrdParSetAsic* parset) ----
+Bool_t CbmRichUnpackAlgoBase::initParSet(CbmMcbm2018RichPar* parset)
+{
+  LOG(debug) << fName << "::initParSetAsic - ";
+  fUnpackPar = *parset;
+  fUnpackPar.Print();
+
+  LOG(info) << fName << "::initParSetRichMcbm2018 - Successfully initialized RICH unpacking parameters";
+
+  return kTRUE;
+}
+
+// ---- isLog ----
+bool CbmRichUnpackAlgoBase::isLog()
+{
+  //if (fTsCounter == 25215) return true;
+  return false;
+}
+
+
+bool CbmRichUnpackAlgoBase::checkMaskedDiRICH(Int_t subSubEventId)
+{
+  for (unsigned int i = 0; i < fMaskedDiRICHes->size(); ++i) {
+    if (fMaskedDiRICHes->at(i) == subSubEventId) return true;
+  }
+
+  return false;
+}
+
+ClassImp(CbmRichUnpackAlgoBase)
diff --git a/reco/detectors/rich/unpack/CbmRichUnpackAlgoBase.h b/reco/detectors/rich/unpack/CbmRichUnpackAlgoBase.h
new file mode 100644
index 0000000000000000000000000000000000000000..2f6cfc61113614cf49ff4d04ddf56ac64f117f81
--- /dev/null
+++ b/reco/detectors/rich/unpack/CbmRichUnpackAlgoBase.h
@@ -0,0 +1,314 @@
+/* Copyright (C) 2021 Goethe-University Frankfurt, Frankfurt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Pascal Raisig [committer] */
+
+/**
+ * @file CbmRichUnpackAlgo.h
+ * @author Pascal Raisig (praisig@ikf.uni-frankfurt.de)
+ * @brief Baseclass for the TrdR unpacker algorithms
+ * @version 0.1
+ * @date 2021-04-21
+ * 
+ * @copyright Copyright (c) 2021
+ * 
+ * This is the base class for the algorithmic part of the tsa data unpacking 
+ * processes of the CbmTrd.
+ * The actual translation from tsa to digi happens in the derived classes. 
+ * 
+ * 
+*/
+
+#ifndef CbmRichUnpackAlgoBase_H
+#define CbmRichUnpackAlgoBase_H
+
+#include "CbmMcbm2018RichPar.h"
+#include "CbmRecoUnpackAlgo.tmpl"
+#include "CbmRichDigi.h"
+
+#include "Timeslice.hpp"  // timeslice
+
+#include <Rtypes.h>  // for types
+#include <RtypesCore.h>
+
+#include <cstddef>
+#include <cstdint>
+#include <iomanip>
+#include <memory>
+#include <utility>
+
+enum class CbmRichUnpackAlgoErrorType
+{
+  mtsError,
+  tdcHeader,
+  tdcTrailer,
+  ctsHeader,
+  ctsTrailer,
+  subEventError
+};
+
+enum class CbmRichUnpackAlgoTdcWordType
+{
+  TimeData,
+  Header,
+  Epoch,
+  Trailer,
+  Debug,
+  Error
+};
+
+class CbmRichUnpackAlgoTdcTimeData {
+public:
+  uint32_t fCoarse  = 0;  // 11 bits
+  uint32_t fEdge    = 0;  // 1 bit
+  uint32_t fFine    = 0;  // 10 bits
+  uint32_t fChannel = 0;  // 7 bits
+
+  std::string ToString()
+  {
+    std::stringstream stream;
+    stream << "channel:" << fChannel << " coarse:" << fCoarse << " fine:" << fFine
+           << " edge:" << ((fEdge == 1) ? "R" : "F");
+    return stream.str();
+  }
+
+  bool IsRisingEdge() { return (fEdge == 1); }
+};
+
+class CbmRichUnpackAlgoTdcWordReader {
+public:
+  static CbmRichUnpackAlgoTdcWordType GetTdcWordType(uint32_t tdcWord)
+  {
+    uint32_t tdcTimeDataMarker = (tdcWord >> 31) & 0x1;  // 1 bit
+    uint32_t tdcMarker         = (tdcWord >> 29) & 0x7;  // 3 bits
+
+    if (tdcTimeDataMarker == 0x1) {
+      // TODO: I also include tdcMarker == 0x5, some tdc time data words have this marker. Is it correct?
+      if (tdcMarker == 0x4 || tdcMarker == 0x5) { return CbmRichUnpackAlgoTdcWordType::TimeData; }
+      else {
+        return CbmRichUnpackAlgoTdcWordType::Error;
+      }
+    }
+
+    if (tdcMarker == 0x0) return CbmRichUnpackAlgoTdcWordType::Trailer;
+    if (tdcMarker == 0x1) return CbmRichUnpackAlgoTdcWordType::Header;
+    if (tdcMarker == 0x2) return CbmRichUnpackAlgoTdcWordType::Debug;
+    if (tdcMarker == 0x3) return CbmRichUnpackAlgoTdcWordType::Epoch;
+
+    return CbmRichUnpackAlgoTdcWordType::Error;
+  }
+
+  static void ProcessTimeData(uint32_t tdcWord, CbmRichUnpackAlgoTdcTimeData& outData)
+  {
+    outData.fCoarse  = static_cast<uint32_t>(tdcWord & 0x7ff);          // 11 bits
+    outData.fEdge    = static_cast<uint32_t>((tdcWord >> 11) & 0x1);    // 1 bit
+    outData.fFine    = static_cast<uint32_t>((tdcWord >> 12) & 0x3ff);  // 10 bits
+    outData.fChannel = static_cast<uint32_t>((tdcWord >> 22) & 0x7f);   // 7 bits
+  }
+
+  static uint32_t ProcessEpoch(uint32_t tdcWord) { return static_cast<uint32_t>(tdcWord & 0xfffffff); }
+
+  static uint16_t ProcessHeader(uint32_t tdcWord)
+  {
+    // for the moment just extract error bits
+    return static_cast<uint16_t>(tdcWord & 0xff);  //8 bits
+  }
+
+  static uint16_t ProcessTrailer(uint32_t tdcWord)
+  {
+    // for the moment just extract error bits
+    return static_cast<uint16_t>(tdcWord & 0xffff);
+  }
+
+  static void ProcessDebug(uint32_t tdcWord)
+  {
+    LOG(debug4) << "ProcessDebug is not implemented. tdcWord:0x" << std::hex << tdcWord << std::dec;
+    // for the moment do nothing
+  }
+};
+
+class CbmRichUnpackAlgoMicrosliceReader {
+private:
+  const uint8_t* fData = nullptr;
+  size_t fSize         = 0;
+  size_t fOffset       = 0;  // offset in bytes
+  size_t fWordCounter  = 0;
+  uint32_t fCurWord;
+
+public:
+  void SetData(const uint8_t* data, size_t size)
+  {
+    fData        = data;
+    fSize        = size;
+    fOffset      = 0;
+    fWordCounter = 0;
+    fCurWord     = 0;
+  }
+
+  const uint8_t* GetData() { return fData; }
+
+  size_t GetSize() { return fSize; }
+
+  size_t GetOffset() { return fOffset; }
+
+  size_t GetWordCounter() { return fWordCounter; }
+
+  uint32_t GetCurWord() { return fCurWord; }
+
+  std::string GetWordAsHexString(uint32_t word)
+  {
+    std::stringstream stream;
+    stream << "0x" << std::setfill('0') << std::setw(sizeof(uint32_t) * 2) << std::hex << word;
+    return stream.str();
+  }
+
+  uint32_t NextWord()
+  {
+    //mRichSupport::SwapBytes(4, fData + fOffset);
+    //Int_t* dataPtr = (Int_t*) (fData + fOffset);
+    uint32_t i = ((uint32_t*) (fData + fOffset))[0];
+    //swap bytes
+    i = (i >> 24) | ((i << 8) & 0x00FF0000) | ((i >> 8) & 0x0000FF00) | (i << 24);
+    //i = ((i&0xFF)<<24) | (((i>>8)&0xFF)<<16) |   (((i>>16)&0xFF)<<8) | (((i>>24)&0xFF)<<0);
+
+    fOffset += 4;
+    fWordCounter++;
+    fCurWord = i;
+    //return (Int_t)(dataPtr[0]);
+    return i;
+  }
+
+  bool IsNextPadding()
+  {
+    uint32_t nextWord = ((uint32_t*) (fData + fOffset))[0];
+    if (nextWord == 0xffffffff) return true;
+    return false;
+  }
+
+  bool IsLastSubSubEvent(uint32_t subSubEventSize)
+  {
+    uint32_t i = ((uint32_t*) (fData + fOffset + 4 * subSubEventSize))[0];
+    i          = (i >> 24) | ((i << 8) & 0x00ff0000) | ((i >> 8) & 0x0000ff00) | (i << 24);
+    if (i == 0x00015555) return true;
+    return false;
+  }
+};
+
+class CbmRichUnpackAlgoBase : public CbmRecoUnpackAlgo<CbmRichDigi> {
+public:
+  /** @brief Create the Cbm Trd Unpack AlgoBase object */
+  CbmRichUnpackAlgoBase(std::string name);
+
+  /** @brief Destroy the Cbm Trd Unpack Task object */
+  virtual ~CbmRichUnpackAlgoBase();
+
+  /** @brief Copy constructor - not implemented **/
+  CbmRichUnpackAlgoBase(const CbmRichUnpackAlgoBase&) = delete;
+
+  /** @brief Assignment operator - not implemented **/
+  CbmRichUnpackAlgoBase& operator=(const CbmRichUnpackAlgoBase&) = delete;
+
+  /**
+   * @brief Get the requested parameter containers. To be defined in the derived classes!
+   * Return the required parameter containers together with the paths to the ascii 
+   * files to.
+   *  
+   * @param[in] std::string geoTag as used in CbmSetup
+   * @param[in] std::uint32_t runId for runwise defined parameters
+   * @return fParContVec
+  */
+  virtual std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>*
+  GetParContainerRequest(std::string geoTag, std::uint32_t runId);
+
+  void SetMaskedDiRICHes(std::vector<Int_t>* maskedDiRICHes) { fMaskedDiRICHes = maskedDiRICHes; }
+
+protected:
+  double calculateTime(uint32_t epoch, uint32_t coarse, uint32_t fine);
+
+  /** @brief Finish function for this algorithm base clase */
+  void finish()
+  {
+    finishDerived();
+    // Finish the monitor if we have one
+    // if (fMonitor) fMonitor->Finish();
+  }
+
+  /** @brief Function that allows special calls during Finish in the derived algos */
+  virtual void finishDerived() { return; }
+
+  std::string getLogHeader(CbmRichUnpackAlgoMicrosliceReader& reader);
+
+  Int_t getPixelUID(Int_t fpgaID, Int_t ch) const
+  {
+    // First 16 bits are used for the FPGA ID, then
+    // 8 bits unused and then 8 bits are used for the channel
+    return ((fpgaID << 16) | (ch & 0x00FF));
+  }
+
+  /**
+   * @brief Intialisation at begin of run. Special inits of the derived algos.
+   * 
+   * @retval Bool_t initOk
+  */
+  Bool_t init();
+
+  /**
+   * @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 Handles the distribution of the hidden derived classes to their explicit functions.
+   * 
+   * @param parset 
+   * @return Bool_t initOk 
+  */
+  Bool_t initParSet(CbmMcbm2018RichPar* parset);
+
+  bool isLog();
+
+  /**
+   * @brief Set the Derived Ts Parameters
+   * 
+   * In this function parameters required by the explicit algo connected to the timeslice can be set.
+   * 
+   * @param itimeslice 
+   * @return true 
+   * @return false 
+  */
+  bool setDerivedTsParameters(size_t /*itimeslice*/) { return true; }
+
+  /**
+   * @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);
+
+  bool checkMaskedDiRICH(Int_t subSubEventId);
+
+  /** @brief Parameters for the unpacking */
+  CbmMcbm2018RichPar fUnpackPar;
+
+  std::vector<Int_t>* fMaskedDiRICHes = nullptr;
+
+  size_t fMsRefTime = 0;
+
+  double fToTMin = -20.;
+  double fToTMax = 100.;
+
+  Bool_t fbDoToTCorr = true;  // kTRUE activates ToT correction from Parameterfile
+
+private:
+  ClassDef(CbmRichUnpackAlgoBase, 2)
+};
+
+#endif  // CbmRichUnpackAlgoBase
diff --git a/reco/detectors/rich/unpack/CbmRichUnpackConfig.cxx b/reco/detectors/rich/unpack/CbmRichUnpackConfig.cxx
index a2d2700dcfda7013fe6690a6b8821b240ee5bc7c..6aa968f57d8064078d295b1d11a65604124e5fed 100644
--- a/reco/detectors/rich/unpack/CbmRichUnpackConfig.cxx
+++ b/reco/detectors/rich/unpack/CbmRichUnpackConfig.cxx
@@ -5,6 +5,7 @@
 #include "CbmRichUnpackConfig.h"
 
 #include "CbmRichUnpackAlgo.h"
+#include "CbmRichUnpackAlgo2022.h"
 
 #include <Logger.h>
 
@@ -32,15 +33,23 @@ void CbmRichUnpackConfig::InitAlgo()
 }
 
 // ---- chooseAlgo ----
-std::shared_ptr<CbmRichUnpackAlgo> CbmRichUnpackConfig::chooseAlgo()
+std::shared_ptr<CbmRichUnpackAlgoBase> CbmRichUnpackConfig::chooseAlgo()
 {
   if (fDoLog) LOG(info) << fName << "::Init - chooseAlgo";
 
   // Default unpacker selection
   // Unpacker algo from mcbm 2021 on and hopefully default for a long time.
-  auto algo = std::make_shared<CbmRichUnpackAlgo>();
-  LOG(info) << fName << "::chooseAlgo() - selected algo = " << algo->Class_Name();
-  return algo;
+  if (fUnpackerVersion == CbmRichUnpackerVersion::v02) {
+    auto algo = std::make_shared<CbmRichUnpackAlgo>();
+    LOG(info) << fName << "::chooseAlgo() - selected algo = " << algo->Class_Name();
+    return algo;
+  }
+
+  if (fUnpackerVersion == CbmRichUnpackerVersion::v03) {
+    auto algo = std::make_shared<CbmRichUnpackAlgo2022>();
+    LOG(info) << fName << "::chooseAlgo() - selected algo = " << algo->Class_Name();
+    return algo;
+  }
 
   LOG(error) << fName
              << "::Init - chooseAlgo() - no algorithm created something went wrong. We can not work like this!";
diff --git a/reco/detectors/rich/unpack/CbmRichUnpackConfig.h b/reco/detectors/rich/unpack/CbmRichUnpackConfig.h
index f73bd36f95305d3501d7157c7e1574ea27beb9c5..68c5da1d5999592bc0504c5e465618a7df73717b 100644
--- a/reco/detectors/rich/unpack/CbmRichUnpackConfig.h
+++ b/reco/detectors/rich/unpack/CbmRichUnpackConfig.h
@@ -20,7 +20,7 @@
 
 #include "CbmRecoUnpackConfig.tmpl"
 #include "CbmRichDigi.h"
-#include "CbmRichUnpackAlgo.h"
+#include "CbmRichUnpackAlgoBase.h"
 
 #include <FairLogger.h>
 #include <Logger.h>
@@ -33,7 +33,14 @@
 #include <memory>
 #include <vector>
 
-class CbmRichUnpackConfig : public CbmRecoUnpackConfig<CbmRichUnpackAlgo, CbmRichDigi, std::nullptr_t, std::nullptr_t> {
+enum class CbmRichUnpackerVersion
+{
+  v02,
+  v03
+};
+
+class CbmRichUnpackConfig :
+  public CbmRecoUnpackConfig<CbmRichUnpackAlgoBase, CbmRichDigi, std::nullptr_t, std::nullptr_t> {
 
 public:
   /**
@@ -70,16 +77,21 @@ public:
 
   void MaskDiRICH(Int_t DiRICH) { fMaskedDiRICHes.push_back(DiRICH); }
 
+  void SetUnpackerVersion(CbmRichUnpackerVersion vers) { fUnpackerVersion = vers; }
+
 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
   */
-  virtual std::shared_ptr<CbmRichUnpackAlgo> chooseAlgo();
+  virtual std::shared_ptr<CbmRichUnpackAlgoBase> chooseAlgo();
 
   std::vector<Int_t> fMaskedDiRICHes = {};
 
+  /** @brief Selector of Unpacker Version. */
+  CbmRichUnpackerVersion fUnpackerVersion = CbmRichUnpackerVersion::v02;
+
 private:
   ClassDef(CbmRichUnpackConfig, 3)
 };