From b8e756c96fe0d6e37a250fd820cf3e3f41a81d36 Mon Sep 17 00:00:00 2001
From: Felix Weiglhofer <weiglhofer@fias.uni-frankfurt.de>
Date: Tue, 16 May 2023 13:14:17 +0000
Subject: [PATCH] algo: Add STS data types.

---
 algo/CMakeLists.txt                 |   8 +-
 algo/base/gpu/Params.cxx            |   6 ++
 algo/base/gpu/Params.h              |  19 ++++
 algo/base/gpu/xpu_legacy.h          | 131 ++++++++++++++--------------
 algo/data/sts/Cluster.h             |  23 +++++
 algo/data/sts/Hit.h                 |  27 ++++++
 algo/data/sts/HitfinderPars.h       |  81 +++++++++++++++++
 algo/data/sts/LandauTable.cxx       |  31 +++++++
 algo/data/sts/LandauTable.h         |  25 ++++++
 algo/detectors/sts/UnpackStsXpu.cxx | 116 ++++++++++++------------
 algo/detectors/sts/UnpackStsXpu.h   |   8 +-
 11 files changed, 346 insertions(+), 129 deletions(-)
 create mode 100644 algo/base/gpu/Params.cxx
 create mode 100644 algo/base/gpu/Params.h
 create mode 100644 algo/data/sts/Cluster.h
 create mode 100644 algo/data/sts/Hit.h
 create mode 100644 algo/data/sts/HitfinderPars.h
 create mode 100644 algo/data/sts/LandauTable.cxx
 create mode 100644 algo/data/sts/LandauTable.h

diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt
index 8aa73488fb..20414a13a1 100644
--- a/algo/CMakeLists.txt
+++ b/algo/CMakeLists.txt
@@ -3,6 +3,7 @@ add_subdirectory(test)
 
 set(DEVICE_SRCS
   base/gpu/DeviceImage.cxx
+  base/gpu/Params.cxx
   detectors/sts/UnpackStsXpu.cxx
   detectors/sts/StsHitfinder.cxx
 )
@@ -10,6 +11,7 @@ set(DEVICE_SRCS
 set(SRCS
   ${DEVICE_SRCS}
   base/Options.cxx
+  data/sts/LandauTable.cxx
   evbuild/EventBuilder.cxx
   global/Reco.cxx
   trigger/TimeClusterTrigger.cxx
@@ -51,6 +53,7 @@ add_library(Algo SHARED ${SRCS})
 
 target_include_directories(Algo
   PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
+         ${CMAKE_CURRENT_SOURCE_DIR}/data
          ${CMAKE_CURRENT_SOURCE_DIR}/base
          ${CMAKE_CURRENT_SOURCE_DIR}/evbuild
          ${CMAKE_CURRENT_SOURCE_DIR}/global
@@ -77,9 +80,8 @@ target_compile_definitions(Algo PUBLIC NO_ROOT)
 xpu_attach(Algo ${DEVICE_SRCS})
 
 install(TARGETS Algo DESTINATION lib)
-install(DIRECTORY base/gpu TYPE INCLUDE
-  FILES_MATCHING PATTERN "*.h"
-)
+install(DIRECTORY base/gpu TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
+install(DIRECTORY data/sts TYPE INCLUDE FILES_MATCHING PATTERN "*.h")
 
 install(
   FILES       ca/simd/CaSimd.h
diff --git a/algo/base/gpu/Params.cxx b/algo/base/gpu/Params.cxx
new file mode 100644
index 0000000000..7dacbf36d7
--- /dev/null
+++ b/algo/base/gpu/Params.cxx
@@ -0,0 +1,6 @@
+/* Copyright (C) 2022 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Felix Weiglhofer [committer]*/
+#include "Params.h"
+
+XPU_EXPORT(cbm::algo::Params);
diff --git a/algo/base/gpu/Params.h b/algo/base/gpu/Params.h
new file mode 100644
index 0000000000..b5e3beb259
--- /dev/null
+++ b/algo/base/gpu/Params.h
@@ -0,0 +1,19 @@
+/* Copyright (C) 2022 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Felix Weiglhofer [committer] */
+#ifndef CBM_ALGO_GPU_CONFIG_H
+#define CBM_ALGO_GPU_CONFIG_H
+
+#include <xpu/device.h>
+
+#include "DeviceImage.h"
+#include "Prelude.h"
+#include "RecoParams.h"
+
+namespace cbm::algo
+{
+  struct Params : xpu::constant<GPUReco, RecoParams> {
+  };
+}  // namespace cbm::algo
+
+#endif
diff --git a/algo/base/gpu/xpu_legacy.h b/algo/base/gpu/xpu_legacy.h
index 861f15f2fe..fbdc3a17ef 100644
--- a/algo/base/gpu/xpu_legacy.h
+++ b/algo/base/gpu/xpu_legacy.h
@@ -6,98 +6,99 @@
 
 #include <xpu/host.h>
 
-namespace xpu {
+namespace xpu
+{
 
-inline constexpr auto host_to_device = xpu::h2d;
-inline constexpr auto device_to_host = xpu::d2h;
+  inline constexpr auto host_to_device = xpu::h2d;
+  inline constexpr auto device_to_host = xpu::d2h;
 
-template<typename T>
-class hd_buffer {
+  template<typename T>
+  class hd_buffer {
 
-public:
-  hd_buffer() = default;
-  hd_buffer(size_t size) : m_buffer(size, xpu::buf_io) {}
+  public:
+    hd_buffer() = default;
+    hd_buffer(size_t size) : m_buffer(size, xpu::buf_io) {}
 
-  T *h() { return xpu::h_view(m_buffer).begin(); }
-  T *d() { return m_buffer.get(); }
+    T* h() { return xpu::h_view(m_buffer).begin(); }
+    T* d() { return m_buffer.get(); }
 
-  xpu::buffer<T> &underlying() { return m_buffer; }
+    xpu::buffer<T>& underlying() { return m_buffer; }
 
-private:
-  xpu::buffer<T> m_buffer;
+  private:
+    xpu::buffer<T> m_buffer;
+  };
 
-};
+  template<typename T>
+  class d_buffer {
 
-template<typename T>
-class d_buffer {
+  public:
+    d_buffer() = default;
+    d_buffer(size_t size) : m_buffer(size, xpu::buf_device) {}
 
-public:
-  d_buffer() = default;
-  d_buffer(size_t size) : m_buffer(size, xpu::buf_device) {}
+    T* d() { return m_buffer.get(); }
 
-  T *d() { return m_buffer.get(); }
+    xpu::buffer<T>& underlying() { return m_buffer; }
 
-  xpu::buffer<T> &underlying() { return m_buffer; }
+  private:
+    xpu::buffer<T> m_buffer;
+  };
 
-private:
-  xpu::buffer<T> m_buffer;
 
-};
-
-
-template<typename T>
-void copy(hd_buffer<T> &buf, direction dir) {
-  static xpu::queue _Q;
-  _Q.copy(buf.underlying(), dir);
-  _Q.wait();
-}
+  template<typename T>
+  void copy(hd_buffer<T>& buf, direction dir)
+  {
+    static xpu::queue _Q;
+    _Q.copy(buf.underlying(), dir);
+    _Q.wait();
+  }
 
-enum class side {
-  host,
-  device
-};
+  enum class side
+  {
+    host,
+    device
+  };
 
-template<typename T, side S>
-struct cmem_io {
-  using type = T *;
-};
+  template<typename T, side S>
+  struct cmem_io {
+    using type = T*;
+  };
 
-template<typename T>
-struct cmem_io<T, side::host> {
-  using type = hd_buffer<T>;
-};
+  template<typename T>
+  struct cmem_io<T, side::host> {
+    using type = hd_buffer<T>;
+  };
 
-template<typename T, side S>
-using cmem_io_t = typename cmem_io<T, S>::type;
+  template<typename T, side S>
+  using cmem_io_t = typename cmem_io<T, S>::type;
 
-template<typename T, side S>
-struct cmem_device {
-  using type = T *;
-};
+  template<typename T, side S>
+  struct cmem_device {
+    using type = T*;
+  };
 
-template<typename T>
-struct cmem_device<T, side::host> {
-  using type = d_buffer<T>;
-};
+  template<typename T>
+  struct cmem_device<T, side::host> {
+    using type = d_buffer<T>;
+  };
 
-template<typename T, side S>
-using cmem_device_t = typename cmem_device<T, S>::type;
+  template<typename T, side S>
+  using cmem_device_t = typename cmem_device<T, S>::type;
 
-} // namespace xpu
+}  // namespace xpu
 
 #define XPU_BLOCK_SIZE_1D(...)
 
 #define XPU_EXPORT_KERNEL(Image, Kernel, ...) XPU_EXPORT_KERNEL_II(Image, Kernel, xpu::no_smem, 64, ##__VA_ARGS__)
 
-#define XPU_EXPORT_KERNEL_II(Image, Kernel, SMEM, BlockSize, ...) \
-  struct Kernel : xpu::kernel<Image> { \
-    using block_size = xpu::block_size<BlockSize>; \
-    using context = xpu::kernel_context<SMEM>; \
-    XPU_D void operator()(context &ctx, ##__VA_ARGS__); \
+#define XPU_EXPORT_KERNEL_II(Image, Kernel, SMEM, BlockSize, ...)                                                      \
+  struct Kernel : xpu::kernel<Image> {                                                                                 \
+    using block_size = xpu::block_size<BlockSize>;                                                                     \
+    using context    = xpu::kernel_context<SMEM>;                                                                      \
+    XPU_D void operator()(context& ctx, ##__VA_ARGS__);                                                                \
   }
 
-#define XPU_KERNEL(Kernel, smemIgnored, ...) \
-  XPU_EXPORT(Kernel); \
-  XPU_D void Kernel::operator()(context &ctx, ##__VA_ARGS__)
+#define XPU_KERNEL(Kernel, smemIgnored, ...)                                                                           \
+  XPU_EXPORT(Kernel);                                                                                                  \
+  XPU_D void Kernel::operator()(context& ctx, ##__VA_ARGS__)
 
 #endif
diff --git a/algo/data/sts/Cluster.h b/algo/data/sts/Cluster.h
new file mode 100644
index 0000000000..0cd4fd8636
--- /dev/null
+++ b/algo/data/sts/Cluster.h
@@ -0,0 +1,23 @@
+/* Copyright (C) 2022 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Felix Weiglhofer [committer]*/
+#ifndef CBM_ALGO_DATA_STS_CLUSTER_H
+#define CBM_ALGO_DATA_STS_CLUSTER_H
+
+#include "Prelude.h"
+
+namespace cbm::algo::sts
+{
+
+  struct Cluster {
+    real fCharge;         ///< Total charge
+    i32 fSize;            ///< Difference between first and last channel
+    real fPosition;       ///< Cluster centre in channel number units
+    real fPositionError;  ///< Cluster centre error (r.m.s.) in channel number units
+    u32 fTime;            ///< cluster time [ns]
+    real fTimeError;      ///< Error of cluster time [ns]
+  };
+
+}  // namespace cbm::algo::sts
+
+#endif  // CBM_ALGO_DATA_STS_CLUSTER_H
diff --git a/algo/data/sts/Hit.h b/algo/data/sts/Hit.h
new file mode 100644
index 0000000000..1a1aa6d9e0
--- /dev/null
+++ b/algo/data/sts/Hit.h
@@ -0,0 +1,27 @@
+/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Felix Weiglhofer [committer] */
+
+#ifndef CBM_ALGO_DATA_STS_HIT_H
+#define CBM_ALGO_DATA_STS_HIT_H
+
+#include "Prelude.h"
+
+namespace cbm::algo::sts
+{
+
+  struct Hit {
+    real fX, fY;      ///< X, Y positions of hit [cm]
+    real fZ;          ///< Z position of hit [cm]
+    u32 fTime;        ///< Hit time [ns]
+    real fDx, fDy;    ///< X, Y errors [cm]
+    real fDz;         ///< Z position error [cm]
+    real fDxy;        ///< XY correlation
+    real fTimeError;  ///< Error of hit time [ns]
+    real fDu;         ///< Error of coordinate across front-side strips [cm]
+    real fDv;         ///< Error of coordinate across back-side strips [cm]
+  };
+
+}  // namespace cbm::algo::sts
+
+#endif  // CBM_ALGO_DATA_STS_HIT_H
diff --git a/algo/data/sts/HitfinderPars.h b/algo/data/sts/HitfinderPars.h
new file mode 100644
index 0000000000..b89cf25a4b
--- /dev/null
+++ b/algo/data/sts/HitfinderPars.h
@@ -0,0 +1,81 @@
+/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Felix Weiglhofer [committer] */
+#ifndef CBM_ALGO_DATA_STS_HITFINDERPARS_H
+#define CBM_ALGO_DATA_STS_HITFINDERPARS_H
+
+#include "LandauTable.h"
+#include "Prelude.h"
+#include "config/Property.h"
+
+namespace cbm::algo::sts
+{
+  struct HitfinderPars {
+    struct Asic {
+      int nAdc;
+      float dynamicRange;
+      float threshold;
+      float timeResolution;
+      float deadTime;
+      float noise;
+      float zeroNoiseRate;
+
+      XPU_D float AdcToCharge(unsigned short adc) const
+      {
+        return threshold + dynamicRange / float(nAdc) * (float(adc) + 0.5f);
+      }
+
+      static constexpr auto Properties = std::make_tuple(
+        config::Property(&Asic::nAdc, "nAdc"), config::Property(&Asic::dynamicRange, "dynamicRange"),
+        config::Property(&Asic::threshold, "threshold"), config::Property(&Asic::timeResolution, "timeResolution"),
+        config::Property(&Asic::deadTime, "deadTime"), config::Property(&Asic::noise, "noise"),
+        config::Property(&Asic::zeroNoiseRate, "zeroNoiseRate"));
+    };
+
+    struct ModuleTransform {
+      // Rotation + translation matrix to transform
+      // local module coordinates into global coordinate system.
+      // No need for fancy math types here. These values are just copied
+      // and moved to the GPU.
+      // TODO: thats a lie, should use glm::mat3x4
+      std::array<float, 9> rotation;  // 3x3 matrix
+      std::array<float, 3> translation;
+
+      static constexpr auto Properties = std::make_tuple(
+        config::Property(&ModuleTransform::rotation, "rotation", "Rotation matrix", YAML::Flow),
+        config::Property(&ModuleTransform::translation, "translation", "Translation vector", YAML::Flow));
+    };
+
+    struct Module {
+      int32_t address;
+      float dY;
+      float pitch;
+      float stereoF;
+      float stereoB;
+      float lorentzF;
+      float lorentzB;
+      ModuleTransform localToGlobal;
+
+      static constexpr auto Properties = std::make_tuple(
+        config::Property(&Module::address, "address", "Hardware Address", YAML::Hex),
+        config::Property(&Module::dY, "dY"), config::Property(&Module::pitch, "pitch"),
+        config::Property(&Module::stereoF, "stereoF"), config::Property(&Module::stereoB, "stereoB"),
+        config::Property(&Module::lorentzF, "lorentzF"), config::Property(&Module::lorentzB, "lorentzB"),
+        config::Property(&Module::localToGlobal, "localToGlobal"));
+    };
+
+    Asic asic;
+    int nChannels;
+    std::vector<Module> modules;
+    LandauTable landauTable;  // Landau table for hitfinder, read from a seperate file
+
+    static constexpr auto Properties = std::make_tuple(
+      config::Property(&HitfinderPars::asic, "asic",
+                       "Asic definitions. Currently assumes same parameters for all asics."),
+      config::Property(&HitfinderPars::nChannels, "nChannels",
+                       "Total number of channels per module. Hitfinder assumes nChannels / 2 channels per side."),
+      config::Property(&HitfinderPars::modules, "modules"));
+  };
+}  // namespace cbm::algo::sts
+
+#endif
diff --git a/algo/data/sts/LandauTable.cxx b/algo/data/sts/LandauTable.cxx
new file mode 100644
index 0000000000..ba99e8b783
--- /dev/null
+++ b/algo/data/sts/LandauTable.cxx
@@ -0,0 +1,31 @@
+/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Felix Weiglhofer [committer] */
+#include "LandauTable.h"
+
+#include <fstream>
+
+using namespace cbm::algo;
+
+sts::LandauTable sts::LandauTable::FromFile(std::filesystem::path path)
+{
+  sts::LandauTable table;
+
+  std::vector<f32> charge;
+  std::vector<f32> prob;
+  std::ifstream file(path);
+
+  while (!file.eof()) {
+    f32 q, p;
+    file >> q >> p;
+    charge.push_back(q);
+    prob.push_back(p);
+  }
+
+  // TODO: check if charge is monotonically increasing, also more than 2 entries
+
+  table.stepSize = charge[1] - charge[0];
+  table.values   = std::move(prob);
+
+  return table;
+}
diff --git a/algo/data/sts/LandauTable.h b/algo/data/sts/LandauTable.h
new file mode 100644
index 0000000000..b6ab665e0e
--- /dev/null
+++ b/algo/data/sts/LandauTable.h
@@ -0,0 +1,25 @@
+/* Copyright (C) 2023 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Felix Weiglhofer [committer] */
+#ifndef CBM_ALGO_DATA_STS_LANDAUTABLE_H
+#define CBM_ALGO_DATA_STS_LANDAUTABLE_H
+
+#include <filesystem>
+#include <vector>
+
+#include "Prelude.h"
+
+namespace cbm::algo::sts
+{
+
+  struct LandauTable {
+
+    static LandauTable FromFile(std::filesystem::path path);
+
+    std::vector<f32> values;
+    f32 stepSize = 0;
+  };
+
+}  // namespace cbm::algo::sts
+
+#endif  // CBM_ALGO_DATA_STS_LANDAUTABLE_H
diff --git a/algo/detectors/sts/UnpackStsXpu.cxx b/algo/detectors/sts/UnpackStsXpu.cxx
index ab0dfcf45d..6d8f3aabb5 100644
--- a/algo/detectors/sts/UnpackStsXpu.cxx
+++ b/algo/detectors/sts/UnpackStsXpu.cxx
@@ -16,78 +16,80 @@ using std::unique_ptr;
 using std::vector;
 
 XPU_KERNEL(cbm::algo::UnpackK, xpu::no_smem, UnpackStsXpuPar* params, UnpackStsXpuElinkPar* elinkParams,
-             stsxyter::Message* content, uint64_t* msMessCount, uint64_t* msMessOffset, uint64_t* msStartTime,
-             uint32_t* msCompIdx, CbmStsDigi* digisOut, const uint64_t currentTsTime, int NElems)
-  {
-    int id = ctx.block_idx_x() * ctx.block_dim_x() + ctx.thread_idx_x();
-    if (id >= NElems || msMessCount[id] < 2) return;  // exit if out of bounds or too few messages
+           stsxyter::Message* content, uint64_t* msMessCount, uint64_t* msMessOffset, uint64_t* msStartTime,
+           uint32_t* msCompIdx, CbmStsDigi* digisOut, const uint64_t currentTsTime, int NElems)
+{
+  int id = ctx.block_idx_x() * ctx.block_dim_x() + ctx.thread_idx_x();
+  if (id >= NElems || msMessCount[id] < 2) return;  // exit if out of bounds or too few messages
 
-    UnpackStsXpuMonitorData monitor;  //Monitor data, currently not stored. TO DO: Implement!
+  UnpackStsXpuMonitorData monitor;  //Monitor data, currently not stored. TO DO: Implement!
 
-    // --- Get message count and offset for this MS
-    const uint32_t numMessages = msMessCount[id];
-    const uint32_t messOffset  = msMessOffset[id];
+  // --- Get message count and offset for this MS
+  const uint32_t numMessages = msMessCount[id];
+  const uint32_t messOffset  = msMessOffset[id];
 
-    // --- Get starting position of this MS in message buffer
-    stsxyter::Message* message = &content[messOffset];
+  // --- Get starting position of this MS in message buffer
+  stsxyter::Message* message = &content[messOffset];
 
-    // --- Get starting position of this MS in digi buffer
-    CbmStsDigi* digis = &digisOut[messOffset];
+  // --- Get starting position of this MS in digi buffer
+  CbmStsDigi* digis = &digisOut[messOffset];
 
-    // --- Get component index and unpack parameters of this MS
-    const uint32_t comp              = msCompIdx[id];
-    const UnpackStsXpuPar& unpackPar = params[comp];
+  // --- Get component index and unpack parameters of this MS
+  const uint32_t comp              = msCompIdx[id];
+  const UnpackStsXpuPar& unpackPar = params[comp];
 
-    // --- Get starting position of elink parameters of this MS
-    UnpackStsXpuElinkPar* elinkPar = &elinkParams[unpackPar.fElinkOffset];
+  // --- Get starting position of elink parameters of this MS
+  UnpackStsXpuElinkPar* elinkPar = &elinkParams[unpackPar.fElinkOffset];
 
-    // --- Init counter for produced digis
-    uint64_t numDigis = 0;
+  // --- Init counter for produced digis
+  uint64_t numDigis = 0;
 
-    // --- The first message in the MS is expected to be of type EPOCH and can be ignored.
-    if (message[0].GetMessType() != stsxyter::MessType::Epoch) {
-      monitor.fNumErrInvalidFirstMessage++;
-      msMessCount[id] = 0;
-      return;
-    }
+  // --- The first message in the MS is expected to be of type EPOCH and can be ignored.
+  if (message[0].GetMessType() != stsxyter::MessType::Epoch) {
+    monitor.fNumErrInvalidFirstMessage++;
+    msMessCount[id] = 0;
+    return;
+  }
 
-    // --- The second message must be of type ts_msb.
-    if (message[1].GetMessType() != stsxyter::MessType::TsMsb) {
-      monitor.fNumErrInvalidFirstMessage++;
-      msMessCount[id] = 0;
-      return;
-    }
+  // --- The second message must be of type ts_msb.
+  if (message[1].GetMessType() != stsxyter::MessType::TsMsb) {
+    monitor.fNumErrInvalidFirstMessage++;
+    msMessCount[id] = 0;
+    return;
+  }
 
-    // --- Current TS_MSB epoch cycle
-    uint64_t currentCycle = msStartTime[id] / UnpackStsXpu::fkCycleLength;
+  // --- Current TS_MSB epoch cycle
+  uint64_t currentCycle = msStartTime[id] / UnpackStsXpu::fkCycleLength;
 
-    // --- Process first message (ts_msb)
-    uint32_t currentEpoch     = 0;  ///< Current epoch number within epoch cycle
-    uint64_t currentEpochTime = 0;  ///< Current epoch time relative to timeslice in clock cycles
-    UnpackStsXpu::ProcessTsmsbMessage(message[1], currentEpoch, currentEpochTime, currentCycle, currentTsTime);
+  // --- Process first message (ts_msb)
+  uint32_t currentEpoch     = 0;  ///< Current epoch number within epoch cycle
+  uint64_t currentEpochTime = 0;  ///< Current epoch time relative to timeslice in clock cycles
+  UnpackStsXpu::ProcessTsmsbMessage(message[1], currentEpoch, currentEpochTime, currentCycle, currentTsTime);
 
-    // --- Message loop
-    for (uint32_t messageNr = 2; messageNr < numMessages; messageNr++) {
+  // --- Message loop
+  for (uint32_t messageNr = 2; messageNr < numMessages; messageNr++) {
 
-      // --- Action depending on message type
-      switch (message[messageNr].GetMessType()) {
-        case stsxyter::MessType::Hit: {
-          UnpackStsXpu::ProcessHitMessage(message[messageNr], digis, numDigis, unpackPar, elinkPar, monitor, currentEpochTime);
-          break;
-        }
-        case stsxyter::MessType::TsMsb: {
-          UnpackStsXpu::ProcessTsmsbMessage(message[messageNr], currentEpoch, currentEpochTime, currentCycle, currentTsTime);
-          break;
-        }
-        default: {
-          monitor.fNumNonHitOrTsbMessage++;
-          break;
-        }
+    // --- Action depending on message type
+    switch (message[messageNr].GetMessType()) {
+      case stsxyter::MessType::Hit: {
+        UnpackStsXpu::ProcessHitMessage(message[messageNr], digis, numDigis, unpackPar, elinkPar, monitor,
+                                        currentEpochTime);
+        break;
+      }
+      case stsxyter::MessType::TsMsb: {
+        UnpackStsXpu::ProcessTsmsbMessage(message[messageNr], currentEpoch, currentEpochTime, currentCycle,
+                                          currentTsTime);
+        break;
+      }
+      default: {
+        monitor.fNumNonHitOrTsbMessage++;
+        break;
       }
     }
-    // --- Store number of digis in buffer
-    msMessCount[id] = numDigis;
   }
+  // --- Store number of digis in buffer
+  msMessCount[id] = numDigis;
+}
 
 
 namespace cbm::algo
@@ -176,7 +178,7 @@ namespace cbm::algo
 
     // --- Do unpacking for each microslice
     xpu::run_kernel<UnpackK>(xpu::n_threads(numMs), fParams.d(), fElinkParams.d(), tsContent.d(), msMessCount.d(),
-                            msMessOffset.d(), msStartTime.d(), msCompIdx.d(), digisOut.d(), currentTsTime, numMs);
+                             msMessOffset.d(), msStartTime.d(), msCompIdx.d(), digisOut.d(), currentTsTime, numMs);
 
     // --- Copy results back to host (only two buffers are modified on device)
     xpu::copy(msMessCount, xpu::device_to_host);
diff --git a/algo/detectors/sts/UnpackStsXpu.h b/algo/detectors/sts/UnpackStsXpu.h
index f9da48db38..acd7857e56 100644
--- a/algo/detectors/sts/UnpackStsXpu.h
+++ b/algo/detectors/sts/UnpackStsXpu.h
@@ -7,8 +7,6 @@
 
 
 #include "CbmStsDigi.h"
-#include "gpu/DeviceImage.h"
-#include "gpu/xpu_legacy.h"
 
 #include "MicrosliceDescriptor.hpp"
 #include "Timeslice.hpp"
@@ -24,6 +22,8 @@
 
 #include "StsReadoutConfig.h"
 #include "StsXyterMessage.h"
+#include "gpu/DeviceImage.h"
+#include "gpu/xpu_legacy.h"
 
 
 namespace cbm::algo
@@ -76,8 +76,8 @@ namespace cbm::algo
   };
 
   XPU_EXPORT_KERNEL(GPUReco, UnpackK, UnpackStsXpuPar* params, UnpackStsXpuElinkPar* elinkParams,
-                  stsxyter::Message* content, uint64_t* msMessCount, uint64_t* msMessOffset, uint64_t* msStartTime,
-                  uint32_t* msCompIdx, CbmStsDigi* digisOut, const uint64_t currentTsTime, int NElems);
+                    stsxyter::Message* content, uint64_t* msMessCount, uint64_t* msMessOffset, uint64_t* msStartTime,
+                    uint32_t* msCompIdx, CbmStsDigi* digisOut, const uint64_t currentTsTime, int NElems);
 
   /** @class UnpackStsXpu
    ** @author Pierre-Alain Loizeau <p.-a.loizeau@gsi.de>
-- 
GitLab