diff --git a/macro/run/run_unpack_tsa.C b/macro/run/run_unpack_tsa.C
index 32e4e157333fad26cfc3f64afe911417edcb48d6..aa0f262f347da5d07333826df6faefa3ca1c0bd3 100644
--- a/macro/run/run_unpack_tsa.C
+++ b/macro/run/run_unpack_tsa.C
@@ -81,6 +81,15 @@ void run_unpack_tsa(std::string infile = "test.tsa", UInt_t runid = 0, const cha
   psdconfig->SetParFilesBasePath(parfilesbasepathPsd);
   // -------------
 
+  // ---- RICH ----
+  auto richconfig = std::make_shared<CbmRichUnpackConfig>("", runid);
+  // psdconfig->SetDebugState();
+  richconfig->SetDoWriteOutput();
+  // psdconfig->SetDoWriteOptOutA("CbmPsdDsp");
+  std::string parfilesbasepathRich = Form("%s/macro/beamtime/mcbm2021/", srcDir.Data());
+  richconfig->SetParFilesBasePath(parfilesbasepathRich);
+  // -------------
+
   // ---- TRD ----
   TString trdsetuptag = "";
   cbmsetup->GetGeoTag(ECbmModuleId::kTrd, trdsetuptag);
@@ -113,8 +122,9 @@ void run_unpack_tsa(std::string infile = "test.tsa", UInt_t runid = 0, const cha
   // -----   CbmSourceTsArchive   -------------------------------------------
   auto source = new CbmSourceTsArchive(infile.data());
   auto unpack = source->GetRecoUnpack();
-  unpack->SetUnpackConfig(trdconfig);
   unpack->SetUnpackConfig(psdconfig);
+  unpack->SetUnpackConfig(richconfig);
+  unpack->SetUnpackConfig(trdconfig);
   // ------------------------------------------------------------------------
 
 
diff --git a/reco/detectors/psd/unpack/CbmPsdUnpackAlgo.cxx b/reco/detectors/psd/unpack/CbmPsdUnpackAlgo.cxx
index 6655db4a17a36a3bca4505a7ca170a76fcd42704..4dd7d2607dc7a6e4c7f3fbdb9985010728aada60 100644
--- a/reco/detectors/psd/unpack/CbmPsdUnpackAlgo.cxx
+++ b/reco/detectors/psd/unpack/CbmPsdUnpackAlgo.cxx
@@ -11,6 +11,7 @@
 #include <Rtypes.h>
 #include <RtypesCore.h>
 
+#include <cstdint>
 #include <numeric>
 
 #include "../../core/detectors/psd/PronyFitter.h"
@@ -143,10 +144,9 @@ bool CbmPsdUnpackAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp, UI
   const uint8_t* msContent = reinterpret_cast<const uint8_t*>(ts->content(icomp, imslice));
 
   uint32_t uSize = msDescriptor.size;
-  auto msidx     = msDescriptor.idx;
+  auto mstime    = msDescriptor.idx;
 
-  auto mstime = static_cast<double>(msidx);
-  LOG(debug4) << "Microslice: " << msidx << " from EqId " << std::hex << eqid << std::dec << " has size: " << uSize;
+  LOG(debug4) << "Microslice: " << mstime << " from EqId " << std::hex << eqid << std::dec << " has size: " << uSize;
 
   if (0 == fvbMaskedComponents.size()) fvbMaskedComponents.resize(ts->num_components(), kFALSE);
 
@@ -203,7 +203,7 @@ bool CbmPsdUnpackAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp, UI
   while (PsdReader.GetTotalGbtWordsRead() < uNbMessages) {
     int ReadResult = PsdReader.ReadMs();
     if (fair::Logger::Logging(fair::Severity::debug)) {
-      printf("\nMicroslice idx: %lu\n", msidx);
+      printf("\nMicroslice idx: %lu\n", mstime);
       PsdReader.PrintOut(); /*PsdReader.PrintSaveBuff();*/
     }
     if (ReadResult == 0) {
@@ -228,10 +228,8 @@ bool CbmPsdUnpackAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp, UI
         }
         UInt_t uChanUId = fviPsdChUId[uHitChannel];  //unique ID
 
-        auto dTime = static_cast<double>(PsdReader.VectPackHdr.at(hit_iter).uAdcTime * 12.5);
-        dTime -= fdTimeOffsetNs;  // Subtract system-side offset
-        dTime += msidx;           // Add the microslice start time
-        dTime -= fTsStartTime;    // Get the time relative to the TS start time
+        auto dTime = dMsRelativeTime + (double) PsdReader.VectPackHdr.at(hit_iter).uAdcTime * 12.5 - fdTimeOffsetNs;
+
 
         Double_t dEdep = (double) PsdReader.VectHitHdr.at(hit_iter).uSignalCharge / getMipCalibration(uHitChannel);
         /// Energy deposition from FPGA [MeV]
@@ -291,7 +289,7 @@ bool CbmPsdUnpackAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp, UI
           uFitWfm     = Pfitter.GetFitWfm();
         }
 
-        CbmPsdDsp dsp = CbmPsdDsp(uChanUId, dTime, dEdep, uZL, dAccum, dAdcTime,
+        CbmPsdDsp dsp = CbmPsdDsp(uChanUId, dTime, fTsStartTime, dEdep, uZL, dAccum, dAdcTime,
 
                                   dEdepWfm, dAmpl, uMinimum, uTimeMax, uWfm,
 
@@ -300,6 +298,8 @@ bool CbmPsdUnpackAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp, UI
         // Create the actual digi and move it to the output vector
         makeDigi(dsp);
 
+        if (dTime < prev_hit_time) printf("negative time btw hits! %f after %f \n", dTime, prev_hit_time);
+
         prev_hit_time = dTime;
 
       }  // for (uint64_t hit_iter = 0; hit_iter < PsdReader.VectHitHdr.size(); hit_iter++) {
diff --git a/reco/detectors/rich/CMakeLists.txt b/reco/detectors/rich/CMakeLists.txt
index b45f03e2a2005e85dfd173fb0dd9012cda9eb93f..684f371057b99cebde6c29ed16ffcc4aa98f6d7e 100644
--- a/reco/detectors/rich/CMakeLists.txt
+++ b/reco/detectors/rich/CMakeLists.txt
@@ -132,7 +132,7 @@ set(LINKDEF  CbmRichRecoLinkDef.h)
 Set(LIBRARY_NAME CbmRichReco)
 Set(DEPENDENCIES
     KF L1 CbmRichBase CbmRecoBase CbmBase CbmData Base MLP boost_regex Gdml 
-    fles_ipc # for unpacker
+    # fles_ipc # for unpacker
     )
 
 GENERATE_LIBRARY()
diff --git a/reco/detectors/rich/unpack/CbmRichUnpackAlgo.cxx b/reco/detectors/rich/unpack/CbmRichUnpackAlgo.cxx
index 55b597878ad802837ebd95089053ea02cf72b1d5..ca31db39bdaa8d509ab0df71d20dbd13c04e67b2 100644
--- a/reco/detectors/rich/unpack/CbmRichUnpackAlgo.cxx
+++ b/reco/detectors/rich/unpack/CbmRichUnpackAlgo.cxx
@@ -16,5 +16,239 @@ CbmRichUnpackAlgo::CbmRichUnpackAlgo() : CbmRecoUnpackAlgo(fgkFlesSubsystemIdTrd
 
 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.par";
+  LOG(info) << "HelloWorld " << temppath;
+  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(CbmMcbm2018RichMicrosliceReader& 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;
+
+  LOG(info) << fName << "::initParSetRichMcbm2018 - Successfully initialized Spadic hardware address map";
+
+  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)
+{
+
+  const fles::MicrosliceView mv            = ts->get_microslice(icomp, imslice);
+  const fles::MicrosliceDescriptor& msDesc = mv.desc();
+
+  CbmMcbm2018RichMicrosliceReader reader;
+  reader.SetData(mv.content(), msDesc.size);
+
+  // 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 CbmRichUnpackAlgo::processTrbPacket(CbmMcbm2018RichMicrosliceReader& reader)
+{
+  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 CbmRichUnpackAlgo::processMbs(CbmMcbm2018RichMicrosliceReader& 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     = CbmMcbm2018RichTdcWordReader::ProcessEpoch(wordEpoch);
+    if (isLog()) LOG(debug4) << getLogHeader(reader) << "MBS ch:" << i << " epoch:" << epoch;
+
+    uint32_t wordTime = reader.NextWord();
+    CbmMcbm2018RichTdcTimeData td;
+    CbmMcbm2018RichTdcWordReader::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 CbmRichUnpackAlgo::processTimeDataWord(CbmMcbm2018RichMicrosliceReader& reader, int iTdc, uint32_t epoch,
+                                            uint32_t tdcWord, uint32_t subSubEventId, std::vector<double>& raisingTime)
+{
+  CbmMcbm2018RichTdcTimeData td;
+  CbmMcbm2018RichTdcWordReader::ProcessTimeData(tdcWord, td);
+  double fullTime = calculateTime(epoch, td.fCoarse, td.fFine);
+
+
+  if (td.fChannel == 0) {
+    if (td.IsRisingEdge()) {
+      fPrevLastCh0ReTime[subSubEventId] = fLastCh0ReTime[subSubEventId];
+      fLastCh0ReTime[subSubEventId]     = fullTime;
+      if (isLog())
+        LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << iTdc << "] " << td.ToString()
+                    << " CH0 Last:" << std::setprecision(15) << fLastCh0ReTime[subSubEventId]
+                    << " PrevLast:" << fPrevLastCh0ReTime[subSubEventId]
+                    << " diff:" << fLastCh0ReTime[subSubEventId] - fPrevLastCh0ReTime[subSubEventId];
+    }
+  }
+  else {
+    double dT           = fullTime - fPrevLastCh0ReTime[subSubEventId];
+    double mbsCorr      = fMbsPrevTimeCh1 - fMbsPrevTimeCh0;
+    double fullTimeCorr = dT - mbsCorr;
+    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);
+          //  }
+          writeOutputDigi(subSubEventId, td.fChannel, raisingTime[td.fChannel], ToT);
+        }
+        // pair was created, set raising edge to -1.
+        raisingTime[td.fChannel] = -1.;
+      }
+    }
+  }
+}
+
+void CbmRichUnpackAlgo::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) msRefTS - fSystemTimeoffset;
+  Double_t finalTime = time - fSystemTimeoffset - fTsStartTime;
+
+  Double_t lastTime = 0.;
+
+  if (fOutputVec.size() < 1) { fOutputVec.emplace_back(pixelUID, finalTime, tot - ToTcorr); }
+  else {
+    lastTime = fOutputVec[fOutputVec.size() - 1].GetTime();
+    if (fOutputVec[0].GetTime() > finalTime) {
+      fOutputVec.emplace(fOutputVec.begin(), pixelUID, finalTime, tot - ToTcorr);
+    }
+    else if (lastTime > finalTime) {
+      for (int i = fOutputVec.size() - 1; i >= 0; i--) {
+        lastTime = fOutputVec[i].GetTime();
+        if (lastTime <= finalTime) {
+          fOutputVec.emplace(fOutputVec.begin() + i + 1, pixelUID, finalTime, tot - ToTcorr);
+          break;
+        }
+      }
+    }
+    else {
+      fOutputVec.emplace_back(pixelUID, finalTime, tot - ToTcorr);
+    }
+  }
+}
 
 ClassImp(CbmRichUnpackAlgo)
diff --git a/reco/detectors/rich/unpack/CbmRichUnpackAlgo.h b/reco/detectors/rich/unpack/CbmRichUnpackAlgo.h
index effe35cae3ddcae5a10084d722f501157aa6aa3e..ac52e93e9de36d6134e229817e37178aabc9b579 100644
--- a/reco/detectors/rich/unpack/CbmRichUnpackAlgo.h
+++ b/reco/detectors/rich/unpack/CbmRichUnpackAlgo.h
@@ -21,6 +21,8 @@
 #ifndef CbmRichUnpackAlgo_H
 #define CbmRichUnpackAlgo_H
 
+// #include "CbmMcbm2018RichPar.h"
+#include "../../core/detectors/rich/CbmMcbm2018RichPar.h"
 #include "CbmRecoUnpackAlgo.tmpl"
 #include "CbmRichDigi.h"
 
@@ -34,8 +36,165 @@
 #include <memory>
 #include <utility>
 
+
 class CbmRichUnpackAlgo : public CbmRecoUnpackAlgo<CbmRichDigi> {
 public:
+  enum class CbmMcbm2018RichErrorType
+  {
+    mtsError,
+    tdcHeader,
+    tdcTrailer,
+    ctsHeader,
+    ctsTrailer,
+    subEventError
+  };
+
+  enum class CbmMcbm2018RichTdcWordType
+  {
+    TimeData,
+    Header,
+    Epoch,
+    Trailer,
+    Debug,
+    Error
+  };
+
+  class CbmMcbm2018RichTdcTimeData {
+  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 CbmMcbm2018RichTdcWordReader {
+  public:
+    static CbmMcbm2018RichTdcWordType 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 CbmMcbm2018RichTdcWordType::TimeData; }
+        else {
+          return CbmMcbm2018RichTdcWordType::Error;
+        }
+      }
+
+      if (tdcMarker == 0x0) return CbmMcbm2018RichTdcWordType::Trailer;
+      if (tdcMarker == 0x1) return CbmMcbm2018RichTdcWordType::Header;
+      if (tdcMarker == 0x2) return CbmMcbm2018RichTdcWordType::Debug;
+      if (tdcMarker == 0x3) return CbmMcbm2018RichTdcWordType::Epoch;
+
+      return CbmMcbm2018RichTdcWordType::Error;
+    }
+
+    static void ProcessTimeData(uint32_t tdcWord, CbmMcbm2018RichTdcTimeData& 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 CbmMcbm2018RichMicrosliceReader {
+  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;
+    }
+  };
   /** @brief Create the Cbm Trd Unpack AlgoBase object */
   CbmRichUnpackAlgo();
 
@@ -58,12 +217,11 @@ public:
    * @return fParContVec
   */
   virtual std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>*
-  GetParContainerRequest(std::string geoTag, std::uint32_t runId)
-  {
-    return {};
-  };
+  GetParContainerRequest(std::string geoTag, std::uint32_t runId);
 
 protected:
+  double calculateTime(uint32_t epoch, uint32_t coarse, uint32_t fine);
+
   /** @brief Finish function for this algorithm base clase */
   void finish()
   {
@@ -75,12 +233,29 @@ protected:
   /** @brief Function that allows special calls during Finish in the derived algos */
   virtual void finishDerived() { return; }
 
+  std::string getLogHeader(CbmMcbm2018RichMicrosliceReader& 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() { return kTRUE; }
+  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.
@@ -88,7 +263,27 @@ protected:
    * @param parset 
    * @return Bool_t initOk 
   */
-  Bool_t initParSet(FairParGenericSet* parset) { return kTRUE; }
+  Bool_t initParSet(CbmMcbm2018RichPar* parset);
+
+  bool isLog();
+
+  void processTrbPacket(CbmMcbm2018RichMicrosliceReader& reader);
+
+  void processMbs(CbmMcbm2018RichMicrosliceReader& reader, bool isPrev);
+
+  void processHubBlock(CbmMcbm2018RichMicrosliceReader& reader);
+
+  void processCtsSubSubEvent(CbmMcbm2018RichMicrosliceReader& reader, uint32_t subSubEventSize, uint32_t subSubEventId);
+
+  void processSubSubEvent(CbmMcbm2018RichMicrosliceReader& reader, int nofTimeWords, uint32_t subSubEventId);
+
+  void processTimeDataWord(CbmMcbm2018RichMicrosliceReader& 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 Set the Derived Ts Parameters
@@ -112,11 +307,25 @@ protected:
    * 
    * @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) { return true; }
+  bool unpack(const fles::Timeslice* ts, std::uint16_t icomp, UInt_t imslice);
 
   /** @brief Fles Subsystem Identifier for the TRD R data */
   static constexpr int fgkFlesSubsystemIdTrdR = static_cast<int>(fles::SubsystemIdentifier::RICH);
 
+  /** @brief Parameters for the unpacking */
+  CbmMcbm2018RichPar fUnpackPar;
+
+  double fMbsPrevTimeCh0 = 0.;
+  double fMbsPrevTimeCh1 = 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/CbmRichUnpackConfig.cxx b/reco/detectors/rich/unpack/CbmRichUnpackConfig.cxx
index 279e552fa8f6ee32882684a076668053800a1ef3..de94c27a96ab9d1cd81ac651651f8aa46adc135c 100644
--- a/reco/detectors/rich/unpack/CbmRichUnpackConfig.cxx
+++ b/reco/detectors/rich/unpack/CbmRichUnpackConfig.cxx
@@ -33,6 +33,9 @@ void CbmRichUnpackConfig::InitUnpacker()
   // First choose the derived unpacking algorithm to be used and pass the raw to digi method
   auto algo = chooseAlgo();
 
+  if (fDoLog) LOG(info) << fName << "::Init - SetParFilesBasePath";
+  algo->SetParFilesBasePath(fParFilesBasePath);
+
   // Initialise the parameter containers required by the unpacker algo. Includes loading the corresponding ascii files
   auto reqparvec = algo->GetParContainerRequest(fGeoSetupTag, fRunId);
   initOk &= initParContainers(reqparvec);
diff --git a/reco/steer/CbmRecoUnpack.cxx b/reco/steer/CbmRecoUnpack.cxx
index b59fba60fb08f9984686fbf612151f1aac24ad39..d8dc446850c51fbe6ffa8f8ef4e2de94fc6af6be 100644
--- a/reco/steer/CbmRecoUnpack.cxx
+++ b/reco/steer/CbmRecoUnpack.cxx
@@ -129,6 +129,12 @@ void CbmRecoUnpack::Unpack(unique_ptr<Timeslice> ts)
             unpack(&timeslice, component, fPsdConfig, fPsdConfig->GetOptOutAVec(), fPsdConfig->GetOptOutBVec()));
         break;
       }
+      case fkFlesRich: {
+        if (fRichConfig)
+          fCbmTsEventHeader->SetNDigisRich(
+            unpack(&timeslice, component, fRichConfig, fRichConfig->GetOptOutAVec(), fRichConfig->GetOptOutBVec()));
+        break;
+      }
       case fkFlesTrd: {
         if (fTrdConfig)
           fCbmTsEventHeader->SetNDigisTrd(