Project
Loading...
Searching...
No Matches
DataDecoder.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
18
20
23#include "Framework/Logger.h"
29#include <fairlogger/Logger.h>
30#include <fstream>
31
32#define MCH_DECODER_MAX_ERROR_COUNT 100
33
34namespace o2
35{
36namespace mch
37{
38namespace raw
39{
40
41using namespace o2;
42using namespace o2::mch::mapping;
44
45static constexpr uint32_t bcRollOver = (1 << 20);
46static constexpr uint32_t twentyBitsAtOne = 0xFFFFF;
47static constexpr uint32_t bcInOrbit = o2::constants::lhc::LHCMaxBunches;
48
49// conversion matrix between the original channels numbering of the RUN2 readout electronics and the final version of the RUN3 DualSAMPA-based readout
50static std::array<int, 64> refManu2ds_st345_v5 = {
51 63, 62, 61, 60, 59, 57, 56, 53, 51, 50, 47, 45, 44, 41, 38, 35,
52 36, 33, 34, 37, 32, 39, 40, 42, 43, 46, 48, 49, 52, 54, 55, 58,
53 7, 8, 5, 2, 6, 1, 3, 0, 4, 9, 10, 15, 17, 18, 22, 25,
54 31, 30, 29, 28, 27, 26, 24, 23, 20, 21, 16, 19, 12, 14, 11, 13};
55
56// conversion matrix between the original channels numbering of the RUN2 readout electronics and the intermediate version of the RUN3 DualSAMPA-based readout
57static std::array<int, 64> refManu2ds_st345_v2 = {
58 62, 61, 63, 60, 59, 55, 58, 57, 56, 54, 50, 46, 42, 39, 37, 41,
59 35, 36, 33, 34, 32, 38, 43, 40, 45, 44, 47, 48, 49, 52, 51, 53,
60 7, 6, 5, 4, 2, 3, 1, 0, 9, 11, 13, 15, 17, 19, 21, 23,
61 31, 30, 29, 28, 27, 26, 25, 24, 22, 20, 18, 16, 14, 12, 10, 8};
62
63#define refManu2ds_st345 refManu2ds_st345_v5
64
65// inverse channel conversion matrix
66static std::array<int, 64> refDs2manu_st345;
67
68// function returning the RUN3 DualSAMPA channel number given the original RUN2 channel
69static int manu2ds(int i)
70{
71 return refManu2ds_st345[i];
72}
73
74// function returning the original RUN2 channel number given the RUN3 DualSAMPA channel
75static int ds2manu(int i)
76{
77 return refDs2manu_st345[i];
78}
79
80//_________________________________________________________________________________________________
81
82static void patchPage(gsl::span<const std::byte> rdhBuffer, bool verbose)
83{
84 auto& rdhAny = *reinterpret_cast<RDH*>(const_cast<std::byte*>(&(rdhBuffer[0])));
85
86 auto existingFeeId = o2::raw::RDHUtils::getFEEID(rdhAny);
87 if (existingFeeId == 0) {
88 // early versions of raw data did not set the feeId
89 // which we need to select the right decoder
90
91 auto cruId = o2::raw::RDHUtils::getCRUID(rdhAny) & 0xFF;
92 auto endpoint = o2::raw::RDHUtils::getEndPointID(rdhAny);
93 auto flags = o2::raw::RDHUtils::getCRUID(rdhAny) & 0xFF00;
94
95 uint32_t feeId = cruId * 2 + endpoint + flags;
96 o2::raw::RDHUtils::setFEEID(rdhAny, feeId);
97 }
98};
99
100//_________________________________________________________________________________________________
101
103{
104 if (d1.getTime() == d2.getTime()) {
105 if (d1.getDetID() == d2.getDetID()) {
106 return d1.getPadID() < d2.getPadID();
107 }
108 return d1.getDetID() < d2.getDetID();
109 }
110 return (d1.getTime() < d2.getTime());
111}
112
113std::string asString(const DataDecoder::RawDigit& d)
114{
115 return fmt::format("DE {:4d} PADID {:5d} ADC {:5d} TIME {} BX {}",
116 d.getDetID(), d.getPadID(), d.getADC(), d.getTime(), d.getBunchCrossing());
117}
118
119std::ostream& operator<<(std::ostream& os, const DataDecoder::RawDigit& d)
120{
121 os << asString(d);
122 return os;
123}
124
125//_________________________________________________________________________________________________
126
127static bool isValidDeID(int deId)
128{
129 for (auto id : o2::mch::constants::deIdsForAllMCH) {
130 if (id == deId) {
131 return true;
132 }
133 }
134
135 return false;
136}
137
138//=======================
139// Data decoder
140
142{
143 return chip == other.chip &&
144 ds == other.ds &&
145 solar == other.solar &&
146 sampaTime == other.sampaTime &&
147 bunchCrossing == other.bunchCrossing &&
148 orbit == other.orbit &&
149 tfTime == other.tfTime;
150 ;
151}
152
154{
155 return digit == other.digit && info == other.info;
156}
157
158bool DataDecoder::TimeFrameStartRecord::update(uint32_t orbit, uint32_t bunchCrossing, bool verbose)
159{
160 if (verbose) {
161 LOGP(info, "[TimeFrameStartRecord::update()] new {}/{} current {}/{} prev {}/{} valid {}",
162 orbit, bunchCrossing, mOrbit, mBunchCrossing, mOrbitPrev, mBunchCrossingPrev, mValid);
163 }
164
165 // if this is the first occurence, simply initialize the orbit and binch crossing and mark the start recortd as valid
166 if (mOrbit < 0) {
167 mOrbit = orbit;
168 mBunchCrossing = bunchCrossing;
169
170 mValid = true;
171 return true;
172 }
173
174 if (mOrbit == orbit) {
175 if (mValid) {
176 // there is already one valid record for this orbit, so the current one is discarded
177 return false;
178 } else {
179 // there is already one record for this orbit, but it is invalid
180 // check if the current one is compatible with the previous, if yes replace the existing one
181 if (check(orbit, bunchCrossing, mOrbitPrev, mBunchCrossingPrev, verbose)) {
182 mOrbit = orbit;
183 mBunchCrossing = bunchCrossing;
184
185 mValid = true;
186 }
187 }
188 } else {
189 // we received an HB packet for a new TF, check if it is compatible with the last stored one
190 bool valid = check(orbit, bunchCrossing, mOrbit, mBunchCrossing, verbose);
191
192 bool replace = valid || (mOrbitPrev < 0) || (mValid == false);
193
194 if (replace) {
195 mOrbitPrev = mOrbit;
196 mBunchCrossingPrev = mBunchCrossing;
197
198 mOrbit = orbit;
199 mBunchCrossing = bunchCrossing;
200
201 mValid = valid;
202 }
203 }
204
205 if (verbose) {
206 LOGP(info, "[TimeFrameStartRecord::update()] set to {}/{} prev {}/{} valid {}",
207 mOrbit, mBunchCrossing, mOrbitPrev, mBunchCrossingPrev, mValid);
208 }
209
210 return mValid;
211}
212
213bool DataDecoder::TimeFrameStartRecord::check(int32_t orbit, uint32_t bc, int32_t orbitRef, uint32_t bcRef, bool verbose)
214{
215 if (verbose) {
216 LOGP(info, "[TimeFrameStartRecord::check()] current {}/{} ref {}/{}", orbit, bc, orbitRef, bcRef);
217 }
218
219 if (orbitRef < 0) {
220 return true;
221 }
222
223 int64_t dOrbit = orbit - orbitRef;
224 if (verbose) {
225 LOGP(info, "[TimeFrameStartRecord::check()] dOrbit{}", dOrbit);
226 }
227 int64_t bcExpected = dOrbit * bcInOrbit + bcRef;
228
229 uint64_t bcExpected20bits = bcExpected & twentyBitsAtOne;
230
231 bool result = (bcExpected20bits == bc);
232
233 if (verbose) {
234 LOGP(info, " dOrbit {} expected {} expected20bits {} bc {} valid {}", dOrbit, bcExpected, bcExpected20bits, bc, result);
235 }
236
237 return result;
238}
239
240//_________________________________________________________________________________________________
241
243 std::string mapCRUfile, std::string mapFECfile,
244 bool ds2manu, bool verbose, bool useDummyElecMap,
245 TimeRecoMode timeRecoMode,
246 uint32_t nofOrbitsPerTF)
247 : mChannelHandler(channelHandler), mRdhHandler(rdhHandler), mMapCRUfile(mapCRUfile), mMapFECfile(mapFECfile), mDs2manu(ds2manu), mDebug(verbose), mUseDummyElecMap(useDummyElecMap), mTimeRecoMode(timeRecoMode), mOrbitsInTF(nofOrbitsPerTF)
248{
249 init();
250}
251
252void DataDecoder::logErrorMap(int tfcount) const
253{
254 for (auto err : mErrorMap) {
255 LOGP(warning, "{} ({} time{}) [{} TFs seen]", err.first, err.second,
256 err.second > 1 ? "s" : "", tfcount);
257 }
258}
259
260//_________________________________________________________________________________________________
261
263{
264 mFirstOrbitInTF = orbit;
265}
266
267//_________________________________________________________________________________________________
268
269bool DataDecoder::decodeBuffer(gsl::span<const std::byte> buf)
270{
271 if (mDebug) {
272 std::cout << "\n\n============================\nStart of new buffer\n";
273 }
274 size_t bufSize = buf.size();
275 size_t pageStart = 0;
276 while (bufSize > pageStart) {
277 RDH* rdh = reinterpret_cast<RDH*>(const_cast<std::byte*>(&(buf[pageStart])));
278 if (mDebug) {
279 if (pageStart == 0) {
280 std::cout << "+++\n[decodeBuffer]" << std::endl;
281 } else {
282 std::cout << "---\n[decodeBuffer]" << std::endl;
283 }
285 }
286 auto rdhVersion = o2::raw::RDHUtils::getVersion(rdh);
287 auto rdhHeaderSize = o2::raw::RDHUtils::getHeaderSize(rdh);
288 if (rdhHeaderSize != 64) {
289 break;
290 }
291 auto pageSize = o2::raw::RDHUtils::getOffsetToNext(rdh);
292
293 gsl::span<const std::byte> page(reinterpret_cast<const std::byte*>(rdh), pageSize);
294 try {
295 decodePage(page);
296 } catch (const std::exception& e) {
297 mErrors.emplace_back(DecoderError(0, 0, 0, ErrorNonRecoverableDecodingError));
298 return false;
299 }
300
301 pageStart += pageSize;
302 }
303
304 if (mDebug) {
305 std::cout << "[decodeBuffer] mOrbits size: " << mOrbits.size() << std::endl;
306 dumpOrbits(mOrbits);
307 std::cout << "[decodeBuffer] mDigits size: " << mDigits.size() << std::endl;
308 dumpDigits();
309 }
310 return true;
311}
312
313//_________________________________________________________________________________________________
314
315void DataDecoder::dumpDigits()
316{
317 for (size_t di = 0; di < mDigits.size(); di++) {
318 auto& d = mDigits[di];
319 auto detID = d.getDetID();
320 auto padID = d.getPadID();
321 if (padID < 0) {
322 continue;
323 }
324 const Segmentation& segment = segmentation(detID);
325 bool bend = segment.isBendingPad(padID);
326 float X = segment.padPositionX(padID);
327 float Y = segment.padPositionY(padID);
328 uint32_t orbit = d.getOrbit();
329 uint32_t bunchCrossing = d.getBunchCrossing();
330 uint32_t sampaTime = d.getSampaTime();
331 std::cout << fmt::format(" DE {:4d} PAD {:5d} ADC {:6d} TIME ({} {} {:4d})",
332 detID, padID, d.getADC(), orbit, bunchCrossing, sampaTime);
333 std::cout << fmt::format("\tC {} PAD_XY {:+2.2f} , {:+2.2f}", (bend ? (int)0 : (int)1), X, Y);
334 std::cout << std::endl;
335 }
336};
337
338//_________________________________________________________________________________________________
339
340void dumpOrbits(const std::unordered_set<OrbitInfo, OrbitInfoHash>& mOrbits)
341{
342 std::set<OrbitInfo> ordered_orbits(mOrbits.begin(), mOrbits.end());
343 for (auto o : ordered_orbits) {
344 std::cout << " FEEID " << o.getFeeID() << " LINK " << (int)o.getLinkID() << " ORBIT " << o.getOrbit() << std::endl;
345 }
346};
347
348//_________________________________________________________________________________________________
349
350bool DataDecoder::getMergerChannelId(const DsElecId& dsElecId, DualSampaChannelId channel, uint32_t& chId, uint32_t& boardId)
351{
352 static constexpr uint32_t sChannelsInOneDs = 64;
353 static constexpr uint32_t sDsInOneSolar = 40;
354 static constexpr uint32_t sChannelsInOneSolar = sChannelsInOneDs * sDsInOneSolar;
355 auto solarId = dsElecId.solarId();
356 uint32_t dsId = static_cast<uint32_t>(dsElecId.elinkGroupId()) * 5 + dsElecId.elinkIndexInGroup();
357 if (solarId > DataDecoder::sMaxSolarId || dsId >= 40 || channel >= 64) {
358 return false;
359 }
360
361 boardId = solarId * sDsInOneSolar + dsId;
362 chId = boardId * sChannelsInOneDs + channel;
363 return true;
364}
365
366//_________________________________________________________________________________________________
367
368uint64_t DataDecoder::getMergerChannelBitmask(DualSampaChannelId channel)
369{
370 uint64_t result{1};
371
372 if (channel >= 64) {
373 return 0;
374 }
375
376 result <<= channel;
377
378 return result;
379}
380
381//_________________________________________________________________________________________________
382
383bool DataDecoder::mergeDigits(uint32_t mergerChannelId, uint32_t mergerBoardId, uint64_t mergerChannelBitmask, o2::mch::raw::SampaCluster& sc)
384{
385 uint32_t BCROLLOVER = (mTimeRecoMode == TimeRecoMode::BCReset) ? (mBcInOrbit * mOrbitsInTF) : (1 << 20);
386 static constexpr uint32_t ONEADCCLOCK = 4;
387 static constexpr uint32_t MAXNOFSAMPLES = 0x3FF;
388 static constexpr uint32_t TWENTYBITSATONE = 0xFFFFF;
389
390 // only digits that start at the beginning of the SAMPA window can be merged
391 if (sc.sampaTime != 0) {
392 return false;
393 }
394
395 // if there is not previous digit for this channel then no merging is possible
396 if ((mMergerRecordsReady[mergerBoardId] & mergerChannelBitmask) == 0) {
397 return false;
398 }
399
400 auto& mergerCh = mMergerRecords[mergerChannelId];
401
402 // time stamp of the digits to be merged
403 uint32_t bcStart = sc.bunchCrossing;
404 // correct for bunch crossing counter rollover if needed
405 if (bcStart < mergerCh.bcEnd) {
406 bcStart += BCROLLOVER;
407 }
408
409 // if the new digit starts just one ADC clock cycle after the end of the previous,
410 // the it can be merged into the existing one
411 if ((bcStart - mergerCh.bcEnd) != ONEADCCLOCK) {
412 return false;
413 }
414
415 // add total charge and number of samples to existing digit
416 auto& digit = mDigits[mergerCh.digitId].digit;
417
418 digit.setADC(digit.getADC() + sc.sum());
419 uint32_t newNofSamples = digit.getNofSamples() + sc.nofSamples();
420 if (newNofSamples > MAXNOFSAMPLES) {
421 newNofSamples = MAXNOFSAMPLES;
422 }
423 digit.setNofSamples(newNofSamples);
424
425 // update the time stamp of the signal's end
426 mergerCh.bcEnd = (bcStart & TWENTYBITSATONE) + (sc.nofSamples() - 1) * 4;
427
428 return true;
429}
430
431//_________________________________________________________________________________________________
432
433void DataDecoder::updateMergerRecord(uint32_t mergerChannelId, uint32_t mergerBoardId, uint64_t mergerChannelBitmask, uint32_t digitId)
434{
435 auto& mergerCh = mMergerRecords[mergerChannelId];
436 auto& digit = mDigits[digitId];
437 mergerCh.digitId = digitId;
438 mergerCh.bcEnd = digit.info.bunchCrossing + (digit.info.sampaTime + digit.digit.getNofSamples() - 1) * 4;
439 mMergerRecordsReady[mergerBoardId] |= mergerChannelBitmask;
440 if (mDebug) {
441 std::cout << fmt::format("[updateMergerRecord] updated S{}-DS{}-CHIP{} time {}-{}-{} cs {}",
442 (int)digit.info.solar, (int)digit.info.ds, (int)digit.info.chip,
443 (int)digit.info.orbit, (int)digit.info.bunchCrossing, (int)digit.info.sampaTime, (int)digit.digit.getNofSamples())
444 << std::endl;
445 }
446}
447
448//_________________________________________________________________________________________________
449
450bool DataDecoder::getPadMapping(const DsElecId& dsElecId, DualSampaChannelId channel, int& deId, int& dsIddet, int& padId)
451{
452 deId = -1;
453 dsIddet = -1;
454 padId = -1;
455
456 if (auto opt = mElec2Det(dsElecId); opt.has_value()) {
457 DsDetId dsDetId = opt.value();
458 dsIddet = dsDetId.dsId();
459 deId = dsDetId.deId();
460 }
461 if (mDebug) {
462 auto s = asString(dsElecId);
463 auto ch = fmt::format("{}-CH{:02d}", s, channel);
464 std::cout << ch << " "
465 << "deId " << deId << " dsIddet " << dsIddet << std::endl;
466 }
467
468 if (deId < 0 || dsIddet < 0 || !isValidDeID(deId)) {
469 auto msg = fmt::format("got invalid DsDetId from dsElecId={}", asString(dsElecId));
470 mErrorMap[msg]++;
471 return false;
472 }
473
474 const Segmentation& segment = segmentation(deId);
475 padId = segment.findPadByFEE(dsIddet, int(channel));
476
477 if (padId < 0) {
478 return false;
479 }
480 return true;
481}
482
483//_________________________________________________________________________________________________
484
485bool DataDecoder::addDigit(const DsElecId& dsElecId, DualSampaChannelId channel, const o2::mch::raw::SampaCluster& sc)
486{
487 int deId, dsIddet, padId;
488 if (!getPadMapping(dsElecId, channel, deId, dsIddet, padId)) {
489 return false;
490 }
491
492 uint32_t digitadc = sc.sum();
493
494 if (mDebug) {
495 auto s = asString(dsElecId);
496 auto ch = fmt::format("{}-CH{:02d}", s, channel);
497 LOG(info) << ch << " "
498 << fmt::format("PAD ({:04d} {:04d} {:04d})\tADC {:06d} TIME ({} {} {:02d}) SIZE {} END {}",
499 deId, dsIddet, padId, digitadc, mOrbit, sc.bunchCrossing, sc.sampaTime, sc.nofSamples(), (sc.sampaTime + sc.nofSamples() - 1))
500 << (((sc.sampaTime + sc.nofSamples() - 1) >= 98) ? " *" : "");
501 }
502
503 // skip channels not associated to any pad
504 if (padId < 0) {
505 LOGP(alarm, "got invalid padId from dsElecId={} dualSampaId={} channel={}", asString(dsElecId), dsIddet, channel);
506 return false;
507 }
508
509 RawDigit digit;
510 digit.digit = o2::mch::Digit(deId, padId, digitadc, 0, sc.nofSamples());
511 digit.info.chip = channel / 32;
512 digit.info.ds = dsElecId.elinkId();
513 digit.info.solar = dsElecId.solarId();
514 digit.info.sampaTime = sc.sampaTime;
516 digit.info.orbit = mOrbit;
517
518 mDigits.emplace_back(digit);
519
520 if (mDebug) {
521 RawDigit& lastDigit = mDigits.back();
522 LOGP(info, "DIGIT STORED: ORBIT {} ADC {} DE {} PADID {} TIME {} BXCOUNT {}",
523 mOrbit, lastDigit.getADC(), lastDigit.getDetID(), lastDigit.getPadID(),
524 lastDigit.getSampaTime(), lastDigit.getBunchCrossing());
525 }
526 return true;
527}
528
529uint64_t DataDecoder::getChipId(uint32_t solar, uint32_t ds, uint32_t chip)
530{
531 return solar * 40 * 2 + ds * 2 + chip;
532}
533
534//_________________________________________________________________________________________________
535
536void DataDecoder::updateTimeFrameStartRecord(uint64_t chipId, uint32_t mFirstOrbitInTF, uint32_t bcTF)
537{
538 if (chipId < DataDecoder::sReadoutChipsNum) {
539 mTimeFrameStartRecords[chipId].update(mFirstOrbitInTF, bcTF);
540 }
541}
542
543//_________________________________________________________________________________________________
544
545void DataDecoder::decodePage(gsl::span<const std::byte> page)
546{
547 uint8_t isStopRDH = 0;
548 uint32_t orbit;
549 uint32_t feeId;
550 uint32_t linkId;
551
552 auto heartBeatHandler = [&](DsElecId dsElecId, uint8_t chip, uint32_t bunchCrossing) {
553 auto ds = dsElecId.elinkId();
554 auto solar = dsElecId.solarId();
555 uint64_t chipId = getChipId(solar, ds, chip);
556
557 if (mDebug) {
558 auto s = asString(dsElecId);
559 LOGP(info, "HeartBeat: {}-CHIP{} -> {}/{}",
560 s, chip, mFirstOrbitInTF, bunchCrossing);
561 }
562
563 if (chipId >= DataDecoder::sReadoutChipsNum) {
564 return;
565 }
566
567 mHBPackets.emplace_back(solar, ds, chip, bunchCrossing);
568
569 if (mTimeRecoMode == TimeRecoMode::HBPackets) {
570 bool isOk = mTimeFrameStartRecords[chipId].update(mFirstOrbitInTF, bunchCrossing);
571 if (!isOk && mErrorCount < MCH_DECODER_MAX_ERROR_COUNT) {
572 auto s = asString(dsElecId);
573 LOGP(warning, "Bad HeartBeat packet received: {}-CHIP{} {}/{} (last {}/{})",
574 s, chip, mFirstOrbitInTF, bunchCrossing, mTimeFrameStartRecords[chipId].mOrbitPrev, mTimeFrameStartRecords[chipId].mBunchCrossingPrev);
575 mErrorCount += 1;
576 }
577 }
578 };
579
580 auto channelHandler = [&](DsElecId dsElecId, DualSampaChannelId channel,
582 if (mChannelHandler) {
583 mChannelHandler(dsElecId, channel, sc);
584 }
585
586 if (mDs2manu) {
587 LOGP(error, "using ds2manu");
588 channel = ds2manu(int(channel));
589 }
590
591 uint32_t mergerChannelId;
592 uint32_t mergerBoardId;
593 if (!getMergerChannelId(dsElecId, channel, mergerChannelId, mergerBoardId)) {
594 LOGP(error, "dsElecId={} is out-of-bounds", asString(dsElecId));
595 return;
596 }
597 uint64_t mergerChannelBitmask = getMergerChannelBitmask(channel);
598
599 if (mergeDigits(mergerChannelId, mergerBoardId, mergerChannelBitmask, sc)) {
600 return;
601 }
602
603 if (!addDigit(dsElecId, channel, sc)) {
604 return;
605 }
606
607 updateMergerRecord(mergerChannelId, mergerBoardId, mergerChannelBitmask, mDigits.size() - 1);
608 };
609
610 auto errorHandler = [&](DsElecId dsElecId,
611 int8_t chip,
612 uint32_t error) {
613 std::string msg = fmt::format("{} chip {:2d} error {:4d} ({})", asString(dsElecId), chip, error, errorCodeAsString(error));
614 mErrorMap[msg]++;
615
616 auto solarId = dsElecId.solarId();
617 auto dsId = dsElecId.elinkId();
618 mErrors.emplace_back(o2::mch::DecoderError(solarId, dsId, chip, error));
619 };
620
621 patchPage(page, mDebug);
622
623 auto& rdhAny = *reinterpret_cast<RDH*>(const_cast<std::byte*>(&(page[0])));
624 mOrbit = o2::raw::RDHUtils::getHeartBeatOrbit(rdhAny);
625 if (mDebug) {
626 LOGP(info, "[decodeBuffer] mOrbit set to {}", mOrbit);
627 }
628
629 if (mRdhHandler) {
630 mRdhHandler(&rdhAny);
631 }
632
633 // add orbit to vector if not present yet
634 mOrbits.emplace(page);
635
636 if (!mDecoder) {
637 DecodedDataHandlers handlers;
638 handlers.sampaChannelHandler = channelHandler;
639 handlers.sampaHeartBeatHandler = heartBeatHandler;
640 handlers.sampaErrorHandler = errorHandler;
641 mDecoder = mFee2Solar ? o2::mch::raw::createPageDecoder(page, handlers, mFee2Solar)
642 : o2::mch::raw::createPageDecoder(page, handlers);
643 }
644
645 mDecoder(page);
646};
647
648//_________________________________________________________________________________________________
649
650bool DataDecoder::getTimeFrameStartRecord(const RawDigit& digit, uint32_t& orbitTF, uint32_t& bcTF)
651{
652 static constexpr uint32_t twentyBitsAtOne = 0xFFFFF;
653
654 // first orbit of the current TF
655 orbitTF = mFirstOrbitInTF;
656
657 auto& d = digit.digit;
658 auto& info = digit.info;
659
660 auto chipId = getChipId(info.solar, info.ds, info.chip);
661 auto& tfStart = mTimeFrameStartRecords[chipId];
662
663 if (tfStart.mOrbit < 0) {
664 if (mErrorCount < MCH_DECODER_MAX_ERROR_COUNT) {
665 LOGP(alarm, "Missing TF start record for S{}-J{}-DS{}-CHIP{}", info.solar, info.ds / 5 + 1, info.ds % 5, info.chip);
666 mErrorCount += 1;
667 }
668 return false;
669 }
670
671 if (tfStart.mValid == false) {
672 if (mErrorCount < MCH_DECODER_MAX_ERROR_COUNT) {
673 LOGP(alarm, "Invalid TF start record for S{}-J{}-DS{}-CHIP{}", info.solar, info.ds / 5 + 1, info.ds % 5, info.chip);
674 mErrorCount += 1;
675 }
676 }
677
678 // orbit and BC from the last received HB packet
679 uint32_t orbitHBP = tfStart.mOrbit;
680 // SAMPA BC at the beginning of the current TF
681 bcTF = tfStart.mBunchCrossing;
682
683 if (orbitHBP != orbitTF) {
684 // we correct the BC from the last received HB packet, if it was recorded from an older TF
685 bcTF += (orbitTF - orbitHBP) * mBcInOrbit;
686 // only keep 20 bits
687 bcTF &= twentyBitsAtOne;
688
689 // update the time frame start information for this chip, to speed-up the computations
690 // in case another digit from the same chip is found in the same time frame.
691 tfStart.update(orbitTF, bcTF);
692 }
693
694 return true;
695}
696
697//_________________________________________________________________________________________________
698
699int32_t DataDecoder::getDigitTimeHBPackets(uint32_t orbitStart, uint32_t bcStart, uint32_t orbitDigit, uint32_t bcDigit)
700{
701 // We use the difference of orbits values to estimate the minimum and maximum allowed
702 // difference in bunch crossings
703 int64_t dOrbit = static_cast<int64_t>(orbitDigit) - static_cast<int64_t>(orbitStart);
704
705 // Digits might be sent out later than the orbit in which they were recorded.
706 // We account for this by allowing an extra -3 / +10 orbits when converting the
707 // difference from orbit numbers to bunch crossings.
708 int64_t dBcMin = (dOrbit - 50) * bcInOrbit;
709 int64_t dBcMax = (dOrbit + 3) * bcInOrbit;
710
711 // Difference in bunch crossing values
712 int64_t dBc = static_cast<int64_t>(bcDigit) - static_cast<int64_t>(bcStart);
713
714 if (dBc < dBcMin) {
715 // the difference is too small, so we assume that it needs to be
716 // incremented by one rollover factor
717 dBc += bcRollOver;
718 } else if (dBc > dBcMax) {
719 // the difference is too big, so we assume that it needs to be
720 // decremented by one rollover factor
721 dBc -= bcRollOver;
722 }
723
724 return static_cast<int32_t>(dBc);
725}
726
727//_________________________________________________________________________________________________
728
730{
731 static constexpr int32_t timeInvalid = DataDecoder::tfTimeInvalid;
732
733 auto setDigitTime = [&](Digit& d, int32_t tfTime) {
734 d.setTime(tfTime);
735 };
736
737 for (auto& digit : mDigits) {
738 auto& d = digit.digit;
739 auto& info = digit.info;
740
741 uint32_t orbitTF;
742 uint32_t bcTF;
743 int32_t tfTime = timeInvalid;
744
745 auto orbitDigit = info.orbit;
746 auto bcDigit = info.getBXTime();
747
748 if (getTimeFrameStartRecord(digit, orbitTF, bcTF)) {
749 int solar = info.solar;
750 int ds = info.ds;
751 int chip = info.chip;
752 tfTime = DataDecoder::getDigitTimeHBPackets(orbitTF, bcTF, orbitDigit, bcDigit);
753 }
754
755 setDigitTime(d, tfTime);
756 info.tfTime = tfTime;
757 }
758}
759
760//_________________________________________________________________________________________________
761
762int32_t DataDecoder::getDigitTimeBCRst(uint32_t orbitStart, uint32_t bcStart, uint32_t orbitDigit, uint32_t bcDigit)
763{
764 // We use the difference of orbits values to estimate the minimum and maximum allowed
765 // difference in bunch crossings
766 int64_t dOrbitRDH = static_cast<int64_t>(orbitDigit) - static_cast<int64_t>(orbitStart);
767
768 // Difference in bunch crossing values
769 int64_t dBc = static_cast<int64_t>(bcDigit) - static_cast<int64_t>(bcStart);
770 int64_t dOrbitSampa = dBc / mBcInOrbit;
771
772 if (dOrbitSampa > (dOrbitRDH + 1)) {
773 // The orbit inferred from the SAMPA BC is larger than the one from the RDH
774 // We interpret this as due to SAMPA packets generated before the BC reset is applied at the beginning of the TF
775 dBc -= mBcInOrbit * mOrbitsInTF;
776 }
777
778 return static_cast<int32_t>(dBc);
779}
780
781//_________________________________________________________________________________________________
782
784{
785 static constexpr int32_t timeInvalid = DataDecoder::tfTimeInvalid;
786
787 auto setDigitTime = [&](Digit& d, int32_t tfTime) {
788 d.setTime(tfTime);
789 };
790
791 for (auto& digit : mDigits) {
792 auto& d = digit.digit;
793 auto& info = digit.info;
794
795 uint32_t orbitTF = mFirstOrbitInTF;
796 uint32_t bcTF = 0;
797 int32_t tfTime = timeInvalid;
798
799 auto orbitDigit = info.orbit;
800 auto bcDigit = info.getBXTime();
801
802 tfTime = DataDecoder::getDigitTimeBCRst(orbitTF, bcTF, orbitDigit, bcDigit);
803
804 if (mDebug && tfTime < (-2 * mBcInOrbit)) {
805 int solar = info.solar;
806 int ds = info.ds;
807 int chip = info.chip;
808 std::cout << fmt::format("Out-of-time digit: S{} DS{} CHIP{} TF {}/{} DIGIT {}/{} TIME {}",
809 solar, ds, chip, orbitTF, bcTF, orbitDigit, bcDigit, tfTime)
810 << std::endl;
811 }
812
813 setDigitTime(d, tfTime);
814 info.tfTime = tfTime;
815 }
816}
817
818//_________________________________________________________________________________________________
819
821{
822 switch (mTimeRecoMode) {
825 break;
828 break;
829 default:
830 LOGP(error, "Digit time reconstruction mode undefined");
831 break;
832 }
833}
834
835//_________________________________________________________________________________________________
836
837static std::string readFileContent(std::string& filename)
838{
839 std::string content;
840 std::string s;
841 std::ifstream in(filename);
842 while (std::getline(in, s)) {
843 content += s;
844 content += "\n";
845 }
846 return content;
847};
848
849//_________________________________________________________________________________________________
850
851void DataDecoder::initElec2DetMapper(std::string filename)
852{
853 if (filename.empty()) {
854 if (mUseDummyElecMap) {
855 LOGP(warning, "[initElec2DetMapper] Using dummy electronic mapping");
857 } else {
859 }
860 } else {
861 LOGP(info, "[initElec2DetMapper] filename={}", filename);
862 ElectronicMapperString::sFecMap = readFileContent(filename);
864 }
865};
866
867//_________________________________________________________________________________________________
868
869void DataDecoder::initFee2SolarMapper(std::string filename)
870{
871 if (filename.empty()) {
872 if (mUseDummyElecMap) {
873 LOGP(warning, "[initFee2SolarMapper] Using dummy electronic mapping");
875 } else {
877 }
878 } else {
879 LOGP(info, "[initFee2SolarMapper] filename={}", filename);
880 ElectronicMapperString::sCruMap = readFileContent(filename);
882 }
883};
884
885//_________________________________________________________________________________________________
886
887void DataDecoder::init()
888{
889 for (int i = 0; i < 64; i++) {
890 for (int j = 0; j < 64; j++) {
891 if (refManu2ds_st345[j] != i) {
892 continue;
893 }
894 refDs2manu_st345[i] = j;
895 break;
896 }
897 }
898
899 initFee2SolarMapper(mMapCRUfile);
900 initElec2DetMapper(mMapFECfile);
901
903
904 mTimeFrameStartRecords.resize(sReadoutChipsNum);
905 std::fill(mTimeFrameStartRecords.begin(), mTimeFrameStartRecords.end(), TimeFrameStartRecord());
906
907 mMergerRecords.resize(sReadoutChannelsNum);
908 mMergerRecordsReady.resize(sReadoutBoardsNum);
909
910 reset();
911};
912
913//_________________________________________________________________________________________________
914
916{
917 mDigits.clear();
918 mOrbits.clear();
919 mErrors.clear();
920 mHBPackets.clear();
921 memset(mMergerRecordsReady.data(), 0, sizeof(uint64_t) * mMergerRecordsReady.size());
922}
923
924} // namespace raw
925} // namespace mch
926} // end namespace o2
#define MCH_DECODER_MAX_ERROR_COUNT
#define refManu2ds_st345
Definition of the decoder for the MCH data.
uint64_t orbit
Definition RawEventData.h:6
uint64_t bc
Definition RawEventData.h:5
int32_t i
bool o
Header to collect LHC related constants.
Definition of the RAW Data Header.
uint32_t j
Definition RawData.h:0
uint8_t endpoint
Definition RawData.h:0
int ds2manu(int deId, int ch)
int manu2ds(int deId, int ch)
MCH decoder error implementation.
MCH digit implementation.
Definition Digit.h:31
void setTime(int32_t t)
Definition Digit.h:43
void logErrorMap(int tfcount) const
send all messages from our error map to the infologger
void computeDigitsTimeBCRst()
Compute the time of all the digits that have been decoded in the current TimeFrame.
void computeDigitsTimeHBPackets()
Compute the time of all the digits that have been decoded in the current TimeFrame.
static constexpr int32_t tfTimeInvalid
Definition DataDecoder.h:61
static int32_t getDigitTimeHBPackets(uint32_t orbitTF, uint32_t bcTF, uint32_t orbitDigit, uint32_t bcDigit)
Helper function for computing the digit time relative to the beginning of the TimeFrame.
void setFirstOrbitInTF(uint32_t orbit)
int32_t getDigitTimeBCRst(uint32_t orbitTF, uint32_t bcTF, uint32_t orbitDigit, uint32_t bcDigit)
static uint64_t getChipId(uint32_t solar, uint32_t ds, uint32_t chip)
Convert a Solar/Ds/Chip triplet into an unique chip index.
void updateTimeFrameStartRecord(uint64_t chipId, uint32_t mFirstOrbitInTF, uint32_t bcTF)
For a given SAMPA chip, update the information about the BC counter value at the beginning of the Tim...
DataDecoder(SampaChannelHandler channelHandler, RdhHandler rdhHandler, std::string mapCRUfile, std::string mapFECfile, bool ds2manu, bool verbose, bool useDummyElecMap, TimeRecoMode timeRecoMode=TimeRecoMode::HBPackets, uint32_t nofOrbitsPerTF=32)
bool decodeBuffer(gsl::span< const std::byte > buf)
constexpr uint8_t elinkId() const
Definition DsElecId.h:44
constexpr uint16_t solarId() const
solarId is an identifier that uniquely identify a solar board
Definition DsElecId.h:50
GLuint segment
Definition glcorearb.h:4945
GLuint64EXT * result
Definition glcorearb.h:5662
GLuint GLsizei bufSize
Definition glcorearb.h:790
GLbitfield flags
Definition glcorearb.h:1570
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition glcorearb.h:2514
constexpr int LHCMaxBunches
void check(const std::vector< std::string > &arguments, const std::vector< ConfigParamSpec > &workflowOptions, const std::vector< DeviceSpec > &deviceSpecs, CheckMatrix &matrix)
O2MCHMAPPINGIMPL3_EXPORT const Segmentation & segmentation(int detElemId)
std::function< std::optional< DsDetId >(DsElecId)> createElec2DetMapper< ElectronicMapperGenerated >(uint64_t)
FeeLink2SolarMapper createFeeLink2SolarMapper< ElectronicMapperString >()
std::function< void(o2::header::RDHAny *)> RdhHandler
Definition DataDecoder.h:41
std::function< std::optional< uint16_t >(FeeLinkId)> createFeeLink2SolarMapper< ElectronicMapperGenerated >()
@ ErrorNonRecoverableDecodingError
Definition ErrorCodes.h:41
std::string errorCodeAsString(uint32_t code)
void dumpOrbits(const std::unordered_set< OrbitInfo, OrbitInfoHash > &mOrbits)
Elec2DetMapper createElec2DetMapper< ElectronicMapperString >(uint64_t)
std::function< void(DsElecId dsId, DualSampaChannelId channel, SampaCluster)> SampaChannelHandler
std::function< std::optional< DsDetId >(DsElecId)> createElec2DetMapper< ElectronicMapperDummy >(uint64_t timestamp)
uint6_t DualSampaChannelId
Definition DataFormats.h:65
PageDecoder createPageDecoder(RawBuffer rdhBuffer, DecodedDataHandlers decodedDataHandlers)
will be called for each decoded Sampa packet and in case of decoding errors
std::string asString(const SampaCluster &sc)
std::function< std::optional< uint16_t >(FeeLinkId)> createFeeLink2SolarMapper< ElectronicMapperDummy >()
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
bool operator<(const observer_ptr< W1 > &p1, const observer_ptr< W2 > &p2)
std::ostream & operator<<(std::ostream &stream, o2::InteractionRecord const &ir)
std::string filename()
bool operator==(const RawDigit &) const
Structure storing the raw SAMPA information.
Definition DataDecoder.h:69
bool operator==(const SampaInfo &) const
uint32_t bunchCrossing
bit 0 to 9: sampa time
Definition DataDecoder.h:85
uint32_t orbit
bit 30 to 31: reserved
Definition DataDecoder.h:87
bool check(int32_t orbit, uint32_t bc, int32_t orbitRef, uint32_t bcRef, bool verbose=false)
bool update(uint32_t orbit, uint32_t bunchCrossing, bool verbose=false)
store the new orbit/bc pair, and copy the existing one in the "*Prev" data members
Piece of data for one Sampa channel.
uint32_t sum() const
sum returns the total charge in the cluster
uint16_t nofSamples() const
static void printRDH(const RDHv4 &rdh)
Definition RDHUtils.cxx:26
static void setFEEID(RDHv4 &rdh, uint16_t v)
Definition RDHUtils.h:146
static constexpr int getVersion()
get numeric version of the RDH
Definition RDHUtils.h:58
const bool useDummyElecMap
o2::mch::DsIndex ds
VectorOfTObjectPtrs other
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
uint64_t const void const *restrict const msg
Definition x9.h:153