diff --git a/algo/CMakeLists.txt b/algo/CMakeLists.txt
index 19dacfe7d7988a80ee71cfd342b2228bc576a048..ac9e3f380412904997dfeceaef45b3df00b2257d 100644
--- a/algo/CMakeLists.txt
+++ b/algo/CMakeLists.txt
@@ -63,7 +63,6 @@ endif()
 set(DEVICE_SRCS
   base/gpu/DeviceImage.cxx
   base/gpu/Params.cxx
-  detectors/sts/UnpackStsXpu.cxx
   detectors/sts/Hitfinder.cxx
 )
 
diff --git a/algo/base/gpu/xpu_legacy.h b/algo/base/gpu/xpu_legacy.h
deleted file mode 100644
index 71e4f6bd6b158e133ae447f3a06516f666a39be8..0000000000000000000000000000000000000000
--- a/algo/base/gpu/xpu_legacy.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/* Copyright (C) 2022 FIAS Frankfurt Institute for Advanced Studies, Frankfurt / Main
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Felix Weiglhofer [committer]*/
-#ifndef CORE_COMPAT_XPU_LEGACY_H
-#define CORE_COMPAT_XPU_LEGACY_H
-
-#include <xpu/host.h>
-
-namespace xpu
-{
-
-  inline constexpr auto host_to_device = xpu::h2d;
-  inline constexpr auto device_to_host = xpu::d2h;
-
-  template<typename T>
-  class hd_buffer {
-
-   public:
-    hd_buffer() = default;
-    hd_buffer(size_t size) : m_buffer(size, xpu::buf_io) {}
-
-    T* h() { return xpu::h_view<T>(m_buffer).begin(); }
-    T* d() { return m_buffer.get(); }
-
-    xpu::buffer<T>& underlying() { return m_buffer; }
-
-   private:
-    xpu::buffer<T> m_buffer;
-  };
-
-  template<typename T>
-  class d_buffer {
-
-   public:
-    d_buffer() = default;
-    d_buffer(size_t size) : m_buffer(size, xpu::buf_device) {}
-
-    T* d() { return m_buffer.get(); }
-
-    xpu::buffer<T>& underlying() { return 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(T* dst, const T* src, size_t nelems)
-  {
-    static xpu::queue _Q;
-    _Q.copy(src, dst, nelems);
-    _Q.wait();
-  }
-
-  template<typename Kernel, typename... Args>
-  void run_kernel(xpu::grid params, Args&&... args)
-  {
-    static xpu::queue _Q;
-    _Q.launch<Kernel>(params, std::forward<Args>(args)...);
-    _Q.wait();
-  }
-
-  enum class side
-  {
-    host,
-    device
-  };
-
-  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, 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>
-  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;
-
-}  // 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_KERNEL(Kernel, smemIgnored, ...)                                                                           \
-  XPU_EXPORT(Kernel);                                                                                                  \
-  XPU_D void Kernel::operator()(context& ctx, ##__VA_ARGS__)
-
-#endif
diff --git a/algo/detectors/sts/HitfinderChain.h b/algo/detectors/sts/HitfinderChain.h
index 1926e3395be4d9b0ca184a50e69e4e1534d89750..8bd27cf5604438ba2ae93745c9b5d868499f37f6 100644
--- a/algo/detectors/sts/HitfinderChain.h
+++ b/algo/detectors/sts/HitfinderChain.h
@@ -9,7 +9,6 @@
 #include "PartitionedSpan.h"
 #include "PartitionedVector.h"
 #include "SubChain.h"
-#include "gpu/xpu_legacy.h"
 #include "sts/Hitfinder.h"
 #include "sts/HitfinderPars.h"
 #include "sts/LandauTable.h"
@@ -21,6 +20,8 @@
 #include <optional>
 #include <vector>
 
+#include <xpu/host.h>
+
 namespace cbm::algo::sts
 {
 
diff --git a/algo/detectors/sts/UnpackStsXpu.cxx b/algo/detectors/sts/UnpackStsXpu.cxx
deleted file mode 100644
index 8c66ec04da130fff07b4a29cc7f0c161b5448bb7..0000000000000000000000000000000000000000
--- a/algo/detectors/sts/UnpackStsXpu.cxx
+++ /dev/null
@@ -1,271 +0,0 @@
-/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Dominik Smith [committer] */
-
-#include "UnpackStsXpu.h"
-
-#include "StsXyterMessage.h"
-
-#include <cassert>
-#include <cmath>
-#include <utility>
-#include <vector>
-
-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
-
-  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 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 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];
-
-  // --- 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 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;
-
-  // --- 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++) {
-
-    // --- 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;
-}
-
-
-namespace cbm::algo
-{
-  // ----   Algorithm execution   ---------------------------------------------
-  UnpackStsXpu::resultType UnpackStsXpu::operator()(const fles::Timeslice* ts, sts::ReadoutConfigLegacy& config)
-  {
-    // --- Output data
-    resultType result = {};
-    std::cout << "Called UnpackStsXpu::operator()()." << std::endl;
-
-    // ---  Init local storage vectors
-    std::vector<stsxyter::Message> messages;  //storage of all messages
-    std::vector<uint64_t> messCount;          //storage of number of messages per MS
-    std::vector<uint64_t> messOffset;         //storage of MS offset in message buffer
-    std::vector<uint64_t> msIdx;              //storage of MS idx / start time
-    std::vector<uint32_t> compIdx;            //storage of comp idx for MS
-
-    auto equipIdsSts         = config.GetEquipmentIds();
-    const size_t numStsComps = equipIdsSts.size();
-
-    // --- Loop over components in unpacker config
-    for (size_t comp = 0; comp < numStsComps; comp++) {
-      auto equip = equipIdsSts[comp];
-      // --- Loop over components in timeslice
-      for (uint64_t tsComp = 0; tsComp < ts->num_components(); tsComp++) {
-
-        // --- Skip if TS component is not from STS (equipment IDs are non-unique across systems)
-        auto subsystem = static_cast<fles::Subsystem>(ts->descriptor(tsComp, 0).sys_id);
-        if (subsystem != fles::Subsystem::STS) continue;
-
-        if (equip == ts->descriptor(tsComp, 0).eq_id) {
-          const uint64_t numMsInComp = ts->num_microslices(tsComp);
-          for (uint64_t mslice = 0; mslice < numMsInComp; mslice++) {
-            const auto msDescr = ts->descriptor(tsComp, mslice);
-            if (msDescr.size % sizeof(stsxyter::Message) != 0) {
-              result.second.fNumErrInvalidMsSize++;
-              continue;
-            }
-            const uint32_t numMessages = msDescr.size / sizeof(stsxyter::Message);
-            if (numMessages < 2) {
-              result.second.fNumErrInvalidMsSize++;
-              continue;
-            }
-            xpu::t_add_bytes(msDescr.size);
-            xpu::k_add_bytes<UnpackK>(msDescr.size);
-            msIdx.push_back(msDescr.idx);
-            compIdx.push_back(comp);
-            messCount.push_back(numMessages);
-            messOffset.push_back(messages.size());
-            const auto msContent = ts->content(tsComp, mslice);
-            auto mess            = reinterpret_cast<const stsxyter::Message*>(msContent);
-            messages.insert(messages.end(), mess, mess + numMessages);
-          }
-        }
-      }
-    }
-    // --- Total number of microslices
-    const uint64_t numMs = messCount.size();
-
-    // --- Store SMX messages to be unpacked (TS content)
-    xpu::d_buffer<stsxyter::Message> tsContent{messages.size()};
-    xpu::copy(tsContent.d(), messages.data(), messages.size());
-
-    // --- Store auxiliary host-device buffers
-    xpu::hd_buffer<uint64_t> msMessCount{numMs};  //modified by kernel, stores numDigis after execution
-    xpu::copy(msMessCount.d(), messCount.data(), messCount.size());
-
-    xpu::hd_buffer<uint64_t> msMessOffset{numMs};  //unchanged but needed on device and host
-    std::copy(messOffset.begin(), messOffset.end(), msMessOffset.h());
-    xpu::copy(msMessOffset, xpu::host_to_device);
-
-    // --- Store auxiliary device buffers
-    xpu::d_buffer<uint64_t> msStartTime{numMs};
-    xpu::d_buffer<uint32_t> msCompIdx{numMs};
-    xpu::copy(msStartTime.d(), msIdx.data(), msIdx.size());
-    xpu::copy(msCompIdx.d(), compIdx.data(), compIdx.size());
-
-    // --- Create output buffer with maximum possible size
-    xpu::hd_buffer<CbmStsDigi> digisOut{messages.size()};
-
-    // --- Current Timeslice start time in epoch units. Note that it is always a multiple of epochs
-    // --- and the epoch is a multiple of ns.
-    const uint64_t epochLengthInNs = fkEpochLength * fkClockCycleNom / fkClockCycleDen;
-    const uint64_t currentTsTime   = ts->start_time() / epochLengthInNs;
-
-    // --- 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);
-
-    // --- Copy results back to host (only two buffers are modified on device)
-    xpu::copy(msMessCount, xpu::device_to_host);
-    xpu::copy(digisOut, xpu::device_to_host);
-
-    // --- Store digis  TO DO: make Kernel for this, needs a way to sum arrays in XPU first
-    xpu::push_timer("Store digis");
-    for (uint64_t i = 0; i < numMs; i++) {
-      uint64_t offset   = msMessOffset.h()[i];
-      uint64_t numDigis = msMessCount.h()[i];
-      for (uint64_t j = 0; j < numDigis; j++) {
-        result.first.push_back(digisOut.h()[offset + j]);
-      }
-    }
-    xpu::pop_timer();
-
-    return result;
-  }
-
-  // -----   Process hit message   --------------------------------------------
-  XPU_D inline void UnpackStsXpu::ProcessHitMessage(const stsxyter::Message& message, CbmStsDigi* digis,
-                                                    uint64_t& numDigis, const UnpackStsXpuPar& unpackPar,
-                                                    UnpackStsXpuElinkPar* elinkParams, UnpackStsXpuMonitorData& monitor,
-                                                    const uint64_t currentEpochTime)
-  {
-    // --- Check eLink and get parameters
-    uint16_t elink = message.GetLinkIndexHitBinning();
-    if (elink >= unpackPar.fNumElinks) {
-      monitor.fNumErrElinkOutOfRange++;
-      return;
-    }
-    const UnpackStsXpuElinkPar& elinkPar = elinkParams[elink];
-    uint32_t asicNr                      = elinkPar.fAsicNr;
-
-    // --- Hardware-to-software address
-    uint32_t channel = 0;
-    if (asicNr < unpackPar.fNumAsicsPerModule / 2) {  // front side (n side); channels counted upward
-      channel = message.GetHitChannel() + unpackPar.fNumChansPerAsic * asicNr;
-    }
-    else {  // back side (p side); channels counted downward
-      channel = unpackPar.fNumChansPerAsic * (asicNr + 1) - message.GetHitChannel() - 1;
-    }
-
-    // --- Expand time stamp to time within timeslice (in clock cycle)
-    uint64_t messageTime = message.GetHitTimeBinning() + currentEpochTime;
-
-    // --- Convert time stamp from clock cycles to ns. Round to nearest full ns.
-    messageTime = (messageTime * fkClockCycleNom + fkClockCycleDen / 2) / fkClockCycleDen;
-
-    // --- Correct ASIC-wise offsets
-    messageTime -= elinkPar.fTimeOffset;
-    // --- TODO: Add walk correction (depends on ADC)
-
-    // --- Charge
-    double charge = elinkPar.fAdcOffset + (message.GetHitAdc() - 1) * elinkPar.fAdcGain;
-
-    // --- Create output digi
-    digis[numDigis] = CbmStsDigi(elinkPar.fAddress, channel, messageTime, charge);
-    numDigis++;
-  }
-  // --------------------------------------------------------------------------
-
-
-  // -----   Process an epoch (TS_MSB) message   ------------------------------
-  XPU_D inline void UnpackStsXpu::ProcessTsmsbMessage(const stsxyter::Message& message, uint32_t& currentEpoch,
-                                                      uint64_t& currentEpochTime, uint64_t& currentCycle,
-                                                      const uint64_t currentTsTime)
-  {
-    // The compression of time is based on the hierarchy epoch cycle - epoch - message time.
-    // Cycles are counted from the start of Unix time and are multiples of an epoch (ts_msb).
-    // The epoch number is counted within each cycle. The time in the hit message is expressed
-    // in units of the readout clock cycle relative to the current epoch.
-    // The ts_msb message indicates the start of a new epoch. Its basic information is the epoch
-    // number within the current cycle. A cycle wrap resets the epoch number to zero, so it is
-    // indicated by the epoch number being smaller than the previous one (epoch messages are
-    // seemingly not consecutively in the data stream, but only if there are hit messages in between).
-    auto epoch = message.GetTsMsbValBinning();
-
-    // --- Cycle wrap
-    if (epoch < currentEpoch) currentCycle++;
-
-    // --- Update current epoch counter
-    currentEpoch = epoch;
-
-    // --- Calculate epoch time in clocks cycles relative to timeslice start time
-    currentEpochTime = (currentCycle * fkEpochsPerCycle + epoch - currentTsTime) * fkEpochLength;
-  }
-  // --------------------------------------------------------------------------
-
-
-} /* namespace cbm::algo */
diff --git a/algo/detectors/sts/UnpackStsXpu.h b/algo/detectors/sts/UnpackStsXpu.h
deleted file mode 100644
index d30df029fcf0dbc799609256a8d56a778358716e..0000000000000000000000000000000000000000
--- a/algo/detectors/sts/UnpackStsXpu.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Dominik Smith [committer] */
-
-#ifndef CBM_ALGO_UNPACKSTSXPU_H
-#define CBM_ALGO_UNPACKSTSXPU_H 1
-
-
-#include "CbmStsDigi.h"
-#include "MicrosliceDescriptor.hpp"
-#include "ReadoutConfigLegacy.h"
-#include "StsXyterMessage.h"
-#include "Timeslice.hpp"
-#include "gpu/DeviceImage.h"
-#include "gpu/xpu_legacy.h"
-
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-#include <memory>
-#include <vector>
-
-#include <xpu/device.h>
-#include <xpu/host.h>
-
-
-namespace cbm::algo
-{
-
-  /** @struct UnpackStsXpuElinkPar
-   ** @author Volker Friese <v.friese@gsi.de>
-   ** @since 25 November 2021
-   ** @brief STS Unpacking parameters for one eLink / ASIC
-   **/
-  struct UnpackStsXpuElinkPar {
-    int32_t fAddress     = 0;   ///< CbmStsAddress for the connected module
-    uint32_t fAsicNr     = 0;   ///< Number of connected ASIC within the module
-    uint64_t fTimeOffset = 0.;  ///< Time calibration parameter
-    double fAdcOffset    = 0.;  ///< Charge calibration parameter
-    double fAdcGain      = 0.;  ///< Charge calibration parameter
-  };
-
-
-  /** @struct UnpackStsXpuPar
-   ** @author Volker Friese <v.friese@gsi.de>
-   ** @since 25 November 2021
-   ** @brief Parameters required for the STS unpacking (specific to one component)
-   **/
-  struct UnpackStsXpuPar {
-    uint32_t fNumChansPerAsic   = 0;  ///< Number of channels per ASIC
-    uint32_t fNumAsicsPerModule = 0;  ///< Number of ASICS per module
-    uint32_t fNumElinks         = 0;  ///< Number of elinks for this component
-    uint32_t fElinkOffset       = 0;  ///< Elink index offset for this component
-  };
-
-
-  /** @struct UnpackStsXpuMoni
-   ** @author Volker Friese <v.friese@gsi.de>
-   ** @since 2 December 2021
-   ** @brief Monitoring data for STS unpacking
-   **/
-  struct UnpackStsXpuMonitorData {
-    uint32_t fNumNonHitOrTsbMessage     = 0;
-    uint32_t fNumErrElinkOutOfRange     = 0;  ///< Elink not contained in parameters
-    uint32_t fNumErrInvalidFirstMessage = 0;  ///< First message is not TS_MSB or second is not EPOCH
-    uint32_t fNumErrInvalidMsSize       = 0;  ///< Microslice size is not multiple of message size
-    uint32_t fNumErrTimestampOverflow   = 0;  ///< Overflow in 64 bit time stamp
-    bool HasErrors()
-    {
-      uint32_t numErrors = fNumNonHitOrTsbMessage + fNumErrElinkOutOfRange + fNumErrInvalidFirstMessage
-                           + fNumErrInvalidMsSize + fNumErrTimestampOverflow;
-      return (numErrors > 0 ? true : false);
-    }
-  };
-
-  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);
-
-  /** @class UnpackStsXpu
-   ** @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 UnpackStsXpu {
-
-   public:
-    typedef std::pair<std::vector<CbmStsDigi>, UnpackStsXpuMonitorData> resultType;
-
-    /** @brief Default constructor **/
-    UnpackStsXpu(){};
-
-
-    /** @brief Destructor **/
-    ~UnpackStsXpu(){};
-
-
-    /** @brief Algorithm execution
-     ** @return STS digi data
-     ** @param  ts      Timselice payload
-     ** @param  config  Configuration data
-     ** @return STS digi data
-     **/
-    resultType operator()(const fles::Timeslice* ts, sts::ReadoutConfigLegacy& config);
-
-    //Stores parameter structs for all elinks
-    xpu::hd_buffer<UnpackStsXpuElinkPar> fElinkParams;
-
-
-    //Stores parameter structs for all components
-    xpu::hd_buffer<UnpackStsXpuPar> fParams;
-
-
-   private:  // methods
-    friend struct UnpackK;
-
-    /** @brief Process a hit message
-     ** @param message SMX message (32-bit word)
-     ** @param digi buffer
-     ** @param digi counter
-     ** @param parameters for component
-     ** @param parameter buffer for elinks
-     ** @param reference to monitor object
-     ** @param current epoch number within epoch cycle
-     **/
-    XPU_D static void ProcessHitMessage(const stsxyter::Message& message, CbmStsDigi* digis, uint64_t& numDigis,
-                                        const UnpackStsXpuPar& unpackPar, UnpackStsXpuElinkPar* elinkParams,
-                                        UnpackStsXpuMonitorData& monitor, const uint64_t currentEpochTime);
-
-    /** @brief Process an epoch message (TS_MSB)
-     ** @param message SMX message (32-bit word)
-     ** @param current epoch number within epoch cycle
-     ** @param current epoch time relative to timeslice in clock cycles
-     ** @param current TS_MSB epoch cycle
-     **/
-    XPU_D static void ProcessTsmsbMessage(const stsxyter::Message& message, uint32_t& currentEpoch,
-                                          uint64_t& currentEpochTime, uint64_t& currentCycle,
-                                          const uint64_t currentTsTime);
-
-   private:  // members
-            ///// To do: Make these available on device somehow
-    /** Number of TS_MSB epochs per cycle **/
-    static constexpr uint64_t fkEpochsPerCycle = stsxyter::kuTsMsbNbTsBinsBinning;
-
-    /** Length of TS_MSB epoch in clock cycles **/
-    static constexpr uint64_t fkEpochLength = stsxyter::kuHitNbTsBinsBinning;
-
-    /** Clock cycle nominator [ns] and denominator. The clock cycle in ns is nominator / denominator. **/
-    static constexpr uint32_t fkClockCycleNom = stsxyter::kulClockCycleNom;
-    static constexpr uint32_t fkClockCycleDen = stsxyter::kulClockCycleDen;
-
-    /** Epoch cycle length in ns **/
-    static constexpr uint64_t fkCycleLength = (fkEpochsPerCycle * fkEpochLength * fkClockCycleNom) / fkClockCycleDen;
-  };
-
-
-} /* namespace cbm::algo */
-
-#endif /* CBM_ALGO_UNPACKSTSXPU_H */
diff --git a/reco/tasks/CMakeLists.txt b/reco/tasks/CMakeLists.txt
index ee2b8541c2541f662849480e9ec6f98eecb6dc4b..76d5677cc0654c8261dbc79e77c4ee7b95898241 100644
--- a/reco/tasks/CMakeLists.txt
+++ b/reco/tasks/CMakeLists.txt
@@ -18,7 +18,6 @@ set(SRCS
   CbmTaskTofClusterizer.cxx
   CbmTaskTofClusterizerParWrite.cxx
   CbmTaskUnpack.cxx
-  CbmTaskUnpackXpu.cxx
 )
 
 
diff --git a/reco/tasks/CbmRecoTasksLinkDef.h b/reco/tasks/CbmRecoTasksLinkDef.h
index 3b84f429166ea88e85ec2626922898e8c5881bb9..8f829d3dfc1396d159981bfab070b6d89b98fd3a 100644
--- a/reco/tasks/CbmRecoTasksLinkDef.h
+++ b/reco/tasks/CbmRecoTasksLinkDef.h
@@ -22,7 +22,6 @@
 #pragma link C++ class CbmTaskTofClusterizerParWrite + ;
 #pragma link C++ class CbmTaskTriggerDigi + ;
 #pragma link C++ class CbmTaskUnpack + ;
-#pragma link C++ class CbmTaskUnpackXpu + ;
 //#pragma link C++ class cbm::algo::MainConfig + ;
 
 
diff --git a/reco/tasks/CbmTaskUnpackXpu.cxx b/reco/tasks/CbmTaskUnpackXpu.cxx
deleted file mode 100644
index 07d8fe1a589cb64d6904e1991458ddd41ff6b2f0..0000000000000000000000000000000000000000
--- a/reco/tasks/CbmTaskUnpackXpu.cxx
+++ /dev/null
@@ -1,182 +0,0 @@
-/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Dominik Smith [committer] */
-
-
-#include "CbmTaskUnpackXpu.h"
-
-#include "CbmDefs.h"
-#include "CbmDigiBranchBase.h"
-#include "CbmDigiEvent.h"
-#include "CbmDigiManager.h"
-#include "CbmDigiTimeslice.h"
-#include "CbmSourceTs.h"
-
-#include "MicrosliceDescriptor.hpp"
-
-#include <FairRunOnline.h>
-#include <Logger.h>
-
-#include <TStopwatch.h>
-
-#include <algorithm>
-#include <cassert>
-#include <cstdint>
-#include <iomanip>
-#include <memory>
-#include <sstream>
-#include <vector>
-
-#include <xpu/host.h>
-
-#include "compat/Algorithm.h"
-
-using namespace std;
-using cbm::algo::UnpackStsXpuElinkPar;
-using cbm::algo::UnpackStsXpuPar;
-
-// -----   Constructor   -----------------------------------------------------
-CbmTaskUnpackXpu::CbmTaskUnpackXpu() : FairTask("Unpack") {}
-// ---------------------------------------------------------------------------
-
-
-// -----   Destructor   ------------------------------------------------------
-CbmTaskUnpackXpu::~CbmTaskUnpackXpu()
-{
-  if (fTimeslice) delete fTimeslice;
-}
-// ---------------------------------------------------------------------------
-
-
-// -----   Execution   -------------------------------------------------------
-void CbmTaskUnpackXpu::Exec(Option_t*)
-{
-  // --- Reset output branch (CbmDigiTimeslice)
-  fTimeslice->Clear();
-
-  // --- Get FLES timeslice
-  assert(fSource);
-  fles::Timeslice* timeslice = fSource->GetTimeslice();
-  assert(timeslice);
-
-  // --- Timer and counters
-  TStopwatch timer;
-  timer.Start();
-
-  //Run STS unpacker and store result
-  auto resultSts = fAlgoStsXpu(timeslice, fStsConfig);
-  fTimeslice->fData.fSts.fDigis.insert(fTimeslice->fData.fSts.fDigis.end(), resultSts.first.begin(),
-                                       resultSts.first.end());
-
-  // --- Sorting of output digis. Is required by both digi trigger and event builder.
-  cbm::algo::Sort(fTimeslice->fData.fSts.fDigis.begin(), fTimeslice->fData.fSts.fDigis.end(),
-                  [](CbmStsDigi digi1, CbmStsDigi digi2) { return digi1.GetTime() < digi2.GetTime(); });
-
-
-  // --- Timeslice log
-  timer.Stop();
-  stringstream logOut;
-  logOut << setw(15) << left << GetName() << " [";
-  logOut << fixed << setw(8) << setprecision(1) << right << timer.RealTime() * 1000. << " ms] ";
-  logOut << "TS " << fNumTs << " (index " << timeslice->index() << ")";
-  logOut << ", digis " << fTimeslice->fData.fSts.fDigis.size();
-  LOG(info) << logOut.str();
-
-  // --- Run statistics
-  fNumTs++;
-  // TO DO: implement these
-  //fNumMs += numMs;
-  //fNumBytes += numBytes;
-  //fNumDigis += numDigis;
-  fTime += timer.RealTime();
-}
-
-
-// -----   End-of-run action   ------------------------------------------------
-void CbmTaskUnpackXpu::Finish()
-{
-  double timePerTs = 1000. * fTime / double(fNumTs);  // in ms
-  double rate      = fNumBytes / 1.e6 / fTime;        // in MB/s
-  LOG(info) << "=====================================";
-  LOG(info) << GetName() << ": Run summary";
-  LOG(info) << "Timeslices     : " << fNumTs;
-  LOG(info) << "Microslices    : " << fNumMs;
-  LOG(info) << "Digis          : " << fNumDigis;
-  LOG(info) << "Av. input rate : " << fixed << setprecision(2) << rate << " MB/s";
-  LOG(info) << "Time / TS      : " << fixed << setprecision(2) << timePerTs << " ms";
-  LOG(info) << "=====================================";
-}
-// ----------------------------------------------------------------------------
-
-
-// -----   Initialisation   ---------------------------------------------------
-InitStatus CbmTaskUnpackXpu::Init()
-{
-  // FIXME: this has to be called only once
-  // and should happen during initialization not in reco loop
-  setenv("XPU_PROFILE", "1", 1);
-  xpu::initialize();
-
-  LOG(info) << "==================================================";
-  LOG(info) << GetName() << ": Initialising...";
-
-  // --- Get source instance
-  fSource = dynamic_cast<CbmSourceTs*>(FairRunOnline::Instance()->GetSource());
-  if (fSource == nullptr) {
-    LOG(error) << GetName() << ": No valid source class registered!";
-    return kFATAL;
-  }
-  LOG(info) << "--- Found CbmSourceTs instance";
-
-  // --- Get FairRootManager instance
-  FairRootManager* ioman = FairRootManager::Instance();
-  assert(ioman);
-
-  // --- Register output array (CbmDigiTimeslice)
-  if (ioman->GetObject("DigiTimeslice")) {
-    LOG(fatal) << GetName() << ": Branch DigiTimeslice already exists!";
-    return kFATAL;
-  }
-  fTimeslice = new CbmDigiTimeslice();
-  ioman->RegisterAny("DigiTimeslice.", fTimeslice, IsOutputBranchPersistent("DigiTimeslice."));
-  LOG(info) << "--- Registered branch DigiTimeslice.";
-
-  // Initialize parameter buffers for STS
-  auto equipIdsSts          = fStsConfig.GetEquipmentIds();
-  const size_t numStsElinks = fStsConfig.GetNumElinks();
-  const size_t numStsComps  = equipIdsSts.size();
-  fAlgoStsXpu.fParams       = xpu::hd_buffer<UnpackStsXpuPar>(numStsComps);
-  fAlgoStsXpu.fElinkParams  = xpu::hd_buffer<UnpackStsXpuElinkPar>(numStsElinks);
-
-  // --- Common parameters for all components for STS
-  uint32_t numChansPerAsicSts   = 128;  // R/O channels per ASIC for STS
-  uint32_t numAsicsPerModuleSts = 16;   // Number of ASICs per module for STS
-
-  // Fill parameter buffers for STS
-  for (size_t comp = 0; comp < numStsComps; comp++) {
-    auto equip                      = equipIdsSts[comp];
-    auto params                     = fAlgoStsXpu.fParams.h();
-    auto numElinks                  = fStsConfig.GetNumElinks(equip);
-    params[comp].fNumElinks         = numElinks;
-    params[comp].fNumChansPerAsic   = numChansPerAsicSts;
-    params[comp].fNumAsicsPerModule = numAsicsPerModuleSts;
-    params[comp].fElinkOffset       = (comp == 0) ? 0 : params[comp - 1].fElinkOffset + params[comp - 1].fNumElinks;
-    for (size_t elink = 0; elink < numElinks; elink++) {
-      UnpackStsXpuElinkPar& elinkPar = fAlgoStsXpu.fElinkParams.h()[params[comp].fElinkOffset + elink];
-      auto mapEntry                  = fStsConfig.Map(equip, elink);
-      elinkPar.fAddress              = mapEntry.first;   // Module address for this elink
-      elinkPar.fAsicNr               = mapEntry.second;  // ASIC number within module
-      elinkPar.fTimeOffset           = 0.;
-      elinkPar.fAdcOffset            = 1.;
-      elinkPar.fAdcGain              = 1.;
-    }
-    LOG(info) << "--- Configured equipment " << equip << " with " << numElinks << " elinks";
-  }
-  xpu::copy(fAlgoStsXpu.fParams, xpu::host_to_device);
-  xpu::copy(fAlgoStsXpu.fElinkParams, xpu::host_to_device);
-
-  return kSUCCESS;
-}
-// ----------------------------------------------------------------------------
-
-ClassImp(CbmTaskUnpackXpu)
diff --git a/reco/tasks/CbmTaskUnpackXpu.h b/reco/tasks/CbmTaskUnpackXpu.h
deleted file mode 100644
index d67ac35e1a47d2e0a4bd8a98d23455ce5b90c65f..0000000000000000000000000000000000000000
--- a/reco/tasks/CbmTaskUnpackXpu.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt
-   SPDX-License-Identifier: GPL-3.0-only
-   Authors: Dominik Smith [committer] */
-
-
-#ifndef CBMTASKUNPACKXPU_H
-#define CBMTASKUNPACKXPU_H 1
-
-#include "CbmDefs.h"
-#include "CbmDigiTimeslice.h"
-
-#include <FairTask.h>
-
-#include <sstream>
-#include <vector>
-
-#include "EventBuilder.h"
-#include "sts/ReadoutConfigLegacy.h"
-#include "sts/UnpackStsXpu.h"
-
-
-class CbmDigiManager;
-class CbmSourceTs;
-
-
-/** @class CbmTaskUnpackXpu
- ** @brief Task class for associating digis to events
- ** @author Volker Friese <v.friese@gsi.de>
- ** @since 15.11.2021
- **
- ** Creates objects of class CbmDigiEvent and fills them with digi objects,
- ** using the algorithm EventBuilder.
- **
- ** TOFO: The current implementation is for STS only and with a dummy trigger list
- ** just to establish the framework integration of algorithm and data interfaces.
- **/
-class CbmTaskUnpackXpu : public FairTask {
-
-
-public:
-  /** @brief Constructor **/
-  CbmTaskUnpackXpu();
-
-
-  /** @brief Copy constructor (disabled) **/
-  CbmTaskUnpackXpu(const CbmTaskUnpackXpu&) = delete;
-
-
-  /** @brief Destructor **/
-  virtual ~CbmTaskUnpackXpu();
-
-
-  /** @brief Task execution **/
-  virtual void Exec(Option_t* opt);
-
-
-  /** @brief Finish timeslice **/
-  virtual void Finish();
-
-
-  /** @brief Assignment operator (disabled) **/
-  CbmTaskUnpackXpu& operator=(const CbmTaskUnpackXpu&) = delete;
-
-
-private:  // methods
-  /** @brief Task initialisation **/
-  virtual InitStatus Init();
-
-private:  // members
-  CbmSourceTs* fSource = nullptr;
-
-  cbm::algo::UnpackStsXpu fAlgoStsXpu;
-  cbm::algo::sts::ReadoutConfigLegacy fStsConfig {};
-
-  size_t fNumTs                = 0;
-  size_t fNumMs                = 0;
-  size_t fNumBytes             = 0;
-  size_t fNumDigis             = 0;
-  double fTime                 = 0.;
-  CbmDigiTimeslice* fTimeslice = nullptr;  ///< Output data
-
-  ClassDef(CbmTaskUnpackXpu, 1);
-};
-
-#endif /* CBMTASKUNPACKXPU_H */