diff --git a/algo/detectors/rich/Unpack.cxx b/algo/detectors/rich/Unpack.cxx
index 9f9db43ce10118b4143b322d0daf4bb989f4dc77..a66fb923c4fbbc9cbda0730e7e12848d2fdee5b5 100644
--- a/algo/detectors/rich/Unpack.cxx
+++ b/algo/detectors/rich/Unpack.cxx
@@ -12,30 +12,27 @@ namespace cbm::algo::rich
 {
   // ----   Algorithm execution   ---------------------------------------------
   Unpack::resultType Unpack::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
-                                        const uint64_t tTimeslice)
+                                        const uint64_t tTimeslice) const
   {
-    // --- Output data
-    resultType result = {};
-
-    fMonitor = UnpackMonitorData();
-    fOutputVec.clear();
+    MSContext ctx;
 
     // Clear CbmTime of MS. Used to get time offset of subtriggers to MS start
-    fCbmTimeMS = 0;
+    ctx.cbmTimeMS = 0;
+    ctx.digis.reserve(msDescr.size / sizeof(u32));
 
     rich::MicrosliceReader reader;
     reader.SetData(msContent, msDescr.size);
 
     const auto mstime = msDescr.idx;
-    fMsRefTime        = mstime - tTimeslice;
+    ctx.refTime       = mstime - tTimeslice;
 
     // There are a lot of MS  with 8 bytes size
     // Does one need these MS?
-    if (reader.GetSize() <= 8) return result;
+    if (reader.GetSize() <= 8) return {};
 
     while (true) {
-      ProcessTrbPacket(reader);
-      ProcessHubBlock(reader);
+      ProcessTrbPacket(reader, ctx);
+      ProcessHubBlock(reader, ctx);
 
       // -4*2 for 2 last words which contain microslice index
       if (reader.GetOffset() >= reader.GetSize() - 8) break;
@@ -45,19 +42,17 @@ namespace cbm::algo::rich
     uint32_t msIndexWord1 = reader.NextWord();
     uint32_t msIndexWord2 = reader.NextWord();
 
-    result.first  = fOutputVec;
-    result.second = fMonitor;
-    return result;
+    return std::make_pair(std::move(ctx.digis), std::move(ctx.monitor));
   }
 
 
-  void Unpack::ProcessTrbPacket(rich::MicrosliceReader& reader)
+  void Unpack::ProcessTrbPacket(rich::MicrosliceReader& reader, MSContext& ctx) const
   {
     //process CBM time
     const uint32_t word_MSB = reader.NextWord();  // CBM 63:32
     const uint32_t word_LSB = reader.NextWord();  // CBM 31: 0
-    fCbmTimePacket          = (uint64_t) word_MSB << 32 | word_LSB;
-    if (fCbmTimeMS == 0) fCbmTimeMS = fCbmTimePacket;
+    ctx.cbmTimePacket       = (uint64_t) word_MSB << 32 | word_LSB;
+    if (ctx.cbmTimeMS == 0) ctx.cbmTimeMS = ctx.cbmTimePacket;
 
     //discard unused words
     for (auto l = 0; l < 10; ++l) {
@@ -72,9 +67,9 @@ namespace cbm::algo::rich
       const TdcTimeData td     = ProcessTimeData(wordTime);
       const double fullTime    = CalculateTime(epoch, td.fCoarse, td.fFine);
 
-      if (l == 0) fPrevLastCh0ReTime[12] = fullTime;
-      if (l == 1) fMbsCorr = fullTime - fPrevLastCh0ReTime[12];  // = MbsPrevTimeCh1 - MbsPrevTimeCh0
-      if (l > 1) fPrevLastCh0ReTime[l - 2] = fullTime;
+      if (l == 0) ctx.prevLastCh0ReTime[12] = fullTime;
+      if (l == 1) ctx.mbsCorr = fullTime - ctx.prevLastCh0ReTime[12];  // = MbsPrevTimeCh1 - MbsPrevTimeCh0
+      if (l > 1) ctx.prevLastCh0ReTime[l - 2] = fullTime;
     }
 
     const uint32_t trbNum = reader.NextWord();  // TRB trigger number
@@ -82,7 +77,7 @@ namespace cbm::algo::rich
   }
 
 
-  void Unpack::ProcessHubBlock(rich::MicrosliceReader& reader)
+  void Unpack::ProcessHubBlock(rich::MicrosliceReader& reader, MSContext& ctx) const
   {
     uint32_t word          = reader.NextWord();
     const uint32_t hubId   = word & 0xffff;          // 16 bits
@@ -90,7 +85,7 @@ namespace cbm::algo::rich
 
     bool isLast         = false;  // if true then it is CTS sub-sub-event
     size_t totalSize    = 0;
-    fCurrentSubSubEvent = 0;
+    ctx.currentSubSubEvent = 0;
 
     uint32_t subSubEventId, subSubEventSize;
 
@@ -104,18 +99,18 @@ namespace cbm::algo::rich
 
       if (!isLast) {                                 // all except last are DiRICH events
         if (((subSubEventId >> 12) & 0xF) != 0x7) {  // catch invalid ids
-          fMonitor.fNumErrInvalidHubId++;
+          ctx.monitor.fNumErrInvalidHubId++;
         }
-        if (totalSize == hubSize) { fMonitor.fNumErrInvalidHubSize++; }
-        ProcessSubSubEvent(reader, subSubEventSize, subSubEventId);
-        fCurrentSubSubEvent++;
+        if (totalSize == hubSize) { ctx.monitor.fNumErrInvalidHubSize++; }
+        ProcessSubSubEvent(reader, subSubEventSize, subSubEventId, ctx);
+        ctx.currentSubSubEvent++;
       }
     }
 
     //last event ist expected to be CTS
-    if (totalSize != hubSize || !isLast) { fMonitor.fNumErrInvalidHubSize++; }
+    if (totalSize != hubSize || !isLast) { ctx.monitor.fNumErrInvalidHubSize++; }
     subSubEventSize = ProcessCtsHeader(reader, subSubEventSize, subSubEventId);
-    ProcessSubSubEvent(reader, subSubEventSize, subSubEventId);
+    ProcessSubSubEvent(reader, subSubEventSize, subSubEventId, ctx);
 
     // read last words
     int lastWordsCounter = 0;
@@ -126,11 +121,11 @@ namespace cbm::algo::rich
         if (reader.IsNextPadding()) word = reader.NextWord();
         break;
       }
-      if (lastWordsCounter >= 7) { fMonitor.fNumErrExcessLastWords++; }
+      if (lastWordsCounter >= 7) { ctx.monitor.fNumErrExcessLastWords++; }
     }
   }
 
-  int Unpack::ProcessCtsHeader(rich::MicrosliceReader& reader, uint32_t subSubEventSize, uint32_t subSubEventId)
+  int Unpack::ProcessCtsHeader(rich::MicrosliceReader& reader, uint32_t subSubEventSize, uint32_t subSubEventId) const
   {
     const uint32_t word         = reader.NextWord();
     const uint32_t ctsState     = word & 0xffff;                                                            // 16 bits
@@ -154,7 +149,8 @@ namespace cbm::algo::rich
     return nofTimeWords;
   }
 
-  void Unpack::ProcessSubSubEvent(rich::MicrosliceReader& reader, int nofTimeWords, uint32_t subSubEventId)
+  void Unpack::ProcessSubSubEvent(rich::MicrosliceReader& reader, int nofTimeWords, uint32_t subSubEventId,
+                                  MSContext& ctx) const
   {
     uint32_t epoch = 0;  // store last epoch obtained in sub-sub-event
 
@@ -171,11 +167,11 @@ namespace cbm::algo::rich
     }
 
     // First word is expected to be of type "header"
-    if (GetTdcWordType(reader.NextWord()) != TdcWordType::Header) { fMonitor.fNumErrInvalidFirstMessage++; }
+    if (GetTdcWordType(reader.NextWord()) != TdcWordType::Header) { ctx.monitor.fNumErrInvalidFirstMessage++; }
 
     // Second word is expected to be of type "epoch"
     uint32_t word = reader.NextWord();
-    if (GetTdcWordType(word) != TdcWordType::Epoch) { fMonitor.fNumErrInvalidSecondMessage++; }
+    if (GetTdcWordType(word) != TdcWordType::Epoch) { ctx.monitor.fNumErrInvalidSecondMessage++; }
     else {
       epoch = ProcessEpoch(word);
     }
@@ -185,7 +181,7 @@ namespace cbm::algo::rich
       word = reader.NextWord();
       switch (GetTdcWordType(word)) {
         case TdcWordType::TimeData: {
-          ProcessTimeDataWord(epoch, word, subSubEventId, raisingTime);
+          ProcessTimeDataWord(epoch, word, subSubEventId, raisingTime, ctx);
           break;
         }
         case TdcWordType::Epoch: {
@@ -193,43 +189,44 @@ namespace cbm::algo::rich
           break;
         }
         case TdcWordType::Header: {
-          fMonitor.fNumErrWildHeaderMessage++;
+          ctx.monitor.fNumErrWildHeaderMessage++;
           break;
         }
         case TdcWordType::Trailer: {
-          fMonitor.fNumErrWildTrailerMessage++;
+          ctx.monitor.fNumErrWildTrailerMessage++;
           break;
         }
         case TdcWordType::Debug: {
           break;
           // for the moment do nothing
-          fMonitor.fNumDebugMessage++;
+          ctx.monitor.fNumDebugMessage++;
           break;
         }
         case TdcWordType::Error: {
-          fMonitor.fNumErrTdcErrorWord++;
+          ctx.monitor.fNumErrTdcErrorWord++;
           break;
         }
       }
     }
 
     // Last word is expected to be of type "trailer"
-    if (GetTdcWordType(reader.NextWord()) != TdcWordType::Trailer) { fMonitor.fNumErrInvalidLastMessage++; }
+    if (GetTdcWordType(reader.NextWord()) != TdcWordType::Trailer) { ctx.monitor.fNumErrInvalidLastMessage++; }
   }
 
   // ---- ProcessTimeDataWord ----
   void Unpack::ProcessTimeDataWord(uint32_t epoch, uint32_t tdcWord, uint32_t subSubEventId,
-                                   std::vector<double>& raisingTime)
+                                   std::vector<double>& raisingTime, MSContext& ctx) const
   {
     const TdcTimeData td  = ProcessTimeData(tdcWord);
     const double fullTime = CalculateTime(epoch, td.fCoarse, td.fFine);
 
     if (td.fChannel != 0) {
-      const double dT            = fullTime - fPrevLastCh0ReTime[fCurrentSubSubEvent];
-      const double subtrigOffset = (fCbmTimePacket - fCbmTimeMS) * 25.0;  // offset of SubTrigger to MS start in ns
-      const double fullTimeCorr  = dT - fMbsCorr + subtrigOffset;
+      const double dT = fullTime - ctx.prevLastCh0ReTime[ctx.currentSubSubEvent];
+      const double subtrigOffset =
+        (ctx.cbmTimePacket - ctx.cbmTimeMS) * 25.0;  // offset of SubTrigger to MS start in ns
+      const double fullTimeCorr = dT - ctx.mbsCorr + subtrigOffset;
 
-      if (td.fChannel < 1 || td.fChannel >= raisingTime.size()) { fMonitor.fNumErrChannelOutOfBounds++; }
+      if (td.fChannel < 1 || td.fChannel >= raisingTime.size()) { ctx.monitor.fNumErrChannelOutOfBounds++; }
       if (td.fIsRisingEdge) {
         // always store the latest raising edge. It means that in case RRFF situation only middle RF will be matched.
         raisingTime[td.fChannel] = fullTimeCorr;
@@ -239,7 +236,9 @@ namespace cbm::algo::rich
           // Matching was found, calculate ToT, if tot is in a good range -> create digi
           const double ToT = fullTimeCorr - raisingTime[td.fChannel];
           if (ToT >= fToTMin && ToT <= fToTMax) {
-            if (fullTimeCorr >= 0.0) { WriteOutputDigi(subSubEventId, td.fChannel, raisingTime[td.fChannel], ToT); }
+            if (fullTimeCorr >= 0.0) {
+              WriteOutputDigi(subSubEventId, td.fChannel, raisingTime[td.fChannel], ToT, ctx);
+            }
           }
           // pair was created, set raising edge to -1.
           raisingTime[td.fChannel] = -1.;
@@ -248,25 +247,25 @@ namespace cbm::algo::rich
     }
   }
 
-  double Unpack::CalculateTime(uint32_t epoch, uint32_t coarse, uint32_t fine)
+  double Unpack::CalculateTime(uint32_t epoch, uint32_t coarse, uint32_t fine) const
   {
     return ((double) epoch) * 2048. * 5. + ((double) coarse) * 5. - ((double) fine) * 0.005;
   }
 
-  void Unpack::WriteOutputDigi(int32_t fpgaID, int32_t channel, double time, double tot)
+  void Unpack::WriteOutputDigi(int32_t fpgaID, int32_t channel, double time, double tot, MSContext& ctx) const
   {
-    double ToTcorr   = fbDoToTCorr ? fParams.fElinkParams[fpgaID].fToTshift[channel] : 0.;
+    double ToTcorr   = fbDoToTCorr ? fParams.fElinkParams.at(fpgaID).fToTshift[channel] : 0.;
     int32_t pixelUID = GetPixelUID(fpgaID, channel);
     //check ordering
-    double finalTime = time + (double) fMsRefTime - fParams.fElinkParams[fpgaID].fTimeOffset;
+    double finalTime = time + (double) ctx.refTime - fParams.fElinkParams.at(fpgaID).fTimeOffset;
 
     // Do not accept digis, where the MS und TS differs by more than 6 sec (mainly TS0)
     if (6e9 < finalTime) return;
 
-    fOutputVec.emplace_back(pixelUID, finalTime, tot - ToTcorr);
+    ctx.digis.emplace_back(pixelUID, finalTime, tot - ToTcorr);
   }
 
-  bool Unpack::CheckMaskedDiRICH(int32_t subSubEventId)
+  bool Unpack::CheckMaskedDiRICH(int32_t subSubEventId) const
   {
     for (unsigned int i = 0; i < fMaskedDiRICHes.size(); ++i) {
       if (fMaskedDiRICHes.at(i) == subSubEventId) return true;
@@ -274,7 +273,7 @@ namespace cbm::algo::rich
     return false;
   }
 
-  TdcWordType Unpack::GetTdcWordType(uint32_t tdcWord)
+  TdcWordType Unpack::GetTdcWordType(uint32_t tdcWord) const
   {
     uint32_t tdcTimeDataMarker = (tdcWord >> 31) & 0x1;  // 1 bit
     uint32_t tdcMarker         = (tdcWord >> 29) & 0x7;  // 3 bits
@@ -293,14 +292,14 @@ namespace cbm::algo::rich
     return TdcWordType::Error;
   }
 
-  int32_t Unpack::GetPixelUID(int32_t fpgaID, int32_t ch)
+  int32_t Unpack::GetPixelUID(int32_t fpgaID, int32_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));
   }
 
-  TdcTimeData Unpack::ProcessTimeData(uint32_t tdcWord)
+  TdcTimeData Unpack::ProcessTimeData(uint32_t tdcWord) const
   {
     TdcTimeData out;
     out.fCoarse       = static_cast<uint32_t>(tdcWord & 0x7ff);          // 11 bits
@@ -310,13 +309,13 @@ namespace cbm::algo::rich
     return out;
   }
 
-  uint32_t Unpack::ProcessEpoch(uint32_t tdcWord) { return static_cast<uint32_t>(tdcWord & 0xfffffff); }
+  uint32_t Unpack::ProcessEpoch(uint32_t tdcWord) const { return static_cast<uint32_t>(tdcWord & 0xfffffff); }
 
-  uint16_t Unpack::ProcessHeader(uint32_t tdcWord)
+  uint16_t Unpack::ProcessHeader(uint32_t tdcWord) const
   {
     return static_cast<uint16_t>(tdcWord & 0xff);  //8 bits
   }
 
-  uint16_t Unpack::ProcessTrailer(uint32_t tdcWord) { return static_cast<uint16_t>(tdcWord & 0xffff); }
+  uint16_t Unpack::ProcessTrailer(uint32_t tdcWord) const { return static_cast<uint16_t>(tdcWord & 0xffff); }
 
 }  // namespace cbm::algo::rich
diff --git a/algo/detectors/rich/Unpack.h b/algo/detectors/rich/Unpack.h
index e668c2b1ffa995b8fb1afe6822f92a623ad0f13f..7786e7b3f39983416e96ddb2b85566acaa41b812 100644
--- a/algo/detectors/rich/Unpack.h
+++ b/algo/detectors/rich/Unpack.h
@@ -16,6 +16,8 @@
 #include <sstream>
 #include <utility>
 
+#include "Definitions.h"
+
 namespace cbm::algo::rich
 {
   class MicrosliceReader;
@@ -118,7 +120,7 @@ namespace cbm::algo::rich
      ** @return RICH digi data
      **/
     resultType operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
-                          const uint64_t tTimeslice);
+                          const uint64_t tTimeslice) const;
 
     /** @brief Set the parameter container
      ** @param params Pointer to parameter container
@@ -126,34 +128,49 @@ namespace cbm::algo::rich
     void SetParams(std::unique_ptr<UnpackPar> params) { fParams = *(std::move(params)); }
 
   private:
-    void ProcessTrbPacket(MicrosliceReader& reader);
+    struct MSContext {
+      u64 cbmTimeMS     = 0;  // CbmTime of MS. Used to get time offset of subtriggers to MS start
+      u64 cbmTimePacket = 0;
+      u64 refTime       = 0;
+
+      double prevLastCh0ReTime[13];  // 12 DiRICHes chnl0 + 1 CTS chnl0
+      double mbsCorr = 0.;
+
+      uint16_t currentSubSubEvent = 0;
 
-    void ProcessHubBlock(MicrosliceReader& reader);
+      std::vector<CbmRichDigi> digis;
+      UnpackMonitorData monitor;
+    };
+
+  private:
+    void ProcessTrbPacket(MicrosliceReader& reader, MSContext& ctx) const;
 
-    int ProcessCtsHeader(MicrosliceReader& reader, uint32_t subSubEventSize, uint32_t subSubEventId);
+    void ProcessHubBlock(MicrosliceReader& reader, MSContext& ctx) const;
 
-    void ProcessSubSubEvent(MicrosliceReader& reader, int nofTimeWords, uint32_t subSubEventId);
+    int ProcessCtsHeader(MicrosliceReader& reader, uint32_t subSubEventSize, uint32_t subSubEventId) const;
 
-    void ProcessTimeDataWord(uint32_t epoch, uint32_t tdcWord, uint32_t subSubEventId,
-                             std::vector<double>& raisingTime);
+    void ProcessSubSubEvent(MicrosliceReader& reader, int nofTimeWords, uint32_t subSubEventId, MSContext& ctx) const;
 
-    TdcWordType GetTdcWordType(uint32_t tdcWord);
+    void ProcessTimeDataWord(uint32_t epoch, uint32_t tdcWord, uint32_t subSubEventId, std::vector<double>& raisingTime,
+                             MSContext& ctx) const;
 
-    TdcTimeData ProcessTimeData(uint32_t tdcWord);
+    TdcWordType GetTdcWordType(uint32_t tdcWord) const;
 
-    uint32_t ProcessEpoch(uint32_t tdcWord);
+    TdcTimeData ProcessTimeData(uint32_t tdcWord) const;
 
-    uint16_t ProcessHeader(uint32_t tdcWord);
+    uint32_t ProcessEpoch(uint32_t tdcWord) const;
 
-    uint16_t ProcessTrailer(uint32_t tdcWord);
+    uint16_t ProcessHeader(uint32_t tdcWord) const;
 
-    void WriteOutputDigi(int32_t fpgaID, int32_t channel, double time, double tot);
+    uint16_t ProcessTrailer(uint32_t tdcWord) const;
 
-    double CalculateTime(uint32_t epoch, uint32_t coarse, uint32_t fine);
+    void WriteOutputDigi(int32_t fpgaID, int32_t channel, double time, double tot, MSContext& ctx) const;
 
-    int32_t GetPixelUID(int32_t fpgaID, int32_t ch);
+    double CalculateTime(uint32_t epoch, uint32_t coarse, uint32_t fine) const;
 
-    bool CheckMaskedDiRICH(int32_t subSubEventId);
+    int32_t GetPixelUID(int32_t fpgaID, int32_t ch) const;
+
+    bool CheckMaskedDiRICH(int32_t subSubEventId) const;
 
   private:
     UnpackPar fParams = {};  ///< Parameter container
@@ -162,23 +179,15 @@ namespace cbm::algo::rich
 
     bool fbDoToTCorr = true;  //activates ToT correction from parameter file
 
-    uint64_t fCbmTimeMS;
-    uint64_t fCbmTimePacket;
-
-    double fMbsCorr = 0.;
-    double fPrevLastCh0ReTime[13];  // 12 DiRICHes chnl0 + 1 CTS chnl0
-    uint16_t fCurrentSubSubEvent = 0;
+    // uint64_t fCbmTimeMS;
+    // uint64_t fCbmTimePacket;
 
-    uint64_t fMsRefTime = 0;
+    // double fMbsCorr = 0.;
+    // double fPrevLastCh0ReTime[13];  // 12 DiRICHes chnl0 + 1 CTS chnl0
+    // uint16_t fCurrentSubSubEvent = 0;
 
     double fToTMin = -20.;
     double fToTMax = 100.;
-
-    /** @brief Default return vector for Unpack function. */
-    std::vector<CbmRichDigi> fOutputVec = {};
-
-    /** @brief Storage of monitoring data. */
-    UnpackMonitorData fMonitor;
   };