diff --git a/algo/detectors/trd/Unpack.cxx b/algo/detectors/trd/Unpack.cxx
index 88b2f9c3583f32732361a67b024345c90af8ccd0..f6e3bb135117ab02e2be457145e656335f8d3828 100644
--- a/algo/detectors/trd/Unpack.cxx
+++ b/algo/detectors/trd/Unpack.cxx
@@ -11,8 +11,8 @@ using fles::Subsystem;
 
 Unpack::Unpack(const ReadoutConfig& readout) : fReadout(readout)
 {
-  constexpr i64 SystemTimeOffset = 1300;
-  constexpr u8 SystemVersion     = 0x01;
+  constexpr i64 SystemTimeOffset            = 1300;
+  constexpr std::array<u8, 2> SystemVersion = {0x01, 0x10};
 
   // Create one algorithm per component for TRD and configure it with parameters
   auto equipIdsTrd = fReadout.GetEquipmentIds();
@@ -34,8 +34,10 @@ Unpack::Unpack(const ReadoutConfig& readout) : fReadout(readout)
       }
       par.fCrobParams.push_back(crobPar);
     }
-    auto algo                      = std::make_unique<UnpackMS>(std::move(par));
-    fAlgos[{equip, SystemVersion}] = std::move(algo);
+    auto algo_01                      = std::make_unique<UnpackMS<SystemVersion[0]>>(std::move(par));
+    auto algo_10                      = std::make_unique<UnpackMS<SystemVersion[1]>>(std::move(par));
+    fAlgos[{equip, SystemVersion[0]}] = std::move(algo_01);
+    fAlgos[{equip, SystemVersion[1]}] = std::move(algo_10);
 
     L_(debug) << "--- Configured equipment " << equip << " with " << numCrobs << " crobs";
   }
diff --git a/algo/detectors/trd/UnpackMS.cxx b/algo/detectors/trd/UnpackMS.cxx
index 0ba70becd7dd1bf874a1c216f696bfa24c9609c7..8f41dd695a9bcb9d665f2adae49b25f7fb01608f 100644
--- a/algo/detectors/trd/UnpackMS.cxx
+++ b/algo/detectors/trd/UnpackMS.cxx
@@ -1,6 +1,6 @@
 /* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
    SPDX-License-Identifier: GPL-3.0-only
-   Authors: Pascal Raisig, Dominik Smith [committer] */
+   Authors: Pascal Raisig, Dominik Smith [committer], David Schledt */
 
 #include "UnpackMS.h"
 
@@ -14,214 +14,9 @@ using std::unique_ptr;
 namespace cbm::algo::trd
 {
 
-  UnpackMS::UnpackMS(const UnpackPar& pars) : fParams(pars) {}
-  UnpackMS::~UnpackMS() = default;
-
-  // ----   Algorithm execution   ---------------------------------------------
-  UnpackMS::Result_t UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
-                                          const uint64_t tTimeslice) const
-  {
-    // --- Output data
-    Result_t result = {};
-
-    MsContext ctx = {};
-
-    // Get the µSlice starttime relative to the timeslice starttime (constant is clock length of Spadic in ns)
-    ctx.fMsStartTimeRelCC = (msDescr.idx - tTimeslice) / fAsicClockCycle;
-
-    // We only want to count on TS_MSB per Stream per TS_MSB package (each eLink sends its own TS_MSB frame)
-    // so we store the current TS_MSB and compare it to the incoming.
-    std::int8_t currTsMsb = 0;
-
-    // Reset the TS_MSB counter for the new µSlice we unpack
-    ctx.fNrTsMsbVec.resize(fStreamsPerWord);
-
-
-    // Get the µslice size in bytes to calculate the number of completed words
-    auto mssize = msDescr.size;
-
-    // Get the hardware ids from which the current µSlice is coming
-    std::uint8_t crobId = 0;
-    auto criId          = msDescr.eq_id;
-
-    // Digest the flags from the µSlice
-    digestMsFlags(msDescr.flags, result.second);
-
-    // Get the number of complete words in the input MS buffer.
-    std::uint32_t nwords = mssize / fBytesPerWord;
-
-    // We have 32 bit spadic frames in this readout version
-    const auto mscontent = reinterpret_cast<const size_t*>(msContent);
-
-    result.first.reserve(nwords);
-
-    // Loop over all 64bit-Spadic-Words in the current µslice
-    for (std::uint32_t istream = 0; istream < fStreamsPerWord; istream++) {
-      currTsMsb = -1;
-      for (std::uint32_t iword = 0; iword < nwords; ++iword) {
-        // Access the actual word from the pointer
-        size_t word = static_cast<size_t>(mscontent[iword]);
-
-        // Access the actual frame[iframe] from the word. (see fStreamsPerWord)
-        std::uint32_t frame = (word >> (32 * istream)) & 0xffffffff;
-
-        // Get the type of the frame
-        auto kWordtype = getMessageType(frame);
-
-        // In case we saw any other word than an EPO(TS_MSB) reset the flag,
-        // such that we again increase by one if an EPO frame arrives
-        auto elinkId = (frame >> 24) & 0x3f;
-
-        switch (kWordtype) {
-          case Spadic::MsMessageType::kEPO: {
-            auto tsmsb = getTsMsb(frame, result.second);
-            if (((tsmsb - currTsMsb) & 0x3f) == 1 || currTsMsb == -1) ctx.fNrTsMsbVec.at(istream)++;
-            currTsMsb = tsmsb;
-            result.second.fNumEpochMsgs++;
-            break;
-            // FIXME in the kEPO msg we also have further flags that should be extracted
-          }
-          case Spadic::MsMessageType::kSOM: {
-            // Create the raw message and fill it with all information we can get from the SOM msg
-            CbmTrdRawMessageSpadic raw = makeRaw(frame, criId, crobId, elinkId, istream, ctx);
-
-            // FIXME since we can not deduce the sample position from the messages we need in
-            // future some parameter handling here to place the samples at the correct position
-            // 6 adc bits are stored in the som message
-            size_t nadcbits      = 6;
-            size_t nadcbitstotal = 6;
-            // Get the first bits from the adc signal
-            size_t adcbuffer = frame & 0x3f;
-            size_t isample   = 0;
-            size_t irda      = 0;
-
-            // Now lets check if we have rda words following our som
-            iword++;
-            word  = static_cast<size_t>(mscontent[iword]);
-            frame = (word >> (32 * istream)) & 0xffffffff;
-
-            // The maximum amount of samples (32) equals to 12 RDA messages
-            while (getMessageType(frame) == Spadic::MsMessageType::kRDA && irda < 12) {
-              // We have to count the number of rda frames for sample reconstruction in eom
-              irda++;
-
-              // Ensure that we are on the correct eLink
-              elinkId = (frame >> 24) & 0x3f;
-              if (elinkId != raw.GetElinkId()) {
-                result.second.fNumElinkMis++;
-              }
-
-              // We have 22 adc bits per RDA word lets add them to the buffer...
-              adcbuffer <<= 22;
-              adcbuffer |= static_cast<size_t>((frame & 0x3fffff));
-              // and increase the adcbit counter by 22 bits
-              nadcbits += 22;
-              nadcbitstotal += 22;
-              // If we have 9 or more samples stored we can extract n samples
-              while (nadcbits >= 9) {
-                raw.IncNrSamples();
-                // In case the avg baseline feature was used we need to take special care of sample 0
-                if (isample == 0 && fParams.fUseBaselineAvg)
-                  raw.SetSample(extractAvgSample(&adcbuffer, &nadcbits), isample);
-                else
-                  raw.SetSample(extractSample(&adcbuffer, &nadcbits), isample);
-                isample++;
-              }
-              iword++;
-              word  = static_cast<size_t>(mscontent[iword]);
-              frame = (word >> (32 * istream)) & 0xffffffff;
-            }
-
-            if (getMessageType(frame) == Spadic::MsMessageType::kEOM) {
-              // Ensure that we are on the correct eLink
-              elinkId = (frame >> 24) & 0x3f;
-              if (elinkId != raw.GetElinkId()) {
-                result.second.fNumElinkMis++;
-              }
-
-              // Number of samples indicator = nsamples % 4
-              std::uint8_t nsamplesindicator = (frame >> 18) & 0x3;
-              // Number of required samples as indicated
-              std::uint64_t nreqsamples = (nadcbitstotal + 18) / 9;
-              std::uint8_t nn           = nreqsamples % 4;
-              for (std::uint8_t itest = 0; itest < 3; itest++) {
-                if (nn == nsamplesindicator || nreqsamples == 0) break;
-                nreqsamples--;
-                nn = nreqsamples % 4;
-              }
-
-              // There is a chance that the nsamplesindicator bits are corrupted,
-              // here we check that we do not try to extract more adcbits than actually are streamed
-              if (nreqsamples >= isample) {
-                // Now extract from the above values the number of required adc bits from the eom
-                std::int8_t nrequiredbits = (nreqsamples - isample) * 9 - nadcbits;
-                adcbuffer <<= nrequiredbits;
-
-                // The eom carries at maximum 18 adcbits
-                adcbuffer |= static_cast<size_t>((frame & 0x3ffff) >> (18 - nrequiredbits));
-                nadcbits += nrequiredbits;
-
-                while (nadcbits >= 9) {
-                  raw.IncNrSamples();
-                  raw.SetSample(extractSample(&adcbuffer, &nadcbits), isample);
-                  isample++;
-                }
-              }
-              else {
-                result.second.fNumCorruptEom++;
-              }
-              result.second.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));
-            }
-            else {
-              // We move the word counter backwards by one, such that the unexpected message can correctly be digested
-              iword--;
-              result.second.fNumMissingEom++;
-            }
-            break;
-          }
-          case Spadic::MsMessageType::kRDA: {
-            result.second.fNumWildRda++;
-            break;
-          }
-          case Spadic::MsMessageType::kEOM: {
-            result.second.fNumWildEom++;
-            break;
-          }
-          case Spadic::MsMessageType::kINF: {
-            result.second.fNumCreatedInfoMsgs++;
-            digestInfoMsg(frame);
-            break;
-          }
-          case Spadic::MsMessageType::kNUL: {
-            // last word in Microslice is 0.
-            if (iword != (nwords - 1) || (istream != (fStreamsPerWord - 1))) {
-              result.second.fNumWildNul++;
-            }
-            break;
-          }
-          case Spadic::MsMessageType::kUNK: {
-            result.second.fNumUnknownWords++;
-            return result;
-            break;
-          }
-          default:
-            // We have varying msg types for different versions of the message format.
-            // Hence, to not produce compiler warnings we have a "default break;" here.
-            break;
-        }
-      }
-    }
-    return result;
-  }
-  // --------------------------------------------------------------------------
-
   // ---- digestBufInfoFlags ----
-  Spadic::MsInfoType UnpackMS::digestBufInfoFlags(const std::uint32_t frame) const
+  template<uint8_t sys_ver>
+  Spadic::MsInfoType UnpackMS<sys_ver>::digestBufInfoFlags(const std::uint32_t frame) const
   {
     auto flag = (frame >> 15) & 0x3;
     Spadic::MsInfoType infotype;
@@ -231,8 +26,11 @@ namespace cbm::algo::trd
     return infotype;
   }
 
+  template Spadic::MsInfoType UnpackMS<0x01>::digestBufInfoFlags(const std::uint32_t frame) const;
+
   // ---- digestInfoMsg ----
-  void UnpackMS::digestInfoMsg(const std::uint32_t frame) const
+  template<uint8_t sys_ver>
+  void UnpackMS<sys_ver>::digestInfoMsg(const std::uint32_t frame) const
   {
     /// Save info message if needed.
     //if (fOptOutBVec) { fOptOutBVec->emplace_back(std::make_pair(ctx.fLastFulltime, frame)); }
@@ -240,8 +38,11 @@ namespace cbm::algo::trd
     // "Spadic_Info_Types";
   }
 
+  template void UnpackMS<0x01>::digestInfoMsg(const std::uint32_t frame) const;
+
   // ---- digestInfoMsg ----
-  void UnpackMS::digestMsFlags(const std::uint16_t flags, UnpackMonitorData& monitor) const
+  template<uint8_t sys_ver>
+  void UnpackMS<sys_ver>::digestMsFlags(const std::uint16_t flags, UnpackMonitorData& monitor) const
   {
     if (flags & static_cast<std::uint16_t>(fles::MicrosliceFlags::CrcValid)) {
       monitor.fNumCrcValidFlags++;
@@ -257,8 +58,12 @@ namespace cbm::algo::trd
     }
   }
 
+  template void UnpackMS<0x01>::digestMsFlags(const std::uint16_t flags, UnpackMonitorData& monitor) const;
+  template void UnpackMS<0x10>::digestMsFlags(const std::uint16_t flags, UnpackMonitorData& monitor) const;
+
   // ---- extractSample ----
-  std::float_t UnpackMS::extractAvgSample(size_t* adcbuffer, size_t* nadcbits) const
+  template<uint8_t sys_ver>
+  std::float_t UnpackMS<sys_ver>::extractAvgSample(size_t* adcbuffer, size_t* nadcbits) const
   {
     // can not extract samples from a buffer with less than 9 bits
     assert(*nadcbits >= 9);
@@ -284,8 +89,11 @@ namespace cbm::algo::trd
     return sample;
   }
 
+  template std::float_t UnpackMS<0x01>::extractAvgSample(size_t* adcbuffer, size_t* nadcbits) const;
+
   // ---- extractSample ----
-  std::int16_t UnpackMS::extractSample(size_t* adcbuffer, size_t* nadcbits) const
+  template<uint8_t sys_ver>
+  std::int16_t UnpackMS<sys_ver>::extractSample(size_t* adcbuffer, size_t* nadcbits) const
   {
     // can not extract samples from a buffer with less than 9 bits
     assert(*nadcbits >= 9);
@@ -305,8 +113,11 @@ namespace cbm::algo::trd
     return sample;
   }
 
+  template std::int16_t UnpackMS<0x01>::extractSample(size_t* adcbuffer, size_t* nadcbits) const;
+
   // ---- getInfoType ----
-  Spadic::MsInfoType UnpackMS::getInfoType(const std::uint32_t frame) const
+  template<uint8_t sys_ver>
+  Spadic::MsInfoType UnpackMS<sys_ver>::getInfoType(const std::uint32_t frame) const
   {
     // Set first 20 bits to 1 for the mask
     size_t mask = 0x000FFFFF;
@@ -345,8 +156,11 @@ namespace cbm::algo::trd
     }
   }
 
+  template Spadic::MsInfoType UnpackMS<0x01>::getInfoType(const std::uint32_t frame) const;
+
   // ---- getMessageType ----
-  Spadic::MsMessageType UnpackMS::getMessageType(const std::uint32_t frame) const
+  template<uint8_t sys_ver>
+  Spadic::MsMessageType UnpackMS<sys_ver>::getMessageType(const std::uint32_t frame) const
   {
     std::uint32_t checkframe = frame;
     checkframe &= 0xffffff;
@@ -379,8 +193,11 @@ namespace cbm::algo::trd
     }
   }
 
+  template Spadic::MsMessageType UnpackMS<0x01>::getMessageType(const std::uint32_t frame) const;
+
   // ---- getTsMsb ----
-  std::uint8_t UnpackMS::getTsMsb(const std::uint32_t frame, UnpackMonitorData& monitor) const
+  template<uint8_t sys_ver>
+  std::uint8_t UnpackMS<sys_ver>::getTsMsb(const std::uint32_t frame, UnpackMonitorData& monitor) const
   {
     if ((frame & 0xf) > 0)
       return -2;  // if a 'error' ts_msb is received the tsmsb value is not correct. To not mess up the counting -2 is returned.
@@ -404,8 +221,53 @@ namespace cbm::algo::trd
     return tsmsb[0];
   }
 
-  // ---- makeDigi ----
-  CbmTrdDigi UnpackMS::makeDigi(CbmTrdRawMessageSpadic raw, MsContext& ctx) const
+  template std::uint8_t UnpackMS<0x01>::getTsMsb(const std::uint32_t frame, UnpackMonitorData& monitor) const;
+
+
+  // method definition for specialization
+  template<uint8_t sys_ver>
+  CbmTrdDigi UnpackMS<sys_ver>::makeDigi(Spadic::FexWord<sys_ver> fw, size_t fMsStartTimeRel) const
+  {
+    return CbmTrdDigi();
+  }
+
+  // ---- makeDigi sys_ver <0x10> ----
+  template<>
+  CbmTrdDigi UnpackMS<0x10>::makeDigi(Spadic::FexWord<0x10> fw, size_t fMsStartTimeRel) const
+  {
+    auto rawTriggerType = static_cast<Spadic::eTriggerType>(fw.ht);
+    auto triggerType    = GetDigiTriggerType(rawTriggerType);
+
+    int32_t errClass = 0;
+
+    // Get the address of the originating spadic
+    const UnpackCrobPar& crobPar   = fParams.fCrobParams.at(0);
+    const UnpackElinkPar& elinkPar = crobPar.fElinkParams.at(fw.elink);
+    const uint32_t asicAddress     = elinkPar.fAddress;
+
+    // Get the channel id on the module
+    int32_t padChNr = elinkPar.fChanAddress.at(fw.channel);
+
+    // Get the time information and apply the necessary correction
+    uint64_t time = (fw.timestamp - fw.prec_time) * fAsicClockCycle + fMsStartTimeRel;
+    time -= elinkPar.fTimeOffset;
+
+    auto energy = fw.maxAdc * fParams.fMaxAdcToEnergyCal;
+
+    // Get the unique module id from the asic address
+    int32_t uniqueModuleId = asicAddress / 1000;
+
+    CbmTrdDigi digi = CbmTrdDigi(padChNr, uniqueModuleId, energy, time, triggerType, errClass);
+
+    // If the message was flagged as multi hit, forward this info to the digi
+    if (fw.mh != 0) digi.SetTriggerType(CbmTrdDigi::eTriggerType::kMulti);
+
+    return digi;
+  }
+
+  // ---- makeDigi from raw ----
+  template<uint8_t sys_ver>
+  CbmTrdDigi UnpackMS<sys_ver>::makeDigi(CbmTrdRawMessageSpadic raw, MsContext& ctx) const
   {
     // Extract the trigger type and translate it to the digi enum
     auto rawTriggerType = static_cast<Spadic::eTriggerType>(raw.GetHitType());
@@ -454,9 +316,12 @@ namespace cbm::algo::trd
     return digi;
   }
 
+  template CbmTrdDigi UnpackMS<0x01>::makeDigi(CbmTrdRawMessageSpadic raw, MsContext& ctx) const;
+
   // ---- makeRaw ----
-  CbmTrdRawMessageSpadic UnpackMS::makeRaw(const std::uint32_t frame, std::uint16_t criId, std::uint8_t crobId,
-                                           std::uint16_t elinkId, std::uint8_t istream, MsContext& ctx) const
+  template<uint8_t sys_ver>
+  CbmTrdRawMessageSpadic UnpackMS<sys_ver>::makeRaw(const std::uint32_t frame, std::uint16_t criId, std::uint8_t crobId,
+                                                    std::uint16_t elinkId, std::uint8_t istream, MsContext& ctx) const
   {
     auto chId             = static_cast<std::uint8_t>(((frame >> 17) & 0xf));
     auto timestamp        = static_cast<std::uint8_t>((frame >> 9) & 0xff);
@@ -472,9 +337,14 @@ namespace cbm::algo::trd
     return CbmTrdRawMessageSpadic(chId, elinkId, crobId, criId, hitType, nsamples, multihit, fulltime, samples);
   }
 
+  template CbmTrdRawMessageSpadic UnpackMS<0x01>::makeRaw(const std::uint32_t frame, std::uint16_t criId,
+                                                          std::uint8_t crobId, std::uint16_t elinkId,
+                                                          std::uint8_t istream, MsContext& ctx) const;
+
 
   // ---- GetDigiTriggerType ----
-  CbmTrdDigi::eTriggerType UnpackMS::GetDigiTriggerType(Spadic::eTriggerType tt)
+  template<uint8_t sys_ver>
+  CbmTrdDigi::eTriggerType UnpackMS<sys_ver>::GetDigiTriggerType(Spadic::eTriggerType tt)
   {
     // Shift self trigger to digi selftrigger
     // Shift neighbour trigger to digi neighbour
@@ -488,8 +358,12 @@ namespace cbm::algo::trd
     }
   }
 
+  template CbmTrdDigi::eTriggerType UnpackMS<0x01>::GetDigiTriggerType(Spadic::eTriggerType tt);
+  template CbmTrdDigi::eTriggerType UnpackMS<0x10>::GetDigiTriggerType(Spadic::eTriggerType tt);
+
   // --- GetCharge ----
-  float_t UnpackMS::GetMaxAdcValue(const std::vector<std::int16_t>* samples) const
+  template<uint8_t sys_ver>
+  float_t UnpackMS<sys_ver>::GetMaxAdcValue(const std::vector<std::int16_t>* samples) const
   {
     // Safety for corrupted input samples
     assert(samples->size() >= fPeakingBinMin);
@@ -515,8 +389,11 @@ namespace cbm::algo::trd
     return charge > 0 ? charge : 0;
   }
 
+  template float_t UnpackMS<0x01>::GetMaxAdcValue(const std::vector<std::int16_t>* samples) const;
+
   // ---- GetBaseline ----
-  float_t UnpackMS::GetBaseline(const std::vector<std::int16_t>* samples) const
+  template<uint8_t sys_ver>
+  float_t UnpackMS<sys_ver>::GetBaseline(const std::vector<std::int16_t>* samples) const
   {
     // The spadic 2.2 has a functionality that an average baseline can be written to the first sample.
     // So first we have to check if this is active.
@@ -534,6 +411,248 @@ namespace cbm::algo::trd
       return baseline;
     }
   }
+  template float_t UnpackMS<0x01>::GetBaseline(const std::vector<std::int16_t>* samples) const;
+
+  // ----   Algorithm execution sys_ver >= 0x10  ---------------------------------------------
+  template<std::uint8_t sys_ver>
+  typename UnpackMS<sys_ver>::Result_t UnpackMS<sys_ver>::operator()(const uint8_t* msContent,
+                                                                     const fles::MicrosliceDescriptor& msDescr,
+                                                                     const uint64_t tTimeslice) const
+  {
+    Result_t result = {};
+
+
+    // Digest the flags from the µSlice
+    digestMsFlags(msDescr.flags, result.second);
+
+    size_t fMsStartTimeRel = (msDescr.idx - tTimeslice) / fAsicClockCycle;
+
+    // Get bytes per word used for the given system version
+    constexpr std::uint8_t bytes = Spadic::BytesPerWord<sys_ver>();
+
+    auto mssize          = msDescr.size;
+    std::uint32_t nwords = mssize / bytes;
+
+    const Spadic::NByteContainer<bytes>* bp = reinterpret_cast<const Spadic::NByteContainer<bytes>*>(msContent);
+
+    for (std::uint32_t iword = 0; iword < nwords; ++iword) {
+      Spadic::NByteContainer<bytes> bCont = bp[iword];
+      Spadic::FexWord<sys_ver> fw(bCont);
+      if (fw.ht != 0) {
+        result.first.push_back(makeDigi(fw, fMsStartTimeRel));
+      }
+    }
+    return result;
+  }
+
+  template typename UnpackMS<0x10>::Result_t UnpackMS<0x10>::operator()(const uint8_t* msContent,
+                                                                        const fles::MicrosliceDescriptor& msDescr,
+                                                                        const uint64_t tTimeslice) const;
+  // --------------------------------------------------------------------------
+
+  // ----   Algorithm execution sys_ver - 0x01  ---------------------------------------------
+  template<>
+  typename UnpackMS<0x01>::Result_t UnpackMS<0x01>::operator()(const uint8_t* msContent,
+                                                               const fles::MicrosliceDescriptor& msDescr,
+                                                               const uint64_t tTimeslice) const
+  {
+    // --- Output data
+    Result_t result = {};
+
+    MsContext ctx = {};
+
+    // Get the µSlice starttime relative to the timeslice starttime (constant is clock length of Spadic in ns)
+    ctx.fMsStartTimeRelCC = (msDescr.idx - tTimeslice) / fAsicClockCycle;
+
+    // We only want to count on TS_MSB per Stream per TS_MSB package (each eLink sends its own TS_MSB frame)
+    // so we store the current TS_MSB and compare it to the incoming.
+    std::int8_t currTsMsb = 0;
+
+    // Reset the TS_MSB counter for the new µSlice we unpack
+    ctx.fNrTsMsbVec.resize(fStreamsPerWord);
+
+
+    // Get the µslice size in bytes to calculate the number of completed words
+    auto mssize = msDescr.size;
+
+    // Get the hardware ids from which the current µSlice is coming
+    std::uint8_t crobId = 0;
+    auto criId          = msDescr.eq_id;
+
+    // Digest the flags from the µSlice
+    digestMsFlags(msDescr.flags, result.second);
+
+    // Get the number of complete words in the input MS buffer.
+    std::uint32_t nwords = mssize / fBytesPerWord;
+
+    // We have 32 bit spadic frames in this readout version
+    const auto mscontent = reinterpret_cast<const size_t*>(msContent);
+
+    result.first.reserve(nwords);
+
+    // Loop over all 64bit-Spadic-Words in the current µslice
+    for (std::uint32_t istream = 0; istream < fStreamsPerWord; istream++) {
+      currTsMsb = -1;
+      for (std::uint32_t iword = 0; iword < nwords; ++iword) {
+        // Access the actual word from the pointer
+        size_t word = static_cast<size_t>(mscontent[iword]);
+
+        // Access the actual frame[iframe] from the word. (see fStreamsPerWord)
+        std::uint32_t frame = (word >> (32 * istream)) & 0xffffffff;
+
+        // Get the type of the frame
+        auto kWordtype = getMessageType(frame);
+
+        // In case we saw any other word than an EPO(TS_MSB) reset the flag,
+        // such that we again increase by one if an EPO frame arrives
+        auto elinkId = (frame >> 24) & 0x3f;
+
+        switch (kWordtype) {
+          case Spadic::MsMessageType::kEPO: {
+            auto tsmsb = getTsMsb(frame, result.second);
+            if (((tsmsb - currTsMsb) & 0x3f) == 1 || currTsMsb == -1) ctx.fNrTsMsbVec.at(istream)++;
+            currTsMsb = tsmsb;
+            result.second.fNumEpochMsgs++;
+            break;
+            // FIXME in the kEPO msg we also have further flags that should be extracted
+          }
+          case Spadic::MsMessageType::kSOM: {
+            // Create the raw message and fill it with all information we can get from the SOM msg
+            CbmTrdRawMessageSpadic raw = makeRaw(frame, criId, crobId, elinkId, istream, ctx);
+
+            // FIXME since we can not deduce the sample position from the messages we need in
+            // future some parameter handling here to place the samples at the correct position
+            // 6 adc bits are stored in the som message
+            size_t nadcbits      = 6;
+            size_t nadcbitstotal = 6;
+            // Get the first bits from the adc signal
+            size_t adcbuffer = frame & 0x3f;
+            size_t isample   = 0;
+            size_t irda      = 0;
+
+            // Now lets check if we have rda words following our som
+            iword++;
+            word  = static_cast<size_t>(mscontent[iword]);
+            frame = (word >> (32 * istream)) & 0xffffffff;
+
+            // The maximum amount of samples (32) equals to 12 RDA messages
+            while (getMessageType(frame) == Spadic::MsMessageType::kRDA && irda < 12) {
+              // We have to count the number of rda frames for sample reconstruction in eom
+              irda++;
 
+              // Ensure that we are on the correct eLink
+              elinkId = (frame >> 24) & 0x3f;
+              if (elinkId != raw.GetElinkId()) {
+                result.second.fNumElinkMis++;
+              }
+
+              // We have 22 adc bits per RDA word lets add them to the buffer...
+              adcbuffer <<= 22;
+              adcbuffer |= static_cast<size_t>((frame & 0x3fffff));
+              // and increase the adcbit counter by 22 bits
+              nadcbits += 22;
+              nadcbitstotal += 22;
+              // If we have 9 or more samples stored we can extract n samples
+              while (nadcbits >= 9) {
+                raw.IncNrSamples();
+                // In case the avg baseline feature was used we need to take special care of sample 0
+                if (isample == 0 && fParams.fUseBaselineAvg)
+                  raw.SetSample(extractAvgSample(&adcbuffer, &nadcbits), isample);
+                else
+                  raw.SetSample(extractSample(&adcbuffer, &nadcbits), isample);
+                isample++;
+              }
+              iword++;
+              word  = static_cast<size_t>(mscontent[iword]);
+              frame = (word >> (32 * istream)) & 0xffffffff;
+            }
+
+            if (getMessageType(frame) == Spadic::MsMessageType::kEOM) {
+              // Ensure that we are on the correct eLink
+              elinkId = (frame >> 24) & 0x3f;
+              if (elinkId != raw.GetElinkId()) {
+                result.second.fNumElinkMis++;
+              }
+
+              // Number of samples indicator = nsamples % 4
+              std::uint8_t nsamplesindicator = (frame >> 18) & 0x3;
+              // Number of required samples as indicated
+              std::uint64_t nreqsamples = (nadcbitstotal + 18) / 9;
+              std::uint8_t nn           = nreqsamples % 4;
+              for (std::uint8_t itest = 0; itest < 3; itest++) {
+                if (nn == nsamplesindicator || nreqsamples == 0) break;
+                nreqsamples--;
+                nn = nreqsamples % 4;
+              }
+
+              // There is a chance that the nsamplesindicator bits are corrupted,
+              // here we check that we do not try to extract more adcbits than actually are streamed
+              if (nreqsamples >= isample) {
+                // Now extract from the above values the number of required adc bits from the eom
+                std::int8_t nrequiredbits = (nreqsamples - isample) * 9 - nadcbits;
+                adcbuffer <<= nrequiredbits;
+
+                // The eom carries at maximum 18 adcbits
+                adcbuffer |= static_cast<size_t>((frame & 0x3ffff) >> (18 - nrequiredbits));
+                nadcbits += nrequiredbits;
+
+                while (nadcbits >= 9) {
+                  raw.IncNrSamples();
+                  raw.SetSample(extractSample(&adcbuffer, &nadcbits), isample);
+                  isample++;
+                }
+              }
+              else {
+                result.second.fNumCorruptEom++;
+              }
+              result.second.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));
+            }
+            else {
+              // We move the word counter backwards by one, such that the unexpected message can correctly be digested
+              iword--;
+              result.second.fNumMissingEom++;
+            }
+            break;
+          }
+          case Spadic::MsMessageType::kRDA: {
+            result.second.fNumWildRda++;
+            break;
+          }
+          case Spadic::MsMessageType::kEOM: {
+            result.second.fNumWildEom++;
+            break;
+          }
+          case Spadic::MsMessageType::kINF: {
+            result.second.fNumCreatedInfoMsgs++;
+            digestInfoMsg(frame);
+            break;
+          }
+          case Spadic::MsMessageType::kNUL: {
+            // last word in Microslice is 0.
+            if (iword != (nwords - 1) || (istream != (fStreamsPerWord - 1))) {
+              result.second.fNumWildNul++;
+            }
+            break;
+          }
+          case Spadic::MsMessageType::kUNK: {
+            result.second.fNumUnknownWords++;
+            return result;
+            break;
+          }
+          default:
+            // We have varying msg types for different versions of the message format.
+            // Hence, to not produce compiler warnings we have a "default break;" here.
+            break;
+        }
+      }
+    }
+    return result;
+  }
+  // --------------------------------------------------------------------------
 
 }  // namespace cbm::algo::trd
diff --git a/algo/detectors/trd/UnpackMS.h b/algo/detectors/trd/UnpackMS.h
index 63eaa5e12a5c6aa5f012551b88516f1fe552faf9..59d29bdf2b28721ce43d8bc969e99082a7d60735 100644
--- a/algo/detectors/trd/UnpackMS.h
+++ b/algo/detectors/trd/UnpackMS.h
@@ -1,10 +1,11 @@
 /* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
    SPDX-License-Identifier: GPL-3.0-only
-   Authors: Pascal Raisig, Dominik Smith [committer] */
+   Authors: Pascal Raisig, Dominik Smith [committer], David Schledt */
 
 #pragma once
 
 #include "CbmTrdDigi.h"
+#include "CbmTrdFexMessageSpadic.h"
 #include "CbmTrdRawMessageSpadic.h"
 #include "MicrosliceDescriptor.hpp"
 #include "Timeslice.hpp"
@@ -97,15 +98,16 @@ namespace cbm::algo::trd
    ** @since 31 January 2023
    ** @brief Unpack algorithm for TRD
    **/
+  template<uint8_t sys_ver>
   class UnpackMS : public UnpackMSBase<CbmTrdDigi, UnpackMonitorData> {
 
    public:
     /** @brief Construct from parameters **/
-    UnpackMS(const UnpackPar& pars);
+    UnpackMS(const UnpackPar& pars) : fParams(pars) {}
 
 
     /** @brief Destructor **/
-    ~UnpackMS() override;
+    ~UnpackMS() override = default;
 
 
     /** @brief Algorithm execution
@@ -220,6 +222,12 @@ namespace cbm::algo::trd
      **/
     CbmTrdDigi makeDigi(CbmTrdRawMessageSpadic raw, MsContext& ctx) const;
 
+    /**
+     ** @brief Create an actual digi from the fex message
+     ** @param fw
+     **/
+    CbmTrdDigi makeDigi(Spadic::FexWord<sys_ver> fw, size_t fMsStartTimeRel) const;
+
     /**
      ** @brief Get the Bin Time Shift value
      ** @param samples
diff --git a/core/data/trd/CbmTrdFexMessageSpadic.h b/core/data/trd/CbmTrdFexMessageSpadic.h
index 326813b814052150b1c10798e159447c1a377fdc..ba8c07d36845a07962448e489245b677cc85beb1 100644
--- a/core/data/trd/CbmTrdFexMessageSpadic.h
+++ b/core/data/trd/CbmTrdFexMessageSpadic.h
@@ -26,13 +26,12 @@ namespace Spadic
 
   template<size_t bytes>
   struct NByteContainer {
-    std::array<std::uint8_t, bytes> b;
+    std::uint8_t b[bytes];
 
     operator std::uint64_t()
     {
-      std::uint64_t r = 0;
-      for (std::uint8_t i = 0; i < bytes; ++i)
-        r |= (std::uint64_t) b[i] << (8 * i);
+      std::uint64_t r;
+      memcpy(&r, b, sizeof(long));
       return r;
     }
 
@@ -97,16 +96,18 @@ namespace Spadic
       constexpr int mhs  = trs - 3;
       constexpr int pts  = mhs - 5;
 
+      std::uint64_t w = word;
+
       ht = (word >> 62) & 0x3;  // TODO ext trigger
       if (ht != 0) {
-        elink      = (word >> els) & 0xff;
-        channel    = (word >> chs) & 0xf;
-        maxAdc     = (word >> maxs) & 0x1ff;
-        iMA        = (word >> imas) & 0x3;
-        timesample = (word >> trs) & 0x1ff;
-        mh         = (word >> mhs) & 0x3;
-        prec_time  = (float) ((word >> pts) & 0x1f) / float(1 << 4);
-        timestamp  = word & 0x1fffff;
+        elink      = (w >> els) & 0xff;
+        channel    = (w >> chs) & 0xf;
+        maxAdc     = (w >> maxs) & 0x1ff;
+        iMA        = (w >> imas) & 0x3;
+        timesample = (w >> trs) & 0x1ff;
+        mh         = (w >> mhs) & 0x3;
+        prec_time  = (float) ((w >> pts) & 0x1f) / float(1 << 4);
+        timestamp  = w & 0x1fffff;
       }
     }
   };
diff --git a/macro/run/run_unpack_online.C b/macro/run/run_unpack_online.C
index 7eb0a65d56c1e42c5060976eb7d4ce02e77b01f8..fbd6eff2661c1e9272f078b056262e6160542345 100644
--- a/macro/run/run_unpack_online.C
+++ b/macro/run/run_unpack_online.C
@@ -260,6 +260,10 @@ void run_unpack_online(std::vector<std::string> publisher = {"tcp://localhost:55
   cbmsetup->GetGeoTag(ECbmModuleId::kTrd, trdsetuptag);
   // trd1Dconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data(), runid);
   trd1Dconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data());
+  if (2724 <= runid) {
+    /// mCBM 2024
+    trdsetuptag = "v24b_mcbm";
+  }
   if (trd1Dconfig) {
     trd1Dconfig->SetDoWriteOutput();
     // Activate the line below to write Trd1D digis to a separate "TrdSpadicDigi" branch. Can be used to separate between Fasp and Spadic digis
diff --git a/macro/run/run_unpack_tsa.C b/macro/run/run_unpack_tsa.C
index 55bcb30dc01d537995f532295f1332024aa07318..efa7317878d9ef8af54d55830c1440bce14a1f65 100644
--- a/macro/run/run_unpack_tsa.C
+++ b/macro/run/run_unpack_tsa.C
@@ -286,6 +286,10 @@ void run_unpack_tsa(std::vector<std::string> infile = {"test.tsa"}, UInt_t runid
   cbmsetup->GetGeoTag(ECbmModuleId::kTrd, trdsetuptag);
   // trd1Dconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data(), runid);
   trd1Dconfig = std::make_shared<CbmTrdUnpackConfig>(trdsetuptag.Data());
+  if (2724 <= runid) {
+    /// mCBM 2024
+    trdsetuptag = "v24b_mcbm";
+  }
   if (trd1Dconfig) {
     trd1Dconfig->SetDoWriteOutput();
     // Activate the line below to write Trd1D digis to a separate "TrdSpadicDigi" branch. Can be used to separate between Fasp and Spadic digis