diff --git a/core/detectors/trd/CbmTrdParModAsic.cxx b/core/detectors/trd/CbmTrdParModAsic.cxx
index fbb3ac7bd012f8e27dd8e173dfde73493479e39a..a097edcc9bd4290bcd68fb0f4f7887c64237886c 100644
--- a/core/detectors/trd/CbmTrdParModAsic.cxx
+++ b/core/detectors/trd/CbmTrdParModAsic.cxx
@@ -134,11 +134,18 @@ CbmTrdDigi::eCbmTrdAsicType CbmTrdParModAsic::GetAsicType() const
 }
 
 //_______________________________________________________________________________
-int CbmTrdParModAsic::HasEqId(uint16_t eq) const
+int CbmTrdParModAsic::HasEqId(uint16_t eq, uint8_t& lnk) const
 {
   int idx(0);
   for (auto add : fCrobAdd) {
-    if (add == eq) return idx;
+    if ((add & 0xffff) == eq) {
+      lnk = 0;
+      return idx;
+    }
+    else if (((add >> 16) & 0xffff) == eq) {
+      lnk = 1;
+      return idx;
+    }
     idx++;
   }
   return -1;
diff --git a/core/detectors/trd/CbmTrdParModAsic.h b/core/detectors/trd/CbmTrdParModAsic.h
index c8dee321af72a0ff2e19f170208e271f9c6614b1..0595e7b1764141cfce70bd29d9c7b0540e219e43 100644
--- a/core/detectors/trd/CbmTrdParModAsic.h
+++ b/core/detectors/trd/CbmTrdParModAsic.h
@@ -79,12 +79,12 @@ public:
   virtual Int_t GetChamberType() const { return fType; }
 
   /** \brief Query the type of chamber*/
-  virtual const int* GetCrobAddresses() const { return fCrobAdd.data(); }
+  virtual const int32_t* GetCrobAddresses() const { return fCrobAdd.data(); }
 
   /** \brief Query the existence of an equipment (CROB) by HW id on the current module params.
    * \return Returns the position of the equipment (CROB) on the current module; -1 in case of failure.  
    */
-  virtual int HasEqId(uint16_t eqid) const;
+  virtual int HasEqId(uint16_t eqid, uint8_t& lnk) const;
 
   /** \brief Returns the number of INSTALLED ASICs for the current module
    * It applies to the list of ASICs.
@@ -109,7 +109,7 @@ protected:
   const CbmTrdParModAsic& operator=(const CbmTrdParModAsic& ref);
 
   uint8_t fType;                          ///< type of chamber for current module
-  std::vector<int> fCrobAdd;              ///< ordered list of Crobs for current module
+  std::vector<int32_t> fCrobAdd;          ///< ordered list of Crobs for current module
   std::map<int, CbmTrdParAsic*> fModPar;  ///< list of ASIC params for module
   ClassDef(CbmTrdParModAsic,
            1);  // The set of ASICs for one TRD modules
diff --git a/core/detectors/trd/CbmTrdParSetAsic.cxx b/core/detectors/trd/CbmTrdParSetAsic.cxx
index d8afe850273d123eca20421e0ff0c88a3216da44..dff470890e28c0adcf1948fc6e0dc7eb78c1a26a 100644
--- a/core/detectors/trd/CbmTrdParSetAsic.cxx
+++ b/core/detectors/trd/CbmTrdParSetAsic.cxx
@@ -35,10 +35,10 @@ CbmTrdParSetAsic::CbmTrdParSetAsic(const char* name, const char* title, const ch
 }
 
 //_______________________________________________________________________________
-int CbmTrdParSetAsic::FindModuleByEqId(uint16_t eqid, uint8_t& crob_id) const
+int CbmTrdParSetAsic::FindModuleByEqId(uint16_t eqid, uint8_t& crob_id, uint8_t& lnk_id) const
 {
   for (auto mod : fModuleMap) {
-    int crob = ((const CbmTrdParModAsic*) mod.second)->HasEqId(eqid);
+    int crob = ((const CbmTrdParModAsic*) mod.second)->HasEqId(eqid, lnk_id);
     if (crob < 0) continue;
     crob_id = crob;
     return mod.first;
diff --git a/core/detectors/trd/CbmTrdParSetAsic.h b/core/detectors/trd/CbmTrdParSetAsic.h
index 46993c932ec04879dcb4bb8f60e6ca5dfb65daff..e5171565d81bfa42f45f63a2606900e0cb506c43 100644
--- a/core/detectors/trd/CbmTrdParSetAsic.h
+++ b/core/detectors/trd/CbmTrdParSetAsic.h
@@ -42,7 +42,7 @@ public:
    * \param[out] crob_id index of crob on the module
    * \return module id in the setup
    */
-  virtual int FindModuleByEqId(uint16_t eqid, uint8_t& crob_id) const;
+  virtual int FindModuleByEqId(uint16_t eqid, uint8_t& crob_id, uint8_t& lnk_id) const;
   /** \brief Build the ASICs par for the current module from the info stored in the param file 
    * It applies to the list of ASICs.
    * \param module ASICs par (FASP or SPADIC)
diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackFaspAlgo.cxx b/reco/detectors/trd/unpack/CbmTrdUnpackFaspAlgo.cxx
index 5e30aabea8fcd8c648bffc7f5bdd5215c402ec80..1ac6e0373bf2cb4d811bd4306ba752083eb5f808 100644
--- a/reco/detectors/trd/unpack/CbmTrdUnpackFaspAlgo.cxx
+++ b/reco/detectors/trd/unpack/CbmTrdUnpackFaspAlgo.cxx
@@ -33,16 +33,6 @@
 #define VERBOSE 0
 
 using namespace std;
-CbmTrdUnpackFaspAlgo::CbmTrdFaspMessage::CbmTrdFaspMessage(uint8_t c, uint8_t typ, uint8_t t, uint16_t d, uint8_t rob,
-                                                           uint8_t asic)
-  : ch(c)
-  , type(typ)
-  , tlab(t)
-  , data(d)
-  , crob(rob)
-  , fasp(asic)
-{
-}
 
 CbmTrdUnpackFaspAlgo::CbmTrdUnpackFaspAlgo() : CbmRecoUnpackAlgo("CbmTrdUnpackFaspAlgo") {}
 
@@ -122,62 +112,10 @@ CbmTrdUnpackFaspAlgo::GetParContainerRequest(std::string geoTag, std::uint32_t r
   return &fParContVec;
 }
 
-//_________________________________________________________________________________
-CbmTrdUnpackFaspAlgo::CbmTrdFaspMessageType CbmTrdUnpackFaspAlgo::mess_type(uint32_t wd)
-{
-  if ((wd >> kMessCh) & 0x1) return kData;
-  return kEpoch;
-}
-
-//_________________________________________________________________________________
-void CbmTrdUnpackFaspAlgo::mess_readDW(uint32_t w, CbmTrdFaspMessage* mess)
-{
-  uint32_t wd(w), shift(0);
-  mess->ch = wd & 0xf;
-  shift += Int_t(kMessCh);
-  mess->type = (wd >> shift) & 0x1;
-  shift += Int_t(kMessType);
-  mess->tlab = (wd >> shift) & 0x7f;
-  shift += Int_t(kMessTlab);
-  mess->data = (wd >> shift) & 0x3fff;
-  shift += Int_t(kMessData);
-  mess->fasp = (wd >> shift) & 0x3f;
-
-  printf("DBG :: ");
-  mess_prt(mess);
-}
-
-//_________________________________________________________________________________
-void CbmTrdUnpackFaspAlgo::mess_readEW(uint32_t w, CbmTrdFaspMessage* mess)
-{
-  uint32_t wd(w), shift(0);
-  mess->ch = wd & 0xf;
-  shift += Int_t(kMessCh);
-  mess->type = (wd >> shift) & 0x1;
-  shift += Int_t(kMessType);
-  mess->epoch = (wd >> shift) & 0x1fffff;
-  shift += Int_t(kMessEpoch);
-  mess->crob = (wd >> shift) & 0x3f;
-  printf("DBG :: ");
-  mess_prt(mess);
-}
-
-//_________________________________________________________________________________
-void CbmTrdUnpackFaspAlgo::mess_prt(CbmTrdFaspMessage* mess)
-{
-  if (mess->type == kData)
-    cout << boost::format("    DATA : fasp_id=%02d ch_id=%02d tclk=%03d data=%4d\n")
-              % static_cast<unsigned int>(mess->fasp) % static_cast<unsigned int>(mess->ch)
-              % static_cast<unsigned int>(mess->tlab) % static_cast<unsigned int>(mess->data);
-  else
-    cout << boost::format("    EPOCH: crob_id=%02d ch_id=%02d epoch=%05d\n") % static_cast<unsigned int>(mess->crob)
-              % static_cast<unsigned int>(mess->ch) % static_cast<unsigned int>(mess->epoch);
-}
-
 //_________________________________________________________________________________
 bool CbmTrdUnpackFaspAlgo::pushDigis(std::vector<CbmTrdUnpackFaspAlgo::CbmTrdFaspMessage> messes, const uint16_t mod_id)
 {
-  const UChar_t lFasp             = messes[0].fasp;
+  const UChar_t lFasp             = messes[0].getFaspIdMod();
   const CbmTrdParModAsic* asicPar = (CbmTrdParModAsic*) fAsicSet.GetModulePar(mod_id);
   const CbmTrdParFasp* faspPar    = (CbmTrdParFasp*) asicPar->GetAsicPar(mod_id * 1000 + lFasp);
   const CbmTrdParModDigi* digiPar = (CbmTrdParModDigi*) fDigiSet->GetModulePar(mod_id);
@@ -193,11 +131,11 @@ bool CbmTrdUnpackFaspAlgo::pushDigis(std::vector<CbmTrdUnpackFaspAlgo::CbmTrdFas
     return false;
   }
 
-  // TODO temporary add DAQ time calibration for FASPRO.
-  // Should be absorbed in the ASIC parameter definition
   ULong64_t tdaqOffset(0);
-  if (digiPar->GetPadRow(faspPar->GetPadAddress(messes[0].ch)) % 2 == 0) tdaqOffset = 3;
-
+  if (fMess->version == eMessageVersion::kMessLegacy) {
+    // Add DAQ time calibration for legacy FASPRO.
+    if (digiPar->GetPadRow(faspPar->GetPadAddress(messes[0].ch)) % 2 == 0) tdaqOffset = 3;
+  }
   if (VERBOSE) faspPar->Print();
 
   for (auto imess : messes) {
@@ -214,7 +152,7 @@ bool CbmTrdUnpackFaspAlgo::pushDigis(std::vector<CbmTrdUnpackFaspAlgo::CbmTrdFas
 
     if (VERBOSE) {
       const Int_t ch = 2 * pad + chCalib->HasPairingR();
-      mess_prt(&imess);
+      imess.print();
       printf("fasp[%2d] ch[%4d / %2d] pad[%4d] row[%2d] col[%2d] %c[%4d]\n", lFasp, ch, imess.ch, pad,
              digiPar->GetPadRow(pad), digiPar->GetPadColumn(pad), (chCalib->HasPairingT() ? 'T' : 'R'),
              lchT > 0 ? lchT : lchR);
@@ -254,18 +192,22 @@ bool CbmTrdUnpackFaspAlgo::pushDigis(std::vector<CbmTrdUnpackFaspAlgo::CbmTrdFas
       id = digiBuffer.rbegin();
     }
 
-    // update charge for previously allocated digis to account for FASPRO ADC buffering and read-out feature
-    for (++id; id != digiBuffer.rend(); ++id) {
-      r = (*id).GetCharge(t, dt);
-      if (lchR && int(r)) {  // update R charge and mark on digi
-        (*id).SetCharge(t, lchR, dt);
-        (*id).SetFlag(1);
-        break;
-      }
-      else if (lchT && int(t)) {  // update T charge and mark on digi
-        (*id).SetCharge(lchT, r, dt);
-        (*id).SetFlag(0);
-        break;
+    // LEGACY CODE:
+    if (fMess->version == eMessageVersion::kMessLegacy) {
+      // update charge for previously allocated digis
+      // to account for FASPRO ADC buffering and read-out feature
+      for (++id; id != digiBuffer.rend(); ++id) {
+        r = (*id).GetCharge(t, dt);
+        if (lchR && int(r)) {  // update R charge and mark on digi
+          (*id).SetCharge(t, lchR, dt);
+          (*id).SetFlag(1);
+          break;
+        }
+        else if (lchT && int(t)) {  // update T charge and mark on digi
+          (*id).SetCharge(lchT, r, dt);
+          (*id).SetFlag(0);
+          break;
+        }
       }
     }
   }
@@ -302,10 +244,14 @@ void CbmTrdUnpackFaspAlgo::FinalizeComponent()
     uint nIncomplete(0);
     for (auto id = fDigiBuffer[ipad].begin(); id != fDigiBuffer[ipad].end(); id++) {
       r = (*id).GetCharge(t, dt);
-      // check if digi has all signals CORRECTED
-      if (((t > 0) != (*id).IsFlagged(0)) || ((r > 0) != (*id).IsFlagged(1))) {
-        nIncomplete++;
-        continue;
+
+      // LEGACY CODE:
+      if (fMess->version == eMessageVersion::kMessLegacy) {
+        // check if digi has all signals CORRECTED
+        if (((t > 0) != (*id).IsFlagged(0)) || ((r > 0) != (*id).IsFlagged(1))) {
+          nIncomplete++;
+          continue;
+        }
       }
       if (fMonitor) fMonitor->FillHistos((&(*id)));
       // reset flags as they were used only to mark the correctly setting of the charge/digi
@@ -325,7 +271,7 @@ void CbmTrdUnpackFaspAlgo::FinalizeComponent()
 bool CbmTrdUnpackFaspAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp, UInt_t imslice)
 {
   if (VERBOSE) printf("CbmTrdUnpackFaspAlgo::unpack 0x%04x %d\n", icomp, imslice);
-  // LOG(info) << "Component " << icomp << " connected to config CbmTrdUnpackConfig2D. Slice "<<imslice;
+  LOG(debug2) << "Component " << icomp << " connected to config CbmTrdUnpackConfig2D. Slice " << imslice;
 
   bool unpackOk = true;
   //Double_t fdMsSizeInNs = 1.28e6;
@@ -333,16 +279,30 @@ bool CbmTrdUnpackFaspAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp
   auto msdesc = ts->descriptor(icomp, imslice);
 
   // Cast required to silence a warning on macos (there a uint64_t is a llu)
-  if (VERBOSE) printf("time start %lu\n", static_cast<size_t>(msdesc.idx));
-
+  if (VERBOSE)
+    printf("time start %lu system[0x%x] version[0x%x]\n", static_cast<size_t>(msdesc.idx), msdesc.sys_id,
+           msdesc.sys_ver);
+
+  // this is executed only once, at the beginning, after discovering the packing version of the data
+  if (!fMess) {
+    switch (msdesc.sys_ver) {
+      case (int) eMessageVersion::kMessLegacy:
+        LOG(info) << "CbmTrdUnpackFaspAlgo::unpack : Legacy version.";
+        fMess = new CbmTrdFaspMessage();
+        break;
+      case (int) eMessageVersion::kMess24:
+        LOG(info) << "CbmTrdUnpackFaspAlgo::unpack : 06.2024 version.";
+        fMess = new CbmTrdFaspMessage24();
+        break;
+      default: LOG(fatal) << "CbmTrdUnpackFaspAlgo::unpack : Un-registered version " << msdesc.sys_ver; break;
+    }
+  }
   // define time wrt start of time slice in TRD/FASP clks [80 MHz]
   fTime = ULong64_t((msdesc.idx - fTsStartTime - fSystemTimeOffset) / 12.5);
 
-  // get MOD_id and CROB id from the equipment, using the comp map: eq_id -> (mod_id, crob_id)
-  uint8_t crob_id(0);
-  const uint16_t eq_id = msdesc.eq_id;
-  uint16_t mod_id      = fAsicSet.FindModuleByEqId(eq_id, crob_id);
-
+  // get MOD_id and ROB id from the equipment, using the comp map: eq_id -> (mod_id, rob_id)
+  fMess->mod = fAsicSet.FindModuleByEqId(msdesc.eq_id, fMess->rob, fMess->elink);
+  //printf("AB :: eq_id[0x%x] -> rob[%d] link[%d] mod[%d]\n", msdesc.eq_id, fMess->rob, fMess->elink, fMess->mod);
   // Get the µslice size in bytes to calculate the number of completed words
   auto mssize = msdesc.size;
 
@@ -357,90 +317,188 @@ bool CbmTrdUnpackFaspAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp
   const uint32_t* wd = reinterpret_cast<const uint32_t*>(mscontent);
 
 
-  UChar_t lFaspOld(0xff);
+  uint8_t lFaspOld(0xff);
   vector<CbmTrdFaspMessage> vMess;
   for (uint64_t j = 0; j < nwords; j++, wd++) {
-    //     // Select the appropriate conversion type of the word according to the message type
-    //     switch(mess_type(*wd)){
-    //       case CbmTrdFaspMessageType::kData:
-    //         mess_readDW(*wd, &mess);
-    //         break;
-    //       case CbmTrdFaspMessageType::kEpoch:
-    //         mess_readEW(*wd, &mess);
-    //         break;
-    //     }
     uint32_t w      = *wd;
-    uint8_t ch_id   = w & 0xf;
-    uint8_t isaux   = (w >> 4) & 0x1;
-    uint8_t slice   = (w >> 5) & 0x7f;
-    uint16_t data   = (w >> 12) & 0x3fff;
-    uint32_t epoch  = (w >> 5) & 0x1fffff;
-    uint8_t fasp_id = ((w >> 26) & 0x3f) + crob_id * NFASPCROB;
+    // Select the appropriate conversion type of the word according to
+    // the message version and type
+    switch (fMess->getType(w)) {
+      case eMessageType::kData: fMess->readDW(w); break;
+      case eMessageType::kEpoch: fMess->readEW(w); break;
+      default: break;
+    }
+
+    // uint8_t ch_id   = w & 0xf;
+    // uint8_t isaux   = (w >> 4) & 0x1;
+    // uint8_t slice   = (w >> 5) & 0x7f;
+    // uint16_t data   = (w >> 12) & 0x3fff;
+    // uint32_t epoch  = (w >> 5) & 0x1fffff;
+    // uint8_t fasp_id = ((w >> 26) & 0x3f) + crob_id * NFASPCROB;
     // std::cout<<"fasp_id="<<static_cast<unsigned int>(fasp_id)<<" ch_id="<<static_cast<unsigned int>(ch_id)<<" isaux="<<static_cast<unsigned int>(isaux)<<std::endl;
-    if (isaux) {
-      if (!ch_id) {
+    if (fMess->type == (int) eMessageType::kEpoch) {
+      if (!fMess->ch) {
         // clear buffer
-        if (vMess.size()) { pushDigis(vMess, mod_id); }
+        if (vMess.size()) pushDigis(vMess, fMess->mod);
         vMess.clear();
 
-        if (VERBOSE)
-          cout << boost::format("    EE : fasp_id=%02d ch_id=%02d epoch=%03d\n") % static_cast<unsigned int>(fasp_id)
-                    % static_cast<unsigned int>(ch_id) % static_cast<unsigned int>(epoch);
+        if (VERBOSE) fMess->print();
 
         lFaspOld = 0xff;
         fTime += FASP_EPOCH_LENGTH;
       }
-      else if (ch_id == 1) {
-        if (VERBOSE) cout << boost::format("    PAUSE: fasp_id=%02d\n") % static_cast<unsigned int>(fasp_id);
+      else {
+        LOG(error) << "CbmTrdUnpackFaspAlgo::unpack : Epoch message with wrong signature. Ask an expert.";
       }
       continue;
     }
 
-    if (lFaspOld != fasp_id) {
+    if (lFaspOld != fMess->getFaspIdMod()) {
       // push
-      if (vMess.size()) { pushDigis(vMess, mod_id); }
+      if (vMess.size()) pushDigis(vMess, fMess->mod);
       vMess.clear();
-      lFaspOld = fasp_id;
-    }
-    if (data & 0x1) {
-      LOG(warn) << GetName() << "::unpack - Data corrupted : detect end bit set.";
-      continue;
+      lFaspOld = fMess->getFaspIdMod();
     }
-    if (VERBOSE)
-      cout << boost::format("    DD : fasp_id=%02d ch_id=%02d slice=%03d data=%4d\n")
-                % static_cast<unsigned int>(fasp_id) % static_cast<unsigned int>(ch_id)
-                % static_cast<unsigned int>(slice) % static_cast<unsigned int>(data >> 1);
-    if (data & 0x2000) {
-      LOG(debug) << GetName() << "::unpack - Self-triggered data.";
-      data &= 0x1fff;
-    }
-    vMess.emplace_back(ch_id, kData, slice, data >> 1, crob_id, lFaspOld);
-    //prt_wd(*wd);
+    if (VERBOSE) fMess->print();
+    vMess.emplace_back(*fMess);
+    //vMess.emplace_back(crob_id, lFaspOld, ch_id, kData, slice, data >> 1);
   }
   return unpackOk;
 }
 
+//_________________________________________________________________________________
+CbmTrdUnpackFaspAlgo::CbmTrdFaspMessage::CbmTrdFaspMessage(uint8_t rdaq, uint8_t asic, uint8_t c, uint8_t typ,
+                                                           uint8_t t, uint16_t d, uint8_t lnk)
+  : ch(c)
+  , type(typ)
+  , tlab(t)
+  , data(d)
+  , rob(rdaq)
+  , elink(lnk)
+  , fasp(asic)
+{
+}
+
+//_________________________________________________________________________________
+CbmTrdUnpackFaspAlgo::eMessageType CbmTrdUnpackFaspAlgo::CbmTrdFaspMessage::getType(uint32_t wd) const
+{
+  if ((wd >> (int) eMessageLength::kMessCh) & 0x1) return eMessageType::kEpoch;
+  return eMessageType::kData;
+}
+
 //_____________________________________________________________
-void CbmTrdUnpackFaspAlgo::prt_wd(uint32_t w)
+void CbmTrdUnpackFaspAlgo::CbmTrdFaspMessage::readDW(uint32_t w)
 {
-  //    out<<w<<std::endl;
-  uint8_t ch_id   = w & 0xf;
-  uint8_t isaux   = (w >> 4) & 0x1;
-  uint8_t slice   = (w >> 5) & 0x7f;
-  uint16_t data   = (w >> 12) & 0x3fff;
-  uint32_t epoch  = (w >> 5) & 0x1fffff;
-  uint8_t fasp_id = (w >> 26) & 0x3f;
-  //    out<<"fasp_id="<<static_cast<unsigned int>(fasp_id)<<" ch_id="<<static_cast<unsigned int>(ch_id)<<" isaux="<<static_cast<unsigned int>(isaux)<<std::endl;
-  if (isaux) {
-    if (!ch_id) { cout << boost::format("EE: %08d\n") % epoch; }
-    else if (ch_id == 1) {
-      cout << boost::format("    PAUSE: fasp_id=%02d\n") % static_cast<unsigned int>(fasp_id);
-    }
+  uint8_t shift(0);
+  ch = w & 0xf;
+  shift += uint8_t(eMessageLength::kMessCh);
+  type = (w >> shift) & 0x1;
+  shift += uint8_t(eMessageLength::kMessType);
+  tlab = (w >> shift) & 0x7f;
+  shift += uint8_t(eMessageLength::kMessTlab);
+  data = (w >> shift) & 0x3fff;
+  data = data >> 1;
+  shift += uint8_t(eMessageLength::kMessData);
+  fasp = ((w >> shift) & 0x3f);
+
+  if (VERBOSE >= 2) {
+    printf("legacyMess_readDW[%x]\n", w);
+    print();
   }
-  else {
-    cout << boost::format("    DATA: w=%08x fasp_id=%02d ch_id=%02d slice=%03d data=%04d\n") % w
-              % static_cast<unsigned int>(fasp_id) % static_cast<unsigned int>(ch_id) % static_cast<unsigned int>(slice)
-              % static_cast<unsigned int>(data >> 1);
+}
+
+//_________________________________________________________________________________
+void CbmTrdUnpackFaspAlgo::CbmTrdFaspMessage::readEW(uint32_t w)
+{
+  uint8_t shift(0);
+  ch = w & 0xf;
+  shift += uint8_t(eMessageLength::kMessCh);
+  type = (w >> shift) & 0x1;
+  shift += uint8_t(eMessageLength::kMessType);
+  epoch = (w >> shift) & 0x1fffff;
+  shift += uint8_t(eMessageLength::kMessEpoch);
+  fasp = (w >> shift) & 0x3f;
+
+  if (VERBOSE >= 2) {
+    printf("legacyMess_readEW[%x]\n", w);
+    print();
+  }
+}
+
+//_________________________________________________________________________________
+void CbmTrdUnpackFaspAlgo::CbmTrdFaspMessage::print() const
+{
+  if (type == (uint8_t) eMessageType::kData)
+    cout << Form("    DATA : rob=%d%c fasp_id=%02d [%03d] ch_id=%02d tclk=%03d data=%4d\n", rob, (elink ? 'u' : 'd'),
+                 fasp, getFaspIdMod(), ch, tlab, data);
+  else if (type == (uint8_t) eMessageType::kEpoch)
+    cout << Form("    EPOCH: eq_id=%d%c ch_id=%02d epoch=%05d\n", rob, (elink ? 'u' : 'd'), ch, epoch);
+  else
+    cout << "    MTYPE: unknown";
+}
+
+//_________________________________________________________________________________
+CbmTrdUnpackFaspAlgo::CbmTrdFaspMessage24::CbmTrdFaspMessage24() : CbmTrdFaspMessage()
+{
+  version = eMessageVersion::kMess24;
+}
+
+//_________________________________________________________________________________
+CbmTrdUnpackFaspAlgo::eMessageType CbmTrdUnpackFaspAlgo::CbmTrdFaspMessage24::getType(uint32_t wd) const
+{
+  //printf("mess_type[%x]\n", wd);
+  if ((wd >> 31) & 0x1) return eMessageType::kEpoch;
+  return eMessageType::kData;
+}
+
+//_____________________________________________________________
+void CbmTrdUnpackFaspAlgo::CbmTrdFaspMessage24::readDW(uint32_t w)
+{
+  uint8_t shift(0);
+  uint16_t adc_data = (w >> shift) & 0x3fff;
+  // TODO This data format version delivers the ADC value as bit_sgn + 13 significant bits
+  // TODO The CbmTrdDigi supports digi data with only 12bits unsigned. The first tests will
+  // TODO convert the measurement to the old format leaving the implementation of the new storage to // TODO later time.  (AB 14.06.2024)
+  uint16_t sign = adc_data >> 13;  // sign
+  int value_i;
+  if (!sign)
+    value_i = adc_data;
+  else
+    value_i = (-1) * ((adc_data ^ 0xffff) & 0x1fff);
+  // convert to 12bit unsigned
+  data = (value_i + 0x1fff) >> 2;
+  shift += uint8_t(eMessageLength::kMessData);
+  tlab = (w >> shift) & 0x7f;
+  shift += uint8_t(eMessageLength::kMessTlab);
+  ch = (w >> shift) & 0xf;
+  shift += uint8_t(eMessageLength::kMessCh);
+  fasp = ((w >> shift) & 0x3f);
+  shift += uint8_t(eMessageLength::kMessFasp);
+  type = (w >> shift) & 0x1;
+  shift += uint8_t(eMessageLength::kMessType);
+
+  if (VERBOSE >= 2) {
+    printf("v06.24Mess_readDW[%x] signed charge = %+d\n", w, value_i);
+    print();
+  }
+}
+
+//_________________________________________________________________________________
+void CbmTrdUnpackFaspAlgo::CbmTrdFaspMessage24::readEW(uint32_t w)
+{
+  uint8_t shift(0);
+  epoch = (w >> shift) & 0x1fffff;
+  shift += uint8_t(eMessageLength::kMessEpoch);
+  ch = (w >> shift) & 0xf;
+  shift += uint8_t(eMessageLength::kMessCh);
+  fasp = (w >> shift) & 0x3f;
+  shift += uint8_t(eMessageLength::kMessFasp);
+  type = (w >> shift) & 0x1;
+  shift += uint8_t(eMessageLength::kMessType);
+
+  if (VERBOSE >= 2) {
+    printf("v06.24Mess_readEW[%x]\n", w);
+    print();
   }
 }
 
diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackFaspAlgo.h b/reco/detectors/trd/unpack/CbmTrdUnpackFaspAlgo.h
index 007781bf304d27e07ac224d46f631c211ca74794..a5c68f9b5c1fda695662b111c3ff70fade96a745 100644
--- a/reco/detectors/trd/unpack/CbmTrdUnpackFaspAlgo.h
+++ b/reco/detectors/trd/unpack/CbmTrdUnpackFaspAlgo.h
@@ -45,36 +45,56 @@
 class CbmTrdParSetDigi;
 class CbmTrdUnpackFaspAlgo : public CbmRecoUnpackAlgo<CbmTrdDigi> {
 public:
-  /** @brief Bytes per FASP frame stored in the microslices (32 bits words)
-   * - DATA WORD -
+ /** @brief Bytes per FASP frame stored in the microslices (32 bits words)
+   * - DATA WORD - for legacy version
    * ffff.ffdd dddd.dddd dddd.tttt ttta.cccc
    * f - FASP id
    * d - ADC signal
    * t - time label inside epoch
-   * a - word type (0)
+   * a - word type (1)
    * c - channel id
    * - EPOCH WORD -
    * ffff.fftt tttt.tttt tttt.tttt ttta.cccc
    * f - FASP id
    * t - epoch index
+   * a - word type (0)
+   * c - channel id
+   * =====================================================
+   * - DATA WORD - for 06.2024 version
+   * afff.fffc ccct.tttt ttdd.dddd dddd.dddd
+   * f - FASP id
+   * d - ADC signal
+   * t - time label inside epoch
    * a - word type (1)
    * c - channel id
+   * - EPOCH WORD -
+   * afff.fffc ccct.tttt tttt tttt tttt.tttt
+   * a - word type (0)
+   * f - FASP id
+   * t - epoch index
+   * c - channel id
    */
-  enum CbmTrdFaspMessageLength
-  {
-    kMessCh    = 4,
-    kMessType  = 1,
-    kMessTlab  = 7,
-    kMessData  = 14,
-    kMessFasp  = 6,
-    kMessEpoch = 21
-  };
-  enum CbmTrdFaspMessageType
-  {
-    kEpoch = 0,
-    kData
-  };
-
+ enum class eMessageLength : int
+ {
+   kMessCh    = 4,
+   kMessType  = 1,
+   kMessTlab  = 7,
+   kMessData  = 14,
+   kMessFasp  = 6,
+   kMessEpoch = 21
+ };
+ enum eMessageType
+ {
+   kData  = 0,
+   kEpoch = 1,
+   kNone
+ };
+ enum class eMessageVersion : int
+ {
+   kMessLegacy = 2,  /// unpacker version for 2-board FASPRO+GETS HW
+   kMess24     = 3,  /// unpacker version for 1-board FASPRO HW first used 18.06.24 (mCBM)
+   kMessNoDef        /// default unpacker version
+ };
   /** @brief Create the Cbm Trd Unpack AlgoBase object */
   CbmTrdUnpackFaspAlgo();
 
@@ -89,16 +109,36 @@ public:
 
 
   /** @brief Data structure for unpacking the FASP word */
-  struct CbmTrdFaspMessage {
-    CbmTrdFaspMessage(uint8_t c, uint8_t typ, uint8_t t, uint16_t d, uint8_t rob, uint8_t asic);
+  class CbmTrdFaspMessage {
+   public:
+    CbmTrdFaspMessage()                         = default;
+    CbmTrdFaspMessage(const CbmTrdFaspMessage&) = default;
+    virtual ~CbmTrdFaspMessage()                = default;
+    CbmTrdFaspMessage(uint8_t rob, uint8_t asic, uint8_t c, uint8_t typ, uint8_t t, uint16_t d, uint8_t l);
+    virtual int getFaspIdMod() const { return fasp + rob * NFASPCROB; }
+    virtual eMessageType getType(uint32_t w) const;
+    virtual void print() const;
+    virtual void readDW(uint32_t w);
+    virtual void readEW(uint32_t w);
+
+   public:
+    eMessageVersion version = eMessageVersion::kMessLegacy;  ///< format version
     uint8_t ch     = 0;  ///< ch id in the FASP
-    uint8_t type   = 0;  ///< message type 0 = epoch, 1 = data (not used for the moment)
+    uint8_t type            = 0;  ///< message type 0 = data, 1 = epoch
     uint8_t tlab   = 0;  ///< time of the digi inside the epoch
     uint16_t data  = 0;  ///< ADC value
     uint32_t epoch = 0;  ///< epoch id (not used for the moment)
     uint32_t mod   = 0;  ///< full module address according to CbmTrdAddress
-    uint8_t crob   = 0;  ///< CROB id in the module
-    uint8_t fasp   = 0;  ///< FASP id in the module
+    uint8_t rob             = 0;  ///< Read-Out unit id in the module
+    uint8_t elink           = 0;  ///< optical link for read-out unit (up or down, starting with v2024)
+    uint8_t fasp            = 0;  ///< FASP id in the module
+  };
+  class CbmTrdFaspMessage24 : public CbmTrdFaspMessage {
+   public:
+    CbmTrdFaspMessage24();
+    virtual eMessageType getType(uint32_t w) const;
+    virtual void readDW(uint32_t w);
+    virtual void readEW(uint32_t w);
   };
   /** Access the asic parameter list, read-only*/
   virtual const CbmTrdParSetAsic* GetAsicPar() const { return &fAsicSet; }
@@ -122,26 +162,20 @@ public:
 
 protected:
   /** @brief Get message type from the FASP word */
-  CbmTrdFaspMessageType mess_type(uint32_t wd);
-  /** @brief Convert the FASP word into a DATA message */
-  void mess_readDW(uint32_t wd, CbmTrdFaspMessage* mess);
-  /** @brief Convert the FASP word into a EPOCH message */
-  void mess_readEW(uint32_t wd, CbmTrdFaspMessage* mess);
-  /** @brief Print FASP message */
-  void mess_prt(CbmTrdFaspMessage* mess);
-  bool pushDigis(std::vector<CbmTrdUnpackFaspAlgo::CbmTrdFaspMessage> messages, const uint16_t mod_id);
-  /** @brief Time offset for digi wrt the TS start, expressed in 80 MHz clks. It contains:
+ eMessageType mess_type(uint32_t wd);
+ bool pushDigis(std::vector<CbmTrdUnpackFaspAlgo::CbmTrdFaspMessage> messages, const uint16_t mod_id);
+ /** @brief Time offset for digi wrt the TS start, expressed in 80 MHz clks. It contains:
    *  - relative offset of the MS wrt the TS
    *  - FASP epoch offset for current CROB
    *  - TRD2D system offset wrt to experiment time (e.g. Bmon)
    */
-  ULong64_t fTime = 0;
+ ULong64_t fTime = 0;
 
-  /** @brief Finish function for this algorithm base clase */
-  void finish()
-  {
-    if (fMonitor) fMonitor->Finish();
-  }
+ /** @brief Finish function for this algorithm base clase */
+ void finish()
+ {
+   if (fMonitor) fMonitor->Finish();
+ }
 
   /**
    * @brief Additional initialisation function for all BaseR derived algorithms.
@@ -178,25 +212,10 @@ protected:
   void FinalizeComponent();
 
   // Constants
-  /** @brief Bytes per FASP frame stored in the microslices (32 bits words)
-   * - DATA WORD -
-   * ffff.ffdd dddd.dddd dddd.tttt ttta.cccc
-   * f - FASP id
-   * d - ADC signal
-   * t - time label inside epoch
-   * a - word type (1)
-   * c - channel id
-   * - EPOCH WORD -
-   * ffff.fftt tttt.tttt tttt.tttt ttta.cccc
-   * f - FASP id
-   * t - epoch index
-   * a - word type (0)
-   * c - channel id
-   */
+  /** @brief Bytes per FASP frame stored in the microslices (32 bits words)*/
   static const std::uint8_t fBytesPerWord = 4;
 
 private:
-  void prt_wd(uint32_t w);
   std::map<uint16_t, std::pair<uint16_t, uint16_t>>* fCompMap        = nullptr;  ///> Map eq_id -> (mod_id, crob_id)
   std::array<std::vector<CbmTrdDigi>, NFASPMOD* NFASPCH> fDigiBuffer = {
     {}};  ///> Buffered digi for each pad in CROB component
@@ -205,8 +224,9 @@ private:
   std::vector<uint16_t> fModuleId = {};  ///> list of modules for which there is are calibration parameters
   CbmTrdParSetAsic fAsicSet;
   CbmTrdParSetDigi* fDigiSet = nullptr;
+  CbmTrdFaspMessage* fMess   = nullptr;  ///> current message version
 
-  ClassDef(CbmTrdUnpackFaspAlgo, 3)  // unpack FASP read-out detectors
+  ClassDef(CbmTrdUnpackFaspAlgo, 4)  // unpack FASP read-out detectors
 };
 
 #endif  // CbmTrdUnpackFaspAlgo_H