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 uint16_t sSubSubEvtIdMsb = (subSubEventId >> 12) & 0xF;
107 if ((sSubSubEvtIdMsb != 0x7) && (sSubSubEvtIdMsb != 0x9)) {
108 if (0 == fUnexpectedIds.count(subSubEventId)) {
109 LOG(error) << getLogHeader(reader) << "ERROR: subSubEventId has strange value:0x" << std::hex << subSubEventId
110 << std::dec;
111 fUnexpectedIds.insert(subSubEventId);
112 }
113 }
114 processSubSubEvent(reader, subSubEventSize, subSubEventId);
115 }
116 else { // CTS event
118 processCtsSubSubEvent(reader, subSubEventSize, subSubEventId);
119 }
120
121 // if (fbDebugMonitorMode) {
122 // //This address calculation is just for mCBM; will be a problem when using full CBM RICH acceptance
123 // uint16_t histAddr = ((subSubEventId >> 8) & 0xF) * 18 + ((subSubEventId >> 4) & 0xF) * 2 + (subSubEventId & 0xF);
124 // fhSubSubEventSize->Fill(histAddr, subSubEventSize); // Words in a DiRICH
125 // }
126
127 if ((totalSize == hubSize && !isLast) || (totalSize != hubSize && isLast)) {
128 if (isLog()) LOG(error) << "ERROR: totalSize OR isLast is wrong";
129 }
130
131 if (totalSize >= hubSize || isLast) break;
132
134 }
135
136 // read last words
137 int lastWordsCounter = 0;
138 while (true) {
139 lastWordsCounter++;
140 word = reader.NextWord();
141 if (isLog()) LOG(debug4) << getLogHeader(reader);
142 if (word == 0x600dda7a) {
143 if (reader.IsNextPadding()) word = reader.NextWord();
144 break;
145 }
146 if (lastWordsCounter >= 7) {
147 LOG(error) << getLogHeader(reader)
148 << "CbmMcbm2018UnpackerAlgoRich::ProcessHubBlock() ERROR: No word == 0x600dda7a";
149 }
150 }
151}
152
154 uint32_t subSubEventId)
155{
156 uint32_t word = reader.NextWord();
157 uint32_t ctsState = word & 0xffff; // 16 bits
158 uint32_t nofInputs = (word >> 16) & 0xf; // 4 bits
159 uint32_t nofTrigCh = (word >> 20) & 0x1f; // 5 bits
160 uint32_t inclLastIdle = (word >> 25) & 0x1; // 1 bit
161 uint32_t inclTrigInfo = (word >> 26) & 0x1; // 1 bit
162 uint32_t inclTime = (word >> 27) & 0x1; // 1 bit
163 uint32_t ETM = (word >> 28) & 0x3; // 2 bits
164 uint32_t ctsInfoSize = 2 * nofInputs + 2 * nofTrigCh + 2 * inclLastIdle + 3 * inclTrigInfo + inclTime; // in words
165 switch (ETM) {
166 case 0: break;
167 case 1: ctsInfoSize += 1; break;
168 case 2: ctsInfoSize += 4; break;
169 case 3: break;
170 }
171 if (isLog()) LOG(debug4) << getLogHeader(reader) << "CTS ctsState:" << ctsState << " ctsInfoSize:" << ctsInfoSize;
172 for (uint32_t i = 0; i < ctsInfoSize; i++) {
173 word = reader.NextWord(); // do nothing?
174 if (isLog()) LOG(debug4) << getLogHeader(reader) << "CTS info words";
175 }
176 int nofTimeWords = subSubEventSize - ctsInfoSize - 1;
177 processSubSubEvent(reader, nofTimeWords, subSubEventId);
178}
179
181 uint32_t subSubEventId)
182{
183 // Store if a certain TDC word type was analysed,
184 // later one can check if the order is correct
185 bool wasHeader = false;
186 bool wasEpoch = false;
187 bool wasTime = false;
188 bool wasTrailer = false;
189 uint32_t epoch = 0; // store last epoch obtained in sub-sub-event
190 bool errorInData = false;
191
192 // Store last raising edge time for each channel or -1. if no time
193 // this array is used to match raising and falling edges
194 std::vector<double> raisingTime(33, -1.);
195
196 // check if DiRICH (SubSubEvId) is masked
197 bool DiRICH_masked = false;
198 if (checkMaskedDiRICH(subSubEventId)) {
199 DiRICH_masked = true;
200 }
201
202 // catch unknown DiRICH addresses (Corrupt data or CTS)
203 // TODO: properly handle/skip CTS subsubevents
204 bool DiRICH_unknown = false;
205 if (-1 == fUnpackPar.GetAddressIdx(subSubEventId, false)) {
206 DiRICH_unknown = true;
207 if (0x8000 != (subSubEventId & 0xF000)) {
208 // No log for CTS subsubevents
209 LOG(debug) << "Unknown DiRICH ID 0x" << std::hex << subSubEventId << std::dec;
210 }
211 }
212
213 for (int i = 0; i < nofTimeWords; i++) {
214 uint32_t word = reader.NextWord();
215 // Skip masked/unknown DiRICH
216 if (DiRICH_masked || DiRICH_unknown) continue;
218
220 if (!wasHeader || !wasEpoch || wasTrailer) {
221 LOG(debug) << getLogHeader(reader) << "DiRICH 0x" << std::hex << subSubEventId << std::dec
222 << ": illegal position of TDC Time (before header/epoch or after trailer), skip subsubevent"
223 << " " << wasHeader << "|" << wasEpoch << "|" << wasTrailer;
224 errorInData = true;
225 // Currently skip the subsubevent
226 // TODO: Check if possible to only skip to next Epoch and continue from there
227 for (; i < nofTimeWords - 1; i++) {
228 reader.NextWord();
229 }
230 continue;
231 }
232 wasTime = true;
233 processTimeDataWord(reader, i, epoch, word, subSubEventId, raisingTime);
234 }
235 else if (type == CbmRichUnpackAlgoTdcWordType::Epoch) {
236 if (!wasHeader || wasTrailer) {
237 LOG(debug) << getLogHeader(reader) << "DiRICH 0x" << std::hex << subSubEventId << std::dec
238 << ": illegal position of TDC Epoch (before header or after trailer), skip subsubevent";
239 errorInData = true;
240 // Currently skip the subsubevent
241 // TODO: Check if possible to only skip to next Epoch and continue from there
242 for (; i < nofTimeWords - 1; i++) {
243 reader.NextWord();
244 }
245 continue;
246 }
247 wasEpoch = true;
249 if (isLog()) LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << i << "] epoch:" << epoch;
250 }
251 else if (type == CbmRichUnpackAlgoTdcWordType::Header) {
252 if (wasEpoch || wasTime || wasTrailer) {
253 LOG(debug) << getLogHeader(reader) << "DiRICH 0x" << std::hex << subSubEventId << std::dec
254 << ": illegal position of TDC Header (after time/epoch/trailer), skip subsubevent";
255 errorInData = true;
256 for (; i < nofTimeWords - 1; i++) {
257 reader.NextWord();
258 }
259 continue;
260 }
261 wasHeader = true;
262 // uint16_t errorBits = CbmRichUnpackAlgoTdcWordReader::ProcessHeader(word);
263 // ErrorMsg(errorBits, CbmRichUnpackAlgoErrorType::tdcHeader, subSubEventId);
264 if (isLog()) LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << i << "] header";
265 }
266 else if (type == CbmRichUnpackAlgoTdcWordType::Trailer) {
267 if (!wasEpoch || !wasTime || !wasHeader) {
268 LOG(debug) << getLogHeader(reader) << "DiRICH 0x" << std::hex << subSubEventId << std::dec
269 << ": illegal position of TDC Trailer (before time/epoch/header), skip subsubevent";
270 errorInData = true;
271 for (; i < nofTimeWords - 1; i++) {
272 reader.NextWord();
273 }
274 continue;
275 }
276 wasTrailer = true;
277 // uint16_t errorBits = CbmRichUnpackAlgoTdcWordReader::ProcessTrailer(word);
278 // ErrorMsg(errorBits, CbmRichUnpackAlgoErrorType::tdcTrailer, subSubEventId);
279 if (isLog()) LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << i << "] trailer";
280 }
281 else if (type == CbmRichUnpackAlgoTdcWordType::Debug) {
282 // for the moment do nothing
283 }
284 else if (type == CbmRichUnpackAlgoTdcWordType::Error) {
285 LOG(error) << getLogHeader(reader) << "Wrong TDC word!!! marker:" << ((word >> 29) & 0x7);
286 errorInData = true;
287 }
288 }
289
290 if (errorInData) {
291 //TODO:
292 }
293}
294
296{
297 processCBMtime(reader);
298 uint32_t trigNum_this = reader.NextWord() & 0xFFFFFF;
299 reader.NextWord(); // reserved
300
301 uint32_t wordEpoch; // Create variable out of 1st loop to trick the "unused variable" warning with 2nd loop use
302 uint32_t wordTime; // Create variable out of 1st loop to trick the "unused variable" warning with 2nd loop use
303 for (auto l = 0; l < 2; ++l) {
304 wordEpoch = reader.NextWord();
305 //uint32_t epoch = CbmRichUnpackAlgoTdcWordReader::ProcessEpoch(wordEpoch);
306 wordTime = reader.NextWord();
307 //CbmRichUnpackAlgoTdcTimeData td;
308 //CbmRichUnpackAlgoTdcWordReader::ProcessTimeData(wordTime, td);
309
310 //if (l == 0) fCtsCh0_cur = calculateTime(epoch, td.fCoarse, td.fFine);
311 //if (l == 1) fCtsCh1_cur = calculateTime(epoch, td.fCoarse, td.fFine);
312 }
313
314 //prev CBM time (64bit)
315 uint32_t cbmtime0 = reader.NextWord(); // CBM 63:32
316 uint32_t cbmtime1 = reader.NextWord(); // CBM 31: 0
317 uint64_t CbmTimePacket_prev = (uint64_t) cbmtime0 << 32 | cbmtime1;
318
319 uint32_t trigNum_prevMes = reader.NextWord() & 0xFFFFFF;
320
321 if (false) {
322 // Following just for tricking the unused var warning detection without breaking the existing code
323 LOG(trace) << "trigNum_this =" << trigNum_this << " trigNum_prevMes = " << trigNum_prevMes
324 << " CbmTimePacket_prev = " << CbmTimePacket_prev;
325 }
326
327 reader.NextWord(); // reserved
328
329 for (auto l = 0; l < 14; ++l) {
330 wordEpoch = reader.NextWord();
331 uint32_t epoch = CbmRichUnpackAlgoTdcWordReader::ProcessEpoch(wordEpoch);
332 wordTime = reader.NextWord();
335
336 double fullTime = calculateTime(epoch, td.fCoarse, td.fFine);
337
338 if (l == 0) {
339 fMbsPrevTimeCh0 = fullTime;
340 fPrevLastCh0ReTime[0] = fullTime;
341 }
342 if (l == 1) fMbsPrevTimeCh1 = fullTime;
343 if (l > 1) fPrevLastCh0ReTime[l - 1] = fullTime;
344 }
345
346 uint32_t trbNum = reader.NextWord(); // TRB trigger number
347 if (isLog()) LOG(debug4) << getLogHeader(reader) << "TRB Num:" << reader.GetWordAsHexString(trbNum);
348
349 processHubBlock(reader);
350}
351
353{
354 uint32_t word_MSB = reader.NextWord(); // CBM 63:32
355 uint32_t word_LSB = reader.NextWord(); // CBM 31: 0
356
357 fCbmTimePacket = 0;
358 fCbmTimePacket = (uint64_t) word_MSB << 32 | word_LSB;
360}
361
362// ---- processTimeDataWord ----
364 uint32_t tdcWord, uint32_t subSubEventId,
365 std::vector<double>& raisingTime)
366{
369 double fullTime = calculateTime(epoch, td.fCoarse, td.fFine);
370
371
372 if (td.fChannel == 0) {
373 if (td.IsRisingEdge()) {
374 if (isLog())
375 LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << iTdc << "] " << td.ToString()
376 << " CH0 Last:" << std::setprecision(15) << fullTime
377 << " PrevLast:" << fPrevLastCh0ReTime[fCurrentSubSubEvent]
378 << " diff:" << fullTime - fPrevLastCh0ReTime[fCurrentSubSubEvent];
379 }
380 }
381 else {
382 double dT = fullTime - fPrevLastCh0ReTime[fCurrentSubSubEvent];
383 double mbsCorr = fMbsPrevTimeCh1 - fMbsPrevTimeCh0;
384 double subtrigOffset = (fCbmTimePacket - fCbmTimeMS) * 25.0; // offset of SubTrigger to MS start in ns
385 double fullTimeCorr = dT - mbsCorr + subtrigOffset;
386
387 // if ((subSubEventId >> 12 ) == 0x7)
388 // std::cout<< dT <<" "
389 // << fullTimeCorr <<" "<< std::setprecision(15)
390 // << fullTime <<" "
391 // << fPrevLastCh0ReTime[fCurrentSubSubEvent] <<" "
392 // << mbsCorr <<" "
393 // << subtrigOffset <<" "
394 // << fCurrentSubSubEvent <<" " <<std::hex
395 // << subSubEventId << std::dec <<std::endl;
396
397 if (isLog())
398 LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << iTdc << "] " << td.ToString()
399 << " time:" << std::setprecision(15) << fullTime << " fullTimeCorr:" << fullTimeCorr;
400
401 if (td.fChannel < 1 || td.fChannel >= raisingTime.size()) {
402 LOG(error) << "ERROR: channel number is out of limit. Channel:" << td.fChannel;
403 }
404
405 if (td.IsRisingEdge()) {
406 // always store the latest raising edge. It means that in case RRFF situation only middle RF will be matched.
407 raisingTime[td.fChannel] = fullTimeCorr;
408 }
409 else {
410 if (raisingTime[td.fChannel] == -1.) {
411 //No raising channel was found before. Skip this falling edge time.
412 if (isLog())
413 LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << iTdc << "] "
414 << "No raising channel was found before. Skip this falling edge time.";
415 }
416 else {
417 // Matching was found, calculate ToT, if tot is in a good range -> create digi
418 double ToT = fullTimeCorr - raisingTime[td.fChannel];
419 if (isLog())
420 LOG(debug4) << getLogHeader(reader) << "SubSubEv[" << iTdc << "] "
421 << "ToT:" << ToT;
422 if (ToT >= fToTMin && ToT <= fToTMax) {
423 // if (fbMonitorMode) {
424 // TH1D* h = GetTotH1(subSubEventId, td.fChannel);
425 // if (h != nullptr) h->Fill(ToT);
426
427 // TH2D* h2 = GetTotH2(subSubEventId);
428 // if (h2 != nullptr) h2->Fill(td.fChannel, ToT);
429 // }
430 if (fullTimeCorr >= 0.0) {
431 writeOutputDigi(subSubEventId, td.fChannel, raisingTime[td.fChannel], ToT);
432 }
433 }
434 // pair was created, set raising edge to -1.
435 raisingTime[td.fChannel] = -1.;
436 }
437 }
438 }
439}
440
441void CbmRichUnpackAlgo2022::writeOutputDigi(Int_t fpgaID, Int_t channel, Double_t time, Double_t tot)
442{
443 Double_t ToTcorr = fbDoToTCorr ? fUnpackPar.GetToTshift(fpgaID, channel) : 0.;
444 Int_t pixelUID = this->getPixelUID(fpgaID, channel);
445 //check ordering
446 Double_t finalTime = time + (Double_t) fMsRefTime - fSystemTimeOffset;
447
448 // Do not accept digis, where the MS und TS differs by more than 6 sec (mainly TS0)
449 if (6e9 < finalTime) return;
450
451 fOutputVec.emplace_back(pixelUID, finalTime, tot - ToTcorr);
452}
453
ClassImp(CbmConverterManager)
CbmRichUnpackAlgoTdcWordType
int Int_t
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)
std::unordered_set< uint16_t > fUnexpectedIds
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)