CbmRoot
Loading...
Searching...
No Matches
trd2d/UnpackMS.cxx
Go to the documentation of this file.
1/* Copyright (C) 2023 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Pascal Raisig, Alexandru Bercuci, Dominik Smith [committer] */
4
5#include "UnpackMS.h"
6
8
9#include <algorithm>
10#include <cassert>
11#include <vector>
12
13using std::unique_ptr;
14
15namespace cbm::algo::trd2d
16{
17 // ---- Fasp message constructor ----------------------------------------
18 FaspMessage::FaspMessage(uint8_t c, uint8_t typ, uint8_t t, uint16_t d, uint8_t rob, uint8_t asic)
19 : ch(c)
20 , type(typ)
21 , tlab(t)
22 , data(d)
23 , crob(rob)
24 , fasp(asic)
25 {
26 }
27
28 UnpackMS::UnpackMS(const UnpackPar& pars) : fParams(pars) {}
29 UnpackMS::~UnpackMS() = default;
30
31 // ---- Algorithm execution ---------------------------------------------
32 UnpackMS::Result_t UnpackMS::operator()(const uint8_t* msContent, const fles::MicrosliceDescriptor& msDescr,
33 const uint64_t tTimeslice) const
34 {
35 // --- Output data
36 Result_t result = {};
37
38 MsContext ctx = {};
39
40 // define time wrt start of time slice in TRD/FASP clks [80 MHz]. Contains:
41 // - relative offset of the MS wrt the TS
42 // - FASP epoch offset for current CROB
43 // - TRD2D system offset wrt to experiment time (e.g. Bmon)
44 uint64_t time = uint64_t((msDescr.idx - tTimeslice - fParams.fSystemTimeOffset) / 12.5);
45
46 // Get parameters for current eq id.
47 const uint8_t crob_id = fParams.fCrobId;
48
49 // Get the number of complete words in the input MS buffer.
50 const uint32_t nwords = msDescr.size / 4;
51
52 // We have 32 bit spadic frames in this readout version
53 const uint32_t* wd = reinterpret_cast<const uint32_t*>(msContent);
54
55 unsigned char lFaspOld(0xff);
56 std::vector<FaspMessage> vMess;
57 for (uint64_t j = 0; j < nwords; j++, wd++) {
58 uint32_t w = *wd;
59 uint8_t ch_id = w & 0xf;
60 uint8_t isaux = (w >> 4) & 0x1;
61 uint8_t slice = (w >> 5) & 0x7f;
62 uint16_t data = (w >> 12) & 0x3fff;
63 uint8_t fasp_id = ((w >> 26) & 0x3f);
64
65 if (isaux) {
66 if (ch_id == 0) {
67 // clear buffer
68 if (vMess.size()) {
69 pushDigis(vMess, time, ctx);
70 }
71 vMess.clear();
72
73 lFaspOld = 0xff;
74 time += FASP_EPOCH_LENGTH;
75 }
76 continue;
77 }
78 if (lFaspOld != fasp_id) {
79 if (vMess.size()) {
80 pushDigis(vMess, time, ctx);
81 }
82 vMess.clear();
83 lFaspOld = fasp_id;
84 }
85 if (data & 0x1) {
87 continue;
88 }
89 if (data & 0x2000) {
91 data &= 0x1fff;
92 }
93 vMess.emplace_back(ch_id, kData, slice, data >> 1, crob_id, lFaspOld);
94 }
95 std::get<0>(result) = FinalizeComponent(ctx); //TO DO: Original (non-algo) version calls this after MS loop!!
96 std::get<1>(result) = ctx.fMonitor;
97
98 return result;
99 }
100
101 //_________________________________________________________________________________
102 bool UnpackMS::pushDigis(std::vector<FaspMessage> messes, const uint64_t time, MsContext& ctx) const
103 {
104 const uint16_t mod_id = fParams.fModId;
105 const UnpackAsicPar& asicPar = fParams.fAsicParams[messes[0].fasp];
106 const uint64_t tdaqOffset = asicPar.fChanParams[messes[0].ch].fDaqOffset;
107
108 for (auto imess : messes) {
109 const int32_t pad = std::abs(asicPar.fChanParams[imess.ch].fPadAddress);
110 const bool hasPairingR = bool(asicPar.fChanParams[imess.ch].fPadAddress > 0);
111 const uint64_t lTime = time + tdaqOffset + imess.tlab;
112 const uint16_t lchR = hasPairingR ? imess.data : 0;
113 const uint16_t lchT = hasPairingR ? 0 : imess.data;
114 std::vector<CbmTrdDigi>& digiBuffer = ctx.fDigiBuffer[pad];
115
116 if (digiBuffer.size() == 0) { // init pad position in map and build digi for message
117 digiBuffer.emplace_back(pad, lchT, lchR, lTime);
118 digiBuffer.back().SetAddressModule(mod_id);
119 continue;
120 }
121
122 // check if last digi has both R/T message components. Update if not and is within time window
123 auto id = digiBuffer.rbegin(); // Should always be valid here.
124 // No need to extra check
125 double r, t;
126 int32_t dt;
127 const int32_t dtime = (*id).GetTimeDAQ() - lTime;
128 bool use(false);
129
130 if (abs(dtime) < 5) { // test message part of (last) digi
131 r = (*id).GetCharge(t, dt);
132 if (lchR && r < 0.1) { // set R charge on an empty slot
133 (*id).SetCharge(t, lchR, -dtime);
134 use = true;
135 }
136 else if (lchT && t < 0.1) { // set T charge on an empty slot
137 (*id).SetCharge(lchT, r, +dtime);
138 (*id).SetTimeDAQ(uint64_t((*id).GetTimeDAQ() - dtime));
139 use = true;
140 }
141 }
142
143 // build digi for message when update failed
144 if (!use) {
145 digiBuffer.emplace_back(pad, lchT, lchR, lTime);
146 digiBuffer.back().SetAddressModule(mod_id);
147 id = digiBuffer.rbegin();
148 }
149
150 // update charge for previously allocated digis to account for FASPRO ADC buffering and read-out feature
151 for (++id; id != digiBuffer.rend(); ++id) {
152 r = (*id).GetCharge(t, dt);
153 if (lchR && int(r)) { // update R charge and mark on digi
154 (*id).SetCharge(t, lchR, dt);
155 (*id).SetFlag(1);
156 break;
157 }
158 else if (lchT && int(t)) { // update T charge and mark on digi
159 (*id).SetCharge(lchT, r, dt);
160 (*id).SetFlag(0);
161 break;
162 }
163 }
164 }
165 messes.clear();
166
167 return true;
168 }
169
170 std::vector<CbmTrdDigi> UnpackMS::FinalizeComponent(MsContext& ctx) const
171 {
172 std::vector<CbmTrdDigi> outputDigis;
173
174 for (uint16_t ipad(0); ipad < NFASPMOD * NFASPCH; ipad++) {
175 if (!ctx.fDigiBuffer[ipad].size()) continue;
176 uint nIncomplete(0);
177 for (auto id = ctx.fDigiBuffer[ipad].begin(); id != ctx.fDigiBuffer[ipad].end(); id++) {
178 double r, t;
179 int32_t dt;
180 r = (*id).GetCharge(t, dt);
181 // check if digi has all signals CORRECTED
182 if (((t > 0) != (*id).IsFlagged(0)) || ((r > 0) != (*id).IsFlagged(1))) {
183 nIncomplete++;
184 continue;
185 }
186 // reset flags as they were used only to mark the correctly setting of the charge/digi
187 (*id).SetFlag(0, false);
188 (*id).SetFlag(1, false);
189 outputDigis.emplace_back(std::move((*id)));
190 }
191 // clear digi buffer wrt the digi which was forwarded to higher structures
192 ctx.fDigiBuffer[ipad].clear();
193 if (nIncomplete > 2) {
194 ctx.fMonitor.fNumIncompleteDigis++; //TO DO: This must be moved if finalization is done after MS loop
195 }
196 }
197 return outputDigis;
198 }
199} // namespace cbm::algo::trd2d
std::tuple< std::vector< Digi_t >, Monitor_t, Aux_t > Result_t
Result_t operator()(const uint8_t *msContent, const fles::MicrosliceDescriptor &msDescr, const uint64_t tTimeslice) const override
Algorithm execution.
UnpackMS(const UnpackPar &pars)
Construct from parameters.
std::vector< CbmTrdDigi > FinalizeComponent(MsContext &ctx) const
Finalize component (e.g. copy from temp buffers)
bool pushDigis(std::vector< FaspMessage > messages, const uint64_t time, MsContext &ctx) const
~UnpackMS() override
Destructor.
UnpackPar fParams
Parameter container.
FaspMessage(uint8_t c, uint8_t typ, uint8_t t, uint16_t d, uint8_t rob, uint8_t asic)
TRD Unpacking parameters for one Asic.
std::vector< UnpackChannelPar > fChanParams
Parameters for different channels.
UnpackMonitorData fMonitor
Container for monitoring data.
std::array< std::vector< CbmTrdDigi >, NFASPMOD *NFASPCH > fDigiBuffer
uint32_t fNumSelfTriggeredData
word fulfills data & 0x2000
uint32_t fNumIncompleteDigis
incomplete digis left in pads after finalization
uint32_t fNumErrEndBitSet
Corrupted data with end bit set.
Parameters required for the TRD unpacking (specific to one component)
uint16_t fModId
Module ID of component.
int32_t fSystemTimeOffset
Time calibration parameter.
uint8_t fCrobId
CROB ID of component.
std::vector< UnpackAsicPar > fAsicParams
Parameters for each ASIC.
#define NFASPCH
#define NFASPMOD
#define FASP_EPOCH_LENGTH