From 59dad30e1f50bfa508664664f5d807481075c662 Mon Sep 17 00:00:00 2001
From: "P.-A. Loizeau" <p.-a.loizeau@gsi.de>
Date: Thu, 17 Mar 2022 17:55:20 +0100
Subject: [PATCH] Unpacking: add BMon unpacking based on TOF one + BMon/TOF
 monitoring

- Update Mcbm2018TofPar to map the 2022 BMon diamond
- Update Mcbm2018TofPar to map the new TOF modules for the 2022 iron beams (run 2100 onward)
- Add a BmonUnpackConfig class setting up the TOF unpacker to BMon mode
- Add a TofUnpackMonitor class providing monitoring plots for TOF and BMon unpacking
- Integrate this one in the TOF unpack algo
- Fix incomplete switching for the 2021 epoch hack in the TOF unpack Algo
- Add Bmon in the sterring RecoUnpack task
- Add a monitoring only mode to the RecoUnpack task were data is neither time sorted nor written to disk
- Add BMon in the unpacking macros
- Add the TOF monitor(s) to the unpacking macros
- Add BMon only unpacking macros for fast beam monitoring (especially for beam tuning)
- Add parameter files for TOF and BMon in the 2022 campaign
---
 core/data/CbmTsEventHeader.cxx                |    1 +
 core/data/CbmTsEventHeader.h                  |   10 +-
 core/detectors/tof/CbmMcbm2018TofPar.cxx      |   54 +-
 core/detectors/tof/CbmMcbm2018TofPar.h        |    1 +
 macro/beamtime/mcbm2022/mBmonCriPar.par       |   34 +
 macro/beamtime/mcbm2022/mTofCriPar.par        |    2 +-
 macro/run/run_unpack_online.C                 |   69 +-
 macro/run/run_unpack_online_bmon.C            |  211 +++
 macro/run/run_unpack_tsa.C                    |   72 +-
 macro/run/run_unpack_tsa_bmon.C               |  215 +++
 reco/detectors/tof/CMakeLists.txt             |    3 +
 reco/detectors/tof/CbmTofRecoLinkDef.h        |    4 +-
 .../tof/unpack/CbmBmonUnpackConfig.cxx        |   50 +
 .../tof/unpack/CbmBmonUnpackConfig.h          |   78 +
 .../detectors/tof/unpack/CbmTofUnpackAlgo.cxx |  142 +-
 reco/detectors/tof/unpack/CbmTofUnpackAlgo.h  |   39 +-
 .../tof/unpack/CbmTofUnpackConfig.cxx         |    4 +-
 .../detectors/tof/unpack/CbmTofUnpackConfig.h |   21 +-
 .../tof/unpack/CbmTofUnpackMonitor.cxx        | 1393 +++++++++++++++++
 .../tof/unpack/CbmTofUnpackMonitor.h          |  287 ++++
 reco/steer/CbmRecoUnpack.cxx                  |   26 +-
 reco/steer/CbmRecoUnpack.h                    |   68 +-
 22 files changed, 2690 insertions(+), 94 deletions(-)
 create mode 100644 macro/beamtime/mcbm2022/mBmonCriPar.par
 create mode 100644 macro/run/run_unpack_online_bmon.C
 create mode 100644 macro/run/run_unpack_tsa_bmon.C
 create mode 100644 reco/detectors/tof/unpack/CbmBmonUnpackConfig.cxx
 create mode 100644 reco/detectors/tof/unpack/CbmBmonUnpackConfig.h
 create mode 100644 reco/detectors/tof/unpack/CbmTofUnpackMonitor.cxx
 create mode 100644 reco/detectors/tof/unpack/CbmTofUnpackMonitor.h

diff --git a/core/data/CbmTsEventHeader.cxx b/core/data/CbmTsEventHeader.cxx
index 5676084214..9c3bdc5fbc 100644
--- a/core/data/CbmTsEventHeader.cxx
+++ b/core/data/CbmTsEventHeader.cxx
@@ -19,6 +19,7 @@ void CbmTsEventHeader::Reset()
   fNDigisTof   = 0;
   fNDigisTrd1D = 0;
   fNDigisTrd2D = 0;
+  fNDigisBmon  = 0;
 }
 
 ClassImp(CbmTsEventHeader)
diff --git a/core/data/CbmTsEventHeader.h b/core/data/CbmTsEventHeader.h
index 32e1a72c62..3a9cbdff19 100644
--- a/core/data/CbmTsEventHeader.h
+++ b/core/data/CbmTsEventHeader.h
@@ -31,6 +31,8 @@ public:
   void AddNDigisTrd1D(uint64_t value) { fNDigisTrd1D += value; }
   /** @brief Add a number of digis from this Ts */
   void AddNDigisTrd2D(uint64_t value) { fNDigisTrd2D += value; }
+  /** @brief Add a number of digis from this Ts */
+  void AddNDigisBmon(uint64_t value) { fNDigisBmon += value; }
 
   /** @brief Get the number of digis in this Ts */
   uint64_t GetNDigisPsd() const { return fNDigisPsd; }
@@ -44,6 +46,8 @@ public:
   uint64_t GetNDigisTrd1D() const { return fNDigisTrd1D; }
   /** @brief Get the number of digis in this Ts */
   uint64_t GetNDigisTrd2D() const { return fNDigisTrd2D; }
+  /** @brief Get the number of digis in this Ts */
+  uint64_t GetNDigisBmon() const { return fNDigisBmon; }
 
   /** Get the Start time of the this Timeslice linked to this event header*/
   uint64_t GetTsIndex() const { return fTsIndex; }
@@ -65,6 +69,8 @@ public:
   void SetNDigisTrd1D(uint64_t value) { fNDigisTrd1D = value; }
   /** @brief Set the number of digis in this Ts */
   void SetNDigisTrd2D(uint64_t value) { fNDigisTrd2D = value; }
+  /** @brief Set the number of digis in this Ts */
+  void SetNDigisBmon(uint64_t value) { fNDigisBmon = value; }
 
   /** @brief Set the Ts Start Time @param value Start time of the TS */
   void SetTsIndex(uint64_t value) { fTsIndex = value; }
@@ -93,7 +99,9 @@ protected:
   uint64_t fNDigisTrd1D = 0;
   /** @brief nDigis in "this" timeslice measured by the TRD2D */
   uint64_t fNDigisTrd2D = 0;
+  /** @brief nDigis in "this" timeslice measured by the BMON */
+  uint64_t fNDigisBmon = 0;
 
-  ClassDef(CbmTsEventHeader, 5)
+  ClassDef(CbmTsEventHeader, 6)
 };
 #endif
diff --git a/core/detectors/tof/CbmMcbm2018TofPar.cxx b/core/detectors/tof/CbmMcbm2018TofPar.cxx
index be885c97e2..271315ca45 100644
--- a/core/detectors/tof/CbmMcbm2018TofPar.cxx
+++ b/core/detectors/tof/CbmMcbm2018TofPar.cxx
@@ -149,6 +149,7 @@ Bool_t CbmMcbm2018TofPar::getParams(FairParamList* l)
   if (!l->fill("StarTriggerWinSize", &fdStarTriggerWinSize)) return kFALSE;
   if (!l->fill("TsDeadtimePeriod", &fdTsDeadtimePeriod)) return kFALSE;
 
+  LOG(info) << "Build TOF Channels UId Map:";
   BuildChannelsUidMap();
 
   return kTRUE;
@@ -215,8 +216,9 @@ void CbmMcbm2018TofPar::BuildChannelsUidMap()
 
   UInt_t uCh = 0;
   for (UInt_t uGbtx = 0; uGbtx < uNrOfGbtx; ++uGbtx) {
+    uint32_t uCh0 = uCh;
     switch (fiRpcType[uGbtx]) {
-      case 2: // intended fall-through
+      case 2:  // intended fall-through
       case 0: {
         // CBM modules
         BuildChannelsUidMapCbm(uCh, uGbtx);
@@ -232,6 +234,11 @@ void CbmMcbm2018TofPar::BuildChannelsUidMap()
         BuildChannelsUidMapT0(uCh, uGbtx);
         break;
       }
+      case 99: {
+        /// Special Treatment for the 2022 T0 diamond, keep past behavior for older data!
+        BuildChannelsUidMapT0_2022(uCh, uGbtx);
+        break;
+      }
       case 78: {
         // cern-20-gap + ceramic module
         BuildChannelsUidMapCern(uCh, uGbtx);
@@ -254,6 +261,15 @@ void CbmMcbm2018TofPar::BuildChannelsUidMap()
         BuildChannelsUidMapBuc(uCh, uGbtx);
         break;
       }
+      case 69: {
+        /// 2022 case: 69 is followed by 4 and 9
+        BuildChannelsUidMapBuc(uCh, uGbtx);
+        /// Map also 4 and 9 (equivalent to fallthrough to 4 then 9 but without changing past behaviors)
+        uCh -= 80;  // PAL, 2022/03/17: ?!?
+        BuildChannelsUidMapStar2(uCh, uGbtx);
+        uCh -= 80;  // PAL, 2022/03/17: ?!?
+        break;
+      }
       case -1: {
         LOG(info) << " Found unused GBTX link at uCh = " << uCh;
         uCh += 160;
@@ -263,11 +279,15 @@ void CbmMcbm2018TofPar::BuildChannelsUidMap()
         LOG(error) << "Invalid Tof Type specifier for GBTx " << std::setw(2) << uGbtx << ": " << fiRpcType[uGbtx];
       }
     }  // switch (fiRpcType[uGbtx])
+    if (uCh - uCh0 != fiNrOfFeesPerGdpb * fiNrOfGet4PerFee * fiNrOfChannelsPerGet4 / 2) {
+      LOG(fatal) << "Tof mapping error for Gbtx " << uGbtx << ",  diff = " << uCh - uCh0;
+    }
   }    // for (UInt_t uGbtx = 0; uGbtx < uNrOfGbtx; ++uGbtx)
 }
 // -------------------------------------------------------------------------
 void CbmMcbm2018TofPar::BuildChannelsUidMapCbm(UInt_t& uCh, UInt_t uGbtx)
 {
+  LOG(info) << " Map mTof box " << fiModuleId[uGbtx] << " at GBTX " << uGbtx << " -  uCh = " << uCh;
   if (fiRpcSide[uGbtx] < 2) {  // mTof modules
     LOG(debug) << " Map mTof box " << fiModuleId[uGbtx] << " at GBTX  -  uCh = " << uCh;
     const Int_t RpcMap[5] = {4, 2, 0, 3, 1};
@@ -353,6 +373,28 @@ void CbmMcbm2018TofPar::BuildChannelsUidMapT0(UInt_t& uCh, UInt_t uGbtx)
   }    // for( UInt_t uFee = 0; uFee < kuNbChannelsPerFee; ++uFee )
 }
 // -------------------------------------------------------------------------
+void CbmMcbm2018TofPar::BuildChannelsUidMapT0_2022(UInt_t& uCh, UInt_t uGbtx)
+{
+  LOG(info) << " Map 2022 diamond " << fiModuleId[uGbtx] << " at GBTX " << uGbtx << " -  uCh = " << uCh;
+  for (UInt_t uGet4 = 0; uGet4 < kuNbGet4PerGbtx; ++uGet4) {
+    for (UInt_t uGet4Ch = 0; uGet4Ch < kuNbChannelsPerGet4; ++uGet4Ch) {
+      /// Mapping for the 2022 beamtime
+      if (0 == uGet4 % 4 && 0 == uGet4Ch && -1 < fiModuleId[uGbtx]) {
+        UInt_t uChannelT0 = uGet4 / 8;  // + 4 * fiRpcSide[uGbtx];
+        /// Type hard-coded to allow different parameter values to separate 2022 T0 and pre-2022 T0
+        fviRpcChUId[uCh] = CbmTofAddress::GetUniqueAddress(fiModuleId[uGbtx], 0, uChannelT0, 0, 5);
+        LOG(info) << Form("  T0 channel: %u from GBTx %2u, "
+                          "indx %d address %08x",
+                          uChannelT0, uGbtx, uCh, fviRpcChUId[uCh]);
+      }  // Valid T0 channel
+      else {
+        fviRpcChUId[uCh] = 0;
+      }  // Invalid T0 channel
+      uCh++;
+    }  // for( UInt_t uCh = 0; uCh < kuNbFeePerGbtx; ++uCh )
+  }    // for( UInt_t uFee = 0; uFee < kuNbChannelsPerFee; ++uFee )
+}
+// -------------------------------------------------------------------------
 void CbmMcbm2018TofPar::BuildChannelsUidMapCern(UInt_t& uCh, UInt_t /*uGbtx*/)
 {
   LOG(info) << " Map CERN 20 gap  at GBTX  -  uCh = " << uCh;
@@ -392,7 +434,7 @@ void CbmMcbm2018TofPar::BuildChannelsUidMapCera(UInt_t& uCh, UInt_t /*uGbtx*/)
 // -------------------------------------------------------------------------
 void CbmMcbm2018TofPar::BuildChannelsUidMapStar2(UInt_t& uCh, UInt_t uGbtx)
 {
-  LOG(info) << " Map Star2 box " << fiModuleId[uGbtx] << " at GBTX  -  uCh = " << uCh;
+  LOG(info) << " Map Star2 box " << fiModuleId[uGbtx] << " at GBTX " << uGbtx << " -  uCh = " << uCh;
   const Int_t iRpc[5]  = {1, -1, 1, 0, 0};
   const Int_t iSide[5] = {1, -1, 0, 1, 0};
   for (Int_t iFeet = 0; iFeet < 5; iFeet++) {
@@ -448,7 +490,7 @@ void CbmMcbm2018TofPar::BuildChannelsUidMapStar2(UInt_t& uCh, UInt_t uGbtx)
 // -------------------------------------------------------------------------
 void CbmMcbm2018TofPar::BuildChannelsUidMapBuc(UInt_t& uCh, UInt_t uGbtx)
 {
-  LOG(info) << " Map Buc box  at GBTX  -  uCh = " << uCh;
+  LOG(info) << " Map Buc box " << fiModuleId[uGbtx] << " at GBTX " << uGbtx << " -  uCh = " << uCh;
 
   Int_t iModuleIdMap   = fiModuleId[uGbtx];
   const Int_t iRpc[5]  = {0, -1, 0, 1, 1};
@@ -533,9 +575,9 @@ void CbmMcbm2018TofPar::BuildChannelsUidMapBuc(UInt_t& uCh, UInt_t uGbtx)
             case 4: iSideMap = -1; break;
           }
           iModuleIdMap = fiModuleId[uGbtx];
-          LOG(info) << "Buc of GBTX " << uGbtx << " Ch " << uCh
-                    << Form(", Feet %1d, Str %2d, Ind %3d, i %3d, FeetInd %1d, Rpc %1d, Side %1d, Str %2d ", iFeet,
-                            iStr, iInd, i, iFeetInd, iRpcMap, iSideMap, iStrMap);
+          LOG(debug) << "Buc of GBTX " << uGbtx << " Ch " << uCh
+                     << Form(", Feet %1d, Str %2d, Ind %3d, i %3d, FeetInd %1d, Rpc %1d, Side %1d, Str %2d ", iFeet,
+                             iStr, iInd, i, iFeetInd, iRpcMap, iSideMap, iStrMap);
         } break;
         default:;
       }  // switch (fiRpcSide[uGbtx])
diff --git a/core/detectors/tof/CbmMcbm2018TofPar.h b/core/detectors/tof/CbmMcbm2018TofPar.h
index e134514187..901e3169a8 100644
--- a/core/detectors/tof/CbmMcbm2018TofPar.h
+++ b/core/detectors/tof/CbmMcbm2018TofPar.h
@@ -88,6 +88,7 @@ private:
   void BuildChannelsUidMapCbm(UInt_t& uCh, UInt_t uGbtx);
   void BuildChannelsUidMapStar(UInt_t& uCh, UInt_t uGbtx);
   void BuildChannelsUidMapT0(UInt_t& uCh, UInt_t uGbtx);
+  void BuildChannelsUidMapT0_2022(UInt_t& uCh, UInt_t uGbtx);
   void BuildChannelsUidMapCern(UInt_t& uCh, UInt_t uGbtx);
   void BuildChannelsUidMapCera(UInt_t& uCh, UInt_t uGbtx);
   void BuildChannelsUidMapStar2(UInt_t& uCh, UInt_t uGbtx);
diff --git a/macro/beamtime/mcbm2022/mBmonCriPar.par b/macro/beamtime/mcbm2022/mBmonCriPar.par
new file mode 100644
index 0000000000..98525587b7
--- /dev/null
+++ b/macro/beamtime/mcbm2022/mBmonCriPar.par
@@ -0,0 +1,34 @@
+####################################################################################################
+[CbmMcbm2018TofPar]
+//----------------------------------------------------------------------------
+NrOfGdpbs: Int_t 4
+GdpbIdArray: Int_t \
+0xabf0 0xabf1 0xabf2 0xabf3
+NrOfFeesPerGdpb: Int_t 10
+NrOfGet4PerFee:  Int_t 8
+NrOfChannelsPerGet4: Int_t 4
+NrOfGbtx: Int_t  8
+NrOfModule: Int_t 0
+NrOfRpc: Int_t \
+  1  1  1  1
+RpcType: Int_t \
+ 99 -1 99 -1 99 -1 99 -1
+RpcSide: Int_t \
+  0  0  1  0  0  0  1  0
+ModuleId: Int_t \
+  1 -1  1 -1  0 -1  0 -1
+NbMsTot: Int_t 100
+NbMsOverlap: Int_t 1
+SizeMsInNs: Double_t 102400.0
+//SizeMsInNs: Double_t 1638400
+StarTriggerDeadtime:  Double_t \
+ 1000.0  1000.0  1000.0  1000.0  1000.0
+StarTriggerDelay: Double_t \
+ 2000.0  2000.0  2000.0  2000.0  2000.0
+//  2000.0  2000.0  2000.0  2000.0  2000.0
+//-23000.0  -23000.0  -23000.0  -23000.0  -23000.0
+StarTriggerWinSize: Double_t \
+ 2000.0  2000.0  2000.0  2000.0  2000.0
+TsDeadtimePeriod: Double_t 62.5
+
+####################################################################################################
diff --git a/macro/beamtime/mcbm2022/mTofCriPar.par b/macro/beamtime/mcbm2022/mTofCriPar.par
index 0fe3bc583b..8d928103b2 100644
--- a/macro/beamtime/mcbm2022/mTofCriPar.par
+++ b/macro/beamtime/mcbm2022/mTofCriPar.par
@@ -8,7 +8,7 @@ NrOfFeesPerGdpb: Int_t 10
 NrOfGet4PerFee:  Int_t 8
 NrOfChannelsPerGet4: Int_t 4
 NrOfGbtx: Int_t  16
-NrOfModule: Int_t 20
+NrOfModule: Int_t 0
 NrOfRpc: Int_t \
   5  5  5  5  5  5  5  5  5  5  5  5  2  2  2  2
 RpcType: Int_t \
diff --git a/macro/run/run_unpack_online.C b/macro/run/run_unpack_online.C
index fd3c46a27a..0829dda8fa 100644
--- a/macro/run/run_unpack_online.C
+++ b/macro/run/run_unpack_online.C
@@ -34,6 +34,7 @@ std::shared_ptr<CbmTrdUnpackMonitor> GetTrdMonitor(std::string treefilename, boo
 std::shared_ptr<CbmTrdSpadic> GetTrdSpadic(bool useAvgBaseline = false);
 std::shared_ptr<CbmStsUnpackMonitor> GetStsMonitor(std::string treefilename, bool bDebugMode = false);
 std::shared_ptr<CbmRichUnpackMonitor> GetRichMonitor(std::string treefilename, bool bDebugMode = false);
+std::shared_ptr<CbmTofUnpackMonitor> GetTofMonitor(std::string treefilename, bool bBmonMode = false);
 const char* defaultSetupName = "mcbm_beam_2021_07_surveyed";
 
 void run_unpack_online(std::vector<std::string> publisher = {"tcp://localhost:5556"}, Int_t serverHttpPort = 8080,
@@ -236,16 +237,35 @@ void run_unpack_online(std::vector<std::string> publisher = {"tcp://localhost:55
     tofconfig->SetDoWriteOutput();
     // tofconfig->SetDoWriteOptOutA("CbmTofErrors");
     std::string parfilesbasepathTof = Form("%s/macro/beamtime/mcbm2021/", srcDir.Data());
-    if (2060 <= runid ) {
+    if (2060 <= runid) {
       /// Additional modules added just before the 10/03/2022 Carbon run
       parfilesbasepathTof = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data());
     }
     tofconfig->SetParFilesBasePath(parfilesbasepathTof);
     tofconfig->SetSystemTimeOffset(-1220);  // [ns] value to be updated
-    if (runid <= 1659) {
+    if (runid <= 1659 && runid < 2060) {
       /// Switch ON the -4 offset in epoch count (hack for Spring-Summer 2021)
       tofconfig->SetFlagEpochCountHack2021();
     }
+    /// Enable Monitor plots
+    tofconfig->SetMonitor(GetTofMonitor(outfilename, false));
+  }
+  // -------------
+
+  // ---- BMON ----
+  std::shared_ptr<CbmBmonUnpackConfig> bmonconfig = nullptr;
+
+  bmonconfig = std::make_shared<CbmBmonUnpackConfig>("", runid);
+  if (bmonconfig) {
+    // bmonconfig->SetDebugState();
+    bmonconfig->SetDoWriteOutput();
+    // bmonconfig->SetDoWriteOptOutA("CbmBmonErrors");
+    std::string parfilesbasepathBmon = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data());
+    bmonconfig->SetParFilesBasePath(parfilesbasepathBmon);
+    bmonconfig->SetParFileName("mBmonCriPar.par");
+    bmonconfig->SetSystemTimeOffset(-1220);  // [ns] value to be updated
+    /// Enable Monitor plots
+    bmonconfig->SetMonitor(GetTofMonitor(outfilename, true));
   }
   // -------------
 
@@ -267,6 +287,7 @@ void run_unpack_online(std::vector<std::string> publisher = {"tcp://localhost:55
   unpack->SetOutputFilename(perfProfFileName);
   // Enable full time sorting instead sorting per FLIM link
   unpack->SetTimeSorting(true);
+  unpack->SetMonitoringOnly(true);
 
   if (psdconfig) unpack->SetUnpackConfig(psdconfig);
   if (richconfig) unpack->SetUnpackConfig(richconfig);
@@ -274,6 +295,7 @@ void run_unpack_online(std::vector<std::string> publisher = {"tcp://localhost:55
   if (trd1Dconfig) unpack->SetUnpackConfig(trd1Dconfig);
   if (trdfasp2dconfig) unpack->SetUnpackConfig(trdfasp2dconfig);
   if (tofconfig) unpack->SetUnpackConfig(tofconfig);
+  if (bmonconfig) unpack->SetUnpackConfig(bmonconfig);
   // ------------------------------------------------------------------------
 
 
@@ -475,6 +497,49 @@ std::shared_ptr<CbmRichUnpackMonitor> GetRichMonitor(std::string treefilename, b
   return monitor;
 }
 
+/**
+ * @brief Get the Tof Monitor. Extra function to keep default macro part more silent.
+ * @return std::shared_ptr<CbmTofUnpackMonitor>
+*/
+std::shared_ptr<CbmTofUnpackMonitor> GetTofMonitor(std::string treefilename, bool bBmonMode = false)
+{
+  // -----   Output filename and path   -------------------------------------
+  std::string outpath  = "";
+  std::string filename = "";
+  auto filenamepos     = treefilename.find_last_of("/");
+  if (filenamepos != treefilename.npos) {
+    outpath  = treefilename.substr(0, filenamepos);
+    filename = treefilename.substr(filenamepos++);
+  }
+  if (outpath.empty()) outpath = gSystem->GetWorkingDirectory();
+  //std::string mydir = "/qa";
+  //outpath += mydir;
+
+  auto currentdir = gSystem->GetWorkingDirectory();
+
+  if (!gSystem->cd(outpath.data())) gSystem->MakeDirectory(outpath.data());
+  else
+    gSystem->cd(currentdir.data());
+
+  std::string sSystemType = ".mon.tof.root";
+  if (bBmonMode) {
+    //
+    sSystemType = ".mon.bmon.root";
+  }
+
+  std::string outfilename = outpath + filename;
+  auto filetypepos        = outfilename.find(".digi.root");
+  if (filetypepos != outfilename.npos) outfilename.replace(filetypepos, 10, sSystemType);
+  else
+    outfilename += sSystemType;
+  // ------------------------------------------------------------------------
+
+  auto monitor = std::make_shared<CbmTofUnpackMonitor>();
+  monitor->SetHistoFileName(outfilename);
+  monitor->SetBmonMode(bBmonMode);
+  return monitor;
+}
+
 void run_unpack_online(std::string publisher = "tcp://localhost:5556", Int_t serverHttpPort = 8080,
                        Int_t serverRefreshRate = 100, std::int32_t nevents = -1, UInt_t runid = 1905,
                        const char* setupName = defaultSetupName, std::string outpath = "data/")
diff --git a/macro/run/run_unpack_online_bmon.C b/macro/run/run_unpack_online_bmon.C
new file mode 100644
index 0000000000..e49ed60b6f
--- /dev/null
+++ b/macro/run/run_unpack_online_bmon.C
@@ -0,0 +1,211 @@
+/* Copyright (C) 2022 Facility for Antiproton and Ion Research in Europe, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Pierre-Alain Loizeau [committer]  */
+
+/** @file run_unpack_tsa.C
+ ** @author Volker Friese <v.friese@gsi.de>
+ ** @since May 2021
+ **/
+
+
+// --- Includes needed for IDE
+#include <FairSource.h>
+
+#include <RtypesCore.h>
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+#if !defined(__CLING__)
+#include <FairLogger.h>
+#include <FairRootFileSink.h>
+#include <FairRunOnline.h>
+#include <Logger.h>
+
+#include <TStopwatch.h>
+#include <TSystem.h>
+#endif
+
+std::shared_ptr<CbmTofUnpackMonitor> GetTofMonitor(std::string treefilename, bool bBmonMode = false);
+const char* defaultSetupName = "mcbm_beam_2022_03_09_carbon";
+
+void run_unpack_online_bmon(std::vector<std::string> publisher = {"tcp://localhost:5556"}, Int_t serverHttpPort = 8080,
+                            Int_t serverRefreshRate = 100, std::int32_t nevents = -1, UInt_t runid = 1905,
+                            const char* setupName = defaultSetupName, std::string outpath = "data/")
+{
+
+  // ========================================================================
+  //          Adjust this part according to your requirements
+
+  // --- Logger settings ----------------------------------------------------
+  TString logLevel     = "INFO";
+  TString logVerbosity = "LOW";
+  // ------------------------------------------------------------------------
+
+  // -----   Environment   --------------------------------------------------
+  TString myName = "run_unpack_online";            // this macro's name for screen output
+  TString srcDir = gSystem->Getenv("VMCWORKDIR");  // top source directory
+  // ------------------------------------------------------------------------
+
+  // -----   Output filename   ----------------------------------------------
+  std::string filename    = Form("online_%05d.digi.root", runid);
+  std::string outfilename = outpath + filename;
+  std::cout << "-I- " << myName << ": Output file will be " << outfilename << std::endl;
+  // ------------------------------------------------------------------------
+
+
+  // -----   Performance profiling   ----------------------------------------
+  // Set to true if you want some minimal performance profiling output
+  bool doPerfProfiling = true;
+  // Define if you want a special path and name for the performance profiling output file
+  std::string perfProfFileName = outpath + filename;
+  perfProfFileName.replace(perfProfFileName.find(".digi.root"), 10, ".perf.root");
+  // ------------------------------------------------------------------------
+
+
+  // -----   CbmSetup   -----------------------------------------------------
+  auto cbmsetup = CbmSetup::Instance();
+  cbmsetup->LoadSetup(setupName);
+  // ------------------------------------------------------------------------
+
+  // -----   UnpackerConfigs   ----------------------------------------------
+
+  // ---- BMON ----
+  std::shared_ptr<CbmBmonUnpackConfig> bmonconfig = nullptr;
+
+  bmonconfig = std::make_shared<CbmBmonUnpackConfig>("", runid);
+  if (bmonconfig) {
+    // bmonconfig->SetDebugState();
+    bmonconfig->SetDoWriteOutput();
+    // bmonconfig->SetDoWriteOptOutA("CbmBmonErrors");
+    std::string parfilesbasepathBmon = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data());
+    bmonconfig->SetParFilesBasePath(parfilesbasepathBmon);
+    bmonconfig->SetParFileName("mBmonCriPar.par");
+    bmonconfig->SetSystemTimeOffset(-1220);  // [ns] value to be updated
+    /// Enable Monitor plots
+    bmonconfig->SetMonitor(GetTofMonitor(outfilename, true));
+  }
+  // -------------
+
+
+  // ------------------------------------------------------------------------
+
+  // In general, the following parts need not be touched
+  // ========================================================================
+
+  // -----   Timer   --------------------------------------------------------
+  TStopwatch timer;
+  timer.Start();
+  // ------------------------------------------------------------------------
+
+  // -----   CbmSourceTsArchive   -------------------------------------------
+  auto source = new CbmSourceTsArchive(publisher);
+  auto unpack = source->GetRecoUnpack();
+  unpack->SetDoPerfProfiling(doPerfProfiling);
+  unpack->SetOutputFilename(perfProfFileName);
+  // Enable full time sorting instead sorting per FLIM link
+  unpack->SetTimeSorting(true);
+  unpack->SetMonitoringOnly(true);
+
+  if (bmonconfig) unpack->SetUnpackConfig(bmonconfig);
+  // ------------------------------------------------------------------------
+
+
+  // -----   FairRunAna   ---------------------------------------------------
+  auto run  = new FairRunOnline(source);
+  auto sink = new FairRootFileSink(outfilename.data());
+  run->SetSink(sink);
+  auto eventheader = new CbmTsEventHeader();
+  run->SetRunId(runid);
+  run->SetEventHeader(eventheader);
+  // ------------------------------------------------------------------------
+
+
+  // -----   HttpServer for online monitoring   -----------------------------
+  run->ActivateHttpServer(serverRefreshRate, serverHttpPort);
+  run->GetHttpServer()->GetSniffer()->SetScanGlobalDir(kFALSE);
+  // run->SetAutoFinish(kFALSE);
+  // ------------------------------------------------------------------------
+
+
+  // -----   Logger settings   ----------------------------------------------
+  FairLogger::GetLogger()->SetLogScreenLevel(logLevel.Data());
+  FairLogger::GetLogger()->SetLogVerbosityLevel(logVerbosity.Data());
+  // ------------------------------------------------------------------------
+
+
+  // -----   Run initialisation   -------------------------------------------
+  std::cout << std::endl;
+  std::cout << "-I- " << myName << ": Initialise run" << std::endl;
+  run->Init();
+  // ------------------------------------------------------------------------
+
+
+  // -----   Start run   ----------------------------------------------------
+  std::cout << std::endl << std::endl;
+  std::cout << "-I- " << myName << ": Starting run" << std::endl;
+  if (nevents < 0) run->Run(-1, 0);
+  else
+    run->Run(0, nevents);
+  // ------------------------------------------------------------------------
+
+
+  // -----   Finish   -------------------------------------------------------
+  timer.Stop();
+  std::cout << "Macro finished successfully." << std::endl;
+  std::cout << "After CpuTime = " << timer.CpuTime() << " s RealTime = " << timer.RealTime() << " s." << std::endl;
+  // ------------------------------------------------------------------------
+
+}  // End of main macro function
+
+/**
+ * @brief Get the Tof Monitor. Extra function to keep default macro part more silent.
+ * @return std::shared_ptr<CbmTofUnpackMonitor>
+*/
+std::shared_ptr<CbmTofUnpackMonitor> GetTofMonitor(std::string treefilename, bool bBmonMode = false)
+{
+  // -----   Output filename and path   -------------------------------------
+  std::string outpath  = "";
+  std::string filename = "";
+  auto filenamepos     = treefilename.find_last_of("/");
+  if (filenamepos != treefilename.npos) {
+    outpath  = treefilename.substr(0, filenamepos);
+    filename = treefilename.substr(filenamepos++);
+  }
+  if (outpath.empty()) outpath = gSystem->GetWorkingDirectory();
+  //std::string mydir = "/qa";
+  //outpath += mydir;
+
+  auto currentdir = gSystem->GetWorkingDirectory();
+
+  if (!gSystem->cd(outpath.data())) gSystem->MakeDirectory(outpath.data());
+  else
+    gSystem->cd(currentdir.data());
+
+  std::string sSystemType = ".mon.tof.root";
+  if (bBmonMode) {
+    //
+    sSystemType = ".mon.bmon.root";
+  }
+
+  std::string outfilename = outpath + filename;
+  auto filetypepos        = outfilename.find(".digi.root");
+  if (filetypepos != outfilename.npos) outfilename.replace(filetypepos, 10, sSystemType);
+  else
+    outfilename += sSystemType;
+  // ------------------------------------------------------------------------
+
+  auto monitor = std::make_shared<CbmTofUnpackMonitor>();
+  monitor->SetHistoFileName(outfilename);
+  monitor->SetBmonMode(bBmonMode);
+  return monitor;
+}
+
+void run_unpack_online_bmon(std::string publisher = "tcp://localhost:5556", Int_t serverHttpPort = 8080,
+                            Int_t serverRefreshRate = 100, std::int32_t nevents = -1, UInt_t runid = 1905,
+                            const char* setupName = defaultSetupName, std::string outpath = "data/")
+{
+  std::vector<std::string> vPublisher = {publisher};
+  return run_unpack_online_bmon(vPublisher, serverHttpPort, serverRefreshRate, nevents, runid, setupName, outpath);
+}
diff --git a/macro/run/run_unpack_tsa.C b/macro/run/run_unpack_tsa.C
index 5fce45051b..30f4f8d9fc 100644
--- a/macro/run/run_unpack_tsa.C
+++ b/macro/run/run_unpack_tsa.C
@@ -32,6 +32,7 @@ std::shared_ptr<CbmTrdUnpackMonitor> GetTrdMonitor(std::string treefilename, boo
 std::shared_ptr<CbmTrdSpadic> GetTrdSpadic(bool useAvgBaseline = false);
 std::shared_ptr<CbmStsUnpackMonitor> GetStsMonitor(std::string treefilename, bool bDebugMode = false);
 std::shared_ptr<CbmRichUnpackMonitor> GetRichMonitor(std::string treefilename, bool bDebugMode = false);
+std::shared_ptr<CbmTofUnpackMonitor> GetTofMonitor(std::string treefilename, bool bBmonMode = false);
 const char* defaultSetupName = "mcbm_beam_2021_07_surveyed";
 
 void run_unpack_tsa(std::vector<std::string> infile = {"test.tsa"}, UInt_t runid = 0,
@@ -248,16 +249,35 @@ void run_unpack_tsa(std::vector<std::string> infile = {"test.tsa"}, UInt_t runid
     tofconfig->SetDoWriteOutput();
     // tofconfig->SetDoWriteOptOutA("CbmTofErrors");
     std::string parfilesbasepathTof = Form("%s/macro/beamtime/mcbm2021/", srcDir.Data());
-    if (2060 <= runid ) {
+    if (2060 <= runid) {
       /// Additional modules added just before the 10/03/2022 Carbon run
       parfilesbasepathTof = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data());
     }
     tofconfig->SetParFilesBasePath(parfilesbasepathTof);
     tofconfig->SetSystemTimeOffset(-1220);  // [ns] value to be updated
-    if (runid <= 1659) {
+    if (runid <= 1659 && runid < 2060) {
       /// Switch ON the -4 offset in epoch count (hack for Spring-Summer 2021)
       tofconfig->SetFlagEpochCountHack2021();
     }
+    /// Enable Monitor plots
+    // tofconfig->SetMonitor(GetTofMonitor(outfilename, false));
+  }
+  // -------------
+
+  // ---- BMON ----
+  std::shared_ptr<CbmBmonUnpackConfig> bmonconfig = nullptr;
+
+  bmonconfig = std::make_shared<CbmBmonUnpackConfig>("", runid);
+  if (bmonconfig) {
+    // bmonconfig->SetDebugState();
+    bmonconfig->SetDoWriteOutput();
+    // bmonconfig->SetDoWriteOptOutA("CbmBmonErrors");
+    std::string parfilesbasepathBmon = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data());
+    bmonconfig->SetParFilesBasePath(parfilesbasepathBmon);
+    bmonconfig->SetParFileName("mBmonCriPar.par");
+    bmonconfig->SetSystemTimeOffset(-1220);  // [ns] value to be updated
+    /// Enable Monitor plots
+    // bmonconfig->SetMonitor(GetTofMonitor(outfilename, true));
   }
   // -------------
 
@@ -286,8 +306,10 @@ void run_unpack_tsa(std::vector<std::string> infile = {"test.tsa"}, UInt_t runid
   if (trd1Dconfig) unpack->SetUnpackConfig(trd1Dconfig);
   if (trdfasp2dconfig) unpack->SetUnpackConfig(trdfasp2dconfig);
   if (tofconfig) unpack->SetUnpackConfig(tofconfig);
+  if (bmonconfig) unpack->SetUnpackConfig(bmonconfig);
   // ------------------------------------------------------------------------
 
+
   // -----   FairRunAna   ---------------------------------------------------
   auto run  = new FairRunOnline(source);
   auto sink = new FairRootFileSink(outfilename.data());
@@ -333,7 +355,7 @@ void run_unpack_tsa(std::vector<std::string> infile = {"test.tsa"}, UInt_t runid
  * @brief Get the Trd Monitor. Extra function to keep default macro part more silent.
  * @return std::shared_ptr<CbmTrdUnpackMonitor>
 */
-std::shared_ptr<CbmTrdUnpackMonitor> GetTrdMonitor(std::string treefilename, bool fasp)
+std::shared_ptr<CbmTrdUnpackMonitor> GetTrdMonitor(std::string treefilename, bool fasp = false)
 {
   // -----   Output filename and path   -------------------------------------
   std::string outpath  = "";
@@ -389,7 +411,6 @@ std::shared_ptr<CbmTrdUnpackMonitor> GetTrdMonitor(std::string treefilename, boo
     monitor->SetActiveHistos(digihistovec);
     monitor->SetWriteToFile(outfilename.data());
   }
-
   return monitor;
 }
 
@@ -480,6 +501,49 @@ std::shared_ptr<CbmRichUnpackMonitor> GetRichMonitor(std::string treefilename, b
   return monitor;
 }
 
+/**
+ * @brief Get the Tof Monitor. Extra function to keep default macro part more silent.
+ * @return std::shared_ptr<CbmTofUnpackMonitor>
+*/
+std::shared_ptr<CbmTofUnpackMonitor> GetTofMonitor(std::string treefilename, bool bBmonMode = false)
+{
+  // -----   Output filename and path   -------------------------------------
+  std::string outpath  = "";
+  std::string filename = "";
+  auto filenamepos     = treefilename.find_last_of("/");
+  if (filenamepos != treefilename.npos) {
+    outpath  = treefilename.substr(0, filenamepos);
+    filename = treefilename.substr(filenamepos++);
+  }
+  if (outpath.empty()) outpath = gSystem->GetWorkingDirectory();
+  //std::string mydir = "/qa";
+  //outpath += mydir;
+
+  auto currentdir = gSystem->GetWorkingDirectory();
+
+  if (!gSystem->cd(outpath.data())) gSystem->MakeDirectory(outpath.data());
+  else
+    gSystem->cd(currentdir.data());
+
+  std::string sSystemType = ".mon.tof.root";
+  if (bBmonMode) {
+    //
+    sSystemType = ".mon.bmon.root";
+  }
+
+  std::string outfilename = outpath + filename;
+  auto filetypepos        = outfilename.find(".digi.root");
+  if (filetypepos != outfilename.npos) outfilename.replace(filetypepos, 10, sSystemType);
+  else
+    outfilename += sSystemType;
+  // ------------------------------------------------------------------------
+
+  auto monitor = std::make_shared<CbmTofUnpackMonitor>();
+  monitor->SetHistoFileName(outfilename);
+  monitor->SetBmonMode(bBmonMode);
+  return monitor;
+}
+
 void run_unpack_tsa(std::string infile = "test.tsa", UInt_t runid = 0, const char* setupName = defaultSetupName,
                     std::int32_t nevents = -1, std::string outpath = "data/")
 {
diff --git a/macro/run/run_unpack_tsa_bmon.C b/macro/run/run_unpack_tsa_bmon.C
new file mode 100644
index 0000000000..57c4ecd3b7
--- /dev/null
+++ b/macro/run/run_unpack_tsa_bmon.C
@@ -0,0 +1,215 @@
+/* Copyright (C) 2022 Facility for Antiproton and Ion Research in Europe, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Pierre-Alain Loizeau [committer]  */
+
+/** @file run_unpack_tsa.C
+ ** @author Volker Friese <v.friese@gsi.de>
+ ** @since May 2021
+ **/
+
+
+// --- Includes needed for IDE
+#include <RtypesCore.h>
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+#if !defined(__CLING__)
+#include <FairLogger.h>
+#include <FairRootFileSink.h>
+#include <FairRunOnline.h>
+#include <Logger.h>
+
+#include <TStopwatch.h>
+#include <TSystem.h>
+#endif
+
+std::shared_ptr<CbmTofUnpackMonitor> GetTofMonitor(std::string treefilename, bool bBmonMode = false);
+const char* defaultSetupName = "mcbm_beam_2022_03_09_carbon";
+
+void run_unpack_tsa_bmon(std::vector<std::string> infile = {"test.tsa"}, UInt_t runid = 0,
+                         const char* setupName = defaultSetupName, std::int32_t nevents = -1,
+                         std::string outpath = "data/")
+{
+
+  // ========================================================================
+  //          Adjust this part according to your requirements
+
+  // --- Logger settings ----------------------------------------------------
+  TString logLevel     = "INFO";
+  TString logVerbosity = "LOW";
+  // ------------------------------------------------------------------------
+
+  // -----   Environment   --------------------------------------------------
+  TString myName = "run_unpack_tsa";               // this macro's name for screen output
+  TString srcDir = gSystem->Getenv("VMCWORKDIR");  // top source directory
+  // ------------------------------------------------------------------------
+
+
+  // -----   Potentially hardcode the infile   ------------------------------
+
+  // std::string infile = srcDir + "/input/mcbm_run399_first20Ts.tsa";
+
+  // ------------------------------------------------------------------------
+
+
+  // -----   Output filename   ----------------------------------------------
+  std::string outfilename = infile[0];
+  auto filenamepos        = infile[0].find_last_of("/");
+  filenamepos++;
+  std::string filename = infile[0].substr(filenamepos);
+  if (filename.find("*") != infile[0].npos) filename = std::to_string(runid) + ".tsa";
+  if (filename.find(";") != infile[0].npos) filename = std::to_string(runid) + "_merged" + ".tsa";
+  if (outpath.empty()) { outpath = infile[0].substr(0, filenamepos); }
+  outfilename = outpath + filename;
+  outfilename.replace(outfilename.find(".tsa"), 4, ".digi.root");
+  std::cout << "-I- " << myName << ": Output file will be " << outfilename << std::endl;
+  // ------------------------------------------------------------------------
+
+
+  // -----   Performance profiling   ----------------------------------------
+  // Set to true if you want some minimal performance profiling output
+  bool doPerfProfiling = true;
+  // Define if you want a special path and name for the performance profiling output file
+  std::string perfProfFileName = outpath + filename;
+  perfProfFileName.replace(perfProfFileName.find(".tsa"), 4, ".perf.root");
+  // ------------------------------------------------------------------------
+
+
+  // -----   CbmSetup   -----------------------------------------------------
+  auto cbmsetup = CbmSetup::Instance();
+  cbmsetup->LoadSetup(setupName);
+  // ------------------------------------------------------------------------
+
+  // -----   UnpackerConfigs   ----------------------------------------------
+
+  // ---- BMON ----
+  std::shared_ptr<CbmBmonUnpackConfig> bmonconfig = nullptr;
+
+  bmonconfig = std::make_shared<CbmBmonUnpackConfig>("", runid);
+  if (bmonconfig) {
+    // bmonconfig->SetDebugState();
+    bmonconfig->SetDoWriteOutput();
+    // bmonconfig->SetDoWriteOptOutA("CbmBmonErrors");
+    std::string parfilesbasepathBmon = Form("%s/macro/beamtime/mcbm2022/", srcDir.Data());
+    bmonconfig->SetParFilesBasePath(parfilesbasepathBmon);
+    bmonconfig->SetParFileName("mBmonCriPar.par");
+    bmonconfig->SetSystemTimeOffset(-1220);  // [ns] value to be updated
+    /// Enable Monitor plots
+    bmonconfig->SetMonitor(GetTofMonitor(outfilename, true));
+  }
+  // -------------
+
+
+  // ------------------------------------------------------------------------
+
+  // In general, the following parts need not be touched
+  // ========================================================================
+
+  // -----   Timer   --------------------------------------------------------
+  TStopwatch timer;
+  timer.Start();
+  // ------------------------------------------------------------------------
+
+  // -----   CbmSourceTsArchive   -------------------------------------------
+  auto source = new CbmSourceTsArchive(infile);
+  auto unpack = source->GetRecoUnpack();
+  unpack->SetDoPerfProfiling(doPerfProfiling);
+  unpack->SetOutputFilename(perfProfFileName);
+  // Enable full time sorting instead sorting per FLIM link
+  unpack->SetTimeSorting(true);
+
+  if (bmonconfig) unpack->SetUnpackConfig(bmonconfig);
+  // ------------------------------------------------------------------------
+
+  // -----   FairRunAna   ---------------------------------------------------
+  auto run  = new FairRunOnline(source);
+  auto sink = new FairRootFileSink(outfilename.data());
+  run->SetSink(sink);
+  auto eventheader = new CbmTsEventHeader();
+  run->SetRunId(runid);
+  run->SetEventHeader(eventheader);
+  // ------------------------------------------------------------------------
+
+
+  // -----   Logger settings   ----------------------------------------------
+  FairLogger::GetLogger()->SetLogScreenLevel(logLevel.Data());
+  FairLogger::GetLogger()->SetLogVerbosityLevel(logVerbosity.Data());
+  // ------------------------------------------------------------------------
+
+
+  // -----   Run initialisation   -------------------------------------------
+  std::cout << std::endl;
+  std::cout << "-I- " << myName << ": Initialise run" << std::endl;
+  run->Init();
+  // ------------------------------------------------------------------------
+
+
+  // -----   Start run   ----------------------------------------------------
+  std::cout << std::endl << std::endl;
+  std::cout << "-I- " << myName << ": Starting run" << std::endl;
+  if (nevents < 0) run->Run(-1, 0);
+  else
+    run->Run(0, nevents);
+  // ------------------------------------------------------------------------
+
+
+  // -----   Finish   -------------------------------------------------------
+  timer.Stop();
+  std::cout << "Macro finished successfully." << std::endl;
+  std::cout << "After CpuTime = " << timer.CpuTime() << " s RealTime = " << timer.RealTime() << " s." << std::endl;
+  // ------------------------------------------------------------------------
+
+}  // End of main macro function
+
+
+/**
+ * @brief Get the Tof Monitor. Extra function to keep default macro part more silent.
+ * @return std::shared_ptr<CbmTofUnpackMonitor>
+*/
+std::shared_ptr<CbmTofUnpackMonitor> GetTofMonitor(std::string treefilename, bool bBmonMode = false)
+{
+  // -----   Output filename and path   -------------------------------------
+  std::string outpath  = "";
+  std::string filename = "";
+  auto filenamepos     = treefilename.find_last_of("/");
+  if (filenamepos != treefilename.npos) {
+    outpath  = treefilename.substr(0, filenamepos);
+    filename = treefilename.substr(filenamepos++);
+  }
+  if (outpath.empty()) outpath = gSystem->GetWorkingDirectory();
+  //std::string mydir = "/qa";
+  //outpath += mydir;
+
+  auto currentdir = gSystem->GetWorkingDirectory();
+
+  if (!gSystem->cd(outpath.data())) gSystem->MakeDirectory(outpath.data());
+  else
+    gSystem->cd(currentdir.data());
+
+  std::string sSystemType = ".mon.tof.root";
+  if (bBmonMode) {
+    //
+    sSystemType = ".mon.bmon.root";
+  }
+
+  std::string outfilename = outpath + filename;
+  auto filetypepos        = outfilename.find(".digi.root");
+  if (filetypepos != outfilename.npos) outfilename.replace(filetypepos, 10, sSystemType);
+  else
+    outfilename += sSystemType;
+  // ------------------------------------------------------------------------
+
+  auto monitor = std::make_shared<CbmTofUnpackMonitor>();
+  monitor->SetHistoFileName(outfilename);
+  monitor->SetBmonMode(bBmonMode);
+  return monitor;
+}
+
+void run_unpack_tsa_bmon(std::string infile = "test.tsa", UInt_t runid = 0, const char* setupName = defaultSetupName,
+                         std::int32_t nevents = -1, std::string outpath = "data/")
+{
+  std::vector<std::string> vInFile = {infile};
+  return run_unpack_tsa_bmon(vInFile, runid, setupName, nevents, outpath);
+}
diff --git a/reco/detectors/tof/CMakeLists.txt b/reco/detectors/tof/CMakeLists.txt
index 1f0b6ab60f..0d5d628b84 100644
--- a/reco/detectors/tof/CMakeLists.txt
+++ b/reco/detectors/tof/CMakeLists.txt
@@ -16,6 +16,7 @@ set(INCLUDE_DIRECTORIES
   ${CBMROOT_SOURCE_DIR}/reco/base
 
   ${CBMROOT_SOURCE_DIR}/core/eventdisplay
+  ${CBMROOT_SOURCE_DIR}/core/qa
 
   ${CBMROOT_SOURCE_DIR}/fles/flestools # for Timeslice/Microslice printout formatting tools
 )
@@ -53,6 +54,8 @@ set(SRCS
 
   unpack/CbmTofUnpackAlgo.cxx
   unpack/CbmTofUnpackConfig.cxx
+  unpack/CbmBmonUnpackConfig.cxx
+  unpack/CbmTofUnpackMonitor.cxx
 )
 
 set(LINKDEF CbmTofRecoLinkDef.h)
diff --git a/reco/detectors/tof/CbmTofRecoLinkDef.h b/reco/detectors/tof/CbmTofRecoLinkDef.h
index d96636bbec..40db96c5dc 100644
--- a/reco/detectors/tof/CbmTofRecoLinkDef.h
+++ b/reco/detectors/tof/CbmTofRecoLinkDef.h
@@ -1,6 +1,6 @@
 /* Copyright (C) 2020-2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
    SPDX-License-Identifier: GPL-3.0-only
-   Authors: Florian Uhlig [committer] */
+   Authors: Pierre-Alain Loizeau, Florian Uhlig [committer] */
 
 #ifdef __CINT__
 
@@ -23,5 +23,7 @@
 
 #pragma link C++ class CbmTofUnpackAlgo + ;
 #pragma link C++ class CbmTofUnpackConfig + ;
+#pragma link C++ class CbmBmonUnpackConfig + ;
+#pragma link C++ class CbmTofUnpackMonitor + ;
 
 #endif
diff --git a/reco/detectors/tof/unpack/CbmBmonUnpackConfig.cxx b/reco/detectors/tof/unpack/CbmBmonUnpackConfig.cxx
new file mode 100644
index 0000000000..7bd185d252
--- /dev/null
+++ b/reco/detectors/tof/unpack/CbmBmonUnpackConfig.cxx
@@ -0,0 +1,50 @@
+/* Copyright (C) 2022 Facility for Antiproton and Ion Research in Europe, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Pierre-Alain Loizeau [committer]  */
+
+#include "CbmBmonUnpackConfig.h"
+
+#include "CbmTofUnpackAlgo.h"
+
+#include <Logger.h>
+
+#include <Rtypes.h>
+#include <RtypesCore.h>
+
+#include <memory>
+#include <vector>
+
+CbmBmonUnpackConfig::CbmBmonUnpackConfig(std::string detGeoSetupTag, UInt_t runid)
+  : CbmTofUnpackConfig(detGeoSetupTag, runid)
+{
+}
+
+CbmBmonUnpackConfig::~CbmBmonUnpackConfig() {}
+
+
+/**
+ * @brief Register the output vectors (if needed) to the FairRoot Manager)
+ * FIXME: To be removed with the Manager include whenever the similar code in the CbmRecoUnpack task work as expected
+ *
+*/
+void CbmBmonUnpackConfig::RegisterOutput(FairRootManager* ioman)
+{
+  if (fDoWriteOutput && fOutputVec) {
+    /// Instance of TOF unpacker used for Bmon unpacking
+    ioman->RegisterAny("T0Digi", fOutputVec, kTRUE);
+    LOG(info) << fName << "::registerBranchToTree(CbmBmonDigi)";
+  }
+
+  /** @todo for the optional outputs it is more complicated to check if they exist. Needs exceptions for the std::nullptr_t. Should be added at some point in time. */
+  if (fDoWriteOptOutA && fOptOutAVec) {
+    ioman->RegisterAny(fOptoutABranchName.data(), fOptOutAVec, kTRUE);
+    LOG(info) << fName << "::registerBranchToTree(" << fOptoutABranchName.data() << ")";
+  }
+
+  if (fDoWriteOptOutB && fOptOutBVec) {
+    ioman->RegisterAny(fOptoutBBranchName.data(), fOptOutBVec, kTRUE);
+    LOG(info) << fName << "::registerBranchToTree(" << fOptoutBBranchName.data() << ")";
+  }
+}
+
+ClassImp(CbmBmonUnpackConfig)
diff --git a/reco/detectors/tof/unpack/CbmBmonUnpackConfig.h b/reco/detectors/tof/unpack/CbmBmonUnpackConfig.h
new file mode 100644
index 0000000000..5d1f2ff028
--- /dev/null
+++ b/reco/detectors/tof/unpack/CbmBmonUnpackConfig.h
@@ -0,0 +1,78 @@
+/* Copyright (C) 2022 Facility for Antiproton and Ion Research in Europe, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Pierre-Alain Loizeau [committer]  */
+
+/**
+ * @file CbmBmonUnpackConfig.h
+ * @author Pascal Raisig (praisig@ikf.uni-frankfurt.de)
+ * @brief Configuration class for an unpacker algorithm
+ * @version 0.1
+ * @date 2021-04-21
+ *
+ * @copyright Copyright (c) 2021
+ *
+ * This is the common configuration class for unpacking algorithms
+ *
+*/
+
+#ifndef CbmBmonUnpackConfig_H
+#define CbmBmonUnpackConfig_H
+
+#include "CbmErrorMessage.h"
+#include "CbmTofDigi.h"
+#include "CbmTofUnpackAlgo.h"
+#include "CbmTofUnpackConfig.h"
+
+#include <FairLogger.h>
+#include <Logger.h>
+
+#include <Rtypes.h>
+#include <RtypesCore.h>
+
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+class CbmBmonUnpackConfig : public CbmTofUnpackConfig {
+
+public:
+  /**
+   * @brief Create the Cbm Tof Unpack Task object
+   *
+   * @param geoSetupTag Geometry setup tag for the given detector as used by CbmSetup objects
+   * @param runid set if unpacker is rerun on a special run with special parameters
+   *@remark We use the string instead of CbmSetup here, to not having to link against sim/steer...
+  */
+  CbmBmonUnpackConfig(std::string detGeoSetupTag, UInt_t runid = 0);
+
+  /**
+   * @brief Destroy the Cbm Tof Unpack Task object
+   *
+  */
+  virtual ~CbmBmonUnpackConfig();
+
+  /** @brief Copy constructor - not implemented **/
+  CbmBmonUnpackConfig(const CbmBmonUnpackConfig&) = delete;
+
+  /** @brief Assignment operator - not implemented **/
+  CbmBmonUnpackConfig& operator=(const CbmBmonUnpackConfig&) = delete;
+
+  // Getters
+
+  /**
+   * @brief Register the output vectors (if needed) to the FairRoot Manager)
+   * FIXME: To be removed when the T0/BMON will have its own Digi class properly exposing the right container name
+   *
+  */
+  void RegisterOutput(FairRootManager* ioman);
+
+
+  // Setters
+
+protected:
+private:
+  ClassDef(CbmBmonUnpackConfig, 1)
+};
+
+#endif  // CbmBmonUnpackConfig_H
diff --git a/reco/detectors/tof/unpack/CbmTofUnpackAlgo.cxx b/reco/detectors/tof/unpack/CbmTofUnpackAlgo.cxx
index 9028346435..eb250a654f 100644
--- a/reco/detectors/tof/unpack/CbmTofUnpackAlgo.cxx
+++ b/reco/detectors/tof/unpack/CbmTofUnpackAlgo.cxx
@@ -1,6 +1,6 @@
 /* Copyright (C) 2021 Goethe-University Frankfurt, Frankfurt
    SPDX-License-Identifier: GPL-3.0-only
-   Authors: Pascal Raisig [committer] */
+   Authors: Pierre-Alain Loizeau, Pascal Raisig [committer] */
 
 #include "CbmTofUnpackAlgo.h"
 
@@ -30,7 +30,7 @@ std::vector<std::pair<std::string, std::shared_ptr<FairParGenericSet>>>*
   std::string temppath = "";
 
   // // Get parameter container
-  temppath = basepath + "mTofCriPar.par";
+  temppath = basepath + fParFileName;
   LOG(info) << fName << "::GetParContainerRequest - Trying to open file " << temppath;
   fParContVec.emplace_back(std::make_pair(temppath, std::make_shared<CbmMcbm2018TofPar>()));
 
@@ -93,17 +93,6 @@ Bool_t CbmTofUnpackAlgo::initParSet(CbmMcbm2018TofPar* parset)
   fuNrOfGbtx = parset->GetNrOfGbtx();
   LOG(debug) << "Nr. of GBTx: " << fuNrOfGbtx;
 
-  fviRpcType.resize(fuNrOfGbtx);
-  fviModuleId.resize(fuNrOfGbtx);
-  fviNrOfRpc.resize(fuNrOfGbtx);
-  fviRpcSide.resize(fuNrOfGbtx);
-  for (UInt_t uGbtx = 0; uGbtx < fuNrOfGbtx; ++uGbtx) {
-    fviNrOfRpc[uGbtx]  = parset->GetNrOfRpc(uGbtx);
-    fviRpcType[uGbtx]  = parset->GetRpcType(uGbtx);
-    fviRpcSide[uGbtx]  = parset->GetRpcSide(uGbtx);
-    fviModuleId[uGbtx] = parset->GetModuleId(uGbtx);
-  }  // for( UInt_t uGbtx = 0; uGbtx < fuNrOfGbtx; ++uGbtx)
-
   UInt_t uNrOfChannels = fuNrOfGet4 * fuNrOfChannelsPerGet4;
   LOG(debug) << "Nr. of possible Tof channels: " << uNrOfChannels;
 
@@ -114,12 +103,24 @@ Bool_t CbmTofUnpackAlgo::initParSet(CbmMcbm2018TofPar* parset)
   for (UInt_t uCh = 0; uCh < uNrOfChannels; ++uCh) {
     if (0 == uCh % 8) sPrintout += "\n";
     if (0 == uCh % fuNrOfChannelsPerGdpb) sPrintout += Form("\n Gdpb %u\n", uCh / fuNrOfChannelsPerGdpb);
-    sPrintout += Form(" 0x%08x", fviRpcChUId[uCh]);
+    if (0 == fviRpcChUId[uCh]) {
+      /// Tricking clang to avoid one liner
+      sPrintout += " ----------";
+    }
+    else {
+      sPrintout += Form(" 0x%08x", fviRpcChUId[uCh]);
+    }
   }  // for( UInt_t i = 0; i < uNrOfChannels; ++i)
-  LOG(debug) << sPrintout;
+  LOG(info) << sPrintout;
 
   LOG(info) << fName << "::initParSetTofMcbm2018 - Successfully initialized TOF settings";
 
+  if (fMonitor) {
+    fMonitor->Init(parset);
+    LOG(info) << fName << "::initParSetTofMcbm2018 - Successfully initialized TOF monitor";
+  }
+
+
   return kTRUE;
 }
 
@@ -132,6 +133,7 @@ bool CbmTofUnpackAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp, UI
   fulCurrentTsIdx = ts->index();
   uint32_t uSize  = msDescriptor.size;
   fulCurrentMsIdx = msDescriptor.idx;
+  fdCurrentMsTime = (1e-9) * static_cast<double>(fulCurrentMsIdx);
   //   Double_t dMsTime = (1e-9) * static_cast<double>(fulCurrentMsIdx);
   LOG(debug) << "Microslice: " << fulCurrentMsIdx << " from EqId " << std::hex << fuCurrentEquipmentId << std::dec
              << " has size: " << uSize;
@@ -164,6 +166,13 @@ bool CbmTofUnpackAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp, UI
 
   fuCurrentMsSysId = static_cast<unsigned int>(msDescriptor.sys_id);
 
+  if (fMonitor) {
+    if (0x90 == fuCurrentMsSysId) {
+      /// Tricking clang to avoid one liner
+      fMonitor->CheckBmonSpillLimits(fdCurrentMsTime);
+    }
+  }
+
   // If not integer number of message in input buffer, print warning/error
   if (0 != (uSize % sizeof(critof001::Message)))
     LOG(error) << fName << "::unpack => "
@@ -252,10 +261,31 @@ bool CbmTofUnpackAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp, UI
         }  // if single chip epoch message
         break;
       }  // case critof001::MSG_EPOCH:
-      case critof001::MSG_SLOWC:
+      case critof001::MSG_SLOWC: {
+        /// Ignored messages
+        /// TODO,FIXME: should be filled into fOptOutAVec as CbmErrorMessage
+        if (fMonitor) {
+          fMonitor->FillScmMonitoringHistos(fuCurrDpbIdx, fuGet4Id, pMess[uIdx].getGdpbSlcChan(),
+                                            pMess[uIdx].getGdpbSlcEdge(), pMess[uIdx].getGdpbSlcType());
+        }
+        break;
+      }  // case critof001::MSG_SLOWC:
       case critof001::MSG_SYST: {
         /// Ignored messages
         /// TODO,FIXME: should be filled into fOptOutAVec as CbmErrorMessage
+        if (fMonitor) {
+          fMonitor->FillSysMonitoringHistos(fuCurrDpbIdx, fuGet4Id, pMess[uIdx].getGdpbSysSubType());
+          if (critof001::SYS_GET4_ERROR == pMess[uIdx].getGdpbSysSubType()) {
+            fMonitor->FillErrMonitoringHistos(fuCurrDpbIdx, fuGet4Id, pMess[uIdx].getGdpbSysErrChanId(),
+                                              pMess[uIdx].getGdpbSysErrData());
+
+            if (90 == fuCurrentMsSysId) {
+              fMonitor->FillErrBmonMonitoringHistos(fdCurrentMsTime, fuCurrDpbIdx, fuGet4Id,
+                                                    critof001::GET4_V2X_ERR_LOST_EVT
+                                                      == pMess[uIdx].getGdpbSysErrData());
+            }  // if (90 == fuCurrentMsSysId)
+          }    // if (critof001::SYS_GET4_ERROR == pMess[uIdx].getGdpbSysSubType())
+        }      // if (fMonitor )
         break;
       }  // case critof001::MSG_ERROR
       default:
@@ -264,7 +294,11 @@ bool CbmTofUnpackAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp, UI
                    << " not included in Get4 unpacker.";
     }  // switch( mess.getMessageType() )
   }    // for (uint32_t uIdx = 0; uIdx < uNbMessages; uIdx ++)
-
+       /*
+  if (0x90 == fuCurrentMsSysId && 0xabf3 == fuCurrDpbId) {
+      LOG(fatal) << "Last T0, stop there";
+  }
+*/
   return true;
 }
 
@@ -275,18 +309,17 @@ void CbmTofUnpackAlgo::ExtractTsStartEpoch(const uint64_t& ulTsStart)
 
   /// FIXME: seems there is an offset of +4 Epoch between data and header
   ///        from dt to PSD, the epoch seem to be right => placed in wrong MS!
-  if (fulTsStartInEpoch < 4) { fulTsStartInEpoch = critof001::kulEpochCycleEp + fulTsStartInEpoch - 4; }
-  else {
-    fulTsStartInEpoch -= 4;
-  }
+  if (fbEpochCountHack2021) {
+    if (fulTsStartInEpoch < 4) { fulTsStartInEpoch = critof001::kulEpochCycleEp + fulTsStartInEpoch - 4; }
+    else {
+      fulTsStartInEpoch -= 4;
+    }
+  }  // if (fbEpochCountHack2021)
 }
 
 void CbmTofUnpackAlgo::ProcessEpoch(const critof001::Message& mess, uint32_t uMesgIdx)
 {
-  /// FIXME: seems there is an offset of +4 Epoch between data and header
-  ///        from dt to PSD, the epoch seem to be right => placed in wrong MS!
   ULong64_t ulEpochNr = mess.getGdpbEpEpochNb();
-  //ULong64_t ulEpochNr = (mess.getGdpbEpEpochNb() + 4) % critof001::kulEpochCycleEp;
 
   if (0 == uMesgIdx) {
     uint64_t ulMsStartInEpoch =
@@ -310,7 +343,7 @@ void CbmTofUnpackAlgo::ProcessEpoch(const critof001::Message& mess, uint32_t uMe
                 static_cast<unsigned long long int>(mess.getData()), fuProcEpochUntilError,
                 static_cast<size_t>(fulCurrentMsIdx / critof001::kuEpochInNs),
                 fulCurrentMsIdx / critof001::kuEpochInNs);
-      LOG(error) << fName << "::ProcessEpoch => Ignoring data until next valid epoch";
+      LOG(fatal) << fName << "::ProcessEpoch => Stopping there, system is not synchronized and send corrupt data";
 
       fbLastEpochGood       = false;
       ulEpochNr             = ulMsStartInEpoch;
@@ -323,9 +356,11 @@ void CbmTofUnpackAlgo::ProcessEpoch(const critof001::Message& mess, uint32_t uMe
   }    // if( 0 < uMesgIdx )
   else if (((fulCurrentEpoch + 1) % critof001::kulEpochCycleEp) != ulEpochNr) {
     // Cast required to silence a warning on macos (there a uint64_t is a llu)
-    LOG(error) << fName << "::ProcessEpoch => Error global epoch, "
-               << Form("last 0x%06llx, current 0x%06llx, diff %lld, raw 0x%016lx, NoErr %d", fulCurrentEpoch, ulEpochNr,
-                       ulEpochNr - fulCurrentEpoch, static_cast<size_t>(mess.getData()), fuProcEpochUntilError);
+    LOG(error) << fName << "::ProcessEpoch => Error global epoch, DPB 0x" << std::setw(4) << std::hex << fuCurrDpbId
+               << std::dec
+               << Form(" last 0x%06llx, current 0x%06llx, diff %lld, raw 0x%016lx, NoErr %d", fulCurrentEpoch,
+                       ulEpochNr, ulEpochNr - fulCurrentEpoch, static_cast<size_t>(mess.getData()),
+                       fuProcEpochUntilError);
     LOG(error) << fName << "::ProcessEpoch => Ignoring data until next valid epoch";
 
     ulEpochNr             = (fulCurrentEpoch + 1) % critof001::kulEpochCycleEp;
@@ -342,13 +377,19 @@ void CbmTofUnpackAlgo::ProcessEpoch(const critof001::Message& mess, uint32_t uMe
   else {
     fulEpochIndexInTs = ulEpochNr + critof001::kulEpochCycleEp - fulTsStartInEpoch;
   }
-  if (10e9 < critof001::kuEpochInNs * fulEpochIndexInTs)
+  if (10e9 < critof001::kuEpochInNs * fulEpochIndexInTs) {
     // Cast required to silence a warning on macos (there a uint64_t is a llu)
     LOG(debug) << fName << "::ProcessEpoch => "
                << Form("Raw Epoch: 0x%06llx, Epoch offset 0x%06llx, Epoch in Ts: 0x%07lx, time %f ns (%f * %lu)",
                        ulEpochNr, static_cast<long long unsigned int>(fulTsStartInEpoch),
                        static_cast<size_t>(fulEpochIndexInTs), critof001::kuEpochInNs * fulEpochIndexInTs,
                        critof001::kuEpochInNs, static_cast<size_t>(fulEpochIndexInTs));
+  }
+
+  if (fMonitor) {
+    fMonitor->FillEpochMonitoringHistos(fuCurrDpbIdx, fuGet4Id, mess.getGdpbEpSync(), mess.getGdpbEpDataLoss(),
+                                        mess.getGdpbEpEpochLoss(), mess.getGdpbEpMissmatch());
+  }
 }
 
 void CbmTofUnpackAlgo::ProcessHit(const critof001::Message& mess)
@@ -360,19 +401,40 @@ void CbmTofUnpackAlgo::ProcessHit(const critof001::Message& mess)
   UInt_t uChannelNrInFee = (fuGet4Id % fuNrOfGet4PerFee) * fuNrOfChannelsPerGet4 + uChannel;
   UInt_t uFeeNr          = (fuGet4Id / fuNrOfGet4PerFee);
   UInt_t uFeeNrInSys     = fuCurrDpbIdx * fuNrOfFeePerGdpb + uFeeNr;
-  // UInt_t uRemappedChannelNr = uFeeNr * fuNrOfChannelsPerFee + fUnpackPar->Get4ChanToPadiChan(uChannelNrInFee);
+  UInt_t uRemappedChannelNr = uFeeNr * fuNrOfChannelsPerFee + fUnpackPar->Get4ChanToPadiChan(uChannelNrInFee);
 
   UInt_t uRemappedChannelNrInSys = fuCurrDpbIdx * fuNrOfChannelsPerGdpb + uFeeNr * fuNrOfChannelsPerFee
                                    + fUnpackPar->Get4ChanToPadiChan(uChannelNrInFee);
   /// Diamond FEE have straight connection from Get4 to eLink and from PADI to GET4
   if (0x90 == fuCurrentMsSysId) {
-    // uRemappedChannelNr      = uChannelNr;
-    uRemappedChannelNrInSys = fuCurrDpbIdx * fUnpackPar->GetNrOfChannelsPerGdpb() + uChannelNr;
+    uRemappedChannelNr      = uChannelNr;
+    uRemappedChannelNrInSys = fuCurrDpbIdx * fuNrOfChannelsPerGdpb + uChannelNr;
   }  // if(0x90 == fuCurrentMsSysId)
 
   Double_t dHitTime = mess.getMsgFullTimeD(fulEpochIndexInTs);
   Double_t dHitTot  = uTot;  // in bins
 
+  if (fMonitor) {
+    fMonitor->FillHitMonitoringHistos(fdCurrentMsTime, fuCurrDpbIdx, fuGet4Id, uChannelNr, uRemappedChannelNr, uTot);
+    if (0x90 == fuCurrentMsSysId && 0 == uChannel) {
+      fMonitor->FillHitBmonMonitoringHistos(fdCurrentMsTime, fuCurrDpbIdx, fuGet4Id, uTot);
+    }
+  }
+
+  /// Diamond debug
+  if (0x90 == fuCurrentMsSysId) {
+    LOG(debug) << fName << "::unpack => "
+               << "T0 data item at " << std::setw(4) << uRemappedChannelNrInSys << ", from FLIM " << fuCurrDpbIdx
+               << ", Get4 " << std::setw(2) << fuGet4Id << ", Ch " << uChannel << ", ChNr " << std::setw(2)
+               << uChannelNr << ", ChNrIF " << std::setw(2) << uChannelNrInFee << ", FiS " << std::setw(2)
+               << uFeeNrInSys
+               << (fviRpcChUId.size() < uRemappedChannelNrInSys || 0 == fviRpcChUId[uRemappedChannelNrInSys]
+                     ? " ----------"
+                     : Form(" 0x%08x", fviRpcChUId[uRemappedChannelNrInSys]))
+               << " TOT " << std::setw(3) << uTot << " time " << dHitTime;
+    // return;
+  }  // if(0x90 == fuCurrentMsSysId)
+
   if (fviRpcChUId.size() < uRemappedChannelNrInSys) {
     LOG(fatal) << fName << "::unpack => "
                << "Invalid mapping index " << uRemappedChannelNrInSys << " VS " << fviRpcChUId.size() << ", from FLIM "
@@ -385,10 +447,10 @@ void CbmTofUnpackAlgo::ProcessHit(const critof001::Message& mess)
 
   if (0 == uChanUId) {
     if (0 < fuMapWarnToPrint--)
-      LOG(warning) << fName << "::unpack => "
-                   << "Unused data item at " << uRemappedChannelNrInSys << ", from FLIM " << fuCurrDpbIdx << ", Get4 "
-                   << fuGet4Id << ", Ch " << uChannel << ", ChNr " << uChannelNr << ", ChNrIF " << uChannelNrInFee
-                   << ", FiS " << uFeeNrInSys;
+      LOG(debug) << fName << "::unpack => "
+                 << "Unused data item at " << uRemappedChannelNrInSys << ", from FLIM " << fuCurrDpbIdx << ", Get4 "
+                 << fuGet4Id << ", Ch " << uChannel << ", ChNr " << uChannelNr << ", ChNrIF " << uChannelNrInFee
+                 << ", FiS " << uFeeNrInSys;
     return;  // Hit not mapped to digi
   }
 
@@ -398,9 +460,11 @@ void CbmTofUnpackAlgo::ProcessHit(const critof001::Message& mess)
     dHitTime -= fSystemTimeOffset;
   }
 
-  /// FIXME: seems there is an offset of +4 Epoch between data and header
-  ///        from dt to PSD, the epoch are probably the one off, not the MS time!
-  dHitTime -= 4.0 * critof001::kuEpochInNs;
+  if (fbEpochCountHack2021) {
+    /// FIXME: seems there is an offset of +4 Epoch between data and header
+    ///        from dt to PSD, the epoch are probably the one off, not the MS time!
+    dHitTime -= 4.0 * critof001::kuEpochInNs;
+  }
 
   LOG(debug) << Form("Insert 0x%08x digi with time ", uChanUId) << dHitTime << Form(", Tot %4.0f", dHitTot)
              << " at epoch " << fulEpochIndexInTs;
diff --git a/reco/detectors/tof/unpack/CbmTofUnpackAlgo.h b/reco/detectors/tof/unpack/CbmTofUnpackAlgo.h
index 4f30f574e7..5d67958d9f 100644
--- a/reco/detectors/tof/unpack/CbmTofUnpackAlgo.h
+++ b/reco/detectors/tof/unpack/CbmTofUnpackAlgo.h
@@ -1,6 +1,6 @@
 /* Copyright (C) 2021 Goethe-University Frankfurt, Frankfurt
    SPDX-License-Identifier: GPL-3.0-only
-   Authors: Pascal Raisig [committer] */
+   Authors: Pierre-Alain Loizeau, Pascal Raisig [committer] */
 
 /**
  * @file CbmTofUnpackAlgo.h
@@ -25,6 +25,7 @@
 #include "CbmMcbm2018TofPar.h"
 #include "CbmRecoUnpackAlgo.tmpl"
 #include "CbmTofDigi.h"
+#include "CbmTofUnpackMonitor.h"
 
 #include "Timeslice.hpp"  // timeslice
 
@@ -71,13 +72,26 @@ public:
   */
   void SetFlagEpochCountHack2021(bool bFlagin = true) { fbEpochCountHack2021 = bFlagin; }
 
+  /**
+   * @brief Sets the name of the parameter file to be used.
+   *
+   * @param[in] std:string, path should not be included as set in the Config class
+  */
+  void SetParFileName(std::string sNewName) { fParFileName = sNewName; }
+
+  /** @brief Set a predefined monitor @param monitor predefined unpacking monitor */
+  void SetMonitor(std::shared_ptr<CbmTofUnpackMonitor> monitor) { fMonitor = monitor; }
+
 protected:
   /** @brief Finish function for this algorithm base clase */
   void finish()
   {
     finishDerived();
     // Finish the monitor if we have one
-    // if (fMonitor) fMonitor->Finish();
+    if (fMonitor) {
+      std::cout << "Finish Monitor" << std::endl;
+      fMonitor->Finish();
+    }
   }
 
   /** @brief Function that allows special calls during Finish in the derived algos */
@@ -144,6 +158,7 @@ private:
 
 
   /// Settings from parameter file
+  std::string fParFileName      = "mTofCriPar.par";
   CbmMcbm2018TofPar* fUnpackPar = nullptr;  //! For static/inline mapping functions
 
   /// Readout chain dimensions and mapping
@@ -160,20 +175,17 @@ private:
   /// Detector Mapping
   UInt_t fuNrOfGbtx              = 0;
   UInt_t fuNrOfModules           = 0;
-  std::vector<Int_t> fviNrOfRpc  = {};
-  std::vector<Int_t> fviRpcType  = {};
-  std::vector<Int_t> fviRpcSide  = {};
-  std::vector<Int_t> fviModuleId = {};
   std::vector<Int_t> fviRpcChUId = {};
 
   /// Running indices
   UInt_t fuMapWarnToPrint     = 100;
-  ULong64_t fulCurrentTsIdx   = 0;  //! Idx of the current TS
-  ULong64_t fulCurrentMsIdx   = 0;  //! Idx of the current MS in TS (0 to fuTotalMsNb)
-  size_t fuCurrentMsSysId     = 0;  //! SysId of the current MS in TS (0 to fuTotalMsNb)
-  UInt_t fuCurrentEquipmentId = 0;  //! Current equipment ID, tells from which DPB the current MS is originating
-  UInt_t fuCurrDpbId          = 0;  //! Temp holder until Current equipment ID is properly filled in MS
-  UInt_t fuCurrDpbIdx         = 0;  //! Index of the DPB from which the MS currently unpacked is coming
+  ULong64_t fulCurrentTsIdx   = 0;    //! Idx of the current TS
+  ULong64_t fulCurrentMsIdx   = 0;    //! Idx of the current MS in TS (0 to fuTotalMsNb)
+  double fdCurrentMsTime      = 0.0;  //! Time of the current MS in s
+  size_t fuCurrentMsSysId     = 0;    //! SysId of the current MS in TS (0 to fuTotalMsNb)
+  UInt_t fuCurrentEquipmentId = 0;    //! Current equipment ID, tells from which DPB the current MS is originating
+  UInt_t fuCurrDpbId          = 0;    //! Temp holder until Current equipment ID is properly filled in MS
+  UInt_t fuCurrDpbIdx         = 0;    //! Index of the DPB from which the MS currently unpacked is coming
   UInt_t fuGet4Id =
     0;  //! running number (0 to fuNrOfGet4PerGdpb) of the Get4 chip of a unique GDPB for current message
   UInt_t fuGet4Nr = 0;  //! running number (0 to fuNrOfGet4) of the Get4 chip in the system for current message
@@ -190,6 +202,9 @@ private:
   uint64_t fulTsStartInEpoch     = 0;
   uint64_t fulEpochIndexInTs     = 0;
 
+  /** @brief Potential (online) monitor for the unpacking process */
+  std::shared_ptr<CbmTofUnpackMonitor> fMonitor = nullptr;
+
   ClassDef(CbmTofUnpackAlgo, 2)
 };
 
diff --git a/reco/detectors/tof/unpack/CbmTofUnpackConfig.cxx b/reco/detectors/tof/unpack/CbmTofUnpackConfig.cxx
index 92820a8e1e..a646cb8108 100644
--- a/reco/detectors/tof/unpack/CbmTofUnpackConfig.cxx
+++ b/reco/detectors/tof/unpack/CbmTofUnpackConfig.cxx
@@ -1,6 +1,6 @@
 /* Copyright (C) 2021 Goethe-University Frankfurt, Frankfurt
    SPDX-License-Identifier: GPL-3.0-only
-   Authors: Pascal Raisig [committer] */
+   Authors: Pierre-Alain Loizeau, Pascal Raisig [committer] */
 
 #include "CbmTofUnpackConfig.h"
 
@@ -26,6 +26,8 @@ void CbmTofUnpackConfig::InitAlgo()
 {
   fAlgo->SetFlagEpochCountHack2021(fbEpochCountHack2021);
 
+  if (fMonitor) { fAlgo->SetMonitor(fMonitor); }
+
   // Now we have all information required to initialise the algorithm
   fAlgo->Init();
 }
diff --git a/reco/detectors/tof/unpack/CbmTofUnpackConfig.h b/reco/detectors/tof/unpack/CbmTofUnpackConfig.h
index c99e16ae09..d6bb8313c9 100644
--- a/reco/detectors/tof/unpack/CbmTofUnpackConfig.h
+++ b/reco/detectors/tof/unpack/CbmTofUnpackConfig.h
@@ -1,6 +1,6 @@
 /* Copyright (C) 2021 Goethe-University Frankfurt, Frankfurt
    SPDX-License-Identifier: GPL-3.0-only
-   Authors: Pascal Raisig [committer] */
+   Authors: Pierre-Alain Loizeau, Pascal Raisig [committer] */
 
 /**
  * @file CbmTofUnpackConfig.h
@@ -22,6 +22,7 @@
 #include "CbmRecoUnpackConfig.tmpl"
 #include "CbmTofDigi.h"
 #include "CbmTofUnpackAlgo.h"
+#include "CbmTofUnpackMonitor.h"
 
 #include <FairLogger.h>
 #include <Logger.h>
@@ -75,6 +76,17 @@ public:
   */
   void SetFlagEpochCountHack2021(bool bFlagin = true) { fbEpochCountHack2021 = bFlagin; }
 
+  /**
+   * @brief Sets the name of the parameter file to be used.
+   *
+   * @param[in] std:string, path should not be included as set in the Config class
+  */
+  void SetParFileName(std::string sNewName) { fsParFileName = sNewName; }
+  void LoadParFileName() { fAlgo->SetParFileName(fsParFileName); }
+
+  /** @brief Add a monitor to the unpacker. @param value CbmStsUnpackMonitor */
+  void SetMonitor(std::shared_ptr<CbmTofUnpackMonitor> value) { fMonitor = value; }
+
 protected:
   /**
    * @brief Choose the derived unpacker algorithm to be used for the DAQ output to Digi translation. If algo was already set manually by the user this algorithm is used.
@@ -86,8 +98,13 @@ protected:
 private:
   /// Control flags
   bool fbEpochCountHack2021 = false;
+  /// Parameter file name
+  std::string fsParFileName = "mTofCriPar.par";
+
+  /** @brief pointer to the monitor object */
+  std::shared_ptr<CbmTofUnpackMonitor> fMonitor = nullptr;
 
-  ClassDef(CbmTofUnpackConfig, 2)
+  ClassDef(CbmTofUnpackConfig, 3)
 };
 
 #endif  // CbmTofUnpackConfig_H
diff --git a/reco/detectors/tof/unpack/CbmTofUnpackMonitor.cxx b/reco/detectors/tof/unpack/CbmTofUnpackMonitor.cxx
new file mode 100644
index 0000000000..a2879d9faa
--- /dev/null
+++ b/reco/detectors/tof/unpack/CbmTofUnpackMonitor.cxx
@@ -0,0 +1,1393 @@
+/* Copyright (C) 2022 Facility for Antiproton and Ion Research in Europe, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Pierre-Alain Loizeau [committer]  */
+
+#include "CbmTofUnpackMonitor.h"
+
+#include "CbmFlesHistosTools.h"
+
+#include "MicrosliceDescriptor.hpp"
+
+#include <FairRun.h>
+#include <FairRunOnline.h>
+#include <Logger.h>
+
+#include "TCanvas.h"
+#include <RtypesCore.h>
+#include <TFile.h>
+#include <TH1.h>
+#include <TH2.h>
+#include <THttpServer.h>
+#include <TPaveStats.h>
+#include <TProfile.h>
+
+#include <cstdint>
+#include <iomanip>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <cmath>
+
+#include "CriGet4Mess001.h"
+
+CbmTofUnpackMonitor::CbmTofUnpackMonitor(/* args */) : fvpAllHistoPointers()
+{
+  // Miscroslice component properties histos
+  for (UInt_t component = 0; component < kuMaxNbFlibLinks; component++) {
+    fvhMsSize[component]     = nullptr;
+    fvhMsSizeTime[component] = nullptr;
+  }
+}
+
+CbmTofUnpackMonitor::~CbmTofUnpackMonitor()
+{
+  for (auto iter = fvpAllHistoPointers.begin(); iter != fvpAllHistoPointers.end();) {
+    if (iter->first != nullptr) { delete iter->first; }
+    iter = fvpAllHistoPointers.erase(iter);
+  }
+  for (auto iter = fvpAllCanvasPointers.begin(); iter != fvpAllCanvasPointers.end();) {
+    if (iter->first != nullptr) { delete iter->first; }
+    iter = fvpAllCanvasPointers.erase(iter);
+  }
+}
+
+Bool_t CbmTofUnpackMonitor::CreateHistograms()
+{
+  /// Avoid name collision for the histos and canvases in Root memory
+  std::string sSystem = "tof";
+  if (fBmonMode) {
+    //
+    sSystem = "bmon";
+  }
+
+  // clang-format off
+  fhGet4MessType = new TH2I(Form("%sGet4MessType", sSystem.data()),
+                             "Nb of message for each type per GET4; GET4 chip # ; Type",
+                              fuNbOfGet4InSyst, 0., fuNbOfGet4InSyst,
+                              4, 0., 4.);
+  fhGet4MessType->GetYaxis()->SetBinLabel(1, "DATA 32b");
+  fhGet4MessType->GetYaxis()->SetBinLabel(2, "EPOCH");
+  fhGet4MessType->GetYaxis()->SetBinLabel(3, "S.C.M");
+  fhGet4MessType->GetYaxis()->SetBinLabel(4, "ERROR");
+  //   fhGet4MessType->GetYaxis()->SetBinLabel( 5, "DATA 24b");
+  //   fhGet4MessType->GetYaxis()->SetBinLabel( 6, "STAR Trigger");
+
+  fhGet4EpochFlags = new TH2I(Form("%sGet4EpochFlags", sSystem.data()),
+                              "Epoch flags per GET4; GET4 chip # ; Type",
+                              fuNbOfGet4InSyst, 0., fuNbOfGet4InSyst,
+                              4, 0., 4.);
+  fhGet4EpochFlags->GetYaxis()->SetBinLabel(1, "SYNC");
+  fhGet4EpochFlags->GetYaxis()->SetBinLabel(2, "Ep LOSS");
+  fhGet4EpochFlags->GetYaxis()->SetBinLabel(3, "Da LOSS");
+  fhGet4EpochFlags->GetYaxis()->SetBinLabel(4, "MISSMAT");
+
+  fhGet4ScmType = new TH2I(Form("%sGet4ScmType", sSystem.data()),
+                           "SC messages per GET4 channel; GET4 channel # ; SC type",
+                           fuNbOfGet4InSyst, 0., fuNbOfGet4InSyst,
+                           5, 0., 5.);
+  fhGet4ScmType->GetYaxis()->SetBinLabel(1, "Hit Scal");
+  fhGet4ScmType->GetYaxis()->SetBinLabel(2, "Deadtime");
+  fhGet4ScmType->GetYaxis()->SetBinLabel(3, "SPI");
+  fhGet4ScmType->GetYaxis()->SetBinLabel(4, "SEU Scal");
+  fhGet4ScmType->GetYaxis()->SetBinLabel(5, "START");
+
+  fhGet4SysMessType = new TH2I(Form("%sGet4SysMessType", sSystem.data()),
+                               "Nb of system message for each type per Get4; Get4; System Type",
+                               fuNbOfGet4InSyst, 0., fuNbOfGet4InSyst,
+                               1 + critof001::SYS_PATTERN, 0., 1 + critof001::SYS_PATTERN);
+  fhGet4SysMessType->GetYaxis()->SetBinLabel(1 + critof001::SYS_GET4_ERROR, "GET4 ERROR");
+  fhGet4SysMessType->GetYaxis()->SetBinLabel(1 + critof001::SYS_GDPB_UNKWN, "UNKW GET4 MSG");
+  fhGet4SysMessType->GetYaxis()->SetBinLabel(1 + critof001::SYS_GET4_SYNC_MISS, "SYS_GET4_SYNC_MISS");
+  fhGet4SysMessType->GetYaxis()->SetBinLabel(1 + critof001::SYS_PATTERN, "SYS_PATTERN");
+
+  fhGet4ErrorsType = new TH2I(Form("%sGet4ErrorsType", sSystem.data()),
+                              "Error messages per GET4 channel; GET4 channel # ; Error",
+                              fuNbOfGet4InSyst, 0., fuNbOfGet4InSyst,
+                              22, 0., 22.);
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(1, "0x00: Readout Init    ");
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(2, "0x01: Sync            ");
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(3, "0x02: Epoch count sync");
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(4, "0x03: Epoch           ");
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(5, "0x04: FIFO Write      ");
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(6, "0x05: Lost event      ");
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(7, "0x06: Channel state   ");
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(8, "0x07: Token Ring state");
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(9, "0x08: Token           ");
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(10, "0x09: Error Readout   ");
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(11, "0x0a: SPI             ");
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(12, "0x0b: DLL Lock error  ");  // <- From GET4 v1.2
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(13, "0x0c: DLL Reset invoc.");  // <- From GET4 v1.2
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(14, "0x11: Overwrite       ");
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(15, "0x12: ToT out of range");
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(16, "0x13: Event Discarded ");
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(17, "0x14: Add. Rising edge");  // <- From GET4 v1.3
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(18, "0x15: Unpaired Falling");  // <- From GET4 v1.3
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(19, "0x16: Sequence error  ");  // <- From GET4 v1.3
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(20, "0x7f: Unknown         ");
+  fhGet4ErrorsType->GetYaxis()->SetBinLabel(21, "Corrupt/unsuprtd error");
+
+  /// Add pointers to the vector with all histo for access by steering class
+  std::string sFolder = "Get4InSys";
+  AddHistoToVector(fhGet4MessType, sFolder);
+  AddHistoToVector(fhGet4EpochFlags, sFolder);
+  AddHistoToVector(fhGet4ScmType, sFolder);
+  AddHistoToVector(fhGet4SysMessType, sFolder);
+  AddHistoToVector(fhGet4ErrorsType, sFolder);
+
+  for (UInt_t uComp = 0; uComp < fuNbOfComps; ++uComp) {
+    UInt_t uCompIndex = uComp;
+
+    std::string sFolderComp     = Form("c%02u", uCompIndex);
+
+    /// ---> Per GET4 in Component
+    fvhCompGet4MessType.push_back(
+      new TH2I(Form("%sCompGet4MessType_c%02u", sSystem.data(), uComp),
+               Form("Nb of message for each type per GET4 in Comp %02u; GET4 chip # ; Type", uCompIndex),
+               fuNbOfGet4PerComp, 0., fuNbOfGet4PerComp,
+               4, 0., 4.));
+    fvhCompGet4MessType[uComp]->GetYaxis()->SetBinLabel(1, "DATA 32b");
+    fvhCompGet4MessType[uComp]->GetYaxis()->SetBinLabel(2, "EPOCH");
+    fvhCompGet4MessType[uComp]->GetYaxis()->SetBinLabel(3, "S.C. M");
+    fvhCompGet4MessType[uComp]->GetYaxis()->SetBinLabel(4, "ERROR");
+
+    fvhCompGet4ChScm.push_back(
+      new TH2I(Form("%sCompGet4ChanScm_c%02u", sSystem.data(), uComp),
+               Form("SC messages per GET4 channel in Comp %02u; GET4 channel # ; SC type", uCompIndex),
+               2 * fuNbOfChannelsPerComp, 0., fuNbOfChannelsPerComp,
+               5, 0., 5.));
+    fvhCompGet4ChScm[uComp]->GetYaxis()->SetBinLabel(1, "Hit Scal");
+    fvhCompGet4ChScm[uComp]->GetYaxis()->SetBinLabel(2, "Deadtime");
+    fvhCompGet4ChScm[uComp]->GetYaxis()->SetBinLabel(3, "SPI");
+    fvhCompGet4ChScm[uComp]->GetYaxis()->SetBinLabel(4, "SEU Scal");
+    fvhCompGet4ChScm[uComp]->GetYaxis()->SetBinLabel(5, "START");
+
+    fvhCompGet4ChErrors.push_back(
+      new TH2I(Form("%sCompGet4ChanErrors_c%02u", sSystem.data(), uComp),
+               Form("Error messages per GET4 channel in Comp %02u; GET4 channel # ; Error", uCompIndex),
+               fuNbOfChannelsPerComp, 0., fuNbOfChannelsPerComp,
+               22, 0., 22.));
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(1, "0x00: Readout Init    ");
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(2, "0x01: Sync            ");
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(3, "0x02: Epoch count sync");
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(4, "0x03: Epoch           ");
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(5, "0x04: FIFO Write      ");
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(6, "0x05: Lost event      ");
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(7, "0x06: Channel state   ");
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(8, "0x07: Token Ring state");
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(9, "0x08: Token           ");
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(10, "0x09: Error Readout   ");
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(11, "0x0a: SPI             ");
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(12, "0x0b: DLL Lock error  ");  // <- From GET4 v1.2
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(13, "0x0c: DLL Reset invoc.");  // <- From GET4 v1.2
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(14, "0x11: Overwrite       ");  // <- From GET4 v1.0 to 1.3
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(15, "0x12: ToT out of range");
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(16, "0x13: Event Discarded ");
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(17, "0x14: Add. Rising edge");  // <- From GET4 v1.3
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(18, "0x15: Unpaired Falling");  // <- From GET4 v1.3
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(19, "0x16: Sequence error  ");  // <- From GET4 v1.3
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(20, "0x17: Epoch Overflow  ");  // <- From GET4 v2.0
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(21, "0x7f: Unknown         ");
+    fvhCompGet4ChErrors[uComp]->GetYaxis()->SetBinLabel(22, "Corrupt/unsuprtd error");
+
+    /// ---> Per raw channel in Component
+
+    fvhCompRawChCount.push_back(new TH1I(Form("%sCompRawChCount_c%02u", sSystem.data(), uCompIndex),
+                                         Form("Channel counts comp. %02u raw; Channel; Hits",
+                                              uCompIndex),
+                                         fuNbOfChannelsPerComp, 0, fuNbOfChannelsPerComp));
+
+    fvhCompRawChRate.push_back(new TH2D(Form("%sCompRawChRate_c%02u", sSystem.data(), uCompIndex),
+                                        Form("Raw channel rate comp. %02u; Time in run [s]; Channel; "
+                                             "Rate [1/s]",
+                                             uCompIndex),
+                                        fuHistoryHistoSize, 0, fuHistoryHistoSize,
+                                        fuNbOfChannelsPerComp, 0, fuNbOfChannelsPerComp));
+
+    fvhCompRawChTot.push_back(new TH2I(Form("%sCompRawChTot_c%02u", sSystem.data(), uCompIndex),
+                                       Form("Raw TOT comp. %02u, raw channel; Channel; TOT [bin]", uCompIndex),
+                                       fuNbOfChannelsPerComp, 0, fuNbOfChannelsPerComp,
+                                       256, 0, 256));
+
+    /// ---> Per remapped (PADI) channel in Component
+    fvhCompRemapChCount.push_back(new TH1I(Form("%sCompRemapChCount_c%02u", sSystem.data(), uCompIndex),
+                                           Form("PADI Channel counts comp. %02u, remapped; PADI channel; Hits",
+                                                uCompIndex),
+                                           fuNbOfChannelsPerComp, 0, fuNbOfChannelsPerComp));
+
+    fvhCompRemapChRate.push_back(new TH2D(Form("%sCompRemapChRate_c%02u", sSystem.data(), uCompIndex),
+                                          Form("PADI channel rate comp. %02u, remapped; Time in run [s]; PADI channel; "
+                                               "Rate [1/s]",
+                                               uCompIndex),
+                                          fuHistoryHistoSize, 0, fuHistoryHistoSize,
+                                          fuNbOfChannelsPerComp, 0, fuNbOfChannelsPerComp));
+
+    fvhCompRemapChTot.push_back(new TH2I(Form("%sCompRemapChTot_c%02u", sSystem.data(), uCompIndex),
+                                         Form("Raw TOT comp. %02u, remapped; PADI channel; TOT [bin]", uCompIndex),
+                                         fuNbOfChannelsPerComp, 0, fuNbOfChannelsPerComp,
+                                         256, 0, 256));
+
+    // clang-format on
+
+    /// Add pointers to the vector with all histo for access by steering class
+    /// Per GET4 in gDPB
+    AddHistoToVector(fvhCompGet4MessType[uComp], sFolderComp);
+    AddHistoToVector(fvhCompGet4ChScm[uComp], sFolderComp);
+    AddHistoToVector(fvhCompGet4ChErrors[uComp], sFolderComp);
+    /// ---> Per raw channel in Component
+    AddHistoToVector(fvhCompRawChCount[uComp], sFolderComp);
+    AddHistoToVector(fvhCompRawChRate[uComp], sFolderComp);
+    AddHistoToVector(fvhCompRawChTot[uComp], sFolderComp);
+    /// ---> Per remapped (PADI) channel in Component
+    AddHistoToVector(fvhCompRemapChCount[uComp], sFolderComp);
+    AddHistoToVector(fvhCompRemapChRate[uComp], sFolderComp);
+    AddHistoToVector(fvhCompRemapChTot[uComp], sFolderComp);
+  }  // for( UInt_t uComp = 0; uComp < fuNbOfComps; ++uComp )
+
+  return kTRUE;
+}
+
+void CbmTofUnpackMonitor::DrawCanvases()
+{
+  /// Avoid name collision for the histos and canvases in Root memory
+  std::string sSystem = "tof";
+  if (fBmonMode) {
+    //
+    sSystem = "bmon";
+  }
+
+  /// General summary: Messages types per GET4 (index in system)
+  fcSummaryGet4s =
+    new TCanvas(Form("c%sSummaryGet4s", sSystem.data()), Form("GET4s message stats, %s", sSystem.data()));
+  fcSummaryGet4s->Divide(3, 2);
+
+  fcSummaryGet4s->cd(1);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogz();
+  fhGet4MessType->Draw("colz");
+
+  fcSummaryGet4s->cd(2);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogz();
+  fhGet4EpochFlags->Draw("colz");
+
+  fcSummaryGet4s->cd(3);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogz();
+  fhGet4ScmType->Draw("colz");
+
+  fcSummaryGet4s->cd(4);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogz();
+  fhGet4SysMessType->Draw("colz");
+
+  fcSummaryGet4s->cd(5);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogz();
+  fhGet4ErrorsType->Draw("colz");
+
+  std::string sFolder = "canvases";
+  AddCanvasToVector(fcSummaryGet4s, sFolder);
+  ///----------------------------------------------------------------------------------------------------------------///
+
+  for (UInt_t uComp = 0; uComp < fuNbOfComps; ++uComp) {
+
+    fvcSumComp.push_back(new TCanvas(Form("c%sSumComp%02u", sSystem.data(), uComp),
+                                     Form("Component %2u summary, %s", uComp, sSystem.data())));
+    fvcSumComp[uComp]->Divide(3, 3);
+
+    /// ---> Per GET4 in Component
+    fvcSumComp[uComp]->cd(1);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    gPad->SetLogz();
+    fvhCompGet4MessType[uComp]->Draw("colz");
+
+    fvcSumComp[uComp]->cd(2);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    gPad->SetLogz();
+    fvhCompGet4ChScm[uComp]->Draw("colz");
+
+    fvcSumComp[uComp]->cd(3);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    gPad->SetLogz();
+    fvhCompGet4ChErrors[uComp]->Draw("colz");
+
+    /// ---> Per raw channel in Component
+    fvcSumComp[uComp]->cd(4);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    gPad->SetLogz();
+    fvhCompRawChCount[uComp]->Draw("colz");
+
+    fvcSumComp[uComp]->cd(5);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    gPad->SetLogz();
+    fvhCompRawChRate[uComp]->Draw("colz");
+
+    fvcSumComp[uComp]->cd(6);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    gPad->SetLogz();
+    fvhCompRawChTot[uComp]->Draw("colz");
+
+    /// ---> Per remapped (PADI) channel in Component
+    fvcSumComp[uComp]->cd(7);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    gPad->SetLogz();
+    fvhCompRemapChCount[uComp]->Draw("colz");
+
+    fvcSumComp[uComp]->cd(8);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    gPad->SetLogz();
+    fvhCompRemapChRate[uComp]->Draw("colz");
+
+    fvcSumComp[uComp]->cd(9);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    gPad->SetLogz();
+    fvhCompRemapChTot[uComp]->Draw("colz");
+
+    AddCanvasToVector(fvcSumComp[uComp], sFolder);
+  }
+}
+
+Bool_t CbmTofUnpackMonitor::CreateMsComponentSizeHistos(UInt_t component)
+{
+  if (nullptr == fvhMsSize[component]) {
+    TString sMsSizeName  = Form("MsSize_c%02u", component);
+    TString sMsSizeTitle = Form("Size of MS for component %02u; Ms Size [bytes]", component);
+    fvhMsSize[component] = new TH1F(sMsSizeName.Data(), sMsSizeTitle.Data(), 30000, 0., 30000.);
+    fvhMsSize[component]->SetCanExtend(TH2::kAllAxes);
+    AddHistoToVector(fvhMsSize[component], "MsSzComp");
+  }
+  if (nullptr == fvhMsSizeTime[component]) {
+    TString sMsSizeName      = Form("MsSizeTime_c%02u", component);
+    TString sMsSizeTitle     = Form("Size of MS vs time for component %02u; Time[s] ; Ms Size [bytes]", component);
+    fvhMsSizeTime[component] = new TProfile(sMsSizeName.Data(), sMsSizeTitle.Data(), 15000, 0., 300.);
+    fvhMsSizeTime[component]->SetCanExtend(TH2::kAllAxes);
+    AddHistoToVector(fvhMsSizeTime[component], "MsSzComp");
+  }
+  return kTRUE;
+}
+
+Bool_t CbmTofUnpackMonitor::ResetMsComponentSizeHistos(UInt_t component)
+{
+  if (nullptr != fvhMsSize[component]) { fvhMsSize[component]->Reset(); }
+  if (nullptr != fvhMsSizeTime[component]) { fvhMsSizeTime[component]->Reset(); }
+  return kTRUE;
+}
+
+Bool_t CbmTofUnpackMonitor::ResetHistograms()
+{
+  fhGet4MessType->Reset();
+  fhGet4ScmType->Reset();
+  fhGet4ErrorsType->Reset();
+  fhGet4EpochFlags->Reset();
+  /// ---> Per GET4 in Component
+  for (UInt_t uComp = 0; uComp < fuNbOfComps; ++uComp) {
+    fvhCompGet4MessType[uComp]->Reset();
+    fvhCompGet4ChScm[uComp]->Reset();
+    fvhCompGet4ChErrors[uComp]->Reset();
+    /// ---> Per raw channel in Component
+    fvhCompRawChCount[uComp]->Reset();
+    fvhCompRawChRate[uComp]->Reset();
+    fvhCompRawChTot[uComp]->Reset();
+    /// ---> Per remapped (PADI) channel in Component
+    fvhCompRemapChCount[uComp]->Reset();
+    fvhCompRemapChRate[uComp]->Reset();
+    fvhCompRemapChTot[uComp]->Reset();
+  }
+
+  return kTRUE;
+}
+
+Bool_t CbmTofUnpackMonitor::CreateBmonHistograms()
+{
+  /// Logarithmic bining
+  uint32_t iNbBinsLog = 0;
+  /// Parameters are NbDecadesLog, NbStepsDecade, NbSubStepsInStep
+  std::vector<double> dBinsLogVector = GenerateLogBinArray(4, 9, 1, iNbBinsLog);
+  double* dBinsLog                   = dBinsLogVector.data();
+  //   double * dBinsLog = GenerateLogBinArray( 4, 9, 1, iNbBinsLog );
+
+  // clang-format off
+
+  fhBmonCompMapAll = new TH1I("hBmonCompMapAll", "Map of hits on Bmon detector; Comp.; Hits Count []",
+                             fuNbOfComps, -0.5, fuNbOfComps - 0.5);
+  fhBmonCompGet4 = new TH2I("hBmonCompGet4", "Map of hits on Bmon detector; Comp.; GET4; Counts []",
+                           fuNbOfComps*80, -0.5, fuNbOfComps*80 - 0.5,
+                           2*kuNbChanBmon, -0.5, 2*kuNbChanBmon - 0.5);
+  fhBmonGet4Map = new TH1I("hBmonGet4Map", "Map of hits on Bmon detector; GET4; Hits Count []",
+                          fuNbOfComps*80, -0.5, fuNbOfComps*80 - 0.5);
+  fhBmonGet4MapEvo     = new TH2I("hBmonGet4MapEvo",
+                                  "Map of hits on Bmon detector vs time in run; GET4; "
+                                  "Time in run [s]; Hits Count []",
+                                  fuHistoryHistoSize, 0, fuHistoryHistoSize,
+                                  fuNbOfComps*80, -0.5, fuNbOfComps*80 - 0.5);
+  fhBmonChannelMapAll    = new TH1I("hChannelMapAll", "Map of hits on Bmon detector; Strip; Hits Count []",
+                                    kuNbChanBmon, -0.5, kuNbChanBmon - 0.5);
+  fhBmonChannelTotAll    = new TH2I("hChannelTotAll", "Tot of hits on Bmon detector per channel; Strip; Tot; Hits Count []",
+                                    kuNbChanBmon, -0.5, kuNbChanBmon - 0.5, 256, -0.5, 255.5);
+  fhBmonHitMapEvoAll     = new TH2I("hBmonHitMapEvoAll",
+                                     "Map of hits on Bmon detector vs time in run; Chan; "
+                                     "Time in run [s]; Hits Count []",
+                                     kuNbChanBmon, -0.5, kuNbChanBmon - 0.5,
+                                     fuHistoryHistoSize, 0, fuHistoryHistoSize);
+  fhBmonHitTotEvoAll     = new TH2I("hBmonHitTotEvoAll",
+                                    "Evolution of TOT in Bmon detector vs time in run; Time "
+                                    "in run [s]; TOT [ bin ]; Hits Count []",
+                                    fuHistoryHistoSize, 0, fuHistoryHistoSize, 256, -0.5, 255.5);
+  fhBmonChanHitMapAll    = new TH1D("fhBmonChanHitMapAll", "Map of hits on Bmon detector; Strip; Hits Count []",
+                                    kuNbChanBmon, -0.5, kuNbChanBmon - 0.5);
+  fhBmonChanHitMapEvoAll = new TH2I("hBmonChanHitMapEvoAll",
+                                    "Map of hits on Bmon detector vs time in run; "
+                                    "Strip; Time in run [s]; Hits Count []",
+                                    kuNbChanBmon, 0., kuNbChanBmon, fuHistoryHistoSize, 0, fuHistoryHistoSize);
+
+
+  fhBmonCompMap = new TH1I("hBmonCompMap", "Map of hits on Bmon detector; Comp.; Hits Count []",
+                          fuNbOfComps, -0.5, fuNbOfComps - 0.5);
+  fhBmonChannelMap    = new TH1I("hChannelMap", "Map of hits on Bmon detector; Strip; Hits Count []",
+                                 kuNbChanBmon, -0.5, kuNbChanBmon - 0.5);
+  fhBmonHitMapEvo     = new TH2I("hBmonHitMapEvo",
+                         "Map of hits on Bmon detector vs time in run; Chan; "
+                         "Time in run [s]; Hits Count []",
+                         kuNbChanBmon, -0.5, kuNbChanBmon - 0.5, fuHistoryHistoSize, 0, fuHistoryHistoSize);
+  fhBmonHitTotEvo     = new TH2I("hBmonHitTotEvo",
+                         "Evolution of TOT in Bmon detector vs time in run; Time "
+                         "in run [s]; TOT [ bin ]; Hits Count []",
+                         fuHistoryHistoSize, 0, fuHistoryHistoSize, 256, -0.5, 255.5);
+  fhBmonChanHitMap    = new TH1D("fhBmonChanHitMap", "Map of hits on Bmon detector; Strip; Hits Count []",
+                                 kuNbChanBmon, -0.5, kuNbChanBmon - 0.5);
+  fhBmonChanHitMapEvo = new TH2I("hBmonChanHitMapEvo",
+                             "Map of hits on Bmon detector vs time in run; "
+                             "Strip; Time in run [s]; Hits Count []",
+                             kuNbChanBmon, 0., kuNbChanBmon, fuHistoryHistoSize, 0, fuHistoryHistoSize);
+  for (UInt_t uSpill = 0; uSpill < kuNbSpillPlots; uSpill++) {
+    fvhBmonCompMapSpill.push_back(
+      new TH1I(Form("hBmonCompMapSpill%02u", uSpill),
+               Form("Map of hits on Bmon detector in current spill %02u; Comp.; Hits Count []", uSpill),
+               fuNbOfComps, -0.5, fuNbOfComps - 0.5));
+    fvhBmonChannelMapSpill.push_back(new TH1I(Form("hBmonChannelMapSpill%02u", uSpill),
+                                          Form("Map of hits on Bmon detector in current spill %02u; Strip; "
+                                               "Hits Count []",
+                                               uSpill),
+                                          kuNbChanBmon, -0.5, kuNbChanBmon - 0.5));
+  }  // for( UInt_t uSpill = 0; uSpill < kuNbSpillPlots; uSpill ++)
+  fhBmonHitsPerSpill = new TH1I("hBmonHitsPerSpill", "Hit count per spill; Spill; Hits Count []", 2000, 0., 2000);
+
+  fhBmonMsgCntEvo   = new TH1I("hBmonMsgCntEvo",
+                         "Evolution of Hit & error msgs counts vs time in run; "
+                         "Time in run [s]; Msgs Count []",
+                         fuHistoryHistoSize, 0, fuHistoryHistoSize);
+  fhBmonHitCntEvo   = new TH1I("hBmonHitCntEvo",
+                               "Evolution of Hit counts vs time in run; Time in run [s]; Hits Count []",
+                               fuHistoryHistoSize, 0, fuHistoryHistoSize);
+  fhBmonErrorCntEvo = new TH1I("hBmonErrorCntEvo",
+                               "Evolution of Error counts vs time in run; Time in run [s]; Error Count []",
+                               fuHistoryHistoSize, 0, fuHistoryHistoSize);
+  fhBmonLostEvtCntEvo = new TH1I("hBmonLostEvtCntEvo",
+                             "Evolution of LostEvent counts vs time in run; "
+                             "Time in run [s]; LostEvent Count []",
+                             fuHistoryHistoSize, 0, fuHistoryHistoSize);
+
+  fhBmonErrorFractEvo   = new TProfile("hBmonErrorFractEvo",
+                                 "Evolution of Error Fraction vs time in run; "
+                                 "Time in run [s]; Error Fract []",
+                                 fuHistoryHistoSize, 0, fuHistoryHistoSize);
+  fhBmonLostEvtFractEvo = new TProfile("hBmonLostEvtFractEvo",
+                                   "Evolution of LostEvent Fraction vs time in "
+                                   "run; Time in run [s]; LostEvent Fract []",
+                                   fuHistoryHistoSize, 0, fuHistoryHistoSize);
+
+  fhBmonMsgCntPerMsEvo     = new TH2I("hBmonMsgCntPerMsEvo",
+                              "Evolution of Hit & error msgs counts, per MS vs time in run; "
+                              "Time in run [s]; Hits Count/MS []; MS",
+                              fuHistoryHistoSize, 0, fuHistoryHistoSize, iNbBinsLog, dBinsLog);
+  fhBmonHitCntPerMsEvo     = new TH2I("hBmonHitCntPerMsEvo",
+                              "Evolution of Hit counts, per MS vs time in run; "
+                              "Time in run [s]; Hits Count/MS []; MS",
+                              fuHistoryHistoSize, 0, fuHistoryHistoSize, iNbBinsLog, dBinsLog);
+  fhBmonErrorCntPerMsEvo   = new TH2I("hBmonErrorCntPerMsEvo",
+                                "Evolution of Error counts, per MS vs time in "
+                                "run; Time in run [s]; Error Count/MS []; MS",
+                                fuHistoryHistoSize, 0, fuHistoryHistoSize, iNbBinsLog, dBinsLog);
+  fhBmonLostEvtCntPerMsEvo = new TH2I("hBmonLostEvtCntPerMsEvo",
+                                  "Evolution of LostEvent, per MS counts vs time in run; Time in "
+                                  "run [s]; LostEvent Count/MS []; MS",
+                                  fuHistoryHistoSize, 0, fuHistoryHistoSize, iNbBinsLog, dBinsLog);
+
+  fhBmonErrorFractPerMsEvo   = new TH2I("hBmonErrorFractPerMsEvo",
+                                  "Evolution of Error Fraction, per MS vs time in run; Time in run "
+                                  "[s]; Error Fract/MS []; MS",
+                                  fuHistoryHistoSize, 0, fuHistoryHistoSize, 1000, 0, 1);
+  fhBmonLostEvtFractPerMsEvo = new TH2I("hBmonLostEvtFractPerMsEvo",
+                                    "Evolution of LostEvent Fraction, per MS vs time in run; Time in "
+                                    "run [s]; LostEvent Fract/MS []; MS",
+                                    fuHistoryHistoSize, 0, fuHistoryHistoSize, 1000, 0, 1);
+
+  fhBmonChannelMapPulser = new TH1I("fhBmonChannelMapPulser", "Map of pulser hits on Bmon detector; Chan; Hits Count []",
+                                kuNbChanBmon, 0., kuNbChanBmon);
+  fhBmonHitMapEvoPulser  = new TH2I("fhBmonHitMapEvoPulser",
+                               "Map of hits on Bmon detector vs time in run; "
+                               "Chan; Time in run [s]; Hits Count []",
+                               kuNbChanBmon, 0., kuNbChanBmon, fuHistoryHistoSize, 0, fuHistoryHistoSize);
+  // clang-format on
+
+  /// Add pointers to the vector with all histo for access by steering class
+  std::string sFolder = "All";
+  AddHistoToVector(fhBmonCompMapAll, sFolder);
+  AddHistoToVector(fhBmonCompGet4, sFolder);
+  AddHistoToVector(fhBmonGet4Map, sFolder);
+  AddHistoToVector(fhBmonGet4MapEvo, sFolder);
+  AddHistoToVector(fhBmonChannelMapAll, sFolder);
+  AddHistoToVector(fhBmonChannelTotAll, sFolder);
+  AddHistoToVector(fhBmonHitMapEvoAll, sFolder);
+  AddHistoToVector(fhBmonHitTotEvoAll, sFolder);
+  AddHistoToVector(fhBmonChanHitMapAll, sFolder);
+  AddHistoToVector(fhBmonChanHitMapEvoAll, sFolder);
+
+  sFolder = "NoPulser";
+  AddHistoToVector(fhBmonCompMap, sFolder);
+  AddHistoToVector(fhBmonChannelMap, sFolder);
+  AddHistoToVector(fhBmonHitMapEvo, sFolder);
+  AddHistoToVector(fhBmonHitTotEvo, sFolder);
+  AddHistoToVector(fhBmonChanHitMap, sFolder);
+  AddHistoToVector(fhBmonChanHitMapEvo, sFolder);
+  sFolder = "Spills";
+  for (UInt_t uSpill = 0; uSpill < kuNbSpillPlots; uSpill++) {
+    AddHistoToVector(fvhBmonCompMapSpill[uSpill], sFolder);
+    AddHistoToVector(fvhBmonChannelMapSpill[uSpill], sFolder);
+  }  // for( UInt_t uSpill = 0; uSpill < kuNbSpillPlots; uSpill ++)
+  AddHistoToVector(fhBmonHitsPerSpill, sFolder);
+
+  sFolder = "GlobRates";
+  AddHistoToVector(fhBmonMsgCntEvo, sFolder);
+  AddHistoToVector(fhBmonHitCntEvo, sFolder);
+  AddHistoToVector(fhBmonErrorCntEvo, sFolder);
+  AddHistoToVector(fhBmonLostEvtCntEvo, sFolder);
+
+  AddHistoToVector(fhBmonErrorFractEvo, sFolder);
+  AddHistoToVector(fhBmonLostEvtFractEvo, sFolder);
+
+  sFolder = "GlobRatesMs";
+  AddHistoToVector(fhBmonMsgCntPerMsEvo, sFolder);
+  AddHistoToVector(fhBmonHitCntPerMsEvo, sFolder);
+  AddHistoToVector(fhBmonErrorCntPerMsEvo, sFolder);
+  AddHistoToVector(fhBmonLostEvtCntPerMsEvo, sFolder);
+  AddHistoToVector(fhBmonErrorFractPerMsEvo, sFolder);
+  AddHistoToVector(fhBmonLostEvtFractPerMsEvo, sFolder);
+
+  sFolder = "Pulser";
+  AddHistoToVector(fhBmonChannelMapPulser, sFolder);
+  AddHistoToVector(fhBmonHitMapEvoPulser, sFolder);
+
+  /*******************************************************************/
+  sFolder = "RatePerChan";
+  for (UInt_t uChan = 0; uChan < kuNbChanBmon; ++uChan) {
+    // clang-format off
+    fvhBmonMsgCntEvoChan[uChan]      = new TH1I(Form("hBmonMsgCntEvoChan%02u", uChan),
+                                       Form("Evolution of Messages counts vs time in run for channel "
+                                            "%02u; Time in run [s]; Messages Count []",
+                                            uChan),
+                                       fuHistoryHistoSize, 0, fuHistoryHistoSize);
+    fvhBmonMsgCntPerMsEvoChan[uChan] = new TH2I(Form("hBmonMsgCntPerMsEvoChan%02u", uChan),
+                                            Form("Evolution of Hit counts per MS vs time in run for channel "
+                                                 "%02u; Time in run [s]; Hits Count/MS []; MS",
+                                                 uChan),
+                                            fuHistoryHistoSize, 0, fuHistoryHistoSize, iNbBinsLog, dBinsLog);
+
+    fvhBmonHitCntEvoChan[uChan]      = new TH1I(Form("hBmonHitCntEvoChan%02u", uChan),
+                                       Form("Evolution of Hit counts vs time in run for channel %02u; "
+                                            "Time in run [s]; Hits Count []",
+                                            uChan),
+                                       fuHistoryHistoSize, 0, fuHistoryHistoSize);
+    fvhBmonHitCntPerMsEvoChan[uChan] = new TH2I(Form("hBmonHitCntPerMsEvoChan%02u", uChan),
+                                            Form("Evolution of Hit counts per MS vs time in run for channel "
+                                                 "%02u; Time in run [s]; Hits Count/MS []; MS",
+                                                 uChan),
+                                            fuHistoryHistoSize, 0, fuHistoryHistoSize, iNbBinsLog, dBinsLog);
+
+    fvhBmonErrorCntEvoChan[uChan]      = new TH1I(Form("hBmonErrorCntEvoChan%02u", uChan),
+                                         Form("Evolution of Error counts vs time in run for channel "
+                                              "%02u; Time in run [s]; Error Count []",
+                                              uChan),
+                                         fuHistoryHistoSize, 0, fuHistoryHistoSize);
+    fvhBmonErrorCntPerMsEvoChan[uChan] = new TH2I(Form("hBmonErrorCntPerMsEvoChan%02u", uChan),
+                                              Form("Evolution of Error counts per MS vs time in run for "
+                                                   "channel %02u; Time in run [s]; Error Count/MS []; MS",
+                                                   uChan),
+                                              fuHistoryHistoSize, 0, fuHistoryHistoSize, iNbBinsLog, dBinsLog);
+
+    fvhBmonEvtLostCntEvoChan[uChan]      = new TH1I(Form("hBmonEvtLostCntEvoChan%02u", uChan),
+                                           Form("Evolution of LostEvent counts vs time in run for channel "
+                                                "%02u; Time in run [s]; LostEvent Count []",
+                                                uChan),
+                                           fuHistoryHistoSize, 0, fuHistoryHistoSize);
+    fvhBmonEvtLostCntPerMsEvoChan[uChan] = new TH2I(Form("hBmonEvtLostCntPerMsEvoChan%02u", uChan),
+                                                Form("Evolution of LostEvent counts per MS vs time in run for "
+                                                     "channel %02u; Time in run [s]; LostEvent Count/MS []; MS",
+                                                     uChan),
+                                                fuHistoryHistoSize, 0, fuHistoryHistoSize, iNbBinsLog, dBinsLog);
+
+    fvhBmonErrorFractEvoChan[uChan]      = new TProfile(Form("hBmonErrorFractEvoChan%02u", uChan),
+                                               Form("Evolution of Error Fraction vs time in run for "
+                                                    "channel %02u; Time in run [s]; Error Fract []",
+                                                    uChan),
+                                               fuHistoryHistoSize, 0, fuHistoryHistoSize);
+    fvhBmonErrorFractPerMsEvoChan[uChan] = new TH2I(Form("hBmonErrorFractPerMsEvoChan%02u", uChan),
+                                                Form("Evolution of Error Fraction, per MS vs time in run for "
+                                                     "channel %02u; Time in run [s]; Error Fract/MS []; MS",
+                                                     uChan),
+                                                fuHistoryHistoSize, 0, fuHistoryHistoSize, 1000, 0, 1);
+
+    fvhBmonEvtLostFractEvoChan[uChan] = new TProfile(Form("hBmonEvtLostFractEvoChan%02u", uChan),
+                                                 Form("Evolution of LostEvent Fraction vs time in run for "
+                                                      "channel %02u; Time in run [s]; LostEvent Fract []",
+                                                      uChan),
+                                                 fuHistoryHistoSize, 0, fuHistoryHistoSize);
+    fvhBmonEvtLostFractPerMsEvoChan[uChan] =
+      new TH2I(Form("hBmonEvtLostFractPerMsEvoChan%02u", uChan),
+               Form("Evolution of LostEvent Fraction, per MS vs time in run for channel "
+                    "%02u; Time in run [s]; LostEvent Fract/MS []; MS",
+                    uChan),
+               fuHistoryHistoSize, 0, fuHistoryHistoSize, 1000, 0, 1);
+    // clang-format on
+
+    /// Add pointers to the vector with all histo for access by steering class
+    AddHistoToVector(fvhBmonMsgCntEvoChan[uChan], sFolder);
+    AddHistoToVector(fvhBmonMsgCntPerMsEvoChan[uChan], sFolder);
+    AddHistoToVector(fvhBmonHitCntEvoChan[uChan], sFolder);
+    AddHistoToVector(fvhBmonHitCntPerMsEvoChan[uChan], sFolder);
+    AddHistoToVector(fvhBmonErrorCntEvoChan[uChan], sFolder);
+    AddHistoToVector(fvhBmonErrorCntPerMsEvoChan[uChan], sFolder);
+    AddHistoToVector(fvhBmonEvtLostCntEvoChan[uChan], sFolder);
+    AddHistoToVector(fvhBmonEvtLostCntPerMsEvoChan[uChan], sFolder);
+    AddHistoToVector(fvhBmonErrorFractEvoChan[uChan], sFolder);
+    AddHistoToVector(fvhBmonErrorFractPerMsEvoChan[uChan], sFolder);
+    AddHistoToVector(fvhBmonEvtLostFractEvoChan[uChan], sFolder);
+    AddHistoToVector(fvhBmonEvtLostFractPerMsEvoChan[uChan], sFolder);
+  }  // for( UInt_t uChan = 0; uChan < kuNbChanBmon; ++uChan )
+
+  return kTRUE;
+}
+
+Bool_t CbmTofUnpackMonitor::ResetBmonHistograms(Bool_t bResetTime)
+{
+  for (UInt_t uChan = 0; uChan < kuNbChanBmon; ++uChan) {
+    fvhBmonMsgCntEvoChan[uChan]->Reset();
+    fvhBmonMsgCntPerMsEvoChan[uChan]->Reset();
+
+    fvhBmonHitCntEvoChan[uChan]->Reset();
+    fvhBmonHitCntPerMsEvoChan[uChan]->Reset();
+
+    fvhBmonErrorCntEvoChan[uChan]->Reset();
+    fvhBmonErrorCntPerMsEvoChan[uChan]->Reset();
+
+    fvhBmonEvtLostCntEvoChan[uChan]->Reset();
+    fvhBmonEvtLostCntPerMsEvoChan[uChan]->Reset();
+
+    fvhBmonErrorFractEvoChan[uChan]->Reset();
+    fvhBmonErrorFractPerMsEvoChan[uChan]->Reset();
+
+    fvhBmonEvtLostFractEvoChan[uChan]->Reset();
+    fvhBmonEvtLostFractPerMsEvoChan[uChan]->Reset();
+  }  // for( UInt_t uChan = 0; uChan < kuNbChanBmon; ++uChan )
+
+  fhBmonCompMap->Reset();
+  fhBmonCompGet4->Reset();
+  fhBmonGet4Map->Reset();
+  fhBmonGet4MapEvo->Reset();
+  fhBmonChannelMapAll->Reset();
+  fhBmonChannelTotAll->Reset();
+  fhBmonHitMapEvoAll->Reset();
+  fhBmonHitTotEvoAll->Reset();
+  fhBmonChanHitMapAll->Reset();
+  fhBmonChanHitMapEvoAll->Reset();
+
+  fhBmonCompMap->Reset();
+  fhBmonCompMap->Reset();
+  fhBmonChannelMap->Reset();
+  fhBmonHitMapEvo->Reset();
+  fhBmonHitTotEvo->Reset();
+  fhBmonChanHitMap->Reset();
+  fhBmonChanHitMapEvo->Reset();
+  for (UInt_t uSpill = 0; uSpill < kuNbSpillPlots; uSpill++) {
+    fvhBmonCompMapSpill[uSpill]->Reset();
+    fvhBmonChannelMapSpill[uSpill]->Reset();
+  }  // for( UInt_t uSpill = 0; uSpill < kuNbSpillPlots; uSpill ++)
+  fhBmonHitsPerSpill->Reset();
+
+  fhBmonMsgCntEvo->Reset();
+  fhBmonHitCntEvo->Reset();
+  fhBmonErrorCntEvo->Reset();
+
+  fhBmonErrorFractEvo->Reset();
+  fhBmonLostEvtFractEvo->Reset();
+
+  fhBmonMsgCntPerMsEvo->Reset();
+  fhBmonHitCntPerMsEvo->Reset();
+  fhBmonErrorCntPerMsEvo->Reset();
+  fhBmonLostEvtCntPerMsEvo->Reset();
+  fhBmonErrorFractPerMsEvo->Reset();
+  fhBmonLostEvtFractPerMsEvo->Reset();
+
+  fhBmonChannelMapPulser->Reset();
+  fhBmonHitMapEvoPulser->Reset();
+
+  if (kTRUE == bResetTime) {
+    /// Also reset the Start time for the evolution plots!
+    fdStartTime = -1.0;
+
+    fuCurrentSpillIdx  = 0;
+    fuCurrentSpillPlot = 0;
+  }  // if( kTRUE == bResetTime )
+
+  return kTRUE;
+}
+
+void CbmTofUnpackMonitor::DrawBmonCanvases()
+{
+  std::string sFolder = "canvases";
+
+  /*******************************************************************/
+  /// General summary: Hit maps, Hit rate vs time in run, error fraction vs time un run
+  fcBmonSummary = new TCanvas("cBmonSummary", "Hit maps, Hit rate, Error fraction");
+  fcBmonSummary->Divide(2, 2);
+
+  fcBmonSummary->cd(1);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogy();
+  fhBmonChannelMap->Draw();
+
+  fcBmonSummary->cd(2);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogz();
+  fhBmonHitMapEvo->Draw("colz");
+
+  fcBmonSummary->cd(3);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogy();
+  fhBmonHitCntEvo->Draw();
+
+  fcBmonSummary->cd(4);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogz();
+  fhBmonErrorFractEvo->Draw("hist");
+
+  AddCanvasToVector(fcBmonSummary, sFolder);
+  /*******************************************************************/
+
+  /*******************************************************************/
+  /// General summary after mapping: Hit maps, Hit rate vs time in run, error fraction vs time un run
+  fcBmonSummaryMap = new TCanvas("cBmonSummaryMap", "Hit maps, Hit rate, Error fraction");
+  fcBmonSummaryMap->Divide(2, 2);
+
+  fcBmonSummaryMap->cd(1);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogy();
+  fhBmonChanHitMap->Draw();
+
+  fcBmonSummaryMap->cd(2);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogz();
+  fhBmonChanHitMapEvo->Draw("colz");
+
+  fcBmonSummaryMap->cd(3);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogy();
+  fhBmonHitCntEvo->Draw();
+
+  fcBmonSummaryMap->cd(4);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogz();
+  fhBmonErrorFractEvo->Draw("hist");
+
+  AddCanvasToVector(fcBmonSummaryMap, sFolder);
+  /*******************************************************************/
+
+  /*******************************************************************/
+  /// Map of hits over Bmon detector and same vs time in run
+  fcBmonHitMaps = new TCanvas("cBmonHitMaps", "Hit maps");
+  fcBmonHitMaps->Divide(2);
+
+  fcBmonHitMaps->cd(1);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogy();
+  fhBmonChannelMap->Draw();
+
+  fcBmonHitMaps->cd(2);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogz();
+  fhBmonHitMapEvo->Draw("colz");
+
+  AddCanvasToVector(fcBmonHitMaps, sFolder);
+  /*******************************************************************/
+
+  /*******************************************************************/
+  /// General summary: Hit maps, Hit rate vs time in run, error fraction vs time un run
+  fcBmonGenCntsPerMs =
+    new TCanvas("cBmonGenCntsPerMs", "Messages and hit cnt per MS, Error and Evt Loss Fract. per MS ");
+  fcBmonGenCntsPerMs->Divide(2, 2);
+
+  fcBmonGenCntsPerMs->cd(1);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogy();
+  gPad->SetLogz();
+  fhBmonMsgCntPerMsEvo->Draw("colz");
+
+  fcBmonGenCntsPerMs->cd(2);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogy();
+  gPad->SetLogz();
+  fhBmonHitCntPerMsEvo->Draw("colz");
+
+  fcBmonGenCntsPerMs->cd(3);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogy();
+  gPad->SetLogz();
+  fhBmonErrorFractPerMsEvo->Draw("colz");
+
+  fcBmonGenCntsPerMs->cd(4);
+  gPad->SetGridx();
+  gPad->SetGridy();
+  gPad->SetLogy();
+  gPad->SetLogz();
+  fhBmonLostEvtFractPerMsEvo->Draw("colz");
+
+  AddCanvasToVector(fcBmonGenCntsPerMs, sFolder);
+  /*******************************************************************/
+
+  /*******************************************************************/
+  /// General summary: Hit maps, Hit rate vs time in run, error fraction vs time un run
+  fcBmonSpillCounts = new TCanvas("cBmonSpillCounts", "Counts per spill, last 5 spills including current one");
+  fcBmonSpillCounts->Divide(1, kuNbSpillPlots);
+
+  for (UInt_t uSpill = 0; uSpill < kuNbSpillPlots; uSpill++) {
+    fcBmonSpillCounts->cd(1 + uSpill);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    gPad->SetLogy();
+    //      fvhChannelMapSpill[ uSpill ]->SetStats( kTRUE );
+    fvhBmonChannelMapSpill[uSpill]->Draw();
+    gPad->Update();
+    TPaveStats* st = (TPaveStats*) fvhBmonChannelMapSpill[uSpill]->FindObject("stats");
+    st->SetOptStat(10);
+    st->SetX1NDC(0.25);
+    st->SetX2NDC(0.95);
+    st->SetY1NDC(0.90);
+    st->SetY2NDC(0.95);
+  }  // for( UInt_t uSpill = 0; uSpill < kuNbSpillPlots; uSpill ++)
+
+  AddCanvasToVector(fcBmonSpillCounts, sFolder);
+  /*******************************************************************/
+
+  /*******************************************************************/
+  /// General summary: Hit maps, Hit rate vs time in run, error fraction vs time un run
+  fcBmonSpillCountsHori = new TCanvas("cBmonSpillCountsHori", "Counts per spill, last 5 spills including current one");
+  fcBmonSpillCountsHori->Divide(kuNbSpillPlots);
+
+  for (UInt_t uSpill = 0; uSpill < kuNbSpillPlots; uSpill++) {
+    fcBmonSpillCountsHori->cd(1 + uSpill);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    gPad->SetLogy();
+    fvhBmonChannelMapSpill[uSpill]->Draw();
+    gPad->Update();
+    TPaveStats* st = (TPaveStats*) fvhBmonChannelMapSpill[uSpill]->FindObject("stats");
+    st->SetOptStat(10);
+    st->SetX1NDC(0.25);
+    st->SetX2NDC(0.95);
+    st->SetY1NDC(0.90);
+    st->SetY2NDC(0.95);
+  }  // for( UInt_t uSpill = 0; uSpill < kuNbSpillPlots; uSpill ++)
+
+  AddCanvasToVector(fcBmonSpillCountsHori, sFolder);
+  /*******************************************************************/
+
+  /*******************************************************************/
+  /// General summary: Hit maps, Hit rate vs time in run, error fraction vs time un run
+  fcBmonSpillCompCountsHori =
+    new TCanvas("cBmonSpillCompCountsHori", "Counts in Comp. per spill, last 5 spills including current one");
+  fcBmonSpillCompCountsHori->Divide(kuNbSpillPlots);
+
+  for (UInt_t uSpill = 0; uSpill < kuNbSpillPlots; uSpill++) {
+    fcBmonSpillCompCountsHori->cd(1 + uSpill);
+    gPad->SetGridx();
+    gPad->SetGridy();
+    gPad->SetLogy();
+    fvhBmonCompMapSpill[uSpill]->Draw();
+    gPad->Update();
+    TPaveStats* st = (TPaveStats*) fvhBmonCompMapSpill[uSpill]->FindObject("stats");
+    st->SetOptStat(110);
+    st->SetX1NDC(0.25);
+    st->SetX2NDC(0.95);
+    st->SetY1NDC(0.90);
+    st->SetY2NDC(0.95);
+  }  // for( UInt_t uSpill = 0; uSpill < kuNbSpillPlots; uSpill ++)
+
+  AddCanvasToVector(fcBmonSpillCompCountsHori, sFolder);
+  /*******************************************************************/
+}
+// -------------------------------------------------------------------------
+
+
+// -------------------------------------------------------------------------
+void CbmTofUnpackMonitor::FillHitMonitoringHistos(const double_t& dMsTime, const uint32_t& uCurrCompIdx,
+                                                  const uint32_t& uGet4Id, const uint32_t& uRawCh,
+                                                  const uint32_t& uRemapCh, const uint32_t& uTot)
+{
+  if (-1 == fdStartTime) {
+    /// Initialize Start time for evolution plots
+    fdStartTime = dMsTime;
+  }
+
+  /// ---> Per GET4 in system
+  uint32_t uGet4InSys = uGet4Id + uCurrCompIdx * fuNbOfGet4PerComp;
+  fhGet4MessType->Fill(uGet4InSys, 0);
+  /// ---> Per GET4 in Component
+  fvhCompGet4MessType[uCurrCompIdx]->Fill(uGet4Id, 0);
+  /// ---> Per raw channel in Component
+  fvhCompRawChCount[uCurrCompIdx]->Fill(uRawCh);
+  fvhCompRawChRate[uCurrCompIdx]->Fill(dMsTime - fdStartTime, uRawCh);
+  fvhCompRawChTot[uCurrCompIdx]->Fill(uRawCh, uTot);
+  /// ---> Per remapped (PADI) channel in Component
+  fvhCompRemapChCount[uCurrCompIdx]->Fill(uRemapCh);
+  fvhCompRemapChRate[uCurrCompIdx]->Fill(dMsTime - fdStartTime, uRemapCh);
+  fvhCompRemapChTot[uCurrCompIdx]->Fill(uRemapCh, uTot);
+}
+void CbmTofUnpackMonitor::FillEpochMonitoringHistos(const uint32_t& uCurrCompIdx, const uint32_t& uGet4Id,
+                                                    const bool& bSyncFlag,   // mess.getGdpbEpSync
+                                                    const bool& bDataLoss,   // mess.getGdpbEpDataLoss()
+                                                    const bool& bEpochLoss,  // mess.getGdpbEpEpochLoss()
+                                                    const bool& bMissmMatch  // mess.getGdpbEpMissmatch()
+)
+{
+  /// ---> Per GET4 in system
+  uint32_t uGet4InSys = uGet4Id + uCurrCompIdx * fuNbOfGet4PerComp;
+  fhGet4MessType->Fill(uGet4InSys, 1);
+  if (bSyncFlag) fhGet4EpochFlags->Fill(uGet4InSys, 0);
+  if (bDataLoss) fhGet4EpochFlags->Fill(uGet4InSys, 1);
+  if (bEpochLoss) fhGet4EpochFlags->Fill(uGet4InSys, 2);
+  if (bMissmMatch) fhGet4EpochFlags->Fill(uGet4InSys, 3);
+  /// ---> Per GET4 in Component
+  fvhCompGet4MessType[uCurrCompIdx]->Fill(uGet4Id, 1);
+}
+void CbmTofUnpackMonitor::FillScmMonitoringHistos(const uint32_t& uCurrCompIdx, const uint32_t& uGet4Id,
+                                                  const uint32_t& uCh,    // mess.getGdpbSlcChan()
+                                                  const uint32_t& uEdge,  // mess.getGdpbSlcEdge()
+                                                  const uint32_t& uType   // mess.getGdpbSlcType()
+)
+{
+  /// ---> Per GET4 in system
+  uint32_t uGet4InSys = uGet4Id + uCurrCompIdx * fuNbOfGet4PerComp;
+  fhGet4MessType->Fill(uGet4InSys, 2);
+
+  /// ---> Per GET4 in Component
+  fvhCompGet4MessType[uCurrCompIdx]->Fill(uGet4Id, 2);
+  double_t uChInComp = uCh + 0.5 * uEdge + uGet4Id * fuNbOfChannelsPerGet4;
+  if (uType == critof001::GET4_32B_SLC_START_SEU && 0 == uEdge) {
+    /// Start/SEU + Start flag is set
+    fhGet4ScmType->Fill(uGet4InSys, uType + 1);
+    fvhCompGet4ChScm[uCurrCompIdx]->Fill(uChInComp, uType + 1);
+  }  // if (uType == critof001::GET4_32B_SLC_START_SEU && 0 == uEdge)
+  else {
+    fhGet4ScmType->Fill(uGet4InSys, uType);
+    fvhCompGet4ChScm[uCurrCompIdx]->Fill(uChInComp, uType);
+  }  // else of if (uType == critof001::GET4_32B_SLC_START_SEU && 0 == uEdge)
+}
+void CbmTofUnpackMonitor::FillSysMonitoringHistos(const uint32_t& uCurrCompIdx, const uint32_t& uGet4Id,
+                                                  const uint32_t& uType  // mess.getGdpbSysSubType()
+)
+{
+  /// ---> Per GET4 in system
+  uint32_t uGet4InSys = uGet4Id + uCurrCompIdx * fuNbOfGet4PerComp;
+  fhGet4SysMessType->Fill(uGet4InSys, uType);
+}
+void CbmTofUnpackMonitor::FillErrMonitoringHistos(const uint32_t& uCurrCompIdx, const uint32_t& uGet4Id,
+                                                  const uint32_t& uCh,   // mess.getGdpbSysErrChanId()
+                                                  const uint32_t& uType  // mess.getGdpbSysErrData()
+)
+{
+  /// ---> Per GET4 in system
+  uint32_t uGet4InSys = uGet4Id + uCurrCompIdx * fuNbOfGet4PerComp;
+  fhGet4MessType->Fill(uGet4InSys, 3);
+  /// ---> Per GET4 in Component
+  fvhCompGet4MessType[uCurrCompIdx]->Fill(uGet4Id, 3);
+
+  uint32_t uChInComp = uCh + uGet4Id * fuNbOfChannelsPerGet4;
+  switch (uType) {
+    case critof001::GET4_V2X_ERR_READ_INIT: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 0);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 0);
+      break;
+    }  // case critof001::GET4_V2X_ERR_READ_INIT:
+    case critof001::GET4_V2X_ERR_SYNC: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 1);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 1);
+      break;
+    }  // case critof001::GET4_V2X_ERR_SYNC:
+    case critof001::GET4_V2X_ERR_EP_CNT_SYNC: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 2);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 2);
+      break;
+    }  // case critof001::GET4_V2X_ERR_EP_CNT_SYNC:
+    case critof001::GET4_V2X_ERR_EP: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 3);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 3);
+      break;
+    }  // case critof001::GET4_V2X_ERR_EP:
+    case critof001::GET4_V2X_ERR_FIFO_WRITE: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 4);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 4);
+      break;
+    }  // case critof001::GET4_V2X_ERR_FIFO_WRITE:
+    case critof001::GET4_V2X_ERR_LOST_EVT: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 5);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 5);
+      break;
+    }  // case critof001::GET4_V2X_ERR_LOST_EVT:
+    case critof001::GET4_V2X_ERR_CHAN_STATE: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 6);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 6);
+      break;
+    }  // case critof001::GET4_V2X_ERR_CHAN_STATE:
+    case critof001::GET4_V2X_ERR_TOK_RING_ST: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 7);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 7);
+      break;
+    }  // case critof001::GET4_V2X_ERR_TOK_RING_ST:
+    case critof001::GET4_V2X_ERR_TOKEN: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 8);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 8);
+      break;
+    }  // case critof001::GET4_V2X_ERR_TOKEN:
+    case critof001::GET4_V2X_ERR_READOUT_ERR: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 9);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 9);
+      break;
+    }  // case critof001::GET4_V2X_ERR_READOUT_ERR:
+    case critof001::GET4_V2X_ERR_SPI: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 10);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 10);
+      break;
+    }  // case critof001::GET4_V2X_ERR_SPI:
+    case critof001::GET4_V2X_ERR_DLL_LOCK: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 11);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 11);
+      break;
+    }  // case critof001::GET4_V2X_ERR_DLL_LOCK:
+    case critof001::GET4_V2X_ERR_DLL_RESET: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 12);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 12);
+      break;
+    }  // case critof001::GET4_V2X_ERR_DLL_RESET:
+    case critof001::GET4_V2X_ERR_TOT_OVERWRT: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 13);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 13);
+      break;
+    }  // case critof001::GET4_V2X_ERR_TOT_OVERWRT:
+    case critof001::GET4_V2X_ERR_TOT_RANGE: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 14);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 14);
+      break;
+    }  // case critof001::GET4_V2X_ERR_TOT_RANGE:
+    case critof001::GET4_V2X_ERR_EVT_DISCARD: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 15);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 15);
+      break;
+    }  // case critof001::GET4_V2X_ERR_EVT_DISCARD:
+    case critof001::GET4_V2X_ERR_ADD_RIS_EDG: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 16);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 16);
+      break;
+    }  // case critof001::GET4_V2X_ERR_ADD_RIS_EDG:
+    case critof001::GET4_V2X_ERR_UNPAIR_FALL: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 17);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 17);
+      break;
+    }  // case critof001::GET4_V2X_ERR_UNPAIR_FALL:
+    case critof001::GET4_V2X_ERR_SEQUENCE_ER: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 18);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 18);
+      break;
+    }  // case critof001::GET4_V2X_ERR_SEQUENCE_ER:
+    case critof001::GET4_V2X_ERR_EPOCH_OVERF: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 19);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 19);
+      break;
+    }  // case critof001::GET4_V2X_ERR_EPOCH_OVERF:
+    case critof001::GET4_V2X_ERR_UNKNOWN: {
+      fhGet4ErrorsType->Fill(uGet4InSys, 20);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 20);
+      break;
+    }  // case critof001::GET4_V2X_ERR_UNKNOWN:
+    default: // Corrupt error or not yet supported error
+      {
+      fhGet4ErrorsType->Fill(uGet4InSys, 21);
+      fvhCompGet4ChErrors[uCurrCompIdx]->Fill(uChInComp, 21);
+      break;
+    }  //
+  }    // Switch( mess.getGdpbSysErrData() )
+}
+
+
+// -------------------------------------------------------------------------
+void CbmTofUnpackMonitor::CheckBmonSpillLimits(const double_t& dMsTime)
+{
+  if (-1 == fdStartTime) {
+    /// Initialize Start time for evolution plots
+    fdStartTime = dMsTime;
+  }
+
+  /// Spill Detection
+  /// Check only every second
+  if (fdSpillCheckInterval < dMsTime - fdBmonLastInterTime) {
+    /// Spill Off detection
+    if (fbSpillOn && fuBmonCountsLastInter < fuOffSpillCountLimit
+        && fuBmonNonPulserCountsLastInter < fuOffSpillCountLimitNonPulser) {
+      fbSpillOn = kFALSE;
+      fuCurrentSpillIdx++;
+      fuCurrentSpillPlot = (fuCurrentSpillPlot + 1) % kuNbSpillPlots;
+      fdStartTimeSpill   = dMsTime;
+      fvhBmonCompMapSpill[fuCurrentSpillPlot]->Reset();
+      fvhBmonChannelMapSpill[fuCurrentSpillPlot]->Reset();
+    }  // if( fbSpillOn && fuCountsLastInter < fuOffSpillCountLimit && same for non pulser)
+    else if (fuOffSpillCountLimit < fuBmonCountsLastInter) {
+      fbSpillOn = kTRUE;
+    }
+
+    //    LOG(debug) << Form("%6llu %6.4f %9u %9u %2d", fulCurrentTsIdx, dMsTime - fdLastInterTime, fuBmonCountsLastInter,
+    //                       fuBmonNonPulserCountsLastInter, fuCurrentSpillIdx);
+
+    fuBmonCountsLastInter          = 0;
+    fuBmonNonPulserCountsLastInter = 0;
+    fdBmonLastInterTime            = dMsTime;
+  }  // if( fdSpillCheckInterval < dMsTime - fdLastInterTime )
+}
+void CbmTofUnpackMonitor::FillHitBmonMonitoringHistos(const double_t& dMsTime, const uint32_t& uCurrCompIdx,
+                                                      const uint32_t& uGet4Id, const uint32_t& uTot)
+{
+  if (-1 == fdStartTime) {
+    /// Initialize Start time for evolution plots
+    fdStartTime = dMsTime;
+  }
+
+  /// 2022 mapping: Y[0-3] on c0, Y[4-7] on c1, X[0-3] on c2, X[4-7] on c3
+  /// Y not cabled for diamond but pulser there
+  UInt_t uChannelBmon = (uGet4Id / 8) + 4 * uCurrCompIdx;
+
+  fhBmonGet4Map->Fill(uGet4Id + 80 * uCurrCompIdx);
+  fhBmonGet4MapEvo->Fill(dMsTime - fdStartTime, uGet4Id + 80 * uCurrCompIdx);
+  fhBmonCompGet4->Fill(uGet4Id + 80 * uCurrCompIdx, uChannelBmon);
+  if (kuNbChanBmon <= uChannelBmon) return;
+
+  fhBmonCompMapAll->Fill(uCurrCompIdx);
+  fhBmonChannelMapAll->Fill(uChannelBmon);
+  fhBmonChannelTotAll->Fill(uChannelBmon, uTot);
+  fhBmonHitMapEvoAll->Fill(uChannelBmon, dMsTime - fdStartTime);
+  fhBmonHitTotEvoAll->Fill(dMsTime - fdStartTime, uTot);
+  fhBmonChanHitMapAll->Fill(fuBmonChanMap[uChannelBmon]);
+  fhBmonChanHitMapEvoAll->Fill(fuBmonChanMap[uChannelBmon], dMsTime - fdStartTime);
+
+  /// Spill detection
+  fuBmonCountsLastInter++;
+
+  fhBmonErrorFractEvo->Fill(dMsTime - fdStartTime, 0.0);
+  fhBmonLostEvtFractEvo->Fill(dMsTime - fdStartTime, 0.0);
+  fvhBmonErrorFractEvoChan[uChannelBmon]->Fill(dMsTime - fdStartTime, 0.0);
+  fvhBmonEvtLostFractEvoChan[uChannelBmon]->Fill(dMsTime - fdStartTime, 0.0);
+
+  fhBmonMsgCntEvo->Fill(dMsTime - fdStartTime);
+  fhBmonHitCntEvo->Fill(dMsTime - fdStartTime);
+
+  fvhBmonHitCntEvoChan[uChannelBmon]->Fill(dMsTime - fdStartTime);
+
+  fvuBmonHitCntChanMs[uChannelBmon]++;
+
+  /// Do not fill the pulser hits to keep counts low for channel 0 of each Board
+  /// For now hard-code the pulser channel
+  if ((0 == uGet4Id / 8) && (fuMinTotPulser <= uTot) && (uTot <= fuMaxTotPulser)) {
+    fhBmonChannelMapPulser->Fill(uChannelBmon);
+    fhBmonHitMapEvoPulser->Fill(uChannelBmon, dMsTime - fdStartTime);
+  }  // if ( (0 == uGet4Id / 8) && (fuMinTotPulser <= uTot) && (uTot <= fuMaxTotPulser) )
+  else {
+    fuBmonNonPulserCountsLastInter++;
+
+    fhBmonCompMap->Fill(uCurrCompIdx);
+    fhBmonChannelMap->Fill(uChannelBmon);
+    fhBmonHitMapEvo->Fill(uChannelBmon, dMsTime - fdStartTime);
+    fhBmonHitTotEvo->Fill(dMsTime - fdStartTime, uTot);
+    fhBmonChanHitMap->Fill(fuBmonChanMap[uChannelBmon]);
+    fhBmonChanHitMapEvo->Fill(fuBmonChanMap[uChannelBmon], dMsTime - fdStartTime);
+
+    fvhBmonCompMapSpill[fuCurrentSpillPlot]->Fill(uCurrCompIdx);
+    fvhBmonChannelMapSpill[fuCurrentSpillPlot]->Fill(fuBmonChanMap[uChannelBmon]);
+    fhBmonHitsPerSpill->Fill(fuCurrentSpillIdx);
+  }  // else of if ( (0 == uGet4Id / 8) && (fuMinTotPulser <= uTot) && (uTot <= fuMaxTotPulser) )
+}
+
+void CbmTofUnpackMonitor::FillErrBmonMonitoringHistos(const double_t& dMsTime, const uint32_t& uCurrCompIdx,
+                                                      const uint32_t& uGet4Id, const bool& bErrEvtLost)
+{
+  /// 2022 mapping:
+  /// Y[0-3] on c0, Y[4-7] on c1, X[0-3] on c2, X[4-7] on c3
+  /// Y not cabled for diamond but pulser there
+  UInt_t uChannelBmon = (uGet4Id / 8) + 4 * uCurrCompIdx;
+
+  fhBmonErrorFractEvo->Fill(dMsTime - fdStartTime, 0.0);
+  fhBmonLostEvtFractEvo->Fill(dMsTime - fdStartTime, 0.0);
+  fvhBmonErrorFractEvoChan[uChannelBmon]->Fill(dMsTime - fdStartTime, 0.0);
+  fvhBmonEvtLostFractEvoChan[uChannelBmon]->Fill(dMsTime - fdStartTime, 0.0);
+
+  fhBmonMsgCntEvo->Fill(dMsTime - fdStartTime);
+  fhBmonErrorCntEvo->Fill(dMsTime - fdStartTime);
+  fhBmonErrorFractEvo->Fill(dMsTime - fdStartTime, 1.0);
+
+  fvhBmonErrorCntEvoChan[uChannelBmon]->Fill(dMsTime - fdStartTime);
+  fvhBmonErrorFractEvoChan[uChannelBmon]->Fill(dMsTime - fdStartTime, 1.0);
+
+  fvuBmonErrorCntChanMs[uChannelBmon]++;
+  if (bErrEvtLost) {
+    fhBmonLostEvtCntEvo->Fill(dMsTime - fdStartTime);
+    fhBmonLostEvtFractEvo->Fill(dMsTime - fdStartTime, 1.0);
+
+    fvhBmonEvtLostCntEvoChan[uChannelBmon]->Fill(dMsTime - fdStartTime);
+    fvhBmonEvtLostFractEvoChan[uChannelBmon]->Fill(dMsTime - fdStartTime, 1.0);
+
+    fvuBmonEvtLostCntChanMs[uChannelBmon]++;
+  }  // if( gdpbv100::GET4_V2X_ERR_LOST_EVT == mess.getGdpbSysErrData() )
+}
+
+// -------------------------------------------------------------------------
+
+// ---- Init ----
+Bool_t CbmTofUnpackMonitor::Init(CbmMcbm2018TofPar* parset)
+{
+  // Get Infos from the parset
+  fUnpackPar = parset;
+
+  fuNbOfComps = fUnpackPar->GetNrOfGdpbs();
+  /// Other constants are defined for the AFCK/DPB in the current parameter class!!!
+  // FIXME: Start using again the parameter class accessors once a new CRI oriented class is brought into use
+  fuNbOfGet4PerComp     = 80;
+  fuNbOfChannelsPerGet4 = 4;
+  fuNbOfChannelsPerComp = fuNbOfGet4PerComp * fuNbOfChannelsPerGet4;
+  fuNbOfGet4InSyst      = fuNbOfComps * fuNbOfGet4PerComp;
+
+  /// Trigger histo creation on all associated monitors
+  CreateHistograms();
+  DrawCanvases();
+  if (fBmonMode) {
+    CreateBmonHistograms();
+    DrawBmonCanvases();
+  }
+
+  /// Obtain vector of pointers on each histo from the algo (+ optionally desired folder)
+  std::vector<std::pair<TNamed*, std::string>> vHistos = GetHistoVector();
+
+  /// Obtain vector of pointers on each canvas from the algo (+ optionally desired folder)
+  std::vector<std::pair<TCanvas*, std::string>> vCanvases = GetCanvasVector();
+
+  /// Register the histos and canvases in the HTTP server
+  std::string sSystem = "tof";
+  if (fBmonMode) {
+    //
+    sSystem = "bmon";
+  }
+  THttpServer* server = FairRunOnline::Instance()->GetHttpServer();
+  if (nullptr != server) {
+    for (UInt_t uCanvas = 0; uCanvas < vCanvases.size(); ++uCanvas) {
+      server->Register(Form("/%s/%s", sSystem.data(), vCanvases[uCanvas].second.data()), vCanvases[uCanvas].first);
+    }
+    for (UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto) {
+      server->Register(Form("/%s/%s", sSystem.data(), vHistos[uHisto].second.data()), vHistos[uHisto].first);
+    }
+    /*
+    server->RegisterCommand(Form("/Reset_%s_Hist", sSystem.data()), "bMcbm2018UnpackerTaskStsResetHistos=kTRUE");
+    server->Restrict("/Reset_UnpSts_Hist", "allow=admin");
+*/
+  }
+
+  return kTRUE;
+}
+
+// ---- Finish ----
+void CbmTofUnpackMonitor::Finish()
+{
+  /// Obtain vector of pointers on each histo (+ optionally desired folder)
+  std::vector<std::pair<TNamed*, std::string>> vHistos = GetHistoVector();
+
+  /// Obtain vector of pointers on each canvas (+ optionally desired folder)
+  std::vector<std::pair<TCanvas*, std::string>> vCanvases = GetCanvasVector();
+
+  /// Save old global file and folder pointer to avoid messing with FairRoot
+  TFile* oldFile     = gFile;
+  TDirectory* oldDir = gDirectory;
+  TFile* histoFile   = nullptr;
+
+  // open separate histo file in recreate mode
+  histoFile = new TFile(fHistoFileName, "RECREATE");
+  histoFile->cd();
+
+  /// Write histos to output file
+  for (UInt_t uHisto = 0; uHisto < vHistos.size(); ++uHisto) {
+    /// Make sure we end up in chosen folder
+    TString sFolder = vHistos[uHisto].second.data();
+    if (nullptr == gDirectory->Get(sFolder)) gDirectory->mkdir(sFolder);
+    gDirectory->cd(sFolder);
+
+    /// Write plot
+    vHistos[uHisto].first->Write();
+
+    histoFile->cd();
+  }
+
+  /// Write canvases to output file
+  for (UInt_t uCanvas = 0; uCanvas < vCanvases.size(); ++uCanvas) {
+    /// Make sure we end up in chosen folder
+    TString sFolder = vCanvases[uCanvas].second.data();
+    if (nullptr == gDirectory->Get(sFolder)) gDirectory->mkdir(sFolder);
+    gDirectory->cd(sFolder);
+
+    /// Write canvas
+    vCanvases[uCanvas].first->Write();
+
+    histoFile->cd();
+  }
+
+  /// Restore old global file and folder pointer to avoid messing with FairRoot
+  gFile      = oldFile;
+  gDirectory = oldDir;
+
+  histoFile->Close();
+  delete histoFile;
+}
+
+
+ClassImp(CbmTofUnpackMonitor)
diff --git a/reco/detectors/tof/unpack/CbmTofUnpackMonitor.h b/reco/detectors/tof/unpack/CbmTofUnpackMonitor.h
new file mode 100644
index 0000000000..5039f6dadd
--- /dev/null
+++ b/reco/detectors/tof/unpack/CbmTofUnpackMonitor.h
@@ -0,0 +1,287 @@
+/* Copyright (C) 2022 Facility for Antiproton and Ion Research in Europe, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Pierre-Alain Loizeau [committer]  */
+
+#ifndef CbmTofUnpackMonitor_H
+#define CbmTofUnpackMonitor_H
+
+#include "CbmMcbm2018TofPar.h"
+
+#include "Rtypes.h"
+#include "TH1.h"
+#include "TH2.h"
+#include "TProfile.h"
+#include "TProfile2D.h"
+
+#include <cstdint>
+
+class TCanvas;
+
+class CbmTofUnpackMonitor {
+public:
+  CbmTofUnpackMonitor();
+
+  virtual ~CbmTofUnpackMonitor();
+
+  /** @brief Init all required parameter informations and histograms */
+  Bool_t Init(CbmMcbm2018TofPar* digiParSet);
+
+  Bool_t CreateHistograms();
+  Bool_t ResetHistograms();
+  void DrawCanvases();
+
+  Bool_t CreateBmonHistograms();
+  Bool_t ResetBmonHistograms(Bool_t bResetTime);
+  void DrawBmonCanvases();
+
+  Bool_t CreateMsComponentSizeHistos(UInt_t component);
+  Bool_t ResetMsComponentSizeHistos(UInt_t component);
+
+  /** @brief Write all histograms and canvases to file */
+  void Finish();
+
+  void SetHistoFileName(TString nameIn) { fHistoFileName = nameIn; }
+
+  inline void SetPulserTotLimits(UInt_t uMin, UInt_t uMax)
+  {
+    fuMinTotPulser = uMin;
+    fuMaxTotPulser = uMax;
+  }
+  inline void SetSpillThreshold(UInt_t uCntLimit) { fuOffSpillCountLimit = uCntLimit; }
+  inline void SetSpillThresholdNonPulser(UInt_t uCntLimit) { fuOffSpillCountLimitNonPulser = uCntLimit; }
+  inline void SetSpillCheckInterval(Double_t dIntervalSec) { fdSpillCheckInterval = dIntervalSec; }
+  inline void SetBmonChannelMap(UInt_t uChan0, UInt_t uChan1, UInt_t uChan2, UInt_t uChan3, UInt_t uChan4,
+                                UInt_t uChan5, UInt_t uChan6, UInt_t uChan7)
+  {
+    fuBmonChanMap[0] = uChan0;
+    fuBmonChanMap[1] = uChan1;
+    fuBmonChanMap[2] = uChan2;
+    fuBmonChanMap[3] = uChan3;
+    fuBmonChanMap[4] = uChan4;
+    fuBmonChanMap[5] = uChan5;
+    fuBmonChanMap[6] = uChan6;
+    fuBmonChanMap[7] = uChan7;
+  }
+
+  void SetLongDurationLimits(UInt_t uDurationSeconds, UInt_t uBinSize)
+  {
+    //fbLongHistoEnable     = kTRUE;
+    fuLongHistoNbSeconds  = uDurationSeconds;
+    fuLongHistoBinSizeSec = uBinSize;
+  }
+
+  void AddHistoToVector(TNamed* pointer, std::string sFolder = "")
+  {
+    fvpAllHistoPointers.push_back(std::pair<TNamed*, std::string>(pointer, sFolder));
+  }
+  std::vector<std::pair<TNamed*, std::string>> GetHistoVector() { return fvpAllHistoPointers; }
+
+  void AddCanvasToVector(TCanvas* pointer, std::string sFolder = "")
+  {
+    fvpAllCanvasPointers.push_back(std::pair<TCanvas*, std::string>(pointer, sFolder));
+  }
+  std::vector<std::pair<TCanvas*, std::string>> GetCanvasVector() { return fvpAllCanvasPointers; }
+
+  UInt_t GetMaxNbFlibLinks() { return kuMaxNbFlibLinks; }
+
+  /// Fill Ms Component Size Histos
+  void FillMsSize(UInt_t uMsComp, UInt_t uSize) { fvhMsSize[uMsComp]->Fill(uSize); }
+  void FillMsSizeTime(UInt_t uMsComp, Double_t dTime, UInt_t uSize) { fvhMsSizeTime[uMsComp]->Fill(dTime, uSize); }
+
+
+  /// Fill general histograms
+  //  void FillMsCntEvo(ULong64_t MsIdx) { fhMsCntEvo->Fill(MsIdx * 1e-9); }
+  void FillHitMonitoringHistos(const double_t& dMsTime, const uint32_t& uCurrCompIdx, const uint32_t& uGet4Id,
+                               const uint32_t& uRawCh, const uint32_t& uRemapCh, const uint32_t& uTot);
+  void FillEpochMonitoringHistos(const uint32_t& uCurrCompIdx, const uint32_t& uGet4Id, const bool& bSyncFlag,
+                                 const bool& bDataLoss, const bool& bEpochLoss, const bool& bMissmMatch);
+  void FillScmMonitoringHistos(const uint32_t& uCurrCompIdx, const uint32_t& uGet4Id, const uint32_t& uCh,
+                               const uint32_t& uEdge, const uint32_t& uType);
+  void FillSysMonitoringHistos(const uint32_t& uCurrCompIdx, const uint32_t& uGet4Id, const uint32_t& uType);
+  void FillErrMonitoringHistos(const uint32_t& uCurrCompIdx, const uint32_t& uGet4Id, const uint32_t& uCh,
+                               const uint32_t& uType);
+
+  /// Fill BMon histograms
+  void CheckBmonSpillLimits(const double_t& dMsTime);
+  void FillHitBmonMonitoringHistos(const double_t& dMsTime, const uint32_t& uCurrCompIdx, const uint32_t& uGet4Id,
+                                   const uint32_t& uTot);
+
+  void FillErrBmonMonitoringHistos(const double_t& dMsTime, const uint32_t& uCurrCompIdx, const uint32_t& uGet4Id,
+                                   const bool& bErrEvtLost);
+
+  /** @brief Activate the BMon mode */
+  void SetBmonMode(bool value) { fBmonMode = value; }
+
+  /** @brief Read the Bmon mode */
+  bool GetBmonMode() { return fBmonMode; }
+
+private:
+  TString fHistoFileName = "data/mon.tof.root";
+
+  /// Settings from parameter file
+  CbmMcbm2018TofPar* fUnpackPar = nullptr;
+  /// Readout chain dimensions and mapping
+  UInt_t fuNbOfComps           = 0;  //! Total number of Components in the system
+  UInt_t fuNbOfGet4PerComp     = 0;  //! Max number of Get4 per component
+  UInt_t fuNbOfChannelsPerGet4 = 0;  //! Number of channels per Get4, constant
+  UInt_t fuNbOfChannelsPerComp = 0;  //! Number of channels per Component, recalculated
+  UInt_t fuNbOfGet4InSyst      = 0;  //! Total/maximum number of Get4 in system
+
+  /// Rate evolution histos
+  Double_t fdStartTime = -1.0; /** Time of first valid hit (epoch available), used as reference for evolution plots**/
+  UInt_t fuHistoryHistoSize  = 3600; /** Size in seconds of the evolution histograms **/
+  double_t dFirstTsStartTime = 0;
+  //Bool_t fbLongHistoEnable;
+  UInt_t fuLongHistoNbSeconds  = 3600;
+  UInt_t fuLongHistoBinSizeSec = 10;
+  UInt_t fuLongHistoBinNb      = 1;
+
+  /** @brief Flag if debug mode is active or not */
+  bool fBmonMode = false;
+
+  /// ---> Constants
+  static const UInt_t kuMaxNbFlibLinks  = 32;
+  static const UInt_t kuBytesPerMessage = 8;
+  static const UInt_t kuNbChanBmon      = 16;
+  static const UInt_t kuNbSpillPlots    = 5;
+
+  /// ---> User settings: Data correction parameters
+  UInt_t fuMinTotPulser                = 185;
+  UInt_t fuMaxTotPulser                = 189;
+  UInt_t fuOffSpillCountLimit          = 200;
+  UInt_t fuOffSpillCountLimitNonPulser = 80;
+  Double_t fdSpillCheckInterval        = 1.0;
+  /// Map from electronics channel to BMon strip
+  /// 2022 mapping: Y[0-3] on c0, Y[4-7] on c1, X[0-3] on c2, X[4-7] on c3
+  /// Y not cabled for diamond but pulser there
+  UInt_t fuBmonChanMap[kuNbChanBmon] = {8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7};
+
+  /// MS size histograms
+  TH1* fvhMsSize[kuMaxNbFlibLinks];
+  TProfile* fvhMsSizeTime[kuMaxNbFlibLinks];
+
+  /// TOF system general histograms
+  /// ---> Per GET4 in system
+  TH2* fhGet4MessType    = nullptr;
+  TH2* fhGet4EpochFlags  = nullptr;
+  TH2* fhGet4ScmType     = nullptr;
+  TH2* fhGet4SysMessType = nullptr;
+  TH2* fhGet4ErrorsType  = nullptr;
+  /// ---> Per GET4 in Component
+  std::vector<TH2*> fvhCompGet4MessType = {};
+  std::vector<TH2*> fvhCompGet4ChScm    = {};
+  std::vector<TH2*> fvhCompGet4ChErrors = {};
+  /// ---> Per raw channel in Component
+  std::vector<TH1*> fvhCompRawChCount = {};
+  std::vector<TH2*> fvhCompRawChRate  = {};
+  std::vector<TH2*> fvhCompRawChTot   = {};
+  /// ---> Per remapped (PADI) channel in Component
+  std::vector<TH1*> fvhCompRemapChCount = {};
+  std::vector<TH2*> fvhCompRemapChRate  = {};
+  std::vector<TH2*> fvhCompRemapChTot   = {};
+  /// ---> Pulser
+  TH1* fhPulserChCounts = nullptr;
+  TH2* fhPulserChEvo    = nullptr;
+
+  /// BMon specific histograms
+  /// ---> Channel rate plots
+  std::vector<UInt_t> fvuBmonHitCntChanMs           = std::vector<UInt_t>(kuNbChanBmon, 0);
+  std::vector<UInt_t> fvuBmonErrorCntChanMs         = std::vector<UInt_t>(kuNbChanBmon, 0);
+  std::vector<UInt_t> fvuBmonEvtLostCntChanMs       = std::vector<UInt_t>(kuNbChanBmon, 0);
+  std::vector<TH1*> fvhBmonMsgCntEvoChan            = std::vector<TH1*>(kuNbChanBmon, nullptr);
+  std::vector<TH2*> fvhBmonMsgCntPerMsEvoChan       = std::vector<TH2*>(kuNbChanBmon, nullptr);
+  std::vector<TH1*> fvhBmonHitCntEvoChan            = std::vector<TH1*>(kuNbChanBmon, nullptr);
+  std::vector<TH2*> fvhBmonHitCntPerMsEvoChan       = std::vector<TH2*>(kuNbChanBmon, nullptr);
+  std::vector<TH1*> fvhBmonErrorCntEvoChan          = std::vector<TH1*>(kuNbChanBmon, nullptr);
+  std::vector<TH2*> fvhBmonErrorCntPerMsEvoChan     = std::vector<TH2*>(kuNbChanBmon, nullptr);
+  std::vector<TH1*> fvhBmonEvtLostCntEvoChan        = std::vector<TH1*>(kuNbChanBmon, nullptr);
+  std::vector<TH2*> fvhBmonEvtLostCntPerMsEvoChan   = std::vector<TH2*>(kuNbChanBmon, nullptr);
+  std::vector<TProfile*> fvhBmonErrorFractEvoChan   = std::vector<TProfile*>(kuNbChanBmon, nullptr);
+  std::vector<TH2*> fvhBmonErrorFractPerMsEvoChan   = std::vector<TH2*>(kuNbChanBmon, nullptr);
+  std::vector<TProfile*> fvhBmonEvtLostFractEvoChan = std::vector<TProfile*>(kuNbChanBmon, nullptr);
+  std::vector<TH2*> fvhBmonEvtLostFractPerMsEvoChan = std::vector<TH2*>(kuNbChanBmon, nullptr);
+  /// ---> Channels maps without cuts
+  TH1* fhBmonCompMapAll       = nullptr;
+  TH2* fhBmonCompGet4         = nullptr;
+  TH1* fhBmonGet4Map          = nullptr;
+  TH2* fhBmonGet4MapEvo       = nullptr;
+  TH1* fhBmonChannelMapAll    = nullptr;
+  TH2* fhBmonChannelTotAll    = nullptr;
+  TH2* fhBmonHitMapEvoAll     = nullptr;
+  TH2* fhBmonHitTotEvoAll     = nullptr;
+  TH1* fhBmonChanHitMapAll    = nullptr;
+  TH2* fhBmonChanHitMapEvoAll = nullptr;
+  /// ---> No Pulser cut
+  TH1* fhBmonCompMap       = nullptr;
+  TH1* fhBmonChannelMap    = nullptr;
+  TH2* fhBmonHitMapEvo     = nullptr;
+  TH2* fhBmonHitTotEvo     = nullptr;
+  TH1* fhBmonChanHitMap    = nullptr;
+  TH2* fhBmonChanHitMapEvo = nullptr;
+  /// ---> No Pulser cut + Spill detection
+  std::vector<TH1*> fvhBmonCompMapSpill    = {};
+  std::vector<TH1*> fvhBmonChannelMapSpill = {};
+  TH1* fhBmonHitsPerSpill                  = nullptr;
+  /// ---> Global Rate
+  TH1* fhBmonMsgCntEvo            = nullptr;
+  TH1* fhBmonHitCntEvo            = nullptr;
+  TH1* fhBmonErrorCntEvo          = nullptr;
+  TH1* fhBmonLostEvtCntEvo        = nullptr;
+  TProfile* fhBmonErrorFractEvo   = nullptr;
+  TProfile* fhBmonLostEvtFractEvo = nullptr;
+  /// ---> Global Rate per MS
+  TH2* fhBmonMsgCntPerMsEvo       = nullptr;
+  TH2* fhBmonHitCntPerMsEvo       = nullptr;
+  TH2* fhBmonErrorCntPerMsEvo     = nullptr;
+  TH2* fhBmonLostEvtCntPerMsEvo   = nullptr;
+  TH2* fhBmonErrorFractPerMsEvo   = nullptr;
+  TH2* fhBmonLostEvtFractPerMsEvo = nullptr;
+  /// ---> Pulser
+  TH1* fhBmonChannelMapPulser = nullptr;
+  TH2* fhBmonHitMapEvoPulser  = nullptr;
+
+  /// Canvases
+  /// ---> Generic
+  TCanvas* fcSummaryGet4s          = nullptr;
+  std::vector<TCanvas*> fvcSumComp = {};
+  /// ---> BMon
+  TCanvas* fcBmonSummary             = nullptr;
+  TCanvas* fcBmonSummaryMap          = nullptr;
+  TCanvas* fcBmonHitMaps             = nullptr;
+  TCanvas* fcBmonGenCntsPerMs        = nullptr;
+  TCanvas* fcBmonSpillCounts         = nullptr;
+  TCanvas* fcBmonSpillCountsHori     = nullptr;
+  TCanvas* fcBmonSpillCompCountsHori = nullptr;
+
+  /// Spill detection
+  Bool_t fbSpillOn                      = kTRUE;
+  UInt_t fuCurrentSpillIdx              = 0;
+  UInt_t fuCurrentSpillPlot             = 0;
+  Double_t fdStartTimeSpill             = -1.0;
+  Double_t fdBmonLastInterTime          = -1.0;
+  UInt_t fuBmonCountsLastInter          = 0;
+  UInt_t fuBmonNonPulserCountsLastInter = 0;
+
+  /// For monitoring of internal processes.
+  /// => Pointers should be filled with TH1*, TH2*, TProfile*, ...
+  /// ==> To check if object N is of type T, use "T ObjectPointer = dynamic_cast<T>( fvpAllHistoPointers[N].first );" and check for nullptr
+  /// ==> To get back the original class name use "fvpAllHistoPointers[N].first->ClassName()" which returns a const char * (e.g. "TH1I")
+  /// ===> Usage example with feeding a THttpServer:
+  /// ===> #include "TH2.h"
+  /// ===> std::string sClassName = vHistos[ uHisto ].first.ClassName();
+  /// ===> if( !strncmp( sClassName, "TH1", 3 ) )
+  /// ===>    server->Register( vHistos[ uHisto ].second.data(), dynamic_cast< TH1 * >(vHistos[ uHisto ].first) );
+  /// ===> else if( !strncmp( sClassName, "TH2", 3 ) )
+  /// ===>    server->Register( vHistos[ uHisto ].second.data(), dynamic_cast< TH2 * >(vHistos[ uHisto ].first) );
+  std::vector<std::pair<TNamed*, std::string>>
+    fvpAllHistoPointers;  //! Vector of pointers to histograms + optional folder name
+  std::vector<std::pair<TCanvas*, std::string>>
+    fvpAllCanvasPointers;  //! Vector of pointers to canvases + optional folder name
+
+  CbmTofUnpackMonitor(const CbmTofUnpackMonitor&);
+  CbmTofUnpackMonitor operator=(const CbmTofUnpackMonitor&);
+
+  ClassDef(CbmTofUnpackMonitor, 1)
+};
+
+#endif
diff --git a/reco/steer/CbmRecoUnpack.cxx b/reco/steer/CbmRecoUnpack.cxx
index f63fbb4e81..fbed6d45f8 100644
--- a/reco/steer/CbmRecoUnpack.cxx
+++ b/reco/steer/CbmRecoUnpack.cxx
@@ -47,6 +47,7 @@ void CbmRecoUnpack::Finish()
   if (fTofConfig) fTofConfig->GetUnpacker()->Finish();
   if (fTrd1DConfig) fTrd1DConfig->GetUnpacker()->Finish();
   if (fTrd2DConfig) fTrd2DConfig->GetUnpacker()->Finish();
+  if (fBmonConfig) fBmonConfig->GetUnpacker()->Finish();
 
   // Create some default performance profiling histograms and write them to a file
   if (fDoPerfProf) performanceProfiling();
@@ -101,6 +102,7 @@ Bool_t CbmRecoUnpack::Init()
     fTofConfig->InitOutput();
     RegisterOutputs(ioman, fTofConfig);  /// Framework bound work = kept in this Task
     fTofConfig->SetAlgo();
+    fTofConfig->LoadParFileName();  /// Needed to change the Parameter file name before it is used!!!
     initParContainers(fTofConfig->GetParContainerRequest());  /// Framework bound work = kept in this Task
     fTofConfig->InitAlgo();
     initPerformanceMaps(fkFlesTof, "TOF");
@@ -135,6 +137,17 @@ Bool_t CbmRecoUnpack::Init()
   // The second option workaround is in in Init() to look for the fasp config and create a separate branch
   // for fasp created CbmTrdDigis PR 072021
 
+  // --- Bmon
+  if (fBmonConfig) {
+    fBmonConfig->InitOutput();
+    RegisterOutputs(ioman, fBmonConfig);  /// Framework bound work = kept in this Task
+    fBmonConfig->SetAlgo();
+    fBmonConfig->LoadParFileName();  /// Needed to change the Parameter file name before it is used!!!
+    initParContainers(fBmonConfig->GetParContainerRequest());  /// Framework bound work = kept in this Task
+    fBmonConfig->InitAlgo();
+    initPerformanceMaps(fkFlesBmon, "Bmon");
+  }
+
   return kTRUE;
 }
 // ----------------------------------------------------------------------------
@@ -253,6 +266,8 @@ void CbmRecoUnpack::Reset()
   if (fTrd1DConfig) fTrd1DConfig->Reset();
   // ---- Trd2D ----
   if (fTrd2DConfig) fTrd2DConfig->Reset();
+  // ---- Bmon ----
+  if (fBmonConfig) fBmonConfig->Reset();
 }
 
 // ----------------------------------------------------------------------------
@@ -317,6 +332,13 @@ void CbmRecoUnpack::Unpack(unique_ptr<Timeslice> ts)
         }
         break;
       }
+      case fkFlesBmon: {
+        if (fBmonConfig) {
+          fCbmTsEventHeader->AddNDigisBmon(unpack(systemId, &timeslice, component, fBmonConfig,
+                                                  fBmonConfig->GetOptOutAVec(), fBmonConfig->GetOptOutBVec()));
+        }
+        break;
+      }
       default: {
         if (fDoDebugPrints) LOG(error) << "Unpack: Unknown system ID " << systemId << " for component " << component;
         break;
@@ -324,7 +346,7 @@ void CbmRecoUnpack::Unpack(unique_ptr<Timeslice> ts)
     }
   }
 
-  if (bOutputFullTimeSorting) {
+  if (!bMonitoringOnly && bOutputFullTimeSorting) {
     /// Time sort the output vectors of all unpackers present
     if (fPsdConfig && fPsdConfig->GetOutputVec()) { timesort(fPsdConfig->GetOutputVec()); }
     if (fRichConfig && fRichConfig->GetOutputVec()) { timesort(fRichConfig->GetOutputVec()); }
@@ -332,6 +354,7 @@ void CbmRecoUnpack::Unpack(unique_ptr<Timeslice> ts)
     if (fTofConfig && fTofConfig->GetOutputVec()) { timesort(fTofConfig->GetOutputVec()); }
     if (fTrd1DConfig && fTrd1DConfig->GetOutputVec()) { timesort(fTrd1DConfig->GetOutputVec()); }
     if (fTrd2DConfig && fTrd2DConfig->GetOutputVec()) { timesort(fTrd2DConfig->GetOutputVec()); }
+    if (fBmonConfig && fBmonConfig->GetOutputVec()) { timesort(fBmonConfig->GetOutputVec()); }
 
     /// Time sort the output vectors of all unpackers present
     if (fPsdConfig && fPsdConfig->GetOptOutAVec()) { timesort(fPsdConfig->GetOptOutAVec()); }
@@ -340,6 +363,7 @@ void CbmRecoUnpack::Unpack(unique_ptr<Timeslice> ts)
     if (fTofConfig && fTofConfig->GetOptOutAVec()) { timesort(fTofConfig->GetOptOutAVec()); }
     if (fTrd1DConfig && fTrd1DConfig->GetOptOutAVec()) { timesort(fTrd1DConfig->GetOptOutAVec()); }
     if (fTrd2DConfig && fTrd2DConfig->GetOptOutAVec()) { timesort(fTrd2DConfig->GetOptOutAVec()); }
+    if (fBmonConfig && fBmonConfig->GetOptOutAVec()) { timesort(fBmonConfig->GetOptOutAVec()); }
   }
 }
 // ----------------------------------------------------------------------------
diff --git a/reco/steer/CbmRecoUnpack.h b/reco/steer/CbmRecoUnpack.h
index 0e9840c314..f8691aa096 100644
--- a/reco/steer/CbmRecoUnpack.h
+++ b/reco/steer/CbmRecoUnpack.h
@@ -12,6 +12,7 @@
 #ifndef CBMRECOUNPACK_H
 #define CBMRECOUNPACK_H 1
 
+#include "CbmBmonUnpackConfig.h"
 #include "CbmPsdUnpackConfig.h"
 #include "CbmRichUnpackConfig.h"
 #include "CbmStsUnpackConfig.h"
@@ -105,6 +106,13 @@ public:
   */
   void SetTimeSorting(bool bIn = true) { bOutputFullTimeSorting = bIn; }
 
+  /**
+   * @brief Enable/disable the data output. If On, data unpacked and monitored but neither sorted nor written to disk.
+   *
+   * @param value
+  */
+  void SetMonitoringOnly(bool bIn = true) { bMonitoringOnly = bIn; }
+
   /** @brief Set the Psd Unpack Config @param config */
   void SetUnpackConfig(std::shared_ptr<CbmPsdUnpackConfig> config) { fPsdConfig = config; }
 
@@ -123,6 +131,9 @@ public:
   /** @brief Set the Trd2D Unpack Config @param config */
   void SetUnpackConfig(std::shared_ptr<CbmTrdUnpackFaspConfig> config) { fTrd2DConfig = config; }
 
+  /** @brief Set the Bmon Unpack Config @param config */
+  void SetUnpackConfig(std::shared_ptr<CbmBmonUnpackConfig> config) { fBmonConfig = config; }
+
   /** @brief Trigger the unpacking procedure **/
   void Unpack(std::unique_ptr<fles::Timeslice> ts);
 
@@ -135,6 +146,7 @@ private:
   static constexpr std::uint16_t fkFlesTrd   = static_cast<std::uint16_t>(fles::SubsystemIdentifier::TRD);
   static constexpr std::uint16_t fkFlesTrd2D = static_cast<std::uint16_t>(fles::SubsystemIdentifier::TRD2D);
   static constexpr std::uint16_t fkFlesTof   = static_cast<std::uint16_t>(fles::SubsystemIdentifier::RPC);
+  static constexpr std::uint16_t fkFlesBmon  = static_cast<std::uint16_t>(fles::SubsystemIdentifier::T0);
 
   /** @brief Flag if extended debug output is to be printed or not*/
   bool fDoDebugPrints = false;  //!
@@ -277,29 +289,31 @@ private:
     auto digivec = algo->Unpack(ts, icomp);
 
     // Check if we want to write the output to somewhere (in pure online monitoring mode for example this can/would/should be skipped)
-    if (config->GetOutputVec()) {
-      // Lets do some time-sorting if we are not doing it later
-      if (!bOutputFullTimeSorting) timesort(&digivec);
-
-      // Transfer the data from the timeslice vector to the target branch vector
-      // Digis/default output retrieved as offered by the algorithm
-      for (auto digi : digivec)
-        config->GetOutputVec()->emplace_back(digi);
-    }
-    if (optouttargetvecA) {
-      // Lets do some timesorting
-      if (!bOutputFullTimeSorting) timesort(&optoutAvec);
-      // Transfer the data from the timeslice vector to the target branch vector
-      for (auto optoutA : optoutAvec)
-        optouttargetvecA->emplace_back(optoutA);
-    }
-    if (optouttargetvecB) {
-      // Second opt output is not time sorted to allow non GetTime data container.
-      // Lets do some timesorting
-      timesort(&optoutAvec);
-      // Transfer the data from the timeslice vector to the target branch vector
-      for (auto optoutB : optoutBvec)
-        optouttargetvecB->emplace_back(optoutB);
+    if (!bMonitoringOnly) {
+      if (config->GetOutputVec()) {
+        // Lets do some time-sorting if we are not doing it later
+        if (!bOutputFullTimeSorting) timesort(&digivec);
+
+        // Transfer the data from the timeslice vector to the target branch vector
+        // Digis/default output retrieved as offered by the algorithm
+        for (auto digi : digivec)
+          config->GetOutputVec()->emplace_back(digi);
+      }
+      if (optouttargetvecA) {
+        // Lets do some timesorting
+        if (!bOutputFullTimeSorting) timesort(&optoutAvec);
+        // Transfer the data from the timeslice vector to the target branch vector
+        for (auto optoutA : optoutAvec)
+          optouttargetvecA->emplace_back(optoutA);
+      }
+      if (optouttargetvecB) {
+        // Second opt output is not time sorted to allow non GetTime data container.
+        // Lets do some timesorting
+        timesort(&optoutAvec);
+        // Transfer the data from the timeslice vector to the target branch vector
+        for (auto optoutB : optoutBvec)
+          optouttargetvecB->emplace_back(optoutB);
+      }
     }
 
     std::clock_t cpuendtime = std::clock();
@@ -353,6 +367,9 @@ private:
   /** @brief Configuration of the Trd unpacker. Provides the configured algorithm */
   std::shared_ptr<CbmTrdUnpackFaspConfig> fTrd2DConfig = nullptr;  //!
 
+  /** @brief Configuration of the Bmon unpacker. Provides the configured algorithm */
+  std::shared_ptr<CbmBmonUnpackConfig> fBmonConfig = nullptr;  //!
+
   /** @brief Pointer to the Timeslice start time used to write it to the output tree @remark since we hand this to the FairRootManager it also wants to delete it and we do not have to take care of deletion */
   CbmTsEventHeader* fCbmTsEventHeader = nullptr;
 
@@ -362,8 +379,11 @@ private:
   /** @brief Flag to Enable/disable a full time sorting. If off, time sorting happens per link/FLIM source */
   bool bOutputFullTimeSorting = false;
 
+  /** @brief Flag to Enable/disable the output completely */
+  bool bMonitoringOnly = false;
+
 
-  ClassDef(CbmRecoUnpack, 1);
+  ClassDef(CbmRecoUnpack, 2);
 };
 
 
-- 
GitLab