CbmStsUnpackAlgo.cxx 36.9 KB
Newer Older
1
2
3
/* Copyright (C) 2021 Goethe-University, Frankfurt
   SPDX-License-Identifier: GPL-3.0-only
   Authors: Pierre-Alain Loizeau, Pascal Raisig [committer], Dominik Smith */
4
5
6

#include "CbmStsUnpackAlgo.h"

7
8
#include "CbmStsDigi.h"

9
10
11
12
13
14
15
#include <FairParGenericSet.h>
#include <FairTask.h>
#include <Logger.h>

#include <Rtypes.h>
#include <RtypesCore.h>

16
#include <cstdint>
Pascal Raisig's avatar
Pascal Raisig committed
17
#include <iomanip>
18

19
CbmStsUnpackAlgo::CbmStsUnpackAlgo() : CbmStsUnpackAlgoBase("CbmStsUnpackAlgo") {}
20
21
22

CbmStsUnpackAlgo::~CbmStsUnpackAlgo() {}

23
24
25
26
// ---- getAsicIndex ----
uint32_t CbmStsUnpackAlgo::getAsicIndex(uint32_t dpbidx, uint32_t crobidx, uint16_t elinkidx)
{

27
28
29
  uint32_t asicidx       = 0;
  const int32_t uFebIdx  = fElinkIdxToFebIdxVec.at(elinkidx);
  const uint32_t febtype = fviFebType[dpbidx][crobidx][uFebIdx];
30
31
32
33
34
35
  // Feb type a
  if (febtype == 0) asicidx = fElinkIdxToAsicIdxVec.at(elinkidx).first;
  //   Feb type b
  if (febtype == 1) asicidx = fElinkIdxToAsicIdxVec.at(elinkidx).second;
  // else would be inactive feb, this was not handled in the previous implementation, this I expect it should not happen

36
  const uint32_t uAsicIdx = (dpbidx * fNrCrobPerDpb + crobidx) * fNrAsicsPerCrob + asicidx;
37
38
39
40
41
42
43
44
  return uAsicIdx;
}

// ---- getFullTimeStamp ----
uint64_t CbmStsUnpackAlgo::getFullTimeStamp(const uint16_t usRawTs)
{
  // Use TS w/o overlap bits as they will anyway come from the TS_MSB
  const uint64_t ulTime =
45
46
    usRawTs + fulTsMsbIndexInTs[fuCurrDpbIdx] * static_cast<uint64_t>(stsxyter::kuHitNbTsBinsBinning);
  /*
47
48
49
    + static_cast<uint64_t>(stsxyter::kuHitNbTsBinsBinning) * static_cast<uint64_t>(fvulCurrentTsMsb[fuCurrDpbIdx])
    + static_cast<uint64_t>(stsxyter::kulTsCycleNbBinsBinning)
        * static_cast<uint64_t>(fvuCurrentTsMsbCycle[fuCurrDpbIdx]);
50
*/
51
52
53
54
55
56
57
58
59
60
61
62
  return ulTime;
}

// ---- init
Bool_t CbmStsUnpackAlgo::init() { return kTRUE; }

// ---- initDpbIdIndexMap ----
void CbmStsUnpackAlgo::initDpbIdIndexMap(CbmMcbm2018StsPar* parset)
{
  fDpbIdIndexMap.clear();
  for (uint32_t uDpb = 0; uDpb < parset->GetNrOfDpbs(); ++uDpb) {
    fDpbIdIndexMap[parset->GetDpbId(uDpb)] = uDpb;
63
64
    LOG(debug) << "Eq. ID for DPB #" << std::setw(2) << uDpb << " = 0x" << std::setw(4) << std::hex
               << parset->GetDpbId(uDpb) << std::dec << " => " << fDpbIdIndexMap[parset->GetDpbId(uDpb)];
65
66
67
68
69
70
71
72
73
74
75
76
  }
}

// ---- initParSet(FairParGenericSet* parset) ----
Bool_t CbmStsUnpackAlgo::initParSet(FairParGenericSet* parset)
{
  LOG(info) << fName << "::initParSet - for container " << parset->ClassName();
  if (parset->IsA() == CbmMcbm2018StsPar::Class()) return initParSet(static_cast<CbmMcbm2018StsPar*>(parset));

  // If we do not know the derived ParSet class we return false
  LOG(error)
    << fName << "::initParSet - for container " << parset->ClassName()
77
    << " failed, since CbmStsUnpackAlgo::initParSet() does not know the derived ParSet and what to do with it!";
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
  return kFALSE;
}

// ---- initParSet(CbmMcbm2018StsPar* parset) ----
Bool_t CbmStsUnpackAlgo::initParSet(CbmMcbm2018StsPar* parset)
{
  LOG(debug) << fName << "::initParSetAsic - ";

  //Type of each module: 0 for connectors on the right, 1 for connectors on the left
  std::vector<int32_t> viModuleType;

  // STS address for the first strip of each module
  std::vector<int32_t> viModAddress;

  // Idx of the STS module for each FEB, [ NbDpb ][ NbCrobPerDpb ][ NbFebsPerCrob ], -1 if inactive
  std::vector<std::vector<std::vector<int32_t>>> viFebModuleIdx;

  // Array to hold the active flag for all CROBs, [ NbDpb ][ NbCrobPerDpb ]
  std::vector<std::vector<bool>> vbCrobActiveFlag;

  //STS module side for each FEB, [ NbDpb ][ NbCrobPerDpb ][ NbFebsPerCrob ], 0 = P, 1 = N, -1 if inactive
  std::vector<std::vector<std::vector<int32_t>>> viFebModuleSide;

  // Total number of STS modules in the setup
  const uint32_t uNbModules = parset->GetNbOfModules();
  LOG(debug) << "Nr. of STS Modules:    " << uNbModules;

  // Total number of STS DPBs in system
  const uint32_t uNbOfDpbs = parset->GetNrOfDpbs();
107
  LOG(debug) << "Nr. of STS DPBs:       " << uNbOfDpbs;
108
109
110

  // Get Nr of Febs
  fuNbFebs = parset->GetNrOfFebs();
111
  LOG(debug) << "Nr. of FEBs:           " << fuNbFebs;
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130

  // Get Nr of eLinks per CROB
  fNrElinksPerCrob = parset->GetNbElinkPerCrob();

  // Get Nr of ASICs per CROB
  fNrAsicsPerCrob = parset->GetNbAsicsPerCrob();

  // Get Nr of CROBs per DPB
  fNrCrobPerDpb = parset->GetNbCrobsPerDpb();

  // Get Number of ASICs per FEB
  fNrAsicsPerFeb = parset->GetNbAsicsPerFeb();

  // Get Number of Channels per Asic
  fNrChsPerAsic = parset->GetNbChanPerAsic();

  // Get Number of Channels per FEB
  fNrChsPerFeb = parset->GetNbChanPerFeb();

131
132
133
  // Get Number of FEBs per CROB
  fNrFebsPerCrob = parset->GetNbFebsPerCrob();

134
135
136
137
138
139
140
141
  for (size_t ielink = 0; ielink < fNrElinksPerCrob; ++ielink) {
    fElinkIdxToFebIdxVec.emplace_back(parset->ElinkIdxToFebIdx(ielink));
    fElinkIdxToAsicIdxVec.emplace_back(
      std::make_pair(parset->ElinkIdxToAsicIdxFebA(ielink), parset->ElinkIdxToAsicIdxFebB(ielink)));
  }

  // Get Nr of Asics
  const uint32_t uNbStsXyters = parset->GetNrOfAsics();
142
  LOG(debug) << "Nr. of StsXyter ASICs: " << uNbStsXyters;
143
144
145
146

  //Initialize temporary "per Feb" fields
  initTempVectors(parset, &viModuleType, &viModAddress, &viFebModuleIdx, &vbCrobActiveFlag, &viFebModuleSide);

147
148
149
150
151
152
  // Initialize ADC cuts for FEBs
  fvbFebAdcCut.resize(fuNbFebs, fdAdcCut);
  for (auto cut : fdAdcCut_perFeb) {
    fvbFebAdcCut[cut.first] = cut.second;
  }

153
154
155
156
157
158
159
160
161
162
163
164
165
  // Read dpb index map from parameter container
  initDpbIdIndexMap(parset);

  if (fvdTimeOffsetNsAsics.size() < uNbStsXyters) { fvdTimeOffsetNsAsics.resize(uNbStsXyters, 0.0); }

  //Initialize class-wide "per Feb" fields
  fviFebType.resize(uNbOfDpbs);

  for (uint32_t uDpb = 0; uDpb < uNbOfDpbs; ++uDpb) {
    fviFebType[uDpb].resize(fNrCrobPerDpb);
    for (uint32_t uCrobIdx = 0; uCrobIdx < fNrCrobPerDpb; ++uCrobIdx) {
      fviFebType[uDpb][uCrobIdx].resize(parset->GetNbFebsPerCrob(), -1);
      for (uint32_t uFebIdx = 0; uFebIdx < parset->GetNbFebsPerCrob(); ++uFebIdx) {
166
        fvbFebPulser.push_back(parset->IsFebPulser(uDpb, uCrobIdx, uFebIdx));
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
        fvdFebAdcGain.push_back(parset->GetFebAdcGain(uDpb, uCrobIdx, uFebIdx));
        fvdFebAdcOffs.push_back(parset->GetFebAdcOffset(uDpb, uCrobIdx, uFebIdx));

        if (0 <= viFebModuleIdx[uDpb][uCrobIdx][uFebIdx]
            && static_cast<uint32_t>(viFebModuleIdx[uDpb][uCrobIdx][uFebIdx]) < uNbModules
            && 0 <= viFebModuleSide[uDpb][uCrobIdx][uFebIdx] && viFebModuleSide[uDpb][uCrobIdx][uFebIdx] < 2) {
          switch (viModuleType[viFebModuleIdx[uDpb][uCrobIdx][uFebIdx]]) {
            case 0:  // FEB-8-1 with ZIF connector on the right
            {
              // P side (0) has type A (0)
              // N side (1) has type B (1)
              fviFebType[uDpb][uCrobIdx][uFebIdx] = viFebModuleSide[uDpb][uCrobIdx][uFebIdx];

              ///! FIXME: 1) Geometry is using front/back while we are using P/N !!!!
              ///!            => Assuming that front facing modules have connectors on right side
              ///!            +> Volker warns that the front side should be electrons one so N
              ///!        2) No accessor/setter to change only the side field of an STS address
              ///!            => hardcode the shift
              ///!            +> The bit is unused in the current scheme: the side is encoded in the Digi channel
186
187
              fviFebAddress.push_back(viModAddress[viFebModuleIdx[uDpb][uCrobIdx][uFebIdx]]);
              //                       + (viFebModuleSide[uDpb][uCrobIdx][uFebIdx] << 25));
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
              fviFebSide.push_back(viFebModuleSide[uDpb][uCrobIdx][uFebIdx]);
              break;
            }        // case 0: // FEB-8-1 with ZIF connector on the right
            case 1:  // FEB-8-1 with ZIF connector on the left
            {
              // P side (0) has type B (1)
              // N side (1) has type A (0)
              fviFebType[uDpb][uCrobIdx][uFebIdx] = !(viFebModuleSide[uDpb][uCrobIdx][uFebIdx]);

              ///! FIXME: 1) Geometry is using front/back while we are using P/N !!!!
              ///!            => Assuming that front facing modules have connectors on right side
              ///!            +> Volker warns that the front side should be electrons one so N
              ///!        2) No accessor/setter to change only the side field of an STS address
              ///!            => hardcode the shift
              ///!            +> The bit is unused in the current scheme: the side is encoded in the Digi channel
203
204
              fviFebAddress.push_back(viModAddress[viFebModuleIdx[uDpb][uCrobIdx][uFebIdx]]);
              //                        + ((!viFebModuleSide[uDpb][uCrobIdx][uFebIdx]) << 25));
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
              fviFebSide.push_back(viFebModuleSide[uDpb][uCrobIdx][uFebIdx]);
              break;
            }  // case 1: // FEB-8-1 with ZIF connector on the left
            default:
              LOG(fatal) << Form("Bad module type for DPB #%02u CROB #%u FEB %02u: %d", uDpb, uCrobIdx, uFebIdx,
                                 viModuleType[viFebModuleIdx[uDpb][uCrobIdx][uFebIdx]]);
              break;
          }
        }  // FEB active and module index OK
        else if (-1 == viFebModuleIdx[uDpb][uCrobIdx][uFebIdx] || -1 == viFebModuleSide[uDpb][uCrobIdx][uFebIdx]) {
          fviFebAddress.push_back(0);
          fviFebSide.push_back(-1);
        }  // Module index or type is set to inactive
        else {
          LOG(fatal) << Form("Bad module Index and/or Side for DPB #%02u CROB "
                             "#%u FEB %02u: %d %d",
                             uDpb, uCrobIdx, uFebIdx, viFebModuleIdx[uDpb][uCrobIdx][uFebIdx],
                             viFebModuleSide[uDpb][uCrobIdx][uFebIdx]);
        }  // Bad module index or type for this FEB
      }
    }
  }

  printActiveCrobs(parset, vbCrobActiveFlag);
  printAddressMaps(parset, viFebModuleIdx, viFebModuleSide);

  LOG(debug) << "Unpacking data in bin sorter FW mode";
  initInternalStatus(parset);

  return kTRUE;
}

// ---- initTempVectors ----
void CbmStsUnpackAlgo::initTempVectors(CbmMcbm2018StsPar* parset, std::vector<int32_t>* viModuleType,
                                       std::vector<int32_t>* viModAddress,
                                       std::vector<std::vector<std::vector<int32_t>>>* viFebModuleIdx,
                                       std::vector<std::vector<bool>>* vbCrobActiveFlag,
                                       std::vector<std::vector<std::vector<int32_t>>>* viFebModuleSide)
{
  const uint32_t uNbModules = parset->GetNbOfModules();
  const uint32_t uNbOfDpbs  = parset->GetNrOfDpbs();

  viModuleType->resize(uNbModules);
  viModAddress->resize(uNbModules);
  for (uint32_t uModIdx = 0; uModIdx < uNbModules; ++uModIdx) {
    (*viModuleType)[uModIdx] = parset->GetModuleType(uModIdx);
    (*viModAddress)[uModIdx] = parset->GetModuleAddress(uModIdx);
252
253
    LOG(debug) << "Module #" << std::setw(2) << uModIdx << " Type " << std::setw(4) << (*viModuleType)[uModIdx]
               << " Address 0x" << std::setw(8) << std::hex << (*viModAddress)[uModIdx] << std::dec;
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  }
  vbCrobActiveFlag->resize(uNbOfDpbs);
  viFebModuleIdx->resize(uNbOfDpbs);
  viFebModuleSide->resize(uNbOfDpbs);

  for (uint32_t uDpb = 0; uDpb < uNbOfDpbs; ++uDpb) {
    (*vbCrobActiveFlag)[uDpb].resize(fNrCrobPerDpb);
    (*viFebModuleIdx)[uDpb].resize(fNrCrobPerDpb);
    (*viFebModuleSide)[uDpb].resize(fNrCrobPerDpb);
    for (uint32_t uCrobIdx = 0; uCrobIdx < fNrCrobPerDpb; ++uCrobIdx) {
      (*vbCrobActiveFlag)[uDpb][uCrobIdx] = parset->IsCrobActive(uDpb, uCrobIdx);
      (*viFebModuleIdx)[uDpb][uCrobIdx].resize(parset->GetNbFebsPerCrob());
      (*viFebModuleSide)[uDpb][uCrobIdx].resize(parset->GetNbFebsPerCrob());
      for (uint32_t uFebIdx = 0; uFebIdx < parset->GetNbFebsPerCrob(); ++uFebIdx) {
        (*viFebModuleIdx)[uDpb][uCrobIdx][uFebIdx]  = parset->GetFebModuleIdx(uDpb, uCrobIdx, uFebIdx);
        (*viFebModuleSide)[uDpb][uCrobIdx][uFebIdx] = parset->GetFebModuleSide(uDpb, uCrobIdx, uFebIdx);
      }
    }
  }
}

// ---- initInternalStatus ----
void CbmStsUnpackAlgo::initInternalStatus(CbmMcbm2018StsPar* parset)
{
  const uint32_t uNbOfDpbs    = parset->GetNrOfDpbs();
  const uint32_t uNbStsXyters = parset->GetNrOfAsics();

  fvulCurrentTsMsb.resize(uNbOfDpbs);
  fvuCurrentTsMsbCycle.resize(uNbOfDpbs);
283
  fulTsMsbIndexInTs.resize(uNbOfDpbs);
284
285
286
  for (uint32_t uDpb = 0; uDpb < uNbOfDpbs; ++uDpb) {
    fvulCurrentTsMsb[uDpb]     = 0;
    fvuCurrentTsMsbCycle[uDpb] = 0;
287
    fulTsMsbIndexInTs[uDpb]    = 0;
288
289
290
291
  }

  fvvusLastTsChan.resize(uNbStsXyters);
  fvvusLastAdcChan.resize(uNbStsXyters);
292
  fvvulLastTsMsbChan.resize(uNbStsXyters);
293
294
295
  for (uint32_t uAsicIdx = 0; uAsicIdx < uNbStsXyters; ++uAsicIdx) {
    fvvusLastTsChan[uAsicIdx].resize(fNrChsPerAsic, 0);
    fvvusLastAdcChan[uAsicIdx].resize(fNrChsPerAsic, 0);
296
    fvvulLastTsMsbChan[uAsicIdx].resize(fNrChsPerAsic, 0);
297
298
299
300
  }
}

// ---- loopMsMessages ----
301
void CbmStsUnpackAlgo::loopMsMessages(const uint8_t* msContent, const uint32_t uSize, const size_t uMsIdx)
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
{
  // If not integer number of message in input buffer, print warning/error
  if (0 != (uSize % sizeof(stsxyter::Message))) {
    LOG(error) << "The input microslice buffer does NOT "
               << "contain only complete sDPB messages!";
  }
  // Compute the number of complete messages in the input microslice buffer
  const uint32_t uNbMessages = (uSize - (uSize % sizeof(stsxyter::Message))) / sizeof(stsxyter::Message);

  // Prepare variables for the loop on contents
  const stsxyter::Message* pMess = reinterpret_cast<const stsxyter::Message*>(msContent);

  for (uint32_t uIdx = 0; uIdx < uNbMessages; uIdx++) {
    /// Get message type
    const stsxyter::MessType typeMess = pMess[uIdx].GetMessType();
317
318
319

    LOG(debug2) << " Msg Idx " << std::setw(6) << uIdx << " Type " << stsxyter::Message::PrintMessType(typeMess);

320
    if (fMonitor)
321
      if (fMonitor->GetDebugMode()) { fMonitor->ProcessDebugInfo(pMess[uIdx], fuCurrDpbIdx); }
322
323
324
325
326
327
328
329
330
331
332
333
    switch (typeMess) {
      case stsxyter::MessType::Hit: {
        processHitInfo(pMess[uIdx]);
        break;
      }
      case stsxyter::MessType::TsMsb: {
        processTsMsbInfo(pMess[uIdx], uIdx, uMsIdx);
        break;
      }
      case stsxyter::MessType::Epoch: {
        processEpochInfo(pMess[uIdx]);
        if (0 < uIdx) {
334
          LOG(warning) << "CbmStsUnpackAlgo::loopMsMessages => "
335
                       << "EPOCH message at unexpected position in MS: message " << uIdx << " VS message 0 expected!";
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
        }
        break;
      }
      case stsxyter::MessType::Status: {
        processStatusInfo(pMess[uIdx], uIdx);
        break;
      }
      case stsxyter::MessType::Empty: {
        break;
      }
      case stsxyter::MessType::EndOfMs: {
        processErrorInfo(pMess[uIdx]);
        break;
      }
      case stsxyter::MessType::Dummy: {
        break;
      }
      default: {
354
        LOG(fatal) << "CbmStsUnpackAlgo::loopMsMessages => "
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
                   << "Unknown message type, should never happen, stopping "
                      "here! Type found was: "
                   << static_cast<int>(typeMess);
      }
    }
  }
}

// ---- MaskNoisyChannel ----
void CbmStsUnpackAlgo::MaskNoisyChannel(const uint32_t uFeb, const uint32_t uChan, const bool bMasked)
{
  if (false == fbUseChannelMask) {
    fbUseChannelMask = true;
    fvvbMaskedChannels.resize(fuNbFebs);
    for (uint32_t uFebIdx = 0; uFebIdx < fuNbFebs; ++uFebIdx) {
      fvvbMaskedChannels[uFebIdx].resize(fNrChsPerFeb, false);
    }
  }
  if (uFeb < fuNbFebs && uChan < fNrChsPerFeb) fvvbMaskedChannels[uFeb][uChan] = bMasked;
  else
375
    LOG(fatal) << "CbmStsUnpackAlgo::MaskNoisyChannel => Invalid FEB "
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
                  "and/or CHAN index:"
               << Form(" %u vs %u and %u vs %u", uFeb, fuNbFebs, uChan, fNrChsPerFeb);
}


// ---- printActiveCrobs ----
void CbmStsUnpackAlgo::printActiveCrobs(CbmMcbm2018StsPar* parset,
                                        const std::vector<std::vector<bool>>& vbCrobActiveFlag)
{
  for (uint32_t uDpb = 0; uDpb < parset->GetNrOfDpbs(); ++uDpb) {
    TString sPrintoutLine = Form("DPB #%02u CROB Active ?:       ", uDpb);
    for (uint32_t uCrobIdx = 0; uCrobIdx < fNrCrobPerDpb; ++uCrobIdx) {
      sPrintoutLine += Form("%1u", (vbCrobActiveFlag[uDpb][uCrobIdx] == true));
    }
    LOG(debug) << sPrintoutLine;
  }
}

// ---- printAddressMaps ----
void CbmStsUnpackAlgo::printAddressMaps(CbmMcbm2018StsPar* parset,
                                        const std::vector<std::vector<std::vector<int32_t>>>& viFebModuleIdx,
                                        const std::vector<std::vector<std::vector<int32_t>>>& viFebModuleSide)
{
  uint32_t uGlobalFebIdx = 0;
  for (uint32_t uDpb = 0; uDpb < parset->GetNrOfDpbs(); ++uDpb) {
    for (uint32_t uCrobIdx = 0; uCrobIdx < fNrCrobPerDpb; ++uCrobIdx) {
402
      LOG(debug) << Form("DPB #%02u CROB #%u:       ", uDpb, uCrobIdx);
403
404
      for (uint32_t uFebIdx = 0; uFebIdx < parset->GetNbFebsPerCrob(); ++uFebIdx) {
        if (0 <= viFebModuleIdx[uDpb][uCrobIdx][uFebIdx])
405
406
407
408
409
410
411
          LOG(debug) << Form("      FEB #%02u (%02u): Mod. Idx = %03d Side %c (%2d) Type %c "
                             "(%2d) (Addr. 0x%08x) ADC gain %4.0f e- ADC Offs %5.0f e-",
                             uFebIdx, uGlobalFebIdx, viFebModuleIdx[uDpb][uCrobIdx][uFebIdx],
                             1 == viFebModuleSide[uDpb][uCrobIdx][uFebIdx] ? 'N' : 'P',
                             viFebModuleSide[uDpb][uCrobIdx][uFebIdx],
                             1 == fviFebType[uDpb][uCrobIdx][uFebIdx] ? 'B' : 'A', fviFebType[uDpb][uCrobIdx][uFebIdx],
                             fviFebAddress[uGlobalFebIdx], fvdFebAdcGain[uGlobalFebIdx], fvdFebAdcOffs[uGlobalFebIdx]);
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
        else
          LOG(debug) << Form("Disabled FEB #%02u (%02u): Mod. Idx = %03d Side %c (%2d) Type %c "
                             "(%2d) (Addr. 0x%08x) ADC gain %4.0f e- ADC Offs %5.0f e-",
                             uFebIdx, uGlobalFebIdx, viFebModuleIdx[uDpb][uCrobIdx][uFebIdx],
                             1 == viFebModuleSide[uDpb][uCrobIdx][uFebIdx] ? 'N' : 'P',
                             viFebModuleSide[uDpb][uCrobIdx][uFebIdx],
                             1 == fviFebType[uDpb][uCrobIdx][uFebIdx] ? 'B' : 'A', fviFebType[uDpb][uCrobIdx][uFebIdx],
                             fviFebAddress[uGlobalFebIdx], fvdFebAdcGain[uGlobalFebIdx], fvdFebAdcOffs[uGlobalFebIdx]);
        uGlobalFebIdx++;
      }
    }
  }
}

// -------------------------------------------------------------------------
void CbmStsUnpackAlgo::processErrorInfo(const stsxyter::Message& mess)
{
  if (mess.IsMsErrorFlagOn()) {
    //   I do pass here the Ts start time instead of the ms time, since, we removed the ms time as member for the time being
    if (fMonitor) { fMonitor->FillMsErrorsEvo(fMsStartTime, mess.GetMsErrorType()); }
432
433
    if (fOptOutBVec)
      fOptOutBVec->emplace_back(
434
435
436
437
438
439
440
441
442
        CbmErrorMessage(ECbmModuleId::kSts, fMsStartTime, fuCurrDpbIdx, 0x20, mess.GetMsErrorType()));
  }
}

// ---- processHitInfo ----
void CbmStsUnpackAlgo::processHitInfo(const stsxyter::Message& mess)
{
  const uint16_t usElinkIdx = mess.GetLinkIndexHitBinning();
  const uint32_t uCrobIdx   = usElinkIdx / fNrElinksPerCrob;
443
  int32_t uFebIdx           = fElinkIdxToFebIdxVec.at(usElinkIdx);
444
  if (-1 == uFebIdx) {
445
    LOG(warning) << "CbmStsUnpackAlgo::processHitInfo => "
446
447
448
                 << "Wrong elink Idx! Elink raw " << Form("%d remap %d", usElinkIdx, uFebIdx);
    return;
  }
449
450
451
452
  //uFebIdx +=  ( fuCurrDpbIdx * fNrCrobPerDpb + ____CrobIndexCalculationIfNeeded___() ) * fuNbFebsPerCrob;
  uFebIdx += (fuCurrDpbIdx * fNrCrobPerDpb) * fNrFebsPerCrob;  //no Crob index calculation for now

  // Get the asic index
453
454
455
456
457
458
459
460
  uint32_t uAsicIdx = getAsicIndex(fuCurrDpbIdx, uCrobIdx, usElinkIdx);

  const uint16_t usChan     = mess.GetHitChannel();
  const uint16_t usRawAdc   = mess.GetHitAdc();
  const uint16_t usRawTs    = mess.GetHitTimeBinning();
  const uint32_t uChanInFeb = usChan + fNrChsPerAsic * (uAsicIdx % fNrAsicsPerFeb);

  // Compute the Full time stamp
461
  const uint64_t ulHitTime = getFullTimeStamp(usRawTs);
462

463
464
  if (fMonitor) fMonitor->CountRawHit(uFebIdx, uChanInFeb);

465
  /// Store hit for output only if it is mapped to a module!!!
466
  if (fviFebAddress[uFebIdx] != 0 && fvbFebAdcCut[uFebIdx] < usRawAdc) {
467
468
469
470
471
    /// Store only if masking is disabled or if channeld is not masked
    /// 2D vector is safe as always right size if masking enabled
    if (false == fbUseChannelMask || false == fvvbMaskedChannels[uFebIdx][uChanInFeb]) {
      // If you want to store this as well, add it to the template as TOptOut, otherwise I do not see a reason to create it at all
      // auto finalhit       = stsxyter::FinalHit(ulHitTime, usRawAdc, uAsicIdx, usChan, fuCurrDpbIdx, uCrobIdx);
472
473
474
475
476

      /// Duplicate hits rejection
      if (fbRejectDuplicateDigis) {
        if (usRawTs == fvvusLastTsChan[uAsicIdx][usChan]
            && (fbDupliWithoutAdc || usRawAdc == fvvusLastAdcChan[uAsicIdx][usChan])
477
            && fulTsMsbIndexInTs[fuCurrDpbIdx] == fvvulLastTsMsbChan[uAsicIdx][usChan]) {
478
          /// FIXME: add plots to check what is done in this rejection
479
480
481
          LOG(debug1) << "CbmStsUnpackAlgo::processHitInfo => "
                      << Form("Rejecting duplicate on Asic %3u channel %3u, TS %3u, ADC %2u", uAsicIdx, usChan, usRawTs,
                              usRawAdc);
482
483

          if (fMonitor) fMonitor->FillDuplicateHitsAdc(uFebIdx, uChanInFeb, usRawAdc);
484
485
486
487
          return;
        }  // if same TS, (ADC,) TS MSB, TS MSB cycle, reject
        fvvusLastTsChan[uAsicIdx][usChan]         = usRawTs;
        fvvusLastAdcChan[uAsicIdx][usChan]        = usRawAdc;
488
        fvvulLastTsMsbChan[uAsicIdx][usChan]      = fulTsMsbIndexInTs[fuCurrDpbIdx];
489
490
      }  // if (fbRejectDuplicateDigis)

491
492
493
494
495
496
497
498
499
500
      uint32_t uChanInMod = usChan + fNrChsPerAsic * (uAsicIdx % fNrAsicsPerFeb);

      /// FIXME: see issue #1549
      /// N side: 0-1023 =>    0-1023
      /// P side: 0-1023 => 2047-1024

      if (0 == fviFebSide[uFebIdx])
        uChanInMod = fNrChsPerFeb - uChanInMod - 1  // Invert channel order
                     + fNrChsPerFeb;                // Offset for P (back) side

501
      /*
502
      // Get the time relative to the Timeslice time, I hope that the cast here works as expected. Otherwise Sts will also get into trouble with the size of UTC here
503
504
      auto tsreltime =
        static_cast<uint64_t>((ulHitTime - (fTsStartTime / stsxyter::kdClockCycleNs)) * stsxyter::kdClockCycleNs);
505
*/
506
      const double_t tsreltime = static_cast<double_t>(ulHitTime) * stsxyter::kdClockCycleNs;
507
      double dTimeInNs         = tsreltime - fSystemTimeOffset;
508
509
510
511
512
513
514
515
516
      if (uAsicIdx < fvdTimeOffsetNsAsics.size()) dTimeInNs -= fvdTimeOffsetNsAsics[uAsicIdx];

      const uint64_t ulTimeInNs = static_cast<uint64_t>(dTimeInNs);
      const double dCalAdc      = fvdFebAdcOffs[uFebIdx] + (usRawAdc - 1) * fvdFebAdcGain[uFebIdx];

      if (0 == fviFebAddress[uFebIdx] || -1 == fviFebSide[uFebIdx]) {
        LOG(error) << Form("Digi on disabled FEB %02u has address 0x%08x and side %d", uFebIdx, fviFebAddress[uFebIdx],
                           fviFebSide[uFebIdx]);
      }
517

518
519
      if (fMonitor) fMonitor->CountDigi(uFebIdx, uChanInFeb);

520
521
522
523
524
525
526
527
528
      /// Catch the pulser digis and either save them to their own output or drop them
      if (fvbFebPulser[uFebIdx]) {
        if (fOptOutAVec) {
          fOptOutAVec->emplace_back(CbmStsDigi(fviFebAddress[uFebIdx], uChanInMod, ulTimeInNs, dCalAdc));
        }  // if (fOptOutAVec)
      }    // if (fvbFebPulser[uFebIdx])
      else {
        fOutputVec.emplace_back(CbmStsDigi(fviFebAddress[uFebIdx], uChanInMod, ulTimeInNs, dCalAdc));
      }  // else of if (fvbFebPulser[uFebIdx])
529
530
531

      /// If EM flag ON, store a corresponding error message with the next flag after all other possible status flags set
      if (mess.IsHitMissedEvts())
532
533
        if (fOptOutBVec)
          fOptOutBVec->emplace_back(
534
            CbmErrorMessage(ECbmModuleId::kSts, dTimeInNs, uAsicIdx, 1 << stsxyter::kusLenStatStatus, usChan));
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
    }
  }

  // Convert the Hit time in bins to Hit time in ns
  const double dHitTimeNs = ulHitTime * stsxyter::kdClockCycleNs;

  if (fMonitor) {
    // Check Starting point of histos with time as X axis
    if (-1 == fdStartTime) { fdStartTime = dHitTimeNs; }
    if (fMonitor->GetDebugMode()) {
      fMonitor->FillHitDebugMonitoringHistos(uAsicIdx, usChan, usRawAdc, usRawTs, mess.IsHitMissedEvts());
    }
    const uint32_t uAsicInFeb       = uAsicIdx % fNrAsicsPerFeb;
    const double dTimeSinceStartSec = (dHitTimeNs - fdStartTime) * 1e-9;
    const double dCalAdc            = fvdFebAdcOffs[uFebIdx] + (usRawAdc - 1) * fvdFebAdcGain[uFebIdx];
    fMonitor->FillHitMonitoringHistos(uFebIdx, usChan, uChanInFeb, usRawAdc, dCalAdc, usRawTs, mess.IsHitMissedEvts());
    fMonitor->FillHitEvoMonitoringHistos(uFebIdx, uAsicIdx, uAsicInFeb, uChanInFeb, dTimeSinceStartSec,
                                         mess.IsHitMissedEvts());
  }
}

// ---- processStatusInfo ----
void CbmStsUnpackAlgo::processStatusInfo(const stsxyter::Message& mess, uint32_t uIdx)
{
  // again fMonitor settings used for debugging printouts, I would propose to separat this
  if (fMonitor)
    if (fMonitor->GetDebugMode()) {
      std::cout << Form("DPB %2u TS %12lu mess %5u ", fuCurrDpbIdx, fTsIndex, uIdx);
      mess.PrintMess(std::cout, stsxyter::MessagePrintMask::msg_print_Human);
    }

  const uint16_t usElinkIdx = mess.GetStatusLink();
  const uint32_t uCrobIdx   = usElinkIdx / fNrElinksPerCrob;
  const int32_t uFebIdx     = fElinkIdxToFebIdxVec.at(usElinkIdx);
  if (-1 == uFebIdx) {
570
    LOG(warning) << "CbmStsUnpackAlgo::processStatusInfo => "
571
572
573
574
575
576
577
578
579
580
581
582
583
                 << "Wrong elink Idx! Elink raw " << Form("%d remap %d", usElinkIdx, uFebIdx);
    return;
  }
  const uint32_t uAsicIdx = getAsicIndex(fuCurrDpbIdx, uCrobIdx, usElinkIdx);
  if (fMonitor) {
    const uint16_t usStatusField = mess.GetStatusStatus();
    fMonitor->FillStsStatusMessType(uAsicIdx, usStatusField);
  }
  /// Compute the Full time stamp
  const int64_t ulTime = getFullTimeStamp(0);

  /// Convert the time in bins to Hit time in ns
  const double dTimeNs = ulTime * stsxyter::kdClockCycleNs;
584
585
  if (fOptOutBVec)
    fOptOutBVec->emplace_back(
586
587
588
589
590
591
592
593
594
595
596
597
      CbmErrorMessage(ECbmModuleId::kSts, dTimeNs, uAsicIdx, mess.GetStatusStatus(), mess.GetData()));
}


// ---- processTsMsbInfo ----
void CbmStsUnpackAlgo::processTsMsbInfo(const stsxyter::Message& mess, uint32_t uMessIdx, uint32_t uMsIdx)
{
  const uint32_t uVal = mess.GetTsMsbValBinning();

  // Update Status counters
  if (uVal < fvulCurrentTsMsb[fuCurrDpbIdx]) {

598
    LOG(debug) << " TS " << std::setw(12) << fTsIndex << " MS Idx " << std::setw(4) << uMsIdx << " Msg Idx "
599
600
601
               << std::setw(5) << uMessIdx << " DPB " << std::setw(2) << fuCurrDpbIdx << " Old TsMsb " << std::setw(5)
               << fvulCurrentTsMsb[fuCurrDpbIdx] << " Old MsbCy " << std::setw(5) << fvuCurrentTsMsbCycle[fuCurrDpbIdx]
               << " new TsMsb " << std::setw(5) << uVal;
602
603
604

    fvuCurrentTsMsbCycle[fuCurrDpbIdx]++;
  }
605
606
  if (uVal != fvulCurrentTsMsb[fuCurrDpbIdx] + 1
      /// Case where we reach a normal cycle edge
607
      && !(0 == uVal && stsxyter::kuTsMsbNbTsBinsBinning == fvulCurrentTsMsb[fuCurrDpbIdx])
608
      /// First TS_MSB in MS may jump if TS dropped by DAQ
609
      && !(1 == uMessIdx && 0 == uMsIdx)
610
611
612
613
      /// Msg 1 and 2 will be same TS_MSB if data in 1st bin
      && !(uVal == fvulCurrentTsMsb[fuCurrDpbIdx] && 2 == uMessIdx)
      /// New FW introduced TS_MSB suppression + large TS_MSB => warning only if value not increasing
      && uVal < fvulCurrentTsMsb[fuCurrDpbIdx]) {
614
    LOG(debug) << "TS MSB Jump in "
615
616
617
               << " TS " << std::setw(12) << fTsIndex << " MS Idx " << std::setw(4) << uMsIdx << " Msg Idx "
               << std::setw(5) << uMessIdx << " DPB " << std::setw(2) << fuCurrDpbIdx << " => Old TsMsb "
               << std::setw(5) << fvulCurrentTsMsb[fuCurrDpbIdx] << " new TsMsb " << std::setw(5) << uVal;
618
619
  }

620
  fvulCurrentTsMsb[fuCurrDpbIdx] = uVal;
621

622
623
624
625
  LOG(debug1) << " TS " << std::setw(12) << fTsIndex << " MS Idx " << std::setw(4) << uMsIdx << " Msg Idx "
              << std::setw(5) << uMessIdx << " DPB " << std::setw(2) << fuCurrDpbIdx << " TsMsb " << std::setw(5)
              << fvulCurrentTsMsb[fuCurrDpbIdx] << " MsbCy " << std::setw(5) << fvuCurrentTsMsbCycle[fuCurrDpbIdx];

626
627
  fulTsMsbIndexInTs[fuCurrDpbIdx] =
    fvulCurrentTsMsb[fuCurrDpbIdx]
628
629
630
631
632
633
634
635
636
637
638
    + (fvuCurrentTsMsbCycle[fuCurrDpbIdx] * static_cast<uint64_t>(1 << stsxyter::kusLenTsMsbValBinning));
  if (fulTsMsbIndexInTs[fuCurrDpbIdx] < fulTsStartInTsMsb) {
    LOG(fatal) << "CbmStsUnpackAlgo::processTsMsbInfo => "
               << "Value computed from TS_MSB and TS_MSB cycle smaller than Timeslice start in TS_MSB, "
               << "would lead to a negative value so it cannot be recovered!!!!"
               << std::endl
               /// Values Printout
               << "TS_MSB: " << fvulCurrentTsMsb[fuCurrDpbIdx] << " Cycle: " << fvuCurrentTsMsbCycle[fuCurrDpbIdx]
               << " Full TS_MSB: " << fulTsMsbIndexInTs[fuCurrDpbIdx] << " TS Start offset: " << fulTsStartInTsMsb;
  }
  fulTsMsbIndexInTs[fuCurrDpbIdx] -= fulTsStartInTsMsb;
639

640
641
642
643
644
645
646
647
648
649
650
651
652
  if (fMonitor)
    if (fMonitor->GetDebugMode()) {  //also if( 1 < uMessIdx )?
      fMonitor->FillStsDpbRawTsMsb(fuCurrDpbIdx, fvulCurrentTsMsb[fuCurrDpbIdx]);
      fMonitor->FillStsDpbRawTsMsbSx(fuCurrDpbIdx, fvulCurrentTsMsb[fuCurrDpbIdx]);
      fMonitor->FillStsDpbRawTsMsbDpb(fuCurrDpbIdx, fvulCurrentTsMsb[fuCurrDpbIdx]);
    }
}

// ---- refreshTsMsbFields ----
void CbmStsUnpackAlgo::refreshTsMsbFields(const uint32_t imslice, const size_t mstime)
{
  const uint32_t uTsMsbCycleHeader =
    std::floor(mstime / (stsxyter::kulTsCycleNbBinsBinning * stsxyter::kdClockCycleNs));
653
654
655
  const uint32_t uTsMsbHeader =
    std::floor((mstime - uTsMsbCycleHeader * (stsxyter::kulTsCycleNbBinsBinning * stsxyter::kdClockCycleNs))
               / (stsxyter::kuHitNbTsBinsBinning * stsxyter::kdClockCycleNs));
656

657
658
659
660
661
662
  LOG(debug1) << " TS " << std::setw(12) << fTsIndex << " MS " << std::setw(12) << mstime << " MS Idx " << std::setw(4)
              << imslice << " Msg Idx " << std::setw(5) << 0 << " DPB " << std::setw(2) << fuCurrDpbIdx << " Old TsMsb "
              << std::setw(5) << fvulCurrentTsMsb[fuCurrDpbIdx] << " Old MsbCy " << std::setw(5)
              << fvuCurrentTsMsbCycle[fuCurrDpbIdx] << " header TsMsb " << uTsMsbHeader << " New MsbCy "
              << uTsMsbCycleHeader;

663
664
  if (0 == imslice) {
    if (uTsMsbCycleHeader != fvuCurrentTsMsbCycle[fuCurrDpbIdx])
665
666
667
      LOG(debug) << " TS " << std::setw(12) << fTsIndex << " MS " << std::setw(12) << mstime << " MS Idx "
                 << std::setw(4) << imslice << " Msg Idx " << std::setw(5) << 0 << " DPB " << std::setw(2)
                 << fuCurrDpbIdx << " Old TsMsb " << std::setw(5) << fvulCurrentTsMsb[fuCurrDpbIdx] << " Old MsbCy "
668
669
                 << std::setw(5) << fvuCurrentTsMsbCycle[fuCurrDpbIdx] << " New TsMsb " << uTsMsbHeader << " New MsbCy "
                 << uTsMsbCycleHeader;
670
    fvuCurrentTsMsbCycle[fuCurrDpbIdx] = uTsMsbCycleHeader;
671
    fvulCurrentTsMsb[fuCurrDpbIdx]     = uTsMsbHeader;
672
673
674
675
676
677
678
679
680
681
682
683
684
685

    fulTsMsbIndexInTs[fuCurrDpbIdx] =
      fvulCurrentTsMsb[fuCurrDpbIdx]
      + (fvuCurrentTsMsbCycle[fuCurrDpbIdx] * static_cast<uint64_t>(1 << stsxyter::kusLenTsMsbValBinning));
    if (fulTsMsbIndexInTs[fuCurrDpbIdx] < fulTsStartInTsMsb) {
      LOG(fatal) << "CbmStsUnpackAlgo::refreshTsMsbFields => "
                 << "Value computed from TS_MSB and TS_MSB cycle smaller than Timeslice start in TS_MSB, "
                 << "would lead to a negative value so it cannot be recovered!!!!"
                 << std::endl
                 /// Values Printout
                 << "TS_MSB: " << fvulCurrentTsMsb[fuCurrDpbIdx] << " Cycle: " << fvuCurrentTsMsbCycle[fuCurrDpbIdx]
                 << " Full TS_MSB: " << fulTsMsbIndexInTs[fuCurrDpbIdx] << " TS Start offset: " << fulTsStartInTsMsb;
    }
    fulTsMsbIndexInTs[fuCurrDpbIdx] -= fulTsStartInTsMsb;
686
687
  }
  else if (uTsMsbCycleHeader != fvuCurrentTsMsbCycle[fuCurrDpbIdx]) {
688
689
    if ((stsxyter::kuTsMsbNbTsBinsBinning - 1) == fvulCurrentTsMsb[fuCurrDpbIdx]) {
      /// Transition at the edge of two MS, the first TS_MSB message (idx 1) will make the cycle
690
691
692
693
      LOG(debug) << " TS " << std::setw(12) << fTsIndex << " MS " << std::setw(12) << mstime << " MS Idx "
                 << std::setw(4) << imslice << " Msg Idx " << std::setw(5) << 0 << " DPB " << std::setw(2)
                 << fuCurrDpbIdx << " Old TsMsb " << std::setw(5) << fvulCurrentTsMsb[fuCurrDpbIdx] << " Old MsbCy "
                 << std::setw(5) << fvuCurrentTsMsbCycle[fuCurrDpbIdx] << " New MsbCy " << uTsMsbCycleHeader;
694
695
696
697
698
699
    }
    else {
      LOG(warning) << "TS MSB cycle from MS header does not match current cycle from data "
                   << "for TS " << std::setw(12) << fTsIndex << " MS " << std::setw(12) << mstime << " MsInTs "
                   << std::setw(3) << imslice << " ====> " << fvuCurrentTsMsbCycle[fuCurrDpbIdx] << " (cnt) VS "
                   << uTsMsbCycleHeader << " (header)";
700
      fvuCurrentTsMsbCycle[fuCurrDpbIdx] = uTsMsbCycleHeader;
701
    }
702
  }
703
704
705
706
707
708
709
}

// ---- unpack ----
bool CbmStsUnpackAlgo::unpack(const fles::Timeslice* ts, std::uint16_t icomp, UInt_t imslice)
{
  auto msDescriptor = ts->descriptor(icomp, imslice);

710
711
712
713
714
715
716
717
  /// If monitoring enable, fill here the "Per Timeslice" histograms with info from the previous TS
  /// as only way to detect TS transitions due to the multiple calls in case of multiple components.
  /// Time set to tlast MS in previous TS. Last TS will be missed.
  if (fMonitor && 0 == imslice && 0 < fMsStartTime && msDescriptor.idx == ts->start_time()
      && fMsStartTime < msDescriptor.idx) {
    fMonitor->FillPerTimesliceCountersHistos(static_cast<double_t>(fMsStartTime) / 1e9);
  }

718
719
720
721
722
723
724
  //Current equipment ID, tells from which DPB the current MS is originating
  const uint32_t uCurrentEquipmentId = msDescriptor.eq_id;
  const uint8_t* msContent           = reinterpret_cast<const uint8_t*>(ts->content(icomp, imslice));
  const uint32_t uSize               = msDescriptor.size;

  fMsStartTime = msDescriptor.idx;
  LOG(debug) << "Microslice: " << fMsStartTime << " from EqId " << std::hex << uCurrentEquipmentId << std::dec
725
             << " has size: " << uSize << " (index " << imslice << ")";
726
727
728
729
730
731
732
733
734
735
736

  if (0 == fvbMaskedComponents.size()) fvbMaskedComponents.resize(ts->num_components(), false);

  //Temp holder until current equipment ID is properly filled in MS
  const uint32_t uCurrDpbId = static_cast<uint32_t>(uCurrentEquipmentId & 0xFFFF);

  if (fMonitor)
    if (fMonitor->GetDebugMode()) {
      const double dMsTime = (1e-9) * static_cast<double>(fMsStartTime);
      if (icomp < fMonitor->GetMaxNbFlibLinks()) {
        if (fdStartTimeMsSz < 0) fdStartTimeMsSz = dMsTime;
737
        fMonitor->CreateMsComponentSizeHistos(icomp);
738
739
740
741
742
743
744
745
746
        fMonitor->FillMsSize(icomp, uSize);
        fMonitor->FillMsSizeTime(icomp, dMsTime - fdStartTimeMsSz, uSize);
      }
    }

  /// Check if this sDPB ID was declared in parameter file and stop there if not
  auto it = fDpbIdIndexMap.find(uCurrDpbId);
  if (it == fDpbIdIndexMap.end()) {
    if (false == fvbMaskedComponents[icomp]) {
747
      // LOG(debug) << "---------------------------------------------------------------";
748
      // Had to remove this line otherwise we would get circle dependencies in the current stage of cbmroot, since we still have Unpackers in the fles folders, which require the reco folders
749
      // LOG(debug) << FormatMsHeaderPrintout(msDescriptor);
Pascal Raisig's avatar
Pascal Raisig committed
750
      LOG(warning) << fName << "::unpack(...)::Could not find the sDPB index for AFCK id 0x" << std::hex << uCurrDpbId
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
                   << std::dec << " in timeslice " << fNrProcessedTs << " in microslice " << imslice << " component "
                   << icomp << "\n"
                   << "If valid this index has to be added in the STS "
                      "parameter file in the DbpIdArray field";
      fvbMaskedComponents[icomp] = true;

      /// If first TS being analyzed, we are probably detecting STS/MUCH boards with same sysid
      /// => Do not report the MS as bad, just ignore it
      if (1 == fNrProcessedTs) return true;
    }
    else
      return true;

    // REMARK please check experts, but I think this point can never be reached PR 072021
    return false;
  }
  else
    fuCurrDpbIdx = fDpbIdIndexMap[uCurrDpbId];

  if (fMonitor) fMonitor->FillMsCntEvo(fMsStartTime);

772
773
774
775
776
777
  if (0 == imslice) {
    /// Extract the time base only on MS 0, assuming that we get all TS of a component in order
    fulTsStartInTsMsb =
      static_cast<uint64_t>(fTsStartTime / (stsxyter::kuHitNbTsBinsBinning * stsxyter::kdClockCycleNs));
  }

778
779
780
  // Check the current TS_MSb cycle and correct it if wrong
  refreshTsMsbFields(imslice, fMsStartTime);

781
782
783
784
  //Reset internal monitor variables for debugging info
  if (fMonitor) {
    if (fMonitor->GetDebugMode()) { fMonitor->ResetDebugInfo(); }
  }
785
786

  //Main processing of MS content
787
  loopMsMessages(msContent, uSize, imslice);
788
789

  //Output debugging info
790
  if (fMonitor) {
791
    if (fMonitor->GetDebugMode()) { fMonitor->PrintDebugInfo(fMsStartTime, fNrProcessedTs, msDescriptor.flags, uSize); }
792
793
794
795
796
797
    for (auto itHit = fOutputVec.begin(); itHit != fOutputVec.end(); ++itHit) {
      fMonitor->FillDigisTimeInRun(itHit->GetTime());
    }
    fMonitor->FillVectorSize(ts->index(), fOutputVec.size());
    //fMonitor->DrawCanvases();
  }
798
799
800
  return true;
}

801
ClassImp(CbmStsUnpackAlgo)