CbmRoot
Loading...
Searching...
No Matches
CbmRichUnpackAlgo2022.cxx
Go to the documentation of this file.
1/* Copyright (C) 2021 Goethe-University Frankfurt, Frankfurt
2 SPDX-License-Identifier: GPL-3.0-only
3 Authors: Pascal Raisig [committer] */
4
6
7#include <FairParGenericSet.h>
8#include <FairTask.h>
9#include <Logger.h>
10
11#include <Rtypes.h>
12#include <RtypesCore.h>
13
14#include <cstdint>
15
16
18
20
21// ---- unpack
22bool CbmRichUnpackAlgo2022::unpack(const fles::Timeslice* ts, std::uint16_t icomp, UInt_t imslice)
23{
24
25 const fles::MicrosliceView mv = ts->get_microslice(icomp, imslice);
26 const fles::MicrosliceDescriptor& msDesc = mv.desc();
27
28 // Check the version number of the MS to identify wrong unpacker for data
29 if (msDesc.sys_ver != 0x3) {
30 LOG(fatal) << "CbmRichUnpackAlgo2022: System Version of the microslice is not compatible with this unpacker!";
31 return false;
32 }
33
34 // Clear CbmTime of MS. Used to get time offset of subtriggers to MS start
35 fCbmTimeMS = 0;
36
38 reader.SetData(mv.content(), msDesc.size);
39
40 auto mstime = msDesc.idx;
41 fMsRefTime = mstime - fTsStartTime;
42
43 // There are a lot of MS with 8 bytes size
44 // Does one need these MS?
45 if (reader.GetSize() <= 8) return true;
46
47 while (true) {
48 processTrbPacket(reader);
49 // -4*2 for 2 last words which contain microslice index
50 if (reader.GetOffset() >= reader.GetSize() - 8) break;
51 // -4*3 for 0xffffffff padding and 2 last words which contain microslice index
52 if (reader.IsNextPadding() && reader.GetOffset() >= reader.GetSize() - 12) break;
53 }
54
55 uint32_t msIndexWord1 = reader.NextWord();
56 if (isLog()) LOG(debug4) << getLogHeader(reader) << "Microslice Index 1:" << reader.GetWordAsHexString(msIndexWord1);
57
58 uint32_t msIndexWord2 = reader.NextWord();
59 if (isLog()) LOG(debug4) << getLogHeader(reader) << "Microslice Index 2:" << reader.GetWordAsHexString(msIndexWord2);
60
61 //Output debugging info
62 if (fMonitor) {
63 for (auto itHit = fOutputVec.begin(); itHit != fOutputVec.end(); ++itHit) {
64 fMonitor->FillDigisTimeInRun(itHit->GetTime());
65 fMonitor->FillDigisToT(itHit->GetToT());
66 fMonitor->FillDigisToTDiRICH(itHit->GetAddress(), itHit->GetToT());
67 }
68 fMonitor->FillVectorSize(ts->index(), fOutputVec.size());
69 }
70
71 return true;
72}
73
75{
76 uint32_t word = reader.NextWord();
77 uint32_t hubId = word & 0xffff; // 16 bits
78 uint32_t hubSize = (word >> 16) & 0xffff; // 16 bits
79 if (isLog())
80 LOG(debug4) << getLogHeader(reader) << "hubId:0x" << std::hex << hubId << std::dec << " hubSize:" << hubSize;
81
82 //if ((HubId == 0xc001) || (HubId == 0xc000)) //CTS subevent?
83 //if (HubId == 0x5555)
84 //if (((HubId >> 8) & 0xff) == 0x82) // TRB subevent? // TODO: check if it starts from 0x82
85
86 // if true then it is CTS sub-sub-event
87 bool isLast = false;
88 size_t counter = 0;
89 size_t totalSize = 0;
91
92 while (!isLast) {
93 word = reader.NextWord();
94 uint32_t subSubEventId = word & 0xffff; // 16 bits
95 uint32_t subSubEventSize = (word >> 16) & 0xffff; // 16 bits
96 isLast = reader.IsLastSubSubEvent(subSubEventSize); // if true then it is CTS sub-sub-event
97 counter++;
98 totalSize += (1 + subSubEventSize);
99
100 if (isLog())
101 LOG(debug4) << getLogHeader(reader) << counter << ((isLast) ? " CTS" : " DiRICH") << " subSubEventId:0x"
102 << std::hex << subSubEventId << std::dec << " subSubEventSize:" << subSubEventSize;
103
104 if (!isLast) { // DiRICH event
105 // check correctness of subsub event, for safety reasons
106 if (((subSubEventId >> 12) & 0xF) != 0x7) {
107 LOG(error) << getLogHeader(reader) << "ERROR: subSubEventId has strange value:0x" << std::hex << subSubEventId
108 << std::dec;
109 }
110 processSubSubEvent(reader, subSubEventSize, subSubEventId);
111 }
112 else { // CTS event
114 processCtsSubSubEvent(reader, subSubEventSize, subSubEventId);
115 }
116
117 // if (fbDebugMonitorMode) {
118 // //This address calculation is just for mCBM; will be a problem when using full CBM RICH acceptance
119 // uint16_t histAddr = ((subSubEventId >> 8) & 0xF) * 18 + ((subSubEventId >> 4) & 0xF) * 2 + (subSubEventId & 0xF);
120 // fhSubSubEventSize->Fill(histAddr, subSubEventSize); // Words in a DiRICH
121 // }
122
123 if ((totalSize == hubSize && !isLast) || (totalSize != hubSize && isLast)) {
124 if (isLog()) LOG(error) << "ERROR: totalSize OR isLast is wrong";
125 }
126
127 if (totalSize >= hubSize || isLast) break;
128
130 }
131
132 // read last words
133 int lastWordsCounter = 0;
134 while (true) {
135 lastWordsCounter++;
136 word = reader.NextWord();
137 if (isLog()) LOG(debug4) << getLogHeader(reader);
138 if (word == 0x600dda7a) {
139 if (reader.IsNextPadding()) word = reader.NextWord();
140 break;
141 }
142 if (lastWordsCounter >= 7) {
143 LOG(error) << getLogHeader(reader)
144 << "CbmMcbm2018UnpackerAlgoRich::ProcessHubBlock() ERROR: No word == 0x600dda7a";
145 }
146 }
147}
148
150 uint32_t subSubEventId)
151{
152 uint32_t word = reader.NextWord();
153 uint32_t ctsState = word & 0xffff; // 16 bits
154 uint32_t nofInputs = (word >> 16) & 0xf; // 4 bits
155 uint32_t nofTrigCh = (word >> 20) & 0x1f; // 5 bits
156 uint32_t inclLastIdle = (word >> 25) & 0x1; // 1 bit
157 uint32_t inclTrigInfo = (word >> 26) & 0x1; // 1 bit
158 uint32_t inclTime = (word >> 27) & 0x1; // 1 bit
159 uint32_t ETM = (word >> 28) & 0x3; // 2 bits
160 uint32_t ctsInfoSize = 2 * nofInputs + 2 * nofTrigCh + 2 * inclLastIdle + 3 * inclTrigInfo + inclTime; // in words
161 switch (ETM) {
162 case 0: break;
163 case 1: ctsInfoSize += 1; break;
164 case 2: ctsInfoSize += 4; break;
165 case 3: break;
166 }
167 if (isLog()) LOG(debug4) << getLogHeader(reader) << "CTS ctsState:" << ctsState << " ctsInfoSize:" << ctsInfoSize;
168 for (uint32_t i = 0; i < ctsInfoSize; i++) {
169 word = reader.NextWord(); // do nothing?
170 if (isLog()) LOG(debug4) << getLogHeader(reader) << "CTS info words";
171 }
172 int nofTimeWords = subSubEventSize - ctsInfoSize - 1;
173 processSubSubEvent(reader, nofTimeWords, subSubEventId);
174}
175
177 uint32_t subSubEventId)
178{
179 // Store if a certain TDC word type was analysed,
180 // later one can check if the order is correct
181 bool wasHeader = false;
182 bool wasEpoch = false;
183 bool wasTime = false;
184 bool wasTrailer = false;
185 uint32_t epoch = 0; // store last epoch obtained in sub-sub-event
186 bool errorInData = false;
187
188 // Store last raising edge time for each channel or -1. if no time
189 // this array is used to match raising and falling edges
190 std::vector<double> raisingTime(33, -1.);
191
192 // check if DiRICH (SubSubEvId) is masked
193 bool DiRICH_masked = false;
194 if (checkMaskedDiRICH(subSubEventId)) {
195 DiRICH_masked = true;
196 }
197
198 // catch unknown DiRICH addresses (Corrupt data or CTS)
199 // TODO: properly handle/skip CTS subsubevents
200 bool DiRICH_unknown = false;
201 if (-1 == fUnpackPar.GetAddressIdx(subSubEventId, false)) {
202 DiRICH_unknown = true;
203 if (0x8000 != (subSubEventId & 0xF000)) {
204 // No log for CTS subsubevents
205 LOG(debug) << "Unknown DiRICH ID 0x" << std::hex << subSubEventId << std::dec;
206 }
207 }
208
209 for (int i = 0; i < nofTimeWords; i++) {
210 uint32_t word = reader.NextWord();
211 // Skip masked/unknown DiRICH
212 if (DiRICH_masked || DiRICH_unknown) continue;
214
216 if (!wasHeader || !wasEpoch || wasTrailer) {
217 LOG(debug) << getLogHeader(reader) << "DiRICH 0x" << std::hex << subSubEventId << std::dec
218 << ": illegal position of TDC Time (before header/epoch or after trailer), skip subsubevent"
219 << " " << wasHeader << "|" << wasEpoch << "|" << wasTrailer;
220 errorInData = true;
221 // Currently skip the subsubevent
222 // TODO: Check if possible to only skip to next Epoch and continue from there
223 for (; i < nofTimeWords - 1; i++) {
224 reader.NextWord();
225 }
226 continue;
227 }
228 wasTime = true;
229 processTimeDataWord(reader, i, epoch, word, subSubEventId, raisingTime);
230 }
231 else if (type == CbmRichUnpackAlgoTdcWordType::Epoch) {
232 if (!wasHeader || wasTrailer) {
233 LOG(debug) << getLogHeader(reader) << "DiRICH 0x" << std::hex << subSubEventId << std::dec
234 << ": illegal position of TDC Epoch (before header or after trailer), skip subsubevent";
235 errorInData = true;
236 // Currently skip the subsubevent
237 // TODO: Check if possible to only skip to next Epoch and continue from there
238 for (; i < nofTimeWords - 1; i++) {
239 reader.NextWord();
240 }
241 continue;
242 }
243 wasEpoch = true;
245 if (isLog()) LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << i << "] epoch:" << epoch;
246 }
247 else if (type == CbmRichUnpackAlgoTdcWordType::Header) {
248 if (wasEpoch || wasTime || wasTrailer) {
249 LOG(debug) << getLogHeader(reader) << "DiRICH 0x" << std::hex << subSubEventId << std::dec
250 << ": illegal position of TDC Header (after time/epoch/trailer), skip subsubevent";
251 errorInData = true;
252 for (; i < nofTimeWords - 1; i++) {
253 reader.NextWord();
254 }
255 continue;
256 }
257 wasHeader = true;
258 // uint16_t errorBits = CbmRichUnpackAlgoTdcWordReader::ProcessHeader(word);
259 // ErrorMsg(errorBits, CbmRichUnpackAlgoErrorType::tdcHeader, subSubEventId);
260 if (isLog()) LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << i << "] header";
261 }
262 else if (type == CbmRichUnpackAlgoTdcWordType::Trailer) {
263 if (!wasEpoch || !wasTime || !wasHeader) {
264 LOG(debug) << getLogHeader(reader) << "DiRICH 0x" << std::hex << subSubEventId << std::dec
265 << ": illegal position of TDC Trailer (before time/epoch/header), skip subsubevent";
266 errorInData = true;
267 for (; i < nofTimeWords - 1; i++) {
268 reader.NextWord();
269 }
270 continue;
271 }
272 wasTrailer = true;
273 // uint16_t errorBits = CbmRichUnpackAlgoTdcWordReader::ProcessTrailer(word);
274 // ErrorMsg(errorBits, CbmRichUnpackAlgoErrorType::tdcTrailer, subSubEventId);
275 if (isLog()) LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << i << "] trailer";
276 }
277 else if (type == CbmRichUnpackAlgoTdcWordType::Debug) {
278 // for the moment do nothing
279 }
280 else if (type == CbmRichUnpackAlgoTdcWordType::Error) {
281 LOG(error) << getLogHeader(reader) << "Wrong TDC word!!! marker:" << ((word >> 29) & 0x7);
282 errorInData = true;
283 }
284 }
285
286 if (errorInData) {
287 //TODO:
288 }
289}
290
292{
293 processCBMtime(reader);
294 uint32_t trigNum_this = reader.NextWord() & 0xFFFFFF;
295 reader.NextWord(); // reserved
296
297 uint32_t wordEpoch; // Create variable out of 1st loop to trick the "unused variable" warning with 2nd loop use
298 uint32_t wordTime; // Create variable out of 1st loop to trick the "unused variable" warning with 2nd loop use
299 for (auto l = 0; l < 2; ++l) {
300 wordEpoch = reader.NextWord();
301 //uint32_t epoch = CbmRichUnpackAlgoTdcWordReader::ProcessEpoch(wordEpoch);
302 wordTime = reader.NextWord();
303 //CbmRichUnpackAlgoTdcTimeData td;
304 //CbmRichUnpackAlgoTdcWordReader::ProcessTimeData(wordTime, td);
305
306 //if (l == 0) fCtsCh0_cur = calculateTime(epoch, td.fCoarse, td.fFine);
307 //if (l == 1) fCtsCh1_cur = calculateTime(epoch, td.fCoarse, td.fFine);
308 }
309
310 //prev CBM time (64bit)
311 uint32_t cbmtime0 = reader.NextWord(); // CBM 63:32
312 uint32_t cbmtime1 = reader.NextWord(); // CBM 31: 0
313 uint64_t CbmTimePacket_prev = (uint64_t) cbmtime0 << 32 | cbmtime1;
314
315 uint32_t trigNum_prevMes = reader.NextWord() & 0xFFFFFF;
316
317 if (false) {
318 // Following just for tricking the unused var warning detection without breaking the existing code
319 LOG(trace) << "trigNum_this =" << trigNum_this << " trigNum_prevMes = " << trigNum_prevMes
320 << " CbmTimePacket_prev = " << CbmTimePacket_prev;
321 }
322
323 reader.NextWord(); // reserved
324
325 for (auto l = 0; l < 14; ++l) {
326 wordEpoch = reader.NextWord();
327 uint32_t epoch = CbmRichUnpackAlgoTdcWordReader::ProcessEpoch(wordEpoch);
328 wordTime = reader.NextWord();
331
332 double fullTime = calculateTime(epoch, td.fCoarse, td.fFine);
333
334 if (l == 0) {
335 fMbsPrevTimeCh0 = fullTime;
336 fPrevLastCh0ReTime[0] = fullTime;
337 }
338 if (l == 1) fMbsPrevTimeCh1 = fullTime;
339 if (l > 1) fPrevLastCh0ReTime[l - 1] = fullTime;
340 }
341
342 uint32_t trbNum = reader.NextWord(); // TRB trigger number
343 if (isLog()) LOG(debug4) << getLogHeader(reader) << "TRB Num:" << reader.GetWordAsHexString(trbNum);
344
345 processHubBlock(reader);
346}
347
349{
350 uint32_t word_MSB = reader.NextWord(); // CBM 63:32
351 uint32_t word_LSB = reader.NextWord(); // CBM 31: 0
352
353 fCbmTimePacket = 0;
354 fCbmTimePacket = (uint64_t) word_MSB << 32 | word_LSB;
356}
357
358// ---- processTimeDataWord ----
360 uint32_t tdcWord, uint32_t subSubEventId,
361 std::vector<double>& raisingTime)
362{
365 double fullTime = calculateTime(epoch, td.fCoarse, td.fFine);
366
367
368 if (td.fChannel == 0) {
369 if (td.IsRisingEdge()) {
370 if (isLog())
371 LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << iTdc << "] " << td.ToString()
372 << " CH0 Last:" << std::setprecision(15) << fullTime
373 << " PrevLast:" << fPrevLastCh0ReTime[fCurrentSubSubEvent]
374 << " diff:" << fullTime - fPrevLastCh0ReTime[fCurrentSubSubEvent];
375 }
376 }
377 else {
378 double dT = fullTime - fPrevLastCh0ReTime[fCurrentSubSubEvent];
379 double mbsCorr = fMbsPrevTimeCh1 - fMbsPrevTimeCh0;
380 double subtrigOffset = (fCbmTimePacket - fCbmTimeMS) * 25.0; // offset of SubTrigger to MS start in ns
381 double fullTimeCorr = dT - mbsCorr + subtrigOffset;
382
383 // if ((subSubEventId >> 12 ) == 0x7)
384 // std::cout<< dT <<" "
385 // << fullTimeCorr <<" "<< std::setprecision(15)
386 // << fullTime <<" "
387 // << fPrevLastCh0ReTime[fCurrentSubSubEvent] <<" "
388 // << mbsCorr <<" "
389 // << subtrigOffset <<" "
390 // << fCurrentSubSubEvent <<" " <<std::hex
391 // << subSubEventId << std::dec <<std::endl;
392
393 if (isLog())
394 LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << iTdc << "] " << td.ToString()
395 << " time:" << std::setprecision(15) << fullTime << " fullTimeCorr:" << fullTimeCorr;
396
397 if (td.fChannel < 1 || td.fChannel >= raisingTime.size()) {
398 LOG(error) << "ERROR: channel number is out of limit. Channel:" << td.fChannel;
399 }
400
401 if (td.IsRisingEdge()) {
402 // always store the latest raising edge. It means that in case RRFF situation only middle RF will be matched.
403 raisingTime[td.fChannel] = fullTimeCorr;
404 }
405 else {
406 if (raisingTime[td.fChannel] == -1.) {
407 //No raising channel was found before. Skip this falling edge time.
408 if (isLog())
409 LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << iTdc << "] "
410 << "No raising channel was found before. Skip this falling edge time.";
411 }
412 else {
413 // Matching was found, calculate ToT, if tot is in a good range -> create digi
414 double ToT = fullTimeCorr - raisingTime[td.fChannel];
415 if (isLog())
416 LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << iTdc << "] "
417 << "ToT:" << ToT;
418 if (ToT >= fToTMin && ToT <= fToTMax) {
419 // if (fbMonitorMode) {
420 // TH1D* h = GetTotH1(subSubEventId, td.fChannel);
421 // if (h != nullptr) h->Fill(ToT);
422
423 // TH2D* h2 = GetTotH2(subSubEventId);
424 // if (h2 != nullptr) h2->Fill(td.fChannel, ToT);
425 // }
426 if (fullTimeCorr >= 0.0) {
427 writeOutputDigi(subSubEventId, td.fChannel, raisingTime[td.fChannel], ToT);
428 }
429 }
430 // pair was created, set raising edge to -1.
431 raisingTime[td.fChannel] = -1.;
432 }
433 }
434 }
435}
436
437void CbmRichUnpackAlgo2022::writeOutputDigi(Int_t fpgaID, Int_t channel, Double_t time, Double_t tot)
438{
439 Double_t ToTcorr = fbDoToTCorr ? fUnpackPar.GetToTshift(fpgaID, channel) : 0.;
440 Int_t pixelUID = this->getPixelUID(fpgaID, channel);
441 //check ordering
442 Double_t finalTime = time + (Double_t) fMsRefTime - fSystemTimeOffset;
443
444 // Do not accept digis, where the MS und TS differs by more than 6 sec (mainly TS0)
445 if (6e9 < finalTime) return;
446
447 fOutputVec.emplace_back(pixelUID, finalTime, tot - ToTcorr);
448}
449
ClassImp(CbmConverterManager)
CbmRichUnpackAlgoTdcWordType
Double_t GetToTshift(Int_t tdc, Int_t ch) const
Int_t GetAddressIdx(Int_t addr, bool bVerbose=true) const
void processCtsSubSubEvent(CbmRichUnpackAlgoMicrosliceReader &reader, uint32_t subSubEventSize, uint32_t subSubEventId)
bool unpack(const fles::Timeslice *ts, std::uint16_t icomp, UInt_t imslice)
Unpack a given microslice. To be implemented in the derived unpacker algos.
virtual ~CbmRichUnpackAlgo2022()
Destroy the Cbm Trd Unpack Task object.
void processHubBlock(CbmRichUnpackAlgoMicrosliceReader &reader)
void processTrbPacket(CbmRichUnpackAlgoMicrosliceReader &reader)
void processTimeDataWord(CbmRichUnpackAlgoMicrosliceReader &reader, int iTdc, uint32_t epoch, uint32_t tdcWord, uint32_t subSubEventId, std::vector< double > &raisingTime)
double fMbsPrevTimeCh0
Parameters for the unpacking.
CbmRichUnpackAlgo2022()
Create the Cbm Trd Unpack AlgoBase object.
void processCBMtime(CbmRichUnpackAlgoMicrosliceReader &reader)
void writeOutputDigi(Int_t fpgaID, Int_t channel, Double_t time, Double_t tot)
void processSubSubEvent(CbmRichUnpackAlgoMicrosliceReader &reader, int nofTimeWords, uint32_t subSubEventId)
bool checkMaskedDiRICH(Int_t subSubEventId)
Unpack a given microslice. To be implemented in the derived unpacker algos.
CbmMcbm2018RichPar fUnpackPar
Parameters for the unpacking.
double calculateTime(uint32_t epoch, uint32_t coarse, uint32_t fine)
Int_t getPixelUID(Int_t fpgaID, Int_t ch) const
std::shared_ptr< CbmRichUnpackMonitor > fMonitor
Potential (online) monitor for the unpacking process.
std::string getLogHeader(CbmRichUnpackAlgoMicrosliceReader &reader)
std::string GetWordAsHexString(uint32_t word)
bool IsLastSubSubEvent(uint32_t subSubEventSize)
void SetData(const uint8_t *data, size_t size)
static CbmRichUnpackAlgoTdcWordType GetTdcWordType(uint32_t tdcWord)
static void ProcessTimeData(uint32_t tdcWord, CbmRichUnpackAlgoTdcTimeData &outData)
static uint32_t ProcessEpoch(uint32_t tdcWord)