From eee83311e4b78d228fc0d5bec26078a37a22ed65 Mon Sep 17 00:00:00 2001
From: Dominik Smith <smith@th.physik.uni-frankfurt.de>
Date: Fri, 24 May 2024 13:28:07 +0200
Subject: [PATCH] Added a third object to the return types of all unpackers in
 cbm::algo, which can store optional auxiliary data.

---
 algo/base/AlgoTraits.h            | 15 ++++++++++----
 algo/detectors/bmon/Unpack.h      |  2 +-
 algo/detectors/bmon/UnpackMS.cxx  | 20 +++++++++---------
 algo/detectors/bmon/UnpackMS.h    | 14 ++++++++++---
 algo/detectors/much/Unpack.h      |  2 +-
 algo/detectors/much/UnpackMS.cxx  | 14 ++++++-------
 algo/detectors/much/UnpackMS.h    | 10 ++++++++-
 algo/detectors/rich/Unpack.h      |  2 +-
 algo/detectors/rich/UnpackMS.cxx  |  6 +++---
 algo/detectors/rich/UnpackMS.h    | 10 ++++++++-
 algo/detectors/sts/Unpack.cxx     |  8 ++++----
 algo/detectors/sts/Unpack.h       |  2 +-
 algo/detectors/sts/UnpackMS.cxx   | 14 ++++++-------
 algo/detectors/sts/UnpackMS.h     | 11 +++++++++-
 algo/detectors/tof/Unpack.h       |  2 +-
 algo/detectors/tof/UnpackMS.cxx   | 24 +++++++++++-----------
 algo/detectors/tof/UnpackMS.h     | 11 +++++++++-
 algo/detectors/trd/Unpack.h       |  2 +-
 algo/detectors/trd/UnpackMS.cxx   | 34 +++++++++++++++----------------
 algo/detectors/trd/UnpackMS.h     | 10 ++++++++-
 algo/detectors/trd2d/Unpack.h     |  2 +-
 algo/detectors/trd2d/UnpackMS.cxx |  4 ++--
 algo/detectors/trd2d/UnpackMS.h   | 11 +++++++++-
 algo/global/Reco.cxx              |  3 ++-
 algo/unpack/CommonUnpacker.h      | 22 +++++++++++++-------
 algo/unpack/UnpackMSBase.h        |  5 +++--
 reco/tasks/CbmTaskUnpack.cxx      |  2 +-
 27 files changed, 169 insertions(+), 93 deletions(-)

diff --git a/algo/base/AlgoTraits.h b/algo/base/AlgoTraits.h
index 21954e3030..ecd14f99a4 100644
--- a/algo/base/AlgoTraits.h
+++ b/algo/base/AlgoTraits.h
@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include <tuple>
 #include <type_traits>
 
 /**
@@ -42,19 +43,25 @@ namespace cbm::algo::algo_traits
   template<typename Algo>
   using ResultOf_t = typename detail::ResultOf<Algo>::type;
 
-  // Currently assume algorithms return std::pair<R, M>
-  // where R is the output and M is the monitoring data
+  // Currently assume algorithms return std::tuple<R, M, A>
+  // where R is the output, M is the monitoring data and A is auxiliary data
 
   /**
    * @brief Type alias for the output type produced by an algorithm
    */
   template<typename Algo>
-  using Output_t = typename ResultOf_t<Algo>::first_type;
+  using Output_t = typename std::tuple_element<0, ResultOf_t<Algo>>::type;
 
   /**
    * @brief Type alias for the monitoring type produced by an algorithm
    */
   template<typename Algo>
-  using Monitor_t = typename ResultOf_t<Algo>::second_type;
+  using Monitor_t = typename std::tuple_element<1, ResultOf_t<Algo>>::type;
+
+  /**
+   * @brief Type alias for the auxiliary data type produced by an algorithm
+   */
+  template<typename Algo>
+  using Aux_t = typename std::tuple_element<2, ResultOf_t<Algo>>::type;
 
 }  // namespace cbm::algo::algo_traits
diff --git a/algo/detectors/bmon/Unpack.h b/algo/detectors/bmon/Unpack.h
index 9535c560ec..0a35e0cd1b 100644
--- a/algo/detectors/bmon/Unpack.h
+++ b/algo/detectors/bmon/Unpack.h
@@ -13,7 +13,7 @@ namespace cbm::algo::bmon
 
   namespace detail
   {
-    using UnpackBase = CommonUnpacker<CbmBmonDigi, UnpackMonitorData>;
+    using UnpackBase = CommonUnpacker<CbmBmonDigi, UnpackMonitorData, UnpackAuxData>;
   }
 
   class Unpack : public detail::UnpackBase {
diff --git a/algo/detectors/bmon/UnpackMS.cxx b/algo/detectors/bmon/UnpackMS.cxx
index da858f1519..c6a198f4f2 100644
--- a/algo/detectors/bmon/UnpackMS.cxx
+++ b/algo/detectors/bmon/UnpackMS.cxx
@@ -30,12 +30,12 @@ namespace cbm::algo::bmon
     // --- Number of messages in microslice
     auto msSize = msDescr.size;
     if (msSize % sizeof(critof001::Message) != 0) {
-      result.second.fNumErrInvalidMsSize++;
+      std::get<1>(result).fNumErrInvalidMsSize++;
       return result;
     }
     const uint32_t numMessages = msSize / sizeof(critof001::Message);
     if (numMessages < 2) {
-      result.second.fNumErrInvalidMsSize++;
+      std::get<1>(result).fNumErrInvalidMsSize++;
       return result;
     }
 
@@ -43,11 +43,11 @@ namespace cbm::algo::bmon
     auto message = reinterpret_cast<const critof001::Message*>(msContent);
 
     const uint32_t maxDigis = numMessages - 2;  // -2 for the TS_MSB and EPOCH messages
-    result.first.reserve(maxDigis);
+    std::get<0>(result).reserve(maxDigis);
 
     // --- The first message in the MS is expected to be of type EPOCH.
     if (message[0].getMessageType() != critof001::MSG_EPOCH) {
-      result.second.fNumErrInvalidFirstMessage++;
+      std::get<1>(result).fNumErrInvalidFirstMessage++;
       return result;
     }
 
@@ -55,7 +55,7 @@ namespace cbm::algo::bmon
       const uint64_t msStartEpoch =
         static_cast<uint64_t>(msDescr.idx / critof001::kuEpochInNs) % critof001::kulEpochCycleEp;
       if (message[0].getGdpbEpEpochNb() != msStartEpoch) {
-        result.second.fNumErrInvalidStartEpoch++;
+        std::get<1>(result).fNumErrInvalidStartEpoch++;
         return result;
       }
     }
@@ -69,7 +69,7 @@ namespace cbm::algo::bmon
 
     // --- The last message in the MS is expected to be EndOfMs.
     if (!message[numMessages - 1].isEndOfMs()) {
-      result.second.fNumErrInvalidLastMessage++;
+      std::get<1>(result).fNumErrInvalidLastMessage++;
       return result;
     }
     //Check if last message is "EndOfMs"!! Maybe loop to messageNr < numMessages - 1
@@ -81,7 +81,7 @@ namespace cbm::algo::bmon
       switch (message[messageNr].getMessageType()) {
 
         case critof001::MSG_HIT: {
-          ProcessHitMessage(message[messageNr], time, result.first, result.second);
+          ProcessHitMessage(message[messageNr], time, std::get<0>(result), std::get<1>(result));
           break;
         }
         case critof001::MSG_EPOCH: {
@@ -89,15 +89,15 @@ namespace cbm::algo::bmon
           break;
         }
         case critof001::MSG_SLOWC: {
-          result.second.fNumNonHitOrTsbMessage++;
+          std::get<1>(result).fNumNonHitOrTsbMessage++;
           break;
         }
         case critof001::MSG_SYST: {
-          result.second.fNumNonHitOrTsbMessage++;
+          std::get<1>(result).fNumNonHitOrTsbMessage++;
           break;
         }
         default: {
-          result.second.fNumNonHitOrTsbMessage++;
+          std::get<1>(result).fNumNonHitOrTsbMessage++;
           break;
         }
       }  //? Message type
diff --git a/algo/detectors/bmon/UnpackMS.h b/algo/detectors/bmon/UnpackMS.h
index af37710afa..9c893c5318 100644
--- a/algo/detectors/bmon/UnpackMS.h
+++ b/algo/detectors/bmon/UnpackMS.h
@@ -34,7 +34,7 @@ namespace cbm::algo::bmon
   /** @struct UnpackPar
    ** @author Volker Friese <v.friese@gsi.de>
    ** @since 25 November 2021
-   ** @brief Parameters required for the STS unpacking (specific to one component)
+   ** @brief Parameters required for the BMON unpacking (specific to one component)
    **/
   struct UnpackPar {
     std::vector<UnpackElinkPar> fElinkParams = {};  ///< Parameters for each eLink
@@ -44,7 +44,7 @@ namespace cbm::algo::bmon
   /** @struct UnpackMoni
    ** @author Volker Friese <v.friese@gsi.de>
    ** @since 2 December 2021
-   ** @brief Monitoring data for STS unpacking
+   ** @brief Monitoring data for BMON unpacking
    **/
   struct UnpackMonitorData {
     uint32_t fNumNonHitOrTsbMessage     = 0;
@@ -71,6 +71,14 @@ namespace cbm::algo::bmon
     }
   };
 
+  /** @struct UnpackAux
+   ** @author Dominik Smith <d.smith@gsi.de>
+   ** @since 24 May 2024
+   ** @brief Auxiliary data for BMON unpacking
+   **/
+  struct UnpackAuxData {
+    ///// TO BE FILLED
+  };
 
   /** @class Unpack
    ** @author Pierre-Alain Loizeau <p.-a.loizeau@gsi.de>
@@ -79,7 +87,7 @@ namespace cbm::algo::bmon
    ** @since 25 November 2021
    ** @brief Unpack algorithm for STS
    **/
-  class UnpackMS : public UnpackMSBase<CbmBmonDigi, UnpackMonitorData> {
+  class UnpackMS : public UnpackMSBase<CbmBmonDigi, UnpackMonitorData, UnpackAuxData> {
 
    public:
     /** @brief Construct from parameters **/
diff --git a/algo/detectors/much/Unpack.h b/algo/detectors/much/Unpack.h
index 191d421f96..b89719afb7 100644
--- a/algo/detectors/much/Unpack.h
+++ b/algo/detectors/much/Unpack.h
@@ -13,7 +13,7 @@ namespace cbm::algo::much
 
   namespace detail
   {
-    using UnpackBase = CommonUnpacker<CbmMuchDigi, UnpackMonitorData>;
+    using UnpackBase = CommonUnpacker<CbmMuchDigi, UnpackMonitorData, UnpackAuxData>;
   }
 
   class Unpack : public detail::UnpackBase {
diff --git a/algo/detectors/much/UnpackMS.cxx b/algo/detectors/much/UnpackMS.cxx
index 1274de56bd..d917fa4cda 100644
--- a/algo/detectors/much/UnpackMS.cxx
+++ b/algo/detectors/much/UnpackMS.cxx
@@ -45,30 +45,30 @@ namespace cbm::algo::much
     // --- Number of messages in microslice
     auto msSize = msDescr.size;
     if (msSize % sizeof(stsxyter::Message) != 0) {
-      result.second.fNumErrInvalidMsSize++;
+      std::get<1>(result).fNumErrInvalidMsSize++;
       return result;
     }
     const uint32_t numMessages = msSize / sizeof(stsxyter::Message);
     if (numMessages < 2) {
-      result.second.fNumErrInvalidMsSize++;
+      std::get<1>(result).fNumErrInvalidMsSize++;
       return result;
     }
 
     const uint32_t maxDigis = numMessages - 2;  // -2 for the TS_MSB and EPOCH messages
-    result.first.reserve(maxDigis);
+    std::get<0>(result).reserve(maxDigis);
 
     // --- Interpret MS content as sequence of SMX messages
     auto message = reinterpret_cast<const stsxyter::Message*>(msContent);
 
     // --- The first message in the MS is expected to be of type EPOCH and can be ignored.
     if (message[0].GetMessType() != stsxyter::MessType::Epoch) {
-      result.second.fNumErrInvalidFirstMessage++;
+      std::get<1>(result).fNumErrInvalidFirstMessage++;
       return result;
     }
 
     // --- The second message must be of type ts_msb.
     if (message[1].GetMessType() != stsxyter::MessType::TsMsb) {
-      result.second.fNumErrInvalidFirstMessage++;
+      std::get<1>(result).fNumErrInvalidFirstMessage++;
       return result;
     }
     ProcessTsmsbMessage(message[1], time);
@@ -80,7 +80,7 @@ namespace cbm::algo::much
       switch (message[messageNr].GetMessType()) {
 
         case stsxyter::MessType::Hit: {
-          ProcessHitMessage(message[messageNr], time, result.first, result.second);
+          ProcessHitMessage(message[messageNr], time, std::get<0>(result), std::get<1>(result));
           break;
         }
         case stsxyter::MessType::TsMsb: {
@@ -88,7 +88,7 @@ namespace cbm::algo::much
           break;
         }
         default: {
-          result.second.fNumNonHitOrTsbMessage++;
+          std::get<1>(result).fNumNonHitOrTsbMessage++;
           break;
         }
 
diff --git a/algo/detectors/much/UnpackMS.h b/algo/detectors/much/UnpackMS.h
index 1f9e413f84..c34b9e90b6 100644
--- a/algo/detectors/much/UnpackMS.h
+++ b/algo/detectors/much/UnpackMS.h
@@ -68,6 +68,14 @@ namespace cbm::algo::much
     }
   };
 
+  /** @struct UnpackAux
+   ** @author Dominik Smith <d.smith@gsi.de>
+   ** @since 24 May 2024
+   ** @brief Auxiliary data for BMON unpacking
+   **/
+  struct UnpackAuxData {
+    ///// TO BE FILLED
+  };
 
   /** @class UnpackMS
    ** @author Pierre-Alain Loizeau <p.-a.loizeau@gsi.de>
@@ -75,7 +83,7 @@ namespace cbm::algo::much
    ** @since 25 November 2021
    ** @brief Unpack algorithm for STS
    **/
-  class UnpackMS : public UnpackMSBase<CbmMuchDigi, UnpackMonitorData> {
+  class UnpackMS : public UnpackMSBase<CbmMuchDigi, UnpackMonitorData, UnpackAuxData> {
 
    public:
     /** @brief Construct with parameters **/
diff --git a/algo/detectors/rich/Unpack.h b/algo/detectors/rich/Unpack.h
index ec21c5d847..93f414f51a 100644
--- a/algo/detectors/rich/Unpack.h
+++ b/algo/detectors/rich/Unpack.h
@@ -13,7 +13,7 @@ namespace cbm::algo::rich
 
   namespace detail
   {
-    using UnpackBase = CommonUnpacker<CbmRichDigi, UnpackMonitorData>;
+    using UnpackBase = CommonUnpacker<CbmRichDigi, UnpackMonitorData, UnpackAuxData>;
   }
 
   class Unpack : public detail::UnpackBase {
diff --git a/algo/detectors/rich/UnpackMS.cxx b/algo/detectors/rich/UnpackMS.cxx
index 07c826e6d0..c59e211949 100644
--- a/algo/detectors/rich/UnpackMS.cxx
+++ b/algo/detectors/rich/UnpackMS.cxx
@@ -45,7 +45,7 @@ namespace cbm::algo::rich
     [[maybe_unused]] uint32_t msIndexWord1 = reader.NextWord();
     [[maybe_unused]] uint32_t msIndexWord2 = reader.NextWord();
 
-    return std::make_pair(std::move(ctx.digis), std::move(ctx.monitor));
+    return std::make_tuple(std::move(ctx.digis), std::move(ctx.monitor), UnpackAuxData());
   }
 
 
@@ -243,7 +243,7 @@ namespace cbm::algo::rich
       return;
     }
     else {
-      epoch = ProcessEpoch(word);
+      epoch    = ProcessEpoch(word);
       wasEpoch = true;
     }
 
@@ -280,7 +280,7 @@ namespace cbm::algo::rich
             return;
           }
           wasEpoch = true;
-          epoch = ProcessEpoch(word);
+          epoch    = ProcessEpoch(word);
           break;
         }
         case TdcWordType::Header: {
diff --git a/algo/detectors/rich/UnpackMS.h b/algo/detectors/rich/UnpackMS.h
index 0dd092c301..30e66555ab 100644
--- a/algo/detectors/rich/UnpackMS.h
+++ b/algo/detectors/rich/UnpackMS.h
@@ -105,8 +105,16 @@ namespace cbm::algo::rich
     }
   };
 
+  /** @struct UnpackAux
+   ** @author Dominik Smith <d.smith@gsi.de>
+   ** @since 24 May 2024
+   ** @brief Auxiliary data for BMON unpacking
+   **/
+  struct UnpackAuxData {
+    ///// TO BE FILLED
+  };
 
-  class UnpackMS : public UnpackMSBase<CbmRichDigi, UnpackMonitorData> {
+  class UnpackMS : public UnpackMSBase<CbmRichDigi, UnpackMonitorData, UnpackAuxData> {
 
    public:
     /** @brief Construct from parameters **/
diff --git a/algo/detectors/sts/Unpack.cxx b/algo/detectors/sts/Unpack.cxx
index c153322e42..e5f7003fe2 100644
--- a/algo/detectors/sts/Unpack.cxx
+++ b/algo/detectors/sts/Unpack.cxx
@@ -14,14 +14,14 @@ Unpack::Unpack(const Config& config) : fConfig(config)
   uint32_t numChansPerAsicSts   = 128;  // R/O channels per ASIC for STS
   uint32_t numAsicsPerModuleSts = 16;   // Number of ASICs per module for STS
 
-  constexpr u8 SystemVersion     = 0x20;
+  constexpr u8 SystemVersion = 0x20;
 
   auto equipIdsSts = fConfig.readout.GetEquipmentIds();
   for (auto& equip : equipIdsSts) {
     sts::UnpackPar par{};
-    par.fNumChansPerAsic    = numChansPerAsicSts;
-    par.fNumAsicsPerModule  = numAsicsPerModuleSts;
-    const size_t numElinks  = fConfig.readout.GetNumElinks(equip);
+    par.fNumChansPerAsic   = numChansPerAsicSts;
+    par.fNumAsicsPerModule = numAsicsPerModuleSts;
+    const size_t numElinks = fConfig.readout.GetNumElinks(equip);
     for (size_t elink = 0; elink < numElinks; elink++) {
       sts::UnpackElinkPar elinkPar;
       auto mapEntry        = fConfig.readout.Map(equip, elink);
diff --git a/algo/detectors/sts/Unpack.h b/algo/detectors/sts/Unpack.h
index 8391e86dc6..50e8720861 100644
--- a/algo/detectors/sts/Unpack.h
+++ b/algo/detectors/sts/Unpack.h
@@ -14,7 +14,7 @@ namespace cbm::algo::sts
 
   namespace detail
   {
-    using UnpackBase = CommonUnpacker<CbmStsDigi, UnpackMonitorData>;
+    using UnpackBase = CommonUnpacker<CbmStsDigi, UnpackMonitorData, UnpackAuxData>;
   }
 
   class Unpack : public detail::UnpackBase {
diff --git a/algo/detectors/sts/UnpackMS.cxx b/algo/detectors/sts/UnpackMS.cxx
index e4caf5b730..edb5c1a563 100644
--- a/algo/detectors/sts/UnpackMS.cxx
+++ b/algo/detectors/sts/UnpackMS.cxx
@@ -42,18 +42,18 @@ namespace cbm::algo::sts
     auto msSize = msDescr.size;
     if (msSize % sizeof(stsxyter::Message) != 0) {
       L_(error) << "Invalid microslice size: " << msSize;
-      result.second.fNumErrInvalidMsSize++;
+      std::get<1>(result).fNumErrInvalidMsSize++;
       return result;
     }
     const uint32_t numMessages = msSize / sizeof(stsxyter::Message);
     if (numMessages < 2) {
       L_(error) << "Microslice too small: " << numMessages;
-      result.second.fNumErrInvalidMsSize++;
+      std::get<1>(result).fNumErrInvalidMsSize++;
       return result;
     }
 
     const u32 maxDigis = numMessages - 2;  // -2 for the TS_MSB and EPOCH messages
-    result.first.reserve(maxDigis);
+    std::get<0>(result).reserve(maxDigis);
 
     // --- Interpret MS content as sequence of SMX messages
     auto message = reinterpret_cast<const stsxyter::Message*>(msContent);
@@ -61,14 +61,14 @@ namespace cbm::algo::sts
     // --- The first message in the MS is expected to be of type EPOCH and can be ignored.
     if (message[0].GetMessType() != stsxyter::MessType::Epoch) {
       L_(error) << "First message in microslice is not of type EPOCH";
-      result.second.fNumErrInvalidFirstMessage++;
+      std::get<1>(result).fNumErrInvalidFirstMessage++;
       return result;
     }
 
     // --- The second message must be of type ts_msb.
     if (message[1].GetMessType() != stsxyter::MessType::TsMsb) {
       L_(error) << "Second message in microslice is not of type TS_MSB";
-      result.second.fNumErrInvalidFirstMessage++;
+      std::get<1>(result).fNumErrInvalidFirstMessage++;
       return result;
     }
     ProcessTsmsbMessage(message[1], time);
@@ -80,7 +80,7 @@ namespace cbm::algo::sts
       switch (message[messageNr].GetMessType()) {
 
         case stsxyter::MessType::Hit: {
-          ProcessHitMessage(message[messageNr], time, result.first, result.second);
+          ProcessHitMessage(message[messageNr], time, std::get<0>(result), std::get<1>(result));
           break;
         }
         case stsxyter::MessType::TsMsb: {
@@ -88,7 +88,7 @@ namespace cbm::algo::sts
           break;
         }
         default: {
-          result.second.fNumNonHitOrTsbMessage++;
+          std::get<1>(result).fNumNonHitOrTsbMessage++;
           break;
         }
 
diff --git a/algo/detectors/sts/UnpackMS.h b/algo/detectors/sts/UnpackMS.h
index 33cb29bc0d..b115066d9b 100644
--- a/algo/detectors/sts/UnpackMS.h
+++ b/algo/detectors/sts/UnpackMS.h
@@ -73,13 +73,22 @@ namespace cbm::algo::sts
     }
   };
 
+  /** @struct UnpackStsAux
+   ** @author Dominik Smith <d.smith@gsi.de>
+   ** @since 24 May 2024
+   ** @brief Auxiliary data for STS unpacking
+   **/
+  struct UnpackAuxData {
+    std::vector<bool> fMissedEvent;  ///< Missed event flag for returned digis
+  };
+
   /** @class UnpackMS
    ** @author Pierre-Alain Loizeau <p.-a.loizeau@gsi.de>
    ** @author Volker Friese <v.friese@gsi.de>
    ** @since 25 November 2021
    ** @brief Unpack algorithm for STS
    **/
-  class UnpackMS : public UnpackMSBase<CbmStsDigi, UnpackMonitorData> {
+  class UnpackMS : public UnpackMSBase<CbmStsDigi, UnpackMonitorData, UnpackAuxData> {
 
    public:
     /** @brief Default constructor **/
diff --git a/algo/detectors/tof/Unpack.h b/algo/detectors/tof/Unpack.h
index 3b49776c29..a78ff079ab 100644
--- a/algo/detectors/tof/Unpack.h
+++ b/algo/detectors/tof/Unpack.h
@@ -12,7 +12,7 @@ namespace cbm::algo::tof
 
   namespace detail
   {
-    using UnpackBase = CommonUnpacker<CbmTofDigi, UnpackMonitorData>;
+    using UnpackBase = CommonUnpacker<CbmTofDigi, UnpackMonitorData, UnpackAuxData>;
   }
 
   class Unpack : public detail::UnpackBase {
diff --git a/algo/detectors/tof/UnpackMS.cxx b/algo/detectors/tof/UnpackMS.cxx
index 4294e61c65..b9cd5dcf01 100644
--- a/algo/detectors/tof/UnpackMS.cxx
+++ b/algo/detectors/tof/UnpackMS.cxx
@@ -24,8 +24,8 @@ namespace cbm::algo::tof
   {
 
     // --- Output data
-    Result_t result   = {};
-    TimeSpec time     = {};
+    Result_t result = {};
+    TimeSpec time   = {};
 
     // --- Current Timeslice start time in epoch units. Note that it is always a multiple of epochs
     // --- and the epoch is a multiple of ns.
@@ -34,12 +34,12 @@ namespace cbm::algo::tof
     // --- Number of messages in microslice
     auto msSize = msDescr.size;
     if (msSize % sizeof(critof001::Message) != 0) {
-      result.second.fNumErrInvalidMsSize++;
+      std::get<1>(result).fNumErrInvalidMsSize++;
       return result;
     }
     const uint32_t numMessages = msSize / sizeof(critof001::Message);
     if (numMessages < 2) {
-      result.second.fNumErrInvalidMsSize++;
+      std::get<1>(result).fNumErrInvalidMsSize++;
       return result;
     }
 
@@ -47,11 +47,11 @@ namespace cbm::algo::tof
     auto message = reinterpret_cast<const critof001::Message*>(msContent);
 
     const uint32_t maxDigis = numMessages - 2;  // -2 for the TS_MSB and EPOCH messages
-    result.first.reserve(maxDigis);
+    std::get<0>(result).reserve(maxDigis);
 
     // --- The first message in the MS is expected to be of type EPOCH.
     if (message[0].getMessageType() != critof001::MSG_EPOCH) {
-      result.second.fNumErrInvalidFirstMessage++;
+      std::get<1>(result).fNumErrInvalidFirstMessage++;
       return result;
     }
 
@@ -59,14 +59,14 @@ namespace cbm::algo::tof
       const uint64_t msStartEpoch =
         static_cast<uint64_t>(msDescr.idx / critof001::kuEpochInNs) % critof001::kulEpochCycleEp;
       if (message[0].getGdpbEpEpochNb() != msStartEpoch) {
-        result.second.fNumErrInvalidStartEpoch++;
+        std::get<1>(result).fNumErrInvalidStartEpoch++;
         return result;
       }
     }
 
     // --- The last message in the MS is expected to be EndOfMs.
     if (!message[numMessages - 1].isEndOfMs()) {
-      result.second.fNumErrInvalidLastMessage++;
+      std::get<1>(result).fNumErrInvalidLastMessage++;
       return result;
     }
     // Check if last message is "EndOfMs"!! Maybe loop to messageNr < numMessages - 1
@@ -78,7 +78,7 @@ namespace cbm::algo::tof
       switch (message[messageNr].getMessageType()) {
 
         case critof001::MSG_HIT: {
-          ProcessHitMessage(message[messageNr], result.first, result.second, time);
+          ProcessHitMessage(message[messageNr], std::get<0>(result), std::get<1>(result), time);
           break;
         }
         case critof001::MSG_EPOCH: {
@@ -86,15 +86,15 @@ namespace cbm::algo::tof
           break;
         }
         case critof001::MSG_SLOWC: {
-          result.second.fNumNonHitOrTsbMessage++;
+          std::get<1>(result).fNumNonHitOrTsbMessage++;
           break;
         }
         case critof001::MSG_SYST: {
-          result.second.fNumNonHitOrTsbMessage++;
+          std::get<1>(result).fNumNonHitOrTsbMessage++;
           break;
         }
         default: {
-          result.second.fNumNonHitOrTsbMessage++;
+          std::get<1>(result).fNumNonHitOrTsbMessage++;
           break;
         }
       }  //? Message type
diff --git a/algo/detectors/tof/UnpackMS.h b/algo/detectors/tof/UnpackMS.h
index c919418c59..1a1033cc6b 100644
--- a/algo/detectors/tof/UnpackMS.h
+++ b/algo/detectors/tof/UnpackMS.h
@@ -69,13 +69,22 @@ namespace cbm::algo::tof
     }
   };
 
+  /** @struct UnpackAux
+   ** @author Dominik Smith <d.smith@gsi.de>
+   ** @since 24 May 2024
+   ** @brief Auxiliary data for BMON unpacking
+   **/
+  struct UnpackAuxData {
+    ///// TO BE FILLED
+  };
+
   /** @class UnpackMS
    ** @author Pierre-Alain Loizeau <p.-a.loizeau@gsi.de>
    ** @author Volker Friese <v.friese@gsi.de>
    ** @since 25 November 2021
    ** @brief Unpack algorithm for STS
    **/
-  class UnpackMS : public UnpackMSBase<CbmTofDigi, UnpackMonitorData> {
+  class UnpackMS : public UnpackMSBase<CbmTofDigi, UnpackMonitorData, UnpackAuxData> {
 
    public:
     /** @brief Default constructor **/
diff --git a/algo/detectors/trd/Unpack.h b/algo/detectors/trd/Unpack.h
index 0791cd2f9c..91dc4d769c 100644
--- a/algo/detectors/trd/Unpack.h
+++ b/algo/detectors/trd/Unpack.h
@@ -13,7 +13,7 @@ namespace cbm::algo::trd
 
   namespace detail
   {
-    using UnpackBase = CommonUnpacker<CbmTrdDigi, UnpackMonitorData>;
+    using UnpackBase = CommonUnpacker<CbmTrdDigi, UnpackMonitorData, UnpackAuxData>;
   }
 
   class Unpack : public detail::UnpackBase {
diff --git a/algo/detectors/trd/UnpackMS.cxx b/algo/detectors/trd/UnpackMS.cxx
index d70d8810d7..40fdd3be35 100644
--- a/algo/detectors/trd/UnpackMS.cxx
+++ b/algo/detectors/trd/UnpackMS.cxx
@@ -423,7 +423,7 @@ namespace cbm::algo::trd
 
 
     // Digest the flags from the µSlice
-    digestMsFlags(msDescr.flags, result.second);
+    digestMsFlags(msDescr.flags, std::get<1>(result));
 
     size_t fMsStartTimeRel = (msDescr.idx - tTimeslice);
 
@@ -439,7 +439,7 @@ namespace cbm::algo::trd
       Spadic::NByteContainer<bytes> bCont = bp[iword];
       Spadic::FexWord<sys_ver> fw(bCont);
       if (fw.ht != 0) {
-        result.first.push_back(makeDigi(fw, fMsStartTimeRel));
+        std::get<0>(result).push_back(makeDigi(fw, fMsStartTimeRel));
       }
     }
     return result;
@@ -480,7 +480,7 @@ namespace cbm::algo::trd
     auto criId          = msDescr.eq_id;
 
     // Digest the flags from the µSlice
-    digestMsFlags(msDescr.flags, result.second);
+    digestMsFlags(msDescr.flags, std::get<1>(result));
 
     // Get the number of complete words in the input MS buffer.
     std::uint32_t nwords = mssize / fBytesPerWord;
@@ -488,7 +488,7 @@ namespace cbm::algo::trd
     // We have 32 bit spadic frames in this readout version
     const auto mscontent = reinterpret_cast<const size_t*>(msContent);
 
-    result.first.reserve(nwords);
+    std::get<0>(result).reserve(nwords);
 
     // Loop over all 64bit-Spadic-Words in the current µslice
     for (std::uint32_t istream = 0; istream < fStreamsPerWord; istream++) {
@@ -509,10 +509,10 @@ namespace cbm::algo::trd
 
         switch (kWordtype) {
           case Spadic::MsMessageType::kEPO: {
-            auto tsmsb = getTsMsb(frame, result.second);
+            auto tsmsb = getTsMsb(frame, std::get<1>(result));
             if (((tsmsb - currTsMsb) & 0x3f) == 1 || currTsMsb == -1) ctx.fNrTsMsbVec.at(istream)++;
             currTsMsb = tsmsb;
-            result.second.fNumEpochMsgs++;
+            std::get<1>(result).fNumEpochMsgs++;
             break;
             // FIXME in the kEPO msg we also have further flags that should be extracted
           }
@@ -543,7 +543,7 @@ namespace cbm::algo::trd
               // Ensure that we are on the correct eLink
               elinkId = (frame >> 24) & 0x3f;
               if (elinkId != raw.GetElinkId()) {
-                result.second.fNumElinkMis++;
+                std::get<1>(result).fNumElinkMis++;
               }
 
               // We have 22 adc bits per RDA word lets add them to the buffer...
@@ -571,7 +571,7 @@ namespace cbm::algo::trd
               // Ensure that we are on the correct eLink
               elinkId = (frame >> 24) & 0x3f;
               if (elinkId != raw.GetElinkId()) {
-                result.second.fNumElinkMis++;
+                std::get<1>(result).fNumElinkMis++;
               }
 
               // Number of samples indicator = nsamples % 4
@@ -603,44 +603,44 @@ namespace cbm::algo::trd
                 }
               }
               else {
-                result.second.fNumCorruptEom++;
+                std::get<1>(result).fNumCorruptEom++;
               }
-              result.second.fNumCreatedRawMsgs++;
+              std::get<1>(result).fNumCreatedRawMsgs++;
 
               // the message is done and the raw message container should contain everything we need.
               // So now we can call makeDigi(). Nevertheless there is a chance for a corrupted message,
               // which ends up with 0 samples so we have to check for it.
-              if (isample > 0) result.first.push_back(makeDigi(raw, ctx));
+              if (isample > 0) std::get<0>(result).push_back(makeDigi(raw, ctx));
             }
             else {
               // We move the word counter backwards by one, such that the unexpected message can correctly be digested
               iword--;
-              result.second.fNumMissingEom++;
+              std::get<1>(result).fNumMissingEom++;
             }
             break;
           }
           case Spadic::MsMessageType::kRDA: {
-            result.second.fNumWildRda++;
+            std::get<1>(result).fNumWildRda++;
             break;
           }
           case Spadic::MsMessageType::kEOM: {
-            result.second.fNumWildEom++;
+            std::get<1>(result).fNumWildEom++;
             break;
           }
           case Spadic::MsMessageType::kINF: {
-            result.second.fNumCreatedInfoMsgs++;
+            std::get<1>(result).fNumCreatedInfoMsgs++;
             digestInfoMsg(frame);
             break;
           }
           case Spadic::MsMessageType::kNUL: {
             // last word in Microslice is 0.
             if (iword != (nwords - 1) || (istream != (fStreamsPerWord - 1))) {
-              result.second.fNumWildNul++;
+              std::get<1>(result).fNumWildNul++;
             }
             break;
           }
           case Spadic::MsMessageType::kUNK: {
-            result.second.fNumUnknownWords++;
+            std::get<1>(result).fNumUnknownWords++;
             return result;
             break;
           }
diff --git a/algo/detectors/trd/UnpackMS.h b/algo/detectors/trd/UnpackMS.h
index 59d29bdf2b..35f0d874a5 100644
--- a/algo/detectors/trd/UnpackMS.h
+++ b/algo/detectors/trd/UnpackMS.h
@@ -92,6 +92,14 @@ namespace cbm::algo::trd
     }
   };
 
+  /** @struct UnpackAux
+   ** @author Dominik Smith <d.smith@gsi.de>
+   ** @since 24 May 2024
+   ** @brief Auxiliary data for BMON unpacking
+   **/
+  struct UnpackAuxData {
+    ///// TO BE FILLED
+  };
 
   /** @class Unpack
    ** @author Dominik Smith <d.smith@gsi.de>
@@ -99,7 +107,7 @@ namespace cbm::algo::trd
    ** @brief Unpack algorithm for TRD
    **/
   template<uint8_t sys_ver>
-  class UnpackMS : public UnpackMSBase<CbmTrdDigi, UnpackMonitorData> {
+  class UnpackMS : public UnpackMSBase<CbmTrdDigi, UnpackMonitorData, UnpackAuxData> {
 
    public:
     /** @brief Construct from parameters **/
diff --git a/algo/detectors/trd2d/Unpack.h b/algo/detectors/trd2d/Unpack.h
index 710a90093c..d2c1f37b9e 100644
--- a/algo/detectors/trd2d/Unpack.h
+++ b/algo/detectors/trd2d/Unpack.h
@@ -13,7 +13,7 @@ namespace cbm::algo::trd2d
 
   namespace detail
   {
-    using UnpackBase = CommonUnpacker<CbmTrdDigi, UnpackMonitorData>;
+    using UnpackBase = CommonUnpacker<CbmTrdDigi, UnpackMonitorData, UnpackAuxData>;
   }
 
   class Unpack : public detail::UnpackBase {
diff --git a/algo/detectors/trd2d/UnpackMS.cxx b/algo/detectors/trd2d/UnpackMS.cxx
index 4a51f76db1..714f4c2e81 100644
--- a/algo/detectors/trd2d/UnpackMS.cxx
+++ b/algo/detectors/trd2d/UnpackMS.cxx
@@ -92,8 +92,8 @@ namespace cbm::algo::trd2d
       }
       vMess.emplace_back(ch_id, kData, slice, data >> 1, crob_id, lFaspOld);
     }
-    result.first  = FinalizeComponent(ctx);  //TO DO: Original (non-algo) version calls this after MS loop!!
-    result.second = ctx.fMonitor;
+    std::get<0>(result) = FinalizeComponent(ctx);  //TO DO: Original (non-algo) version calls this after MS loop!!
+    std::get<1>(result) = ctx.fMonitor;
 
     return result;
   }
diff --git a/algo/detectors/trd2d/UnpackMS.h b/algo/detectors/trd2d/UnpackMS.h
index 6a280e1a39..18a498eecc 100644
--- a/algo/detectors/trd2d/UnpackMS.h
+++ b/algo/detectors/trd2d/UnpackMS.h
@@ -98,12 +98,21 @@ namespace cbm::algo::trd2d
     }
   };
 
+  /** @struct UnpackAux
+   ** @author Dominik Smith <d.smith@gsi.de>
+   ** @since 24 May 2024
+   ** @brief Auxiliary data for BMON unpacking
+   **/
+  struct UnpackAuxData {
+    ///// TO BE FILLED
+  };
+
   /** @class UnpackMS
    ** @author Dominik Smith <d.smith@gsi.de>
    ** @since 31 January 2023
    ** @brief Unpack algorithm for TRD
    **/
-  class UnpackMS : public UnpackMSBase<CbmTrdDigi, UnpackMonitorData> {
+  class UnpackMS : public UnpackMSBase<CbmTrdDigi, UnpackMonitorData, UnpackAuxData> {
 
    public:
     /** @brief Construct from parameters **/
diff --git a/algo/global/Reco.cxx b/algo/global/Reco.cxx
index 9a09c0f93b..4288d6df1b 100644
--- a/algo/global/Reco.cxx
+++ b/algo/global/Reco.cxx
@@ -409,8 +409,9 @@ auto Reco::RunUnpacker(const std::unique_ptr<Unpacker>& unpacker, const fles::Ti
   if (!unpacker) {
     return {};
   }
-  auto [digis, monitor] = (*unpacker)(ts);
+  auto [digis, monitor, aux] = (*unpacker)(ts);
   QueueUnpackerMetricsDet(monitor);
+  //// TO DO: Send aux somewhere!!
   return digis;
 }
 
diff --git a/algo/unpack/CommonUnpacker.h b/algo/unpack/CommonUnpacker.h
index c76119cdbd..76f182dc65 100644
--- a/algo/unpack/CommonUnpacker.h
+++ b/algo/unpack/CommonUnpacker.h
@@ -59,6 +59,11 @@ namespace cbm::algo
     std::vector<MSMonitor> msMonitor;  // monitoring data per microslice
   };
 
+  template<class MSAux>
+  struct UnpackAux {
+    std::vector<MSAux> msAux;  // auxiliary data per microslice
+  };
+
   struct UnpackKey {
     u16 eqId;
     u8 sysVer;
@@ -72,13 +77,14 @@ namespace cbm::algo
     }
   };
 
-  template<class Digi, class MSMonitor>
+  template<class Digi, class MSMonitor, class MSAux>
   class CommonUnpacker {
 
    protected:
     using Monitor_t = UnpackMonitor<MSMonitor>;
-    using Result_t  = std::pair<PODVector<Digi>, Monitor_t>;
-    using Unpack_t  = UnpackMSBase<Digi, MSMonitor>;
+    using Aux_t     = UnpackAux<MSAux>;
+    using Result_t  = std::tuple<PODVector<Digi>, Monitor_t, Aux_t>;
+    using Unpack_t  = UnpackMSBase<Digi, MSMonitor, MSAux>;
 
     std::map<UnpackKey, std::unique_ptr<Unpack_t>> fAlgos;  //< Equipment id to unpacker map. Filled by child class!
 
@@ -91,8 +97,9 @@ namespace cbm::algo
       const size_t numMs = msData.monitor.numMs;
 
       Result_t out;
-      auto& digisOut   = out.first;
-      auto& monitorOut = out.second;
+      auto& digisOut   = std::get<0>(out);
+      auto& monitorOut = std::get<1>(out);
+      auto& auxOut     = std::get<2>(out);
 
       static_cast<detail::UnpackMonitorBase&>(monitorOut) = msData.monitor;
 
@@ -123,8 +130,9 @@ namespace cbm::algo
         }
 
         auto result             = (*algo->second)(msData.msContent[i], msData.msDesc[i], ts.start_time());
-        msDigis[i]              = std::move(result.first);
-        monitorOut.msMonitor[i] = std::move(result.second);
+        msDigis[i]              = std::move(std::get<0>(result));
+        monitorOut.msMonitor[i] = std::move(std::get<1>(result));
+        auxOut.msAux[i]         = std::move(std::get<2>(result));
       }
       xpu::pop_timer();
 
diff --git a/algo/unpack/UnpackMSBase.h b/algo/unpack/UnpackMSBase.h
index d345eb05ef..10068e13c6 100644
--- a/algo/unpack/UnpackMSBase.h
+++ b/algo/unpack/UnpackMSBase.h
@@ -14,14 +14,15 @@ namespace fles
 namespace cbm::algo
 {
 
-  template<typename D, typename M>
+  template<typename D, typename M, typename A>
   class UnpackMSBase {
 
    public:
     using Digi_t    = D;
     using Monitor_t = M;
+    using Aux_t     = A;
 
-    using Result_t = std::pair<std::vector<Digi_t>, Monitor_t>;
+    using Result_t = std::tuple<std::vector<Digi_t>, Monitor_t, Aux_t>;
 
     virtual ~UnpackMSBase() = default;
 
diff --git a/reco/tasks/CbmTaskUnpack.cxx b/reco/tasks/CbmTaskUnpack.cxx
index e6a26d5e5a..b7bcae797a 100644
--- a/reco/tasks/CbmTaskUnpack.cxx
+++ b/reco/tasks/CbmTaskUnpack.cxx
@@ -353,7 +353,7 @@ template<class Unpacker>
 auto CbmTaskUnpack::RunUnpacker(const std::unique_ptr<Unpacker>& unpacker, const fles::Timeslice& timeslice,
                                 Monitor& monitor) -> cbm::algo::algo_traits::Output_t<Unpacker>
 {
-  auto [digis, detmon] = (*unpacker)(timeslice);
+  auto [digis, detmon, detaux] = (*unpacker)(timeslice);
   monitor.numCompUsed += detmon.numComponents;
   monitor.numMs += detmon.numMs;
   monitor.numBytes += detmon.sizeBytesIn;
-- 
GitLab