CbmRoot
Loading...
Searching...
No Matches
trd/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, Dominik Smith [committer], David Schledt */
4
6
8
9#include <algorithm>
10#include <cassert>
11#include <vector>
12
13using std::unique_ptr;
14
15namespace cbm::algo::trd
16{
17
18 // ---- digestBufInfoFlags ----
19 template<uint8_t sys_ver>
21 {
22 auto flag = (frame >> 15) & 0x3;
23 Spadic::MsInfoType infotype;
24 if (flag == 1) infotype = Spadic::MsInfoType::kChannelBuf;
25 if (flag == 2) infotype = Spadic::MsInfoType::kOrdFifoBuf;
26 if (flag == 3) infotype = Spadic::MsInfoType::kChannelBufM;
27 return infotype;
28 }
29
30 template Spadic::MsInfoType UnpackMS<0x01>::digestBufInfoFlags(const uint32_t frame) const;
31
32 // ---- digestInfoMsg ----
33 template<uint8_t sys_ver>
34 void UnpackMS<sys_ver>::digestInfoMsg(const uint32_t frame) const
35 {
37 //if (fOptOutBVec) { fOptOutBVec->emplace_back(std::make_pair(ctx.fLastFulltime, frame)); }
38 [[maybe_unused]] Spadic::MsInfoType infotype = getInfoType(frame);
39 // "Spadic_Info_Types";
40 }
41
42 template void UnpackMS<0x01>::digestInfoMsg(const uint32_t frame) const;
43
44 // ---- digestInfoMsg ----
45 template<uint8_t sys_ver>
46 void UnpackMS<sys_ver>::digestMsFlags(const uint16_t flags, UnpackMonitorData& monitor) const
47 {
48 if (flags & static_cast<uint16_t>(fles::MicrosliceFlags::CrcValid)) {
49 monitor.fNumCrcValidFlags++;
50 }
51 if (flags & static_cast<uint16_t>(fles::MicrosliceFlags::OverflowFlim)) {
52 monitor.fNumOverflowFlimFlags++;
53 }
54 if (flags & static_cast<uint16_t>(fles::MicrosliceFlags::OverflowUser)) {
55 monitor.fNumOverflowUserFlags++;
56 }
57 if (flags & static_cast<uint16_t>(fles::MicrosliceFlags::DataError)) {
58 monitor.fNumDataErrorFlags++;
59 }
60 }
61
62 template void UnpackMS<0x01>::digestMsFlags(const uint16_t flags, UnpackMonitorData& monitor) const;
63 template void UnpackMS<0x10>::digestMsFlags(const uint16_t flags, UnpackMonitorData& monitor) const;
64
65 // ---- extractSample ----
66 template<uint8_t sys_ver>
67 std::float_t UnpackMS<sys_ver>::extractAvgSample(size_t* adcbuffer, size_t* nadcbits) const
68 {
69 // can not extract samples from a buffer with less than 9 bits
70 assert(*nadcbits >= 9);
71 *nadcbits -= 9;
72
73 // The decoding of the average sample is kind of interesting:
74 // We get 9 bits in total iiiiiiiff. The 7 "i" bits refer to std integer bits, hence,
75 // covering a range of 0..128.
76 // The 2 "f" bits refer to values after a fix point refering to [0,0.25,0.5,0.75].
77 // The sign we have to assume to be negative (bit-9 = 1) and also bit 8 of our std
78 // interger range we have to assume to be 0, such that the returned number is in
79 // between -256..-128.
80
81 // Activate the 7 "i" bits
82 int16_t sample = 0x07f;
83
84 // Write the content of the 7 "i" bits to temp
85 sample &= (*adcbuffer >> (*nadcbits + 2));
86
87 // Switch on the negative sign
88 sample |= 0xff00;
89
90 return sample;
91 }
92
93 template std::float_t UnpackMS<0x01>::extractAvgSample(size_t* adcbuffer, size_t* nadcbits) const;
94
95 // ---- extractSample ----
96 template<uint8_t sys_ver>
97 int16_t UnpackMS<sys_ver>::extractSample(size_t* adcbuffer, size_t* nadcbits) const
98 {
99 // can not extract samples from a buffer with less than 9 bits
100 assert(*nadcbits >= 9);
101
102 // We want to access the bits stored at the positions between nadcbits and nadcbits - 9, so we can already here
103 // reduce nadcbits by 9 and than shift the adcbuffer by this value to the right and compare it with temp which has the 9 lsbs set to 1
104 *nadcbits -= 9;
105
106 int16_t temp = 0x1ff;
107 temp &= (*adcbuffer >> (*nadcbits));
108
109 // Now we have our 9 bits stored in temp, but for a int16_t this does not match in terms of the sign handling.
110 // So we check on bit 9 for the sign (temp & 0x0100) and if we have a negative value we manipulate bit 16-10 to 1
111 // to get the correct negative number
112 int16_t sample = (temp & 0x0100) ? (temp | 0xff00) : temp;
113
114 return sample;
115 }
116
117 template int16_t UnpackMS<0x01>::extractSample(size_t* adcbuffer, size_t* nadcbits) const;
118
119 // ---- getInfoType ----
120 template<uint8_t sys_ver>
122 {
123 // Set first 20 bits to 1 for the mask
124 size_t mask = 0x000FFFFF;
125
126 // 000011.................. : BOM word
127 // 0000010................. : MSB word
128 // 0000011................. : BUF word
129 // 0000100................. : UNU word
130 // 0000101................. : MIS word
131
132 if (((frame & mask) >> 18) == 3) // BOM
133 {
135 }
136 if (((frame & mask) >> 17) == 2) // MSB
137 {
139 }
140 if (((frame & mask) >> 17) == 3) // BUF
141 {
142 digestBufInfoFlags(frame);
144 }
145 if (((frame & mask) >> 17) == 4) // UNU
146 {
148 }
149 if (((frame & mask) >> 17) == 5) // MIS
150 {
152 }
153 else {
154 // TODO: Track this error!
155 L_(error) << "UnpackMS::GetInfoType] unknown type!";
157 }
158 }
159
160 template Spadic::MsInfoType UnpackMS<0x01>::getInfoType(const uint32_t frame) const;
161
162 // ---- getMessageType ----
163 template<uint8_t sys_ver>
165 {
166 uint32_t checkframe = frame;
167 checkframe &= 0xffffff;
168 if ((checkframe >> 21) == 1) // SOM 001. ....
169 {
171 }
172 else if ((checkframe >> 22) == 1) // RDA 01.. ....
173 {
175 }
176 else if ((checkframe >> 20) == 1) // EOM 0001 ....
177 {
179 }
180 else if ((checkframe >> 22) == 3) // TS_MSB 11.. ....
181 {
183 }
184 else if (0 < (checkframe >> 18) && (checkframe >> 18) <= 3) {
186 }
187 else if (checkframe == 0) // Last Word in a Microslice is 0
188 {
190 }
191 else // not a spadic message
192 {
194 }
195 }
196
197 template Spadic::MsMessageType UnpackMS<0x01>::getMessageType(const uint32_t frame) const;
198
199 // ---- getTsMsb ----
200 template<uint8_t sys_ver>
201 uint8_t UnpackMS<sys_ver>::getTsMsb(const uint32_t frame, UnpackMonitorData& monitor) const
202 {
203 if ((frame & 0xf) > 0)
204 return -2; // if a 'error' ts_msb is received the tsmsb value is not correct. To not mess up the counting -2 is returned.
205 // The epoch in form of the TS_MSBs is written 3 times into the frame to allow to check for bit flips and catch errors.
206 // It has the length of 6 bits and an offset of 4
207 uint8_t tsmsb[3];
208 for (uint iepoch = 0; iepoch < 3; ++iepoch) {
209 tsmsb[iepoch] = static_cast<uint8_t>((frame >> (4 + 6 * iepoch) & 0x3f));
210 }
211
212 // Check if the epoch at position 0 is at least compatible with one of the others.
213 // Since, we only have 3 that value is automatically the majority value.
214 if (tsmsb[0] == tsmsb[1] || tsmsb[0] == tsmsb[2]) return tsmsb[0];
215
216 // If we arrive here the epoch at position 0 is not compatible with the other two.
217 // So let's check if they are compatible with each other. If so we have again a majority epoch
218 if (tsmsb[1] == tsmsb[2]) return tsmsb[1];
219
220 monitor.fNumNonMajorTsMsb++;
221
222 return tsmsb[0];
223 }
224
225 template uint8_t UnpackMS<0x01>::getTsMsb(const uint32_t frame, UnpackMonitorData& monitor) const;
226
227
228 // method definition for specialization
229 template<uint8_t sys_ver>
231 UnpackMonitorData& monitor) const
232 {
233 return CbmTrdDigi();
234 }
235
236 // ---- makeDigi sys_ver <0x10> ----
237 template<>
239 UnpackMonitorData& monitor) const
240 {
241 auto rawTriggerType = static_cast<Spadic::eTriggerType>(fw.ht);
242 auto triggerType = GetDigiTriggerType(rawTriggerType);
243
244 int32_t errClass = 0;
245
246 // Get the address of the originating spadic
247 const UnpackCrobPar& crobPar = fParams.fCrobParams.at(0);
248 const UnpackElinkPar& elinkPar = crobPar.fElinkParams.at(fw.elink);
249 const uint32_t asicAddress = elinkPar.fAddress;
250
251 // Get the channel id on the module
252 int32_t padChNr = elinkPar.fChanAddress.at(fw.channel);
253
254 // Get the time information and apply the necessary correction
255 uint64_t time = (fw.timestamp - fw.prec_time) * fAsicClockCycle + fMsStartTimeRel;
256 if (time < static_cast<uint64_t>(std::abs(elinkPar.fTimeOffset))) {
258 time = 0;
259 }
260 else {
261 time -= elinkPar.fTimeOffset;
262 }
263
264 auto energy = fw.maxAdc * fParams.fMaxAdcToEnergyCal;
265
266 // Get the unique module id from the asic address
267 int32_t uniqueModuleId = asicAddress / 1000;
268
269 CbmTrdDigi digi = CbmTrdDigi(padChNr, uniqueModuleId, energy, time, triggerType, errClass);
270
271 // If the message was flagged as multi hit, forward this info to the digi
273
274 return digi;
275 }
276
277 // ---- makeDigi from raw ----
278 template<uint8_t sys_ver>
280 {
281 // Extract the trigger type and translate it to the digi enum
282 auto rawTriggerType = static_cast<Spadic::eTriggerType>(raw.GetHitType());
283 auto triggerType = GetDigiTriggerType(rawTriggerType);
284
285 // Get the digi error class (dummy for the time being)
286 int32_t errClass = 0;
287
288 // Get the address of the originating spadic
289 const UnpackCrobPar& crobPar = fParams.fCrobParams.at(raw.GetCrobId());
290 const UnpackElinkPar& elinkPar = crobPar.fElinkParams.at(raw.GetElinkId());
291 const uint32_t asicAddress = elinkPar.fAddress;
292
293 // Get the channel id on the module
294 int32_t padChNr = elinkPar.fChanAddress.at(raw.GetChannelId());
295
296 // Store the full time information to last full-time member for error message handling
297 ctx.fLastFulltime = raw.GetFullTime();
298
299 // Get the time information and apply the necessary correction
300 uint64_t time = raw.GetTime();
301 if (time < static_cast<uint64_t>(std::abs(elinkPar.fTimeOffset))) {
303 time = 0;
304 }
305 else {
306 time -= elinkPar.fTimeOffset;
307 }
308
309 // Get the timeshift and set the member, which is required for some of the rtd methods
310 uint64_t currentTimeshift = GetBinTimeShift(raw.GetSamples());
311
312 // In simulation since we often start at time = 0 there is a non negligible chance that a time < 0 is extracted.
313 //Since, this is not allowed in the code we set it to 0 for these cases
314 if (time < currentTimeshift) {
316 time = 0;
317 }
318 else {
319 time = time - currentTimeshift;
320 }
321
322 // In this case of CbmTrdRawToDigi GetCharge calls GetBinTimeshift, since the information is needed.
323 // The shift is stored in fCurrentTimeshift
324 // Hence, the order of charge and time assignement here makes a difference!
325 auto maxadc = GetMaxAdcValue(raw.GetSamples());
326
327 // Get energy from maxadc value
328 auto energy = maxadc * fParams.fMaxAdcToEnergyCal;
329
330 // Get the unique module id from the asic address
331 int32_t uniqueModuleId = asicAddress / 1000;
332
333 CbmTrdDigi digi = CbmTrdDigi(padChNr, uniqueModuleId, energy, time, triggerType, errClass);
334
335 // If the raw message was flagged as multi hit, forward this info to the digi
337
338 return digi;
339 }
340
342 UnpackMonitorData& monitor) const;
343
344 // ---- makeRaw ----
345 template<uint8_t sys_ver>
346 CbmTrdRawMessageSpadic UnpackMS<sys_ver>::makeRaw(const uint32_t frame, uint16_t criId, uint8_t crobId,
347 uint16_t elinkId, uint8_t istream, MsContext& ctx) const
348 {
349 auto chId = static_cast<uint8_t>(((frame >> 17) & 0xf));
350 auto timestamp = static_cast<uint8_t>((frame >> 9) & 0xff);
351 bool multihit = ((frame >> 8) & 0x1);
352 auto hitType = static_cast<uint8_t>((frame >> 6) & 0x3);
353 uint8_t nsamples = 0;
354 // We directly start with the largest possible samples vector to only init it once
355 std::vector<int16_t> samples = std::vector<int16_t>(0);
356
357 uint64_t fulltime = ctx.fMsStartTimeRelCC + (ctx.fNrTsMsbVec.at(istream) * fTsMsbLengthCC) + timestamp;
358
359 // Create message
360 return CbmTrdRawMessageSpadic(chId, elinkId, crobId, criId, hitType, nsamples, multihit, fulltime, samples);
361 }
362
363 template CbmTrdRawMessageSpadic UnpackMS<0x01>::makeRaw(const uint32_t frame, uint16_t criId, uint8_t crobId,
364 uint16_t elinkId, uint8_t istream, MsContext& ctx) const;
365
366
367 // ---- GetDigiTriggerType ----
368 template<uint8_t sys_ver>
370 {
371 // Shift self trigger to digi selftrigger
372 // Shift neighbour trigger to digi neighbour
373 // Hide spadic kSandN in Self
374 switch (tt) {
379 default: return CbmTrdDigi::eTriggerType::kNTrg;
380 }
381 }
382
385
386 // --- GetCharge ----
387 template<uint8_t sys_ver>
388 float_t UnpackMS<sys_ver>::GetMaxAdcValue(const std::vector<int16_t>* samples) const
389 {
390 // Safety for corrupted input samples
391 assert(samples->size() >= fPeakingBinMin);
392
393 // The signal should peak at the shaping time.
394 // The corresponding sample is the peaking time divided by the sample length.
395 auto itbegin = std::next(samples->begin(), fPeakingBinMin);
396
397 // Check if the expected maximum position of the peaking bin exceeds the size of the vector
398 auto nsamples = samples->size();
399 auto peakingBinMax = (nsamples - 1) > fPeakingBinMax ? fPeakingBinMax : nsamples;
400 auto itend = std::next(samples->begin(), peakingBinMax);
401
402 // Get the maximum element
403 auto itmax = std::max_element(itbegin, itend);
404
405 // Get charge and correct for the baseline
406 float_t charge = static_cast<float_t>(*itmax) - GetBaseline(samples);
407
408 // Remark: Due to the fact, that we store the charge UInt_t in the Digi values below 0 are not allowed.
409 // In this case the above only appears if the baseline fluctuated above all values in the applied peaking range.
410 // This can only happen for forced neighbor triggers with a deposited charged that can not be separated from the baseline.
411 return charge > 0 ? charge : 0;
412 }
413
414 template float_t UnpackMS<0x01>::GetMaxAdcValue(const std::vector<int16_t>* samples) const;
415
416 // ---- GetBaseline ----
417 template<uint8_t sys_ver>
418 float_t UnpackMS<sys_ver>::GetBaseline(const std::vector<int16_t>* samples) const
419 {
420 // The spadic 2.2 has a functionality that an average baseline can be written to the first sample.
421 // So first we have to check if this is active.
422 if (fParams.fUseBaselineAvg)
423 return samples->at(0);
424 else {
425 float_t baseline = 0.0;
426 auto itend = samples->begin() + fNrOfPresamples;
427 if (itend > samples->end()) itend = samples->end();
428 for (auto isample = samples->begin(); isample < itend; isample++) {
429 baseline += *isample;
430 }
431 baseline /= fNrOfPresamples;
432
433 return baseline;
434 }
435 }
436 template float_t UnpackMS<0x01>::GetBaseline(const std::vector<int16_t>* samples) const;
437
438 // ---- Algorithm execution sys_ver >= 0x10 ---------------------------------------------
439 template<uint8_t sys_ver>
441 const fles::MicrosliceDescriptor& msDescr,
442 const uint64_t tTimeslice) const
443 {
444 Result_t result = {};
445
446
447 // Digest the flags from the micro-Slice
448 digestMsFlags(msDescr.flags, std::get<1>(result));
449
450 size_t fMsStartTimeRel = (msDescr.idx - tTimeslice);
451
452 // Get bytes per word used for the given system version
453 constexpr uint8_t bytes = Spadic::BytesPerWord<sys_ver>();
454
455 auto mssize = msDescr.size;
456 uint32_t nwords = mssize / bytes;
457
458 const Spadic::NByteContainer<bytes>* bp = reinterpret_cast<const Spadic::NByteContainer<bytes>*>(msContent);
459
460 for (uint32_t iword = 0; iword < nwords; ++iword) {
461 Spadic::NByteContainer<bytes> bCont = bp[iword];
462 Spadic::FexWord<sys_ver> fw(bCont);
463 if (fw.ht != 0) {
464 std::get<0>(result).push_back(makeDigi(fw, fMsStartTimeRel, std::get<1>(result)));
465 }
466 }
467 return result;
468 }
469
470 template typename UnpackMS<0x10>::Result_t UnpackMS<0x10>::operator()(const uint8_t* msContent,
471 const fles::MicrosliceDescriptor& msDescr,
472 const uint64_t tTimeslice) const;
473 // --------------------------------------------------------------------------
474
475 // ---- Algorithm execution sys_ver - 0x01 ---------------------------------------------
476 template<>
477 typename UnpackMS<0x01>::Result_t UnpackMS<0x01>::operator()(const uint8_t* msContent,
478 const fles::MicrosliceDescriptor& msDescr,
479 const uint64_t tTimeslice) const
480 {
481 // --- Output data
482 Result_t result = {};
483
484 MsContext ctx = {};
485
486 // Get the micro-Slice starttime relative to the timeslice starttime (constant is clock length of Spadic in ns)
487 ctx.fMsStartTimeRelCC = (msDescr.idx - tTimeslice) / fAsicClockCycle;
488
489 // We only want to count on TS_MSB per Stream per TS_MSB package (each eLink sends its own TS_MSB frame)
490 // so we store the current TS_MSB and compare it to the incoming.
491 int8_t currTsMsb = 0;
492
493 // Reset the TS_MSB counter for the new micro-Slice we unpack
494 ctx.fNrTsMsbVec.resize(fStreamsPerWord);
495
496
497 // Get the micro-slice size in bytes to calculate the number of completed words
498 auto mssize = msDescr.size;
499
500 // Get the hardware ids from which the current micro-Slice is coming
501 uint8_t crobId = 0;
502 auto criId = msDescr.eq_id;
503
504 // Digest the flags from the micro-Slice
505 digestMsFlags(msDescr.flags, std::get<1>(result));
506
507 // Get the number of complete words in the input MS buffer.
508 uint32_t nwords = mssize / fBytesPerWord;
509
510 // We have 32 bit spadic frames in this readout version
511 const auto mscontent = reinterpret_cast<const size_t*>(msContent);
512
513 std::get<0>(result).reserve(nwords);
514
515 // Loop over all 64bit-Spadic-Words in the current micro-slice
516 for (uint32_t istream = 0; istream < fStreamsPerWord; istream++) {
517 currTsMsb = -1;
518 for (uint32_t iword = 0; iword < nwords; ++iword) {
519 // Access the actual word from the pointer
520 size_t word = static_cast<size_t>(mscontent[iword]);
521
522 // Access the actual frame[iframe] from the word. (see fStreamsPerWord)
523 uint32_t frame = (word >> (32 * istream)) & 0xffffffff;
524
525 // Get the type of the frame
526 auto kWordtype = getMessageType(frame);
527
528 // In case we saw any other word than an EPO(TS_MSB) reset the flag,
529 // such that we again increase by one if an EPO frame arrives
530 auto elinkId = (frame >> 24) & 0x3f;
531
532 switch (kWordtype) {
534 auto tsmsb = getTsMsb(frame, std::get<1>(result));
535 if (((tsmsb - currTsMsb) & 0x3f) == 1 || currTsMsb == -1) ctx.fNrTsMsbVec.at(istream)++;
536 currTsMsb = tsmsb;
537 std::get<1>(result).fNumEpochMsgs++;
538 break;
539 // FIXME in the kEPO msg we also have further flags that should be extracted
540 }
542 // Create the raw message and fill it with all information we can get from the SOM msg
543 CbmTrdRawMessageSpadic raw = makeRaw(frame, criId, crobId, elinkId, istream, ctx);
544
545 // FIXME since we can not deduce the sample position from the messages we need in
546 // future some parameter handling here to place the samples at the correct position
547 // 6 adc bits are stored in the som message
548 size_t nadcbits = 6;
549 size_t nadcbitstotal = 6;
550 // Get the first bits from the adc signal
551 size_t adcbuffer = frame & 0x3f;
552 size_t isample = 0;
553 size_t irda = 0;
554
555 // Now lets check if we have rda words following our som
556 iword++;
557 word = static_cast<size_t>(mscontent[iword]);
558 frame = (word >> (32 * istream)) & 0xffffffff;
559
560 // The maximum amount of samples (32) equals to 12 RDA messages
561 while (getMessageType(frame) == Spadic::MsMessageType::kRDA && irda < 12) {
562 // We have to count the number of rda frames for sample reconstruction in eom
563 irda++;
564
565 // Ensure that we are on the correct eLink
566 elinkId = (frame >> 24) & 0x3f;
567 if (elinkId != raw.GetElinkId()) {
568 std::get<1>(result).fNumElinkMis++;
569 }
570
571 // We have 22 adc bits per RDA word lets add them to the buffer...
572 adcbuffer <<= 22;
573 adcbuffer |= static_cast<size_t>((frame & 0x3fffff));
574 // and increase the adcbit counter by 22 bits
575 nadcbits += 22;
576 nadcbitstotal += 22;
577 // If we have 9 or more samples stored we can extract n samples
578 while (nadcbits >= 9) {
579 raw.IncNrSamples();
580 // In case the avg baseline feature was used we need to take special care of sample 0
581 if (isample == 0 && fParams.fUseBaselineAvg)
582 raw.SetSample(extractAvgSample(&adcbuffer, &nadcbits), isample);
583 else
584 raw.SetSample(extractSample(&adcbuffer, &nadcbits), isample);
585 isample++;
586 }
587 iword++;
588 word = static_cast<size_t>(mscontent[iword]);
589 frame = (word >> (32 * istream)) & 0xffffffff;
590 }
591
593 // Ensure that we are on the correct eLink
594 elinkId = (frame >> 24) & 0x3f;
595 if (elinkId != raw.GetElinkId()) {
596 std::get<1>(result).fNumElinkMis++;
597 }
598
599 // Number of samples indicator = nsamples % 4
600 uint8_t nsamplesindicator = (frame >> 18) & 0x3;
601 // Number of required samples as indicated
602 uint64_t nreqsamples = (nadcbitstotal + 18) / 9;
603 uint8_t nn = nreqsamples % 4;
604 for (uint8_t itest = 0; itest < 3; itest++) {
605 if (nn == nsamplesindicator || nreqsamples == 0) break;
606 nreqsamples--;
607 nn = nreqsamples % 4;
608 }
609
610 // There is a chance that the nsamplesindicator bits are corrupted,
611 // here we check that we do not try to extract more adcbits than actually are streamed
612 if (nreqsamples >= isample) {
613 // Now extract from the above values the number of required adc bits from the eom
614 int8_t nrequiredbits = (nreqsamples - isample) * 9 - nadcbits;
615 adcbuffer <<= nrequiredbits;
616
617 // The eom carries at maximum 18 adcbits
618 adcbuffer |= static_cast<size_t>((frame & 0x3ffff) >> (18 - nrequiredbits));
619 nadcbits += nrequiredbits;
620
621 while (nadcbits >= 9) {
622 raw.IncNrSamples();
623 raw.SetSample(extractSample(&adcbuffer, &nadcbits), isample);
624 isample++;
625 }
626 }
627 else {
628 std::get<1>(result).fNumCorruptEom++;
629 }
630 std::get<1>(result).fNumCreatedRawMsgs++;
631
632 // the message is done and the raw message container should contain everything we need.
633 // So now we can call makeDigi(). Nevertheless there is a chance for a corrupted message,
634 // which ends up with 0 samples so we have to check for it.
635 if (isample > 0) std::get<0>(result).push_back(makeDigi(raw, ctx, std::get<1>(result)));
636 }
637 else {
638 // We move the word counter backwards by one, such that the unexpected message can correctly be digested
639 iword--;
640 std::get<1>(result).fNumMissingEom++;
641 }
642 break;
643 }
645 std::get<1>(result).fNumWildRda++;
646 break;
647 }
649 std::get<1>(result).fNumWildEom++;
650 break;
651 }
653 std::get<1>(result).fNumCreatedInfoMsgs++;
654 digestInfoMsg(frame);
655 break;
656 }
658 // last word in Microslice is 0.
659 if (iword != (nwords - 1) || (istream != (fStreamsPerWord - 1))) {
660 std::get<1>(result).fNumWildNul++;
661 }
662 break;
663 }
665 std::get<1>(result).fNumUnknownWords++;
666 return result;
667 break;
668 }
669 default:
670 // We have varying msg types for different versions of the message format.
671 // Hence, to not produce compiler warnings we have a "default break;" here.
672 break;
673 }
674 }
675 }
676 return result;
677 }
678 // --------------------------------------------------------------------------
679
680} // namespace cbm::algo::trd
#define L_(level)
void SetTriggerType(const eTriggerType triggerType)
Set digi trigger type.
Base class for storing raw information which comes from the Spadic v2.2 trough flib or from a tsa fil...
void SetSample(int16_t value, uint8_t pos)
void IncNrSamples()
increase the number of samples stored in this raw message by one
const std::vector< int16_t > * GetSamples() const
std::tuple< std::vector< Digi_t >, Monitor_t, Aux_t > Result_t
CbmTrdRawMessageSpadic makeRaw(const uint32_t frame, uint16_t criId, uint8_t crobId, uint16_t elinkId, uint8_t istream, MsContext &ctx) const
Create a CbmTrdRawMessageSpadic from the hit message input.
CbmTrdDigi makeDigi(CbmTrdRawMessageSpadic raw, MsContext &ctx, UnpackMonitorData &monitor) const
Create an actual digi from the raw message.
Spadic::MsInfoType getInfoType(const uint32_t frame) const
Identify the InfoType of a 64bit InfoMessage word inside a Microslice.
static constexpr uint8_t fStreamsPerWord
Number of streams per word.
static constexpr size_t fTsMsbLengthCC
length of one ts_msb in [cc]
float_t GetBaseline(const std::vector< int16_t > *samples) const
Get the Baseline value The digi charge is an unsigned. Hence, we need to get the baseline to 0.
Spadic::MsInfoType digestBufInfoFlags(const uint32_t frame) const
Digest the aditional flags stored in the 4 "cccc" bits of the EPO messages.
static CbmTrdDigi::eTriggerType GetDigiTriggerType(Spadic::eTriggerType tt)
Get the Digi Trigger Type from the raw message triggertype.
std::float_t GetMaxAdcValue(const std::vector< int16_t > *samples) const
Get the MaxAdc value.
static constexpr size_t fPeakingBinMax
Last sample to look for the max adc Default value is set based on the Shaping time + 5 samples safety...
void digestMsFlags(const uint16_t flags, UnpackMonitorData &monitor) const
Digest the flags of the currently unpacked micro-Slice.
uint64_t GetBinTimeShift(const std::vector< int16_t > *) const
Get the Bin Time Shift value.
static constexpr size_t fPeakingBinMin
First sample to look for the max adc.
uint8_t getTsMsb(const uint32_t frame, UnpackMonitorData &monitor) const
Get the ts_msb information from the TS_MSB(kEPO) frame. We take the first of the 3 The 3 redundant TS...
Spadic::MsMessageType getMessageType(const uint32_t frame) const
Identify the message type of a given 32bit frame inside a Microslice.
static constexpr size_t fNrOfPresamples
Number of samples not considered for max adc.
static constexpr float_t fAsicClockCycle
Clock length of Spadic in ns.
std::float_t extractAvgSample(size_t *adcbuffer, size_t *nadcbits) const
Extract the baseline average sample from a given adcbuffer. Depending on the Spadic settings sample-0...
static constexpr uint8_t fBytesPerWord
Bytes per spadic frame stored in the microslices.
Result_t operator()(const uint8_t *msContent, const fles::MicrosliceDescriptor &msDescr, const uint64_t tTimeslice) const override
Algorithm execution.
UnpackPar fParams
Parameter container.
void digestInfoMsg(const uint32_t frame) const
Digest a info message run all default information forwarding from the msg.
int16_t extractSample(size_t *adcbuffer, size_t *nadcbits) const
Extract one adc sample from a given adcbuffer.
@ kUNU
Unused request. 100. .... .... .... cccc.
@ kChannelBufM
Channel buffer full and multihit from kEPO msg.
@ kChannelBuf
Channel buffer full from kEPO msg.
@ kBOM
Buffer overflow count. 11nn nnnn nnnn nnnn cccc.
@ kMIS
Missing request. 101. .... .... .... ....
@ kOrdFifoBuf
Multi-hit but ordering buffer full from kEPO msg.
@ kBUF
Buffer full. 011b b... .... .... cccc.
@ kMSB
Message build error. 010. .... .... .... cccc.
@ kSandN
Self and neighbor trigger at the same time.
@ kEPO
Epoch Marker or TS_MSB depending on the hitmessage version.
constexpr uint8_t BytesPerWord()
TRD Unpacking parameters for one CROB.
std::vector< UnpackElinkPar > fElinkParams
Parameters for each eLink.
TRD Unpacking parameters for one eLink.
std::vector< uint32_t > fChanAddress
CbmTrdAddress for different channels.
uint32_t fAddress
Asic address.
int64_t fTimeOffset
Time calibration parameter.
size_t fLastFulltime
Time of the last succesful digest hit message.
std::vector< uint8_t > fNrTsMsbVec
Counter for the ts_msb used to reconstruct the time.
size_t fMsStartTimeRelCC
Start time of the current micro-Slice relative to the Timeslice start time in Spadic CC.
Monitoring data for TRD unpacking.
size_t fNumOverflowFlimFlags
counter for inf/error flags from the micro-Slices
size_t fNumCrcValidFlags
counter for inf/error flags from the micro-Slices
size_t fNumNonMajorTsMsb
Counter for the ts_msb used to reconstruct the time.
size_t fNumOverflowUserFlags
counter for inf/error flags from the micro-Slices
size_t fNumDataErrorFlags
counter for inf/error flags from the micro-Slices
size_t fNumErrTimestampUnderflow
Underflow in 64 bit time stamp if offsetting.