From 5b16d30c711eb4ac7f6935cd68ae23d00f2592a6 Mon Sep 17 00:00:00 2001
From: Alexandru Bercuci <abercuci@niham.nipne.ro>
Date: Fri, 19 Aug 2022 09:47:52 +0300
Subject: [PATCH] fix memory leak reported at
 https://redmine.cbm.gsi.de/issues/2570.     Extend suggestions of PAL

---
 reco/base/CbmRecoUnpackAlgo.tmpl              |   9 +
 .../trd/unpack/CbmTrdUnpackFaspAlgo.cxx       | 203 +++++++++++-------
 .../trd/unpack/CbmTrdUnpackFaspAlgo.h         |  54 +++--
 .../trd/unpack/CbmTrdUnpackFaspConfig.cxx     |   9 +
 .../trd/unpack/CbmTrdUnpackFaspConfig.h       |   5 +-
 5 files changed, 181 insertions(+), 99 deletions(-)

diff --git a/reco/base/CbmRecoUnpackAlgo.tmpl b/reco/base/CbmRecoUnpackAlgo.tmpl
index ad70ec00c8..595f80381d 100644
--- a/reco/base/CbmRecoUnpackAlgo.tmpl
+++ b/reco/base/CbmRecoUnpackAlgo.tmpl
@@ -253,6 +253,12 @@ protected:
   */
   virtual bool unpack(const fles::Timeslice* ts, std::uint16_t icomp, UInt_t imslice) = 0;
 
+  /**
+   * @brief Use this function to implement additional actions to be called to finalize component if necessary.
+            (e.g. copy from temp buffers)
+  */
+  virtual void FinalizeComponent() { return; };
+
 public:
   // Runtime functions
 
@@ -433,6 +439,9 @@ public:
       }
     }
 
+    /// Give opportunity to finalize component (e.g. copy from temp buffers) if necessary
+    FinalizeComponent();
+
     auto ndigis = fOutputVec.size();
     fNrCreatedDigis += ndigis;
 
diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackFaspAlgo.cxx b/reco/detectors/trd/unpack/CbmTrdUnpackFaspAlgo.cxx
index e839fce3a9..19a3fdb0ca 100644
--- a/reco/detectors/trd/unpack/CbmTrdUnpackFaspAlgo.cxx
+++ b/reco/detectors/trd/unpack/CbmTrdUnpackFaspAlgo.cxx
@@ -47,23 +47,26 @@ CbmTrdUnpackFaspAlgo::~CbmTrdUnpackFaspAlgo() {}
 //_________________________________________________________________________________
 Bool_t CbmTrdUnpackFaspAlgo::initParSet(FairParGenericSet* parset)
 {
+  printf("AB :: CbmTrdUnpackFaspAlgo::initParSet\n");
   FairParamList parList;
   Int_t nModules(0);
   if (strcmp(parset->ClassName(), "CbmTrdParSetAsic") == 0) {
     CbmTrdParSetAsic* setPar = static_cast<CbmTrdParSetAsic*>(parset);
     for (auto did : fModuleId) {
+      printf("AB :: check did %d\n", did);
       const CbmTrdParSetAsic* setDet = static_cast<const CbmTrdParSetAsic*>(setPar->GetModuleSet(did));
       if (!setDet) continue;
       if (setDet->GetAsicType() != Int_t(CbmTrdDigi::eCbmTrdAsicType::kFASP)) continue;
       if (fMonitor) fMonitor->addParam(did, setDet);
       nModules++;
+      printf("AB :: register ASIC params for module %d\n", did);
       std::vector<Int_t> a;
       setDet->GetAsicAddresses(&a);
       for (auto add : a) {
         CbmTrdParAsic* asic = (CbmTrdParAsic*) setDet->GetModulePar(add);
         if (asic->IsA() == CbmTrdParSpadic::Class()) continue;
         fAsicPar.addParam(asic);
-        if (VERBOSE) asic->Print();
+        if (VERBOSE > 2) asic->Print();
       }
     }
     //      setPar->printParams();
@@ -213,7 +216,7 @@ void CbmTrdUnpackFaspAlgo::mess_prt(CbmTrdFaspContent* mess)
 }
 
 //_________________________________________________________________________________
-bool CbmTrdUnpackFaspAlgo::pushDigis(std::vector<CbmTrdUnpackFaspAlgo::CbmTrdFaspContent*> messes)
+bool CbmTrdUnpackFaspAlgo::pushDigis(std::vector<CbmTrdUnpackFaspAlgo::CbmTrdFaspContent> messes)
 {
   UChar_t lFasp(0xff);
   UShort_t lchR, lchT;
@@ -223,124 +226,155 @@ bool CbmTrdUnpackFaspAlgo::pushDigis(std::vector<CbmTrdUnpackFaspAlgo::CbmTrdFas
   CbmTrdParFasp* faspPar(nullptr);
   const CbmTrdParFaspChannel* chCalib(nullptr);
   CbmTrdParModDigi* digiPar(nullptr);
+
   for (auto imess : messes) {
     if (lFasp == 0xff) {
-      lFasp = messes[0]->fasp;
+      lFasp = messes[0].fasp;
       // link data to the position on the padplane
-      if (!(faspPar = (CbmTrdParFasp*) fAsicPar.GetAsicPar(imess->mod * 1000 + lFasp))) {
-        LOG(error) << GetName() << "::pushDigis - Par for FASP " << (int) lFasp << " in module " << imess->mod
+      if (!(faspPar = (CbmTrdParFasp*) fAsicPar.GetAsicPar(fMod * 1000 + lFasp))) {
+        LOG(error) << GetName() << "::pushDigis - Par for FASP " << (int) lFasp << " in module " << fMod
                    << " missing. Skip.";
         return false;
       }
-      if (!(digiPar = (CbmTrdParModDigi*) fDigiSet->GetModulePar(imess->mod))) {
-        LOG(error) << GetName() << "::pushDigis - DIGI par for module " << imess->mod << " missing. Skip.";
+      if (!(digiPar = (CbmTrdParModDigi*) fDigiSet->GetModulePar(fMod))) {
+        LOG(error) << GetName() << "::pushDigis - DIGI par for module " << fMod << " missing. Skip.";
         return false;
       }
       // TODO temporary add DAQ time calibration for FASPRO.
       // Should be absorbed in the ASIC parameter definition
-      if (digiPar->GetPadRow(faspPar->GetChannelAddress(imess->ch)) % 2) tdaqOffset = 3;
+      if (digiPar->GetPadRow(faspPar->GetChannelAddress(imess.ch)) % 2) tdaqOffset = 3;
 
       if (VERBOSE) faspPar->Print();
     }
-    if (VERBOSE) mess_prt(imess);
+    if (VERBOSE) mess_prt(&imess);
 
-    pad     = faspPar->GetChannelAddress(imess->ch);
-    chCalib = faspPar->GetChannel(imess->ch);
+    pad     = faspPar->GetChannelAddress(imess.ch);
+    chCalib = faspPar->GetChannel(imess.ch);
     ch      = 2 * pad + chCalib->HasPairingR();
-    lTime   = fTime + tdaqOffset + imess->tlab;
+    lTime   = fTime + tdaqOffset + imess.tlab;
     lchR    = 0;
     lchT    = 0;
-    if (chCalib->HasPairingR()) lchR = imess->data;
+    if (chCalib->HasPairingR()) lchR = imess.data;
     else
-      lchT = imess->data;
+      lchT = imess.data;
     if (VERBOSE)
-      printf("fasp[%2d] ch[%4d / %2d] pad[%4d] row[%2d] col[%2d] %c[%4d]\n", lFasp, ch, imess->ch, pad,
+      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);
 
-    if (fDigiBuffer.find(pad) != fDigiBuffer.end()) {
+    if (fDigiBuffer[fCrob][pad].size()) {
       // check if last digi has both R/T message components. Update if not and is within time window
-      auto id = fDigiBuffer[pad].rbegin();
-      dtime   = (*id)->GetTimeDAQ() - lTime;
+      auto id = fDigiBuffer[fCrob][pad].rbegin();  // Should always be valid here.
+                                                   // No need to extra check
+      dtime = (*id).GetTimeDAQ() - lTime;
       bool use(false);
       if (TMath::Abs(dtime) < 5) {  // test message part of (last) digi
-        r = (*id)->GetCharge(t, dt);
+        r = (*id).GetCharge(t, dt);
         if (lchR && r < 0.1) {  // set R charge on an empty slot
-          (*id)->SetCharge(t, lchR, -dtime);
+          (*id).SetCharge(t, lchR, -dtime);
           use = true;
         }
         else if (lchT && t < 0.1) {  // set T charge on an empty slot
-          (*id)->SetCharge(lchT, r, +dtime);
-          (*id)->SetTimeDAQ(ULong64_t((*id)->GetTimeDAQ() - dtime));
+          (*id).SetCharge(lchT, r, +dtime);
+          (*id).SetTimeDAQ(ULong64_t((*id).GetTimeDAQ() - dtime));
           use = true;
         }
       }
 
       // build digi for message when update failed
       if (!use) {
-        CbmTrdDigi* digi = new CbmTrdDigi(pad, lchT, lchR, lTime);
-        digi->SetAddressModule(imess->mod);
-        fDigiBuffer[pad].push_back(digi);
-        id = fDigiBuffer[pad].rbegin();
+        CbmTrdDigi digi(pad, lchT, lchR, lTime);
+        digi.SetAddressModule(fMod);
+        fDigiBuffer[fCrob][pad].push_back(digi);
+        id = fDigiBuffer[fCrob][pad].rbegin();
       }
 
-      if (id != fDigiBuffer[pad].rend()) id++;
+      if (id != fDigiBuffer[fCrob][pad].rend()) id++;
 
-      // update charge for previously allocated digis to account for FASPRO ADC buffering and read-out problem
+      // update charge for previously allocated digis to account for FASPRO ADC buffering and read-out feature
       use = false;
-      for (; id != fDigiBuffer[pad].rend(); ++id) {
-        r = (*id)->GetCharge(t, dt);
+      for (; id != fDigiBuffer[fCrob][pad].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);
+          (*id).SetCharge(t, lchR, dt);
+          (*id).SetFlag(1);
           use = true;
         }
         else if (lchT && int(t)) {  // update T charge and mark on digi
-          (*id)->SetCharge(lchT, r, dt);
-          (*id)->SetFlag(0);
+          (*id).SetCharge(lchT, r, dt);
+          (*id).SetFlag(0);
           use = true;
         }
         if (use) break;
       }
     }
     else {  // init pad position in map and build digi for message
-      CbmTrdDigi* digi = new CbmTrdDigi(pad, lchT, lchR, lTime);
-      digi->SetAddressModule(imess->mod);
-      fDigiBuffer[pad].push_back(digi);
+      CbmTrdDigi digi(pad, lchT, lchR, lTime);
+      digi.SetAddressModule(fMod);
+      fDigiBuffer[fCrob][pad].push_back(digi);
     }
-    delete imess;
   }
+  messes.clear();
 
-  // push finalized digits to the next level
-  for (int jd(0); jd < NFASPCH; jd += 2) {
-    int ipad(faspPar->GetChannelAddress(jd));
-    if (fDigiBuffer.find(ipad) == fDigiBuffer.end()) continue;
+  return true;
+}
+
+uint32_t CbmTrdUnpackFaspAlgo::ResetTimeslice()
+{
+  uint32_t uNbLostDigis = 0;
+  /// PAL 03/08/2022: clear internal buffer at latest between two timeslices (TS are self contained!)
 
-    for (auto id = fDigiBuffer[ipad].begin(); id != fDigiBuffer[ipad].end(); id++) {
-      r = (*id)->GetCharge(t, dt);
+  for (auto crobBuffer : fDigiBuffer) {
+    for (auto pad_id(0); pad_id < NFASPMOD * NFASPCH; pad_id++) {
+      if (!crobBuffer.second[pad_id].size()) continue;
+
+      LOG(warn) << fName << "::ResetTimeslice - buffered digi @ CROB=" << crobBuffer.first << " / pad=" << pad_id
+                << " store " << crobBuffer.second[pad_id].size() << " unprocessed digi.";
+      uNbLostDigis += crobBuffer.second[pad_id].size();
+
+      crobBuffer.second[pad_id].clear();
+    }
+  }
+  return uNbLostDigis;
+}
+
+void CbmTrdUnpackFaspAlgo::FinalizeComponent()
+{
+  Double_t r, t;
+  Int_t dt;
+  // push finalized digits to the next level
+  for (uint16_t ipad(0); ipad < NFASPMOD * NFASPCH; ipad++) {
+    if (!fDigiBuffer[fCrob][ipad].size()) continue;
+    uint nIncomplete(0);
+    for (auto id = fDigiBuffer[fCrob][ipad].begin(); id != fDigiBuffer[fCrob][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))) continue;
-      if (fMonitor) fMonitor->FillHistos(((*id)));
+      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
-      (*id)->SetFlag(0, false);
-      (*id)->SetFlag(1, false);
-      fOutputVec.emplace_back(*std::move((*id)));
-      // clear digi buffer wrt the digi which was forwarded to higher structures
-      id = fDigiBuffer[ipad].erase(id);
+      (*id).SetFlag(0, false);
+      (*id).SetFlag(1, false);
+      fOutputVec.emplace_back(std::move((*id)));
+    }
+    // clear digi buffer wrt the digi which was forwarded to higher structures
+    fDigiBuffer[fCrob][ipad].clear();
+    if (nIncomplete > 2) {
+      LOG(warn) << fName << "FinalizeComponent(" << fCrob << ") skip " << nIncomplete << " incomplete digi at pad "
+                << ipad << ".\n";
     }
   }
-  messes.clear();
-
-  return true;
+  fCrob = 0xffff;  // reset current crob id
 }
 
 // ---- unpack ----
 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(info) << "Component " << icomp << " connected to config CbmTrdUnpackConfig2D. Slice "<<imslice;
 
-  uint32_t mod_id = 5;
   uint8_t crob_id = 0;
   uint16_t eq_id;
   bool unpackOk   = true;
@@ -351,14 +385,33 @@ bool CbmTrdUnpackFaspAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp
   if (VERBOSE) printf("time start %lu\n", static_cast<size_t>(msdesc.idx));
   // define time wrt start of time slice in TRD/FASP clks [80 MHz]
   fTime = ULong64_t((msdesc.idx - fTsStartTime - fSystemTimeOffset) / 12.5);
-  eq_id = msdesc.eq_id;  // read the CROB id
-  for (; crob_id < NCROBMOD; crob_id++) {
-    if (((*fCrobMap)[mod_id])[crob_id] == eq_id) break;
+
+  // get MOD_id and CROB id from the equipment
+  bool mapped = false;
+  eq_id       = msdesc.eq_id;
+  for (auto mod_id : fModuleId) {
+    for (crob_id = 0; crob_id < NCROBMOD; crob_id++) {
+      if (((*fCrobMap)[mod_id])[crob_id] == eq_id) break;
+    }
+    if (crob_id == NCROBMOD) continue;
+
+    // found module-cri pair
+    // buffer module configuration
+    if (fMod == 0xffff || fMod != mod_id) {
+      fMod = mod_id;
+      if (!init()) {
+        LOG(error) << GetName() << "::unpack - init mod_id=" << mod_id << " failed.";
+        return false;
+      }
+    }
+    mapped = true;
+    break;
   }
-  if (crob_id == NCROBMOD) {
+  if (!mapped) {
     LOG(error) << GetName() << "::unpack - CROB eq_id=" << eq_id << " not registered in the unpacker.";
     return false;
   }
+  if (fCrob == 0xffff) fCrob = icomp;
 
   // Get the µslice size in bytes to calculate the number of completed words
   auto mssize = msdesc.size;
@@ -375,8 +428,8 @@ bool CbmTrdUnpackFaspAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp
 
 
   UChar_t lFaspOld(0xff);
-  vector<CbmTrdFaspContent*> vDigi;
-  CbmTrdFaspContent* mess(nullptr);
+  vector<CbmTrdFaspContent> vMess;
+  CbmTrdFaspContent mess;
   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)){
@@ -398,8 +451,8 @@ bool CbmTrdUnpackFaspAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp
     if (isaux) {
       if (!ch_id) {
         // clear buffer
-        if (vDigi.size()) { pushDigis(vDigi); }
-        vDigi.clear();
+        if (vMess.size()) { pushDigis(vMess); }
+        vMess.clear();
 
         if (VERBOSE)
           cout << boost::format("    EE : fasp_id=%02d ch_id=%02d epoch=%03d\n") % static_cast<unsigned int>(fasp_id)
@@ -413,12 +466,12 @@ bool CbmTrdUnpackFaspAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp
       }
     }
     else {
-      if (fFaspMap) fasp_id = ((*fFaspMap)[mod_id])[fasp_id];
+      if (fFaspMap) fasp_id = ((*fFaspMap)[fMod])[fasp_id];
 
       if (lFaspOld != fasp_id) {
         // push
-        if (vDigi.size()) { pushDigis(vDigi); }
-        vDigi.clear();
+        if (vMess.size()) { pushDigis(vMess); }
+        vMess.clear();
         lFaspOld = fasp_id;
       }
       if (data & 0x1) {
@@ -433,15 +486,13 @@ bool CbmTrdUnpackFaspAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp
         LOG(debug) << GetName() << "::unpack - Self-triggered data.";
         data &= 0x1fff;
       }
-      mess       = new CbmTrdFaspContent;
-      mess->ch   = ch_id;
-      mess->type = kData;
-      mess->tlab = slice;
-      mess->data = data >> 1;
-      mess->fasp = lFaspOld;
-      mess->mod  = mod_id;
-      mess->crob = crob_id;
-      vDigi.push_back(mess);
+      mess.ch   = ch_id;
+      mess.type = kData;
+      mess.tlab = slice;
+      mess.data = data >> 1;
+      mess.fasp = lFaspOld;
+      mess.crob = crob_id;
+      vMess.push_back(mess);
     }
     //prt_wd(*wd);
   }
diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackFaspAlgo.h b/reco/detectors/trd/unpack/CbmTrdUnpackFaspAlgo.h
index 530df41b59..65a91e04e8 100644
--- a/reco/detectors/trd/unpack/CbmTrdUnpackFaspAlgo.h
+++ b/reco/detectors/trd/unpack/CbmTrdUnpackFaspAlgo.h
@@ -9,14 +9,14 @@
  * @brief Trd FASP unpacking algorithm
  * @version 0.1
  * @date 2021-04-21
- * 
+ *
  * @copyright Copyright (c) 2021
- * 
- * This is the base class for the algorithmic part of the tsa data unpacking 
+ *
+ * This is the base class for the algorithmic part of the tsa data unpacking
  * processes of the CbmTrd.
- * The actual translation from tsa to digi happens in the derived classes. 
- * 
- * 
+ * The actual translation from tsa to digi happens in the derived classes.
+ *
+ *
 */
 
 #ifndef CbmTrdUnpackFaspAlgo_H
@@ -45,7 +45,7 @@
 class CbmTrdParSetDigi;
 class CbmTrdUnpackFaspAlgo : public CbmRecoUnpackAlgo<CbmTrdDigi> {
 public:
-  /** @brief Bytes per FASP frame stored in the microslices (32 bits words) 
+  /** @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
@@ -56,7 +56,7 @@ public:
    * - EPOCH WORD -
    * ffff.fftt tttt.tttt tttt.tttt ttta.cccc
    * f - FASP id
-   * t - epoch index 
+   * t - epoch index
    * a - word type (0)
    * c - channel id
    */
@@ -102,7 +102,7 @@ public:
 
   /**
    * @brief Get the requested parameter containers.
-   * Return the required parameter containers together with the paths to the ascii 
+   * Return the required parameter containers together with the paths to the ascii
    * files to.
    *  
    * @param[in] std::string geoTag as used in CbmSetup
@@ -121,6 +121,9 @@ public:
    *  @param monitor predefined unpacking monitor */
   void SetMonitor(std::shared_ptr<CbmTrdUnpackFaspMonitor> monitor) { fMonitor = monitor; }
 
+  /** @brief Check and assure there are no data left-overs */
+  uint32_t ResetTimeslice();
+
 protected:
   /** @brief Get message type from the FASP word */
   CbmTrdFaspMessageType mess_type(uint32_t wd);
@@ -130,11 +133,11 @@ protected:
   void mess_readEW(uint32_t wd, CbmTrdFaspContent* mess);
   /** @brief Print FASP message */
   void mess_prt(CbmTrdFaspContent* mess);
-  bool pushDigis(std::vector<CbmTrdUnpackFaspAlgo::CbmTrdFaspContent*> digis);
+  bool pushDigis(std::vector<CbmTrdUnpackFaspAlgo::CbmTrdFaspContent> messages);
   /** @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. T0) 
+   *  - TRD2D system offset wrt to experiment time (e.g. T0)
    */
   ULong64_t fTime;
 
@@ -147,7 +150,7 @@ protected:
   /**
    * @brief Additional initialisation function for all BaseR derived algorithms.
    * 
-   * @return Bool_t initOk 
+   * @return Bool_t initOk
   */
   virtual Bool_t init() { return kTRUE; }
 
@@ -156,26 +159,30 @@ protected:
   /**
    * @brief Handles the distribution of the hidden derived classes to their explicit functions.
    * 
-   * @param parset 
-   * @return Bool_t initOk 
+   * @param parset
+   * @return Bool_t initOk
   */
   Bool_t initParSet(FairParGenericSet* parset);
 
   /**
    * @brief Unpack a given microslice.
-   * 
+   *
    * @param ts timeslice pointer
    * @param icomp index to the component to be unpacked
    * @param imslice index of the microslice to be unpacked
-   * @return true 
-   * @return false 
-   * 
+   * @return true if all is fine
+   *
    * @remark The content of the µslice can only be accessed via the timeslice. Hence, we need to pass the pointer to the full timeslice
   */
   bool unpack(const fles::Timeslice* ts, std::uint16_t icomp, UInt_t imslice);
 
+  /**
+   * @brief Finalize component (e.g. copy from temp buffers)
+  */
+  void FinalizeComponent();
+
   // Constants
-  /** @brief Bytes per FASP frame stored in the microslices (32 bits words) 
+  /** @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
@@ -186,7 +193,7 @@ protected:
    * - EPOCH WORD -
    * ffff.fftt tttt.tttt tttt.tttt ttta.cccc
    * f - FASP id
-   * t - epoch index 
+   * t - epoch index
    * a - word type (0)
    * c - channel id
    */
@@ -196,10 +203,13 @@ private:
   void prt_wd(uint32_t w);
   std::map<uint32_t, uint8_t[NFASPMOD]>* fFaspMap  = nullptr;  ///> FASP mapping update wrt the default setting
   std::map<uint32_t, uint16_t[NCROBMOD]>* fCrobMap = nullptr;  ///> CRI mapping setting
-  std::map<uint32_t, std::vector<CbmTrdDigi*>> fDigiBuffer;    ///> Map of buffered digi per pad
+  std::map<uint16_t, std::array<std::vector<CbmTrdDigi>, NFASPMOD* NFASPCH>> fDigiBuffer = {
+    {{}}};  ///> Buffered digi for each pad in CROB component
   /** @brief Potential (online) monitor for the unpacking process */
   std::shared_ptr<CbmTrdUnpackFaspMonitor> fMonitor = nullptr;
-  std::vector<Int_t> fModuleId;
+  uint16_t fCrob                                    = 0xffff;  //! current crob being processed
+  uint16_t fMod                                     = 0xffff;  //! current module being processed
+  std::vector<uint16_t> fModuleId;  ///> list of modules for which there is are calibration parameters
   CbmTrdParSetAsic fAsicPar;
   CbmTrdParSetDigi* fDigiSet = nullptr;
 
diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackFaspConfig.cxx b/reco/detectors/trd/unpack/CbmTrdUnpackFaspConfig.cxx
index 683dde77bc..9220aeef74 100644
--- a/reco/detectors/trd/unpack/CbmTrdUnpackFaspConfig.cxx
+++ b/reco/detectors/trd/unpack/CbmTrdUnpackFaspConfig.cxx
@@ -30,6 +30,15 @@ std::shared_ptr<CbmTrdUnpackFaspAlgo> CbmTrdUnpackFaspConfig::chooseAlgo()
   return nullptr;
 }
 
+// ---- reset ----
+void CbmTrdUnpackFaspConfig::reset()
+{
+  uint32_t uNbLostDigis = fAlgo->ResetTimeslice();
+  if (uNbLostDigis /*&& fDoLog*/) {
+    LOG(info) << fName << "::reset - Lost digis after processing timeslice: " << uNbLostDigis;
+  }
+}
+
 //_____________________________________________________________________
 void CbmTrdUnpackFaspConfig::InitAlgo()
 {
diff --git a/reco/detectors/trd/unpack/CbmTrdUnpackFaspConfig.h b/reco/detectors/trd/unpack/CbmTrdUnpackFaspConfig.h
index 54a377eca6..25540834f5 100644
--- a/reco/detectors/trd/unpack/CbmTrdUnpackFaspConfig.h
+++ b/reco/detectors/trd/unpack/CbmTrdUnpackFaspConfig.h
@@ -78,7 +78,7 @@ public:
    */
   void SetCrobMapping(int modAddress, uint16_t crobMap[NFASPMOD]);
 
-  /** @brief Add a monitor to the unpacker. 
+  /** @brief Add a monitor to the unpacker.
    *  @param value CbmTrdUnpackFaspMonitor */
   void SetMonitor(std::shared_ptr<CbmTrdUnpackFaspMonitor> value) { fMonitor = value; }
 
@@ -90,6 +90,9 @@ protected:
   */
   virtual std::shared_ptr<CbmTrdUnpackFaspAlgo> chooseAlgo();
 
+  /** @brief Implement additional actions to be called once per TS, e.g. needed if more than the default output vector is used. */
+  virtual void reset();
+
 private:
   std::map<uint32_t, uint8_t[NFASPMOD]> fFaspMap;   ///> Module address to FASP id mapping
   std::map<uint32_t, uint16_t[NCROBMOD]> fCrobMap;  ///> Module address to CROB id mapping
-- 
GitLab