diff --git a/algo/detectors/sts/ReadoutConfig.cxx b/algo/detectors/sts/ReadoutConfig.cxx
index 1d08012559e01831e9d36b3e7d9fd58bae0de341..f2e187ee6962e7c18ca2908fcc3cc68953aa1cf8 100644
--- a/algo/detectors/sts/ReadoutConfig.cxx
+++ b/algo/detectors/sts/ReadoutConfig.cxx
@@ -5,6 +5,8 @@
 
 #include "CbmStsAddress.h"
 #include "ChannelMaskSet.h"
+#include "Exceptions.h"
+#include "log.hpp"
 
 #include <cassert>
 #include <iomanip>
@@ -16,6 +18,25 @@ using namespace cbm::algo;
 
 CBM_YAML_INSTANTIATE(sts::ReadoutSetup);
 
+sts::FEBType sts::ReadoutSetup::Component::GetFEBType() const
+{
+  size_t febsPerCrob = FEBsPerCrob();
+  switch (febsPerCrob) {
+    case 5: return FEBType::FEB8_1;
+    case 1: return FEBType::FEB8_5;
+  }
+  throw FatalError("Invalid number of FEBs per CROB: {}", febsPerCrob);
+}
+
+const std::vector<sts::ReadoutSetup::Elink>& sts::ReadoutSetup::GetElinks(FEBType type) const
+{
+  switch (type) {
+    case FEBType::FEB8_1: return elinksFeb8_1;
+    case FEBType::FEB8_5: return elinksFeb8_5;
+  }
+  throw FatalError("Unknown FEB type: {}", static_cast<int>(type));
+}
+
 sts::ReadoutConfig::ReadoutConfig(const ReadoutSetup& config, const ChannelMaskSet& chanMaskSet)
 {
   Init(config, chanMaskSet);
@@ -61,16 +82,16 @@ void sts::ReadoutConfig::Init(const ReadoutSetup& config, const ChannelMaskSet&
   // const uint16_t numFebsPerCrob   = config.components.at(0).feb2module.at(0).size();  // Number of FEBs per CROB
   const uint16_t numAsicsPerFeb   = config.numAsicsPerFeb;  // Number of ASICs per FEB
   const uint16_t numAsicsPerMod   = 2 * numAsicsPerFeb;     // Number of ASICs per module
-  const uint16_t numElinksPerCrob = config.elinks.size();   // Number of elinks per CROB
-  const uint16_t numFebsPerCrob   = 5;                      ///< Number of FEBs per CROB
+  const uint16_t numElinksPerCrob = 42;                     // Number of elinks per CROB
   const uint16_t numChanPerAsic   = 128;                    ///< Number of channels per ASIC
+  const uint16_t numElinksPerComp = numCrobPerComp * numElinksPerCrob;
+
 
   // map from feb ID to adc cut
   // TODO: Don't hardcode this. Read from configuration file.
   std::map<size_t, uint32_t> febAdcCuts = {{1, 1}, {2, 1}, {3, 1}, {4, 1}};
 
   // Constructing the map (equipmentId, eLink) -> (module, ASIC within module)
-  uint16_t numElinksPerComp = numCrobPerComp * numElinksPerCrob;
   for (uint16_t compIdx = 0; compIdx < numComp; compIdx++) {
     const auto& component = config.components.at(compIdx);
     uint16_t equipment    = component.equipmentId;
@@ -83,7 +104,8 @@ void sts::ReadoutConfig::Init(const ReadoutSetup& config, const ChannelMaskSet&
         bool isPulser         = false;
 
         uint16_t elinkId  = numElinksPerCrob * crobIdx + elinkIdx;  // elink within component
-        const auto& elink = config.elinks.at(elinkId);
+        const auto& elinks = config.GetElinks(component.GetFEBType());
+        const auto& elink  = elinks.at(elinkId);
 
         int16_t feb = elink.toFeb;  // FEB within CROB
 
@@ -111,8 +133,9 @@ void sts::ReadoutConfig::Init(const ReadoutSetup& config, const ChannelMaskSet&
         asicInModule = (moduleSide == 1 ? asicInFeb : numAsicsPerMod - 1 - asicInFeb);
 
         // Init channel mask
-        const int32_t febId = feb + compIdx * numCrobPerComp * numFebsPerCrob;
-        auto mapIt          = chanMaskSet.values.find(febId);
+        const int32_t numFebsPerCrob = component.FEBsPerCrob();
+        const int32_t febId          = feb + compIdx * numCrobPerComp * numFebsPerCrob;
+        auto mapIt                   = chanMaskSet.values.find(febId);
         if (mapIt != chanMaskSet.values.end()) {
           const auto& mask = mapIt->second;
 
diff --git a/algo/detectors/sts/ReadoutConfig.h b/algo/detectors/sts/ReadoutConfig.h
index 0ce1d1a9ca091bbc0cc5b2ae2db742134b181efb..f78931eebf336434e9ffa9e22c7802e70fbed35c 100644
--- a/algo/detectors/sts/ReadoutConfig.h
+++ b/algo/detectors/sts/ReadoutConfig.h
@@ -17,6 +17,12 @@ namespace cbm::algo::sts
 
   struct ChannelMaskSet;
 
+  enum class FEBType
+  {
+    FEB8_1,
+    FEB8_5
+  };
+
   /**
    * @brief Readout setup / Hardware cabling for STS
    * Used to create the hardware mapping for the STS unpacker.
@@ -40,6 +46,9 @@ namespace cbm::algo::sts
       std::vector<std::vector<i16>> feb2moduleSide;
       std::vector<std::vector<bool>> febIsPulser;
 
+      FEBType GetFEBType() const;
+      size_t FEBsPerCrob() const { return feb2module.at(0).size(); }
+
       CBM_YAML_PROPERTIES(
         yaml::Property(&Component::equipmentId, "equipmentId",
                          "Equipment ID of component. Written to the data stream (MicrosliceDescriptor).", YAML::Hex),
@@ -64,12 +73,18 @@ namespace cbm::algo::sts
     u16 numAsicsPerFeb;
     std::vector<Module> modules;
     std::vector<Component> components;
-    std::vector<Elink> elinks;
+    std::vector<Elink> elinksFeb8_1;
+    std::vector<Elink> elinksFeb8_5;
+
+    const std::vector<Elink>& GetElinks(FEBType type) const;
 
     CBM_YAML_PROPERTIES(yaml::Property(&ReadoutSetup::numAsicsPerFeb, "numAsicsPerFeb", "Number of ASICs per FEB"),
                       yaml::Property(&ReadoutSetup::modules, "modules", "Modules", {}, YAML::Flow),
                       yaml::Property(&ReadoutSetup::components, "components", "Components", {}, YAML::Flow),
-                      yaml::Property(&ReadoutSetup::elinks, "elinks", "Elinks", {}, YAML::Flow));
+                      yaml::Property(&ReadoutSetup::elinksFeb8_1, "elinksFeb8_1",
+                                       "Elinks for FEB8_1 (1:1 elink:ASIC, 5 FEB / ROB)", {}, YAML::Flow),
+                      yaml::Property(&ReadoutSetup::elinksFeb8_5, "elinksFeb8_5",
+                                       "Elinks for FEB8_5 (5:1 elink:ASIC, 1 FEB / ROB)", {}, YAML::Flow));
   };
 
   /** @class ReadoutConfig
diff --git a/algo/detectors/sts/ReadoutConfig_mCBM2022.cxx b/algo/detectors/sts/ReadoutConfig_mCBM2022.cxx
index 882b3ecfb377bb39666373c1c74044e63ba0a056..70c800df5794cb9c7e635e9bce5bc3061d553e90 100644
--- a/algo/detectors/sts/ReadoutConfig_mCBM2022.cxx
+++ b/algo/detectors/sts/ReadoutConfig_mCBM2022.cxx
@@ -37,7 +37,7 @@ ReadoutConfig ReadoutConfig::MakeMCBM2022()
     {.equipmentId = 0x1005, .feb2module = {{12, 12, 11, 11, 10}}, .feb2moduleSide = {{1, 0, 1, 0, 1}}, .febIsPulser = {{false, false, false, false, false}}},
   };
 
-  setup.elinks = {
+  setup.elinksFeb8_1 = {
     {.toFeb = 4, .toAsicFebA = 0x21, .toAsicFebB = 0x27},
     {.toFeb = 4, .toAsicFebA = 0x23, .toAsicFebB = 0x25},
     {.toFeb = 4, .toAsicFebA = 0x25, .toAsicFebB = 0x23},
@@ -81,6 +81,8 @@ ReadoutConfig ReadoutConfig::MakeMCBM2022()
     {.toFeb = 0, .toAsicFebA = 0x7, .toAsicFebB = 0x1},
     {.toFeb = 0, .toAsicFebA = 0x1, .toAsicFebB = 0x7},
   };
+
+  setup.elinksFeb8_5 = {}; // Not present in mCBM2022
   // clang-format on
 
   return ReadoutConfig{setup, ChannelMaskSet::MakeMCBM2022()};
diff --git a/algo/detectors/sts/Unpack.cxx b/algo/detectors/sts/Unpack.cxx
index c40e4e75c9b4dc990efb68efcd98ebb7c4da60f5..34990d21afbdad145baec5b95b26d2d319d629e6 100644
--- a/algo/detectors/sts/Unpack.cxx
+++ b/algo/detectors/sts/Unpack.cxx
@@ -46,5 +46,19 @@ Unpack::Unpack(const Config& config) : fConfig(config)
 Unpack::Result_t Unpack::operator()(const fles::Timeslice& ts) const
 {
   constexpr int SystemVersion = 0x20;
-  return DoUnpack(Subsystem::STS, ts, SystemVersion);
+
+  auto result = DoUnpack(Subsystem::STS, ts, SystemVersion);
+  // PrintDigisPerModule(result.first);
+  return result;
+}
+
+void Unpack::PrintDigisPerModule(const PODVector<CbmStsDigi>& digis) const
+{
+  std::map<u32, size_t> digisPerModule;
+  for (const auto& digi : digis) {
+    digisPerModule[digi.GetAddress()]++;
+  }
+  for (const auto& [module, numDigis] : digisPerModule) {
+    L_(info) << "Module " << std::hex << module << std::dec << " has " << numDigis << " digis";
+  }
 }
diff --git a/algo/detectors/sts/Unpack.h b/algo/detectors/sts/Unpack.h
index 1f01a3beb8aaa06991557932e48a4b906c7c39ca..0670fd8697b7a6e7f4188c7a82716457b503a865 100644
--- a/algo/detectors/sts/Unpack.h
+++ b/algo/detectors/sts/Unpack.h
@@ -33,6 +33,8 @@ namespace cbm::algo::sts
 
    private:
     Config fConfig;
+
+    void PrintDigisPerModule(const PODVector<CbmStsDigi>& digis) const;
   };
 
 }  // namespace cbm::algo::sts
diff --git a/algo/detectors/sts/UnpackMS.cxx b/algo/detectors/sts/UnpackMS.cxx
index 4ffb8dc9221433044f607c6ebe4060ca8edec9da..250981bdf9b283b7d8a176316e034b58def747d8 100644
--- a/algo/detectors/sts/UnpackMS.cxx
+++ b/algo/detectors/sts/UnpackMS.cxx
@@ -5,6 +5,7 @@
 #include "UnpackMS.h"
 
 #include "StsXyterMessage.h"
+#include "log.hpp"
 
 #include <cassert>
 #include <cmath>
@@ -37,11 +38,13 @@ namespace cbm::algo::sts
     // --- Number of messages in microslice
     auto msSize = msDescr.size;
     if (msSize % sizeof(stsxyter::Message) != 0) {
+      L_(error) << "Invalid microslice size: " << msSize;
       result.second.fNumErrInvalidMsSize++;
       return result;
     }
     const uint32_t numMessages = msSize / sizeof(stsxyter::Message);
     if (numMessages < 2) {
+      L_(error) << "Microslice too small: " << numMessages;
       result.second.fNumErrInvalidMsSize++;
       return result;
     }
@@ -54,12 +57,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++;
       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++;
       return result;
     }
diff --git a/algo/log/AlgoFairloggerCompat.h b/algo/log/AlgoFairloggerCompat.h
index 941012523ddf8891630dfce9f4b8586ea70803be..29098c49177aa2a979de4a2033f58898eb40d93f 100644
--- a/algo/log/AlgoFairloggerCompat.h
+++ b/algo/log/AlgoFairloggerCompat.h
@@ -5,6 +5,14 @@
 #define CBM_ALGO_BASE_COMPAT_ONLINEDATALOG_H
 
 #ifndef NO_ROOT
+// Do not include FairLogger in GPU code (header might not be available)
+// FIXME: Ensure NO_ROOT is defined for GPU compilation
+#if !defined(__NVCC__) && !defined(__HIPCC__) && !defined(SYCL_LANGUAGE_VERSION)
+#define CBM_ONLINE_USE_FAIRLOGGER
+#endif
+#endif
+
+#ifdef CBM_ONLINE_USE_FAIRLOGGER
 
 #include <fairlogger/Logger.h>
 
@@ -18,6 +26,6 @@ static constexpr severity_level warn = severity_level::warning;
 
 #endif  // LOG
 
-#endif  // NO_ROOT
+#endif  // CBM_ONLINE_USE_FAIRLOGGER
 
 #endif  // CBM_ALGO_BASE_COMPAT_ONLINEDATALOG_H
diff --git a/algo/unpack/CommonUnpacker.cxx b/algo/unpack/CommonUnpacker.cxx
index b1c657bc7dceb78da23d1afe046e2f155aafc736..a55564b131cf8af8c7ff9b67b17b34435798e58c 100644
--- a/algo/unpack/CommonUnpacker.cxx
+++ b/algo/unpack/CommonUnpacker.cxx
@@ -3,6 +3,8 @@
    Authors: Felix Weiglhofer [committer], Dominik Smith */
 #include "CommonUnpacker.h"
 
+#include "log.hpp"
+
 using namespace cbm::algo;
 
 detail::MSData::MSData(const fles::Timeslice& ts, fles::Subsystem subsystem, gsl::span<u16> legalEqIds, u8 sys_ver)
@@ -16,15 +18,23 @@ detail::MSData::MSData(const fles::Timeslice& ts, fles::Subsystem subsystem, gsl
       continue;
     }
 
+    if (this_subsystem == fles::Subsystem::STS) {
+      L_(debug) << "Found STS component, eq_id: " << ts.descriptor(comp, 0).eq_id
+                << ", sys_ver: " << int{ts.descriptor(comp, 0).sys_ver};
+    }
+
     const u64 numMsInComp = ts.num_microslices(comp);
     const u16 componentId = ts.descriptor(comp, 0).eq_id;
 
     if (ts.descriptor(comp, 0).sys_ver != sys_ver) {
+      L_(error) << "Invalid system version " << int{ts.descriptor(comp, 0).sys_ver} << " for subsystem "
+                << ToString(subsystem);
       monitor.errInvalidSysVer++;
       continue;
     }
 
     if (std::find(legalEqIds.begin(), legalEqIds.end(), componentId) == legalEqIds.end()) {
+      L_(error) << "Invalid equipment id " << componentId << " for subsystem " << ToString(subsystem);
       monitor.errInvalidEqId++;
       continue;
     }
@@ -38,4 +48,5 @@ detail::MSData::MSData(const fles::Timeslice& ts, fles::Subsystem subsystem, gsl
       msContent.push_back(ts.content(comp, mslice));
     }
   }
+  L_(debug) << "Found " << monitor.numMs << " microslices for subsystem " << ToString(subsystem);
 }
diff --git a/core/data/sts/CbmStsAddress.h b/core/data/sts/CbmStsAddress.h
index 6cc0b8780468ed2f5080c15b6b5203873b0bef2c..fe33c6e81b8b976b05cc20b67a39a997555731c8 100644
--- a/core/data/sts/CbmStsAddress.h
+++ b/core/data/sts/CbmStsAddress.h
@@ -10,6 +10,7 @@
 #ifndef CBMSTSADDRESS_H
 #define CBMSTSADDRESS_H 1
 
+#include "AlgoFairloggerCompat.h"
 #include "CbmDefs.h"  // for ECbmModuleId
 
 #include <cassert>  // for assert
@@ -202,7 +203,12 @@ namespace CbmStsAddress
 
     int32_t ret = (address & kDMask) >> kShift[1][kStsUnit];
 
+#if XPU_IS_CPU
     // Check that no bits were set, that are stripped by this function.
+    if (address != UnpackDigiAddress(ret)) {
+      LOG(error) << "Address " << address << " contains bits that are stripped by PackDigiAddress";
+    }
+#endif
     assert(address == UnpackDigiAddress(ret));
 
     return ret;
diff --git a/external/InstallParameter.cmake b/external/InstallParameter.cmake
index 413b66f62c5522aa82b614d43da7198e47650e98..a003eb7399842fc9b2130de245deaecc2037fe5c 100644
--- a/external/InstallParameter.cmake
+++ b/external/InstallParameter.cmake
@@ -1,4 +1,4 @@
-set(PARAMETER_VERSION b67255ed77eb1a803ff95f41a2953c0001127220) # 2024-03-05
+set(PARAMETER_VERSION db9c7e6dc8989998898db60a9c490afa9c9c7891) # 2024-03-06
 
 set(PARAMETER_SRC_URL "https://git.cbm.gsi.de/CbmSoft/cbmroot_parameter.git")