Project
Loading...
Searching...
No Matches
AltroDecoder.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#include <cassert>
12#include <cstring>
13#include <iomanip>
14#include <iostream>
15#include <fmt/format.h>
19#include "Framework/Logger.h"
20
21using namespace o2::emcal;
22
23AltroDecoder::AltroDecoder(RawReaderMemory& reader) : mRawReader(reader),
24 mRCUTrailer(),
25 mChannels(),
26 mChannelsInitialized(false)
27{
28}
29
31{
32 mMinorDecodingErrors.clear();
34 checkRCUTrailer();
36}
37
39{
40 try {
41 auto payloadwordsOrig = mRawReader.getPayload().getPayloadWords();
42 gsl::span<const uint32_t> payloadwords(payloadwordsOrig.data(), payloadwordsOrig.size());
43 mRCUTrailer.constructFromRawPayload(payloadwords);
44 } catch (RCUTrailer::Error& e) {
46 }
47}
48
49void AltroDecoder::checkRCUTrailer()
50{
51 int trailersize = mRCUTrailer.getTrailerSize();
52 int buffersize = mRawReader.getPayload().getPayloadWords().size();
53 if (trailersize > buffersize) {
55 }
56}
57
59{
60 mChannelsInitialized = false;
61 mChannels.clear();
62 int currentpos = 0;
63 auto& buffer = mRawReader.getPayload().getPayloadWords();
64 auto maxpayloadsize = buffer.size() - mRCUTrailer.getTrailerSize();
65 int lastFEC = -1;
66 while (currentpos < maxpayloadsize) {
67 auto currentword = buffer[currentpos++];
68 if (currentword >> 30 != 1) {
69 continue;
70 }
71
72 // decode channel header
73 auto channelheader = currentword;
74 int32_t hwaddress = channelheader & 0xFFF;
75 uint16_t payloadsize = (channelheader >> 16) & 0x3FF;
76 bool badchannel = (channelheader >> 29) & 0x1;
77
78 // check hardware address for consistency
79 if (!checkChannelHWAddress(hwaddress)) {
80 // Inconsistent HW address information, channel header corrupted, payload must be skipped
81 mMinorDecodingErrors.emplace_back(MinorAltroDecodingError::ErrorType_t::CHANNEL_ORDER, channelheader, currentword);
82 continue;
83 }
84
85 int currentfec = 10 * Channel::getBranchIndexFromHwAddress(hwaddress) + Channel::getFecIndexFromHwAddress(hwaddress);
86 // std::cout << "Branch: " << Channel::getBranchIndexFromHwAddress(hwaddress) << ", FEC " << Channel::getFecIndexFromHwAddress(hwaddress) << " -> " << currentfec << " (channel " << Channel::getChannelIndexFromHwAddress(hwaddress) << " )" << std::endl;
87 if (currentfec < lastFEC) {
88 // FECs are ordered by the SRU, breaking the order is a clear sign of data corruption
89 // std::cout << "Error Fec, current " << currentfec << ", last " << lastFEC << std::endl;
90 mMinorDecodingErrors.emplace_back(MinorAltroDecodingError::ErrorType_t::CHANNEL_ORDER, channelheader, currentword);
91 continue;
92 }
93 lastFEC = currentfec;
94
96 bool foundChannelError = false;
97 int numberofwords = (payloadsize + 2) / 3;
98 std::vector<uint16_t> bunchwords;
99 for (int iword = 0; iword < numberofwords; iword++) {
100 if (currentpos >= maxpayloadsize) {
101 mMinorDecodingErrors.emplace_back(MinorAltroDecodingError::ErrorType_t::CHANNEL_PAYLOAD_EXCEED, channelheader, currentword);
102 foundChannelError = true;
103 break; // Must break here in order not to prevent a buffer overrun
104 }
105 currentword = buffer[currentpos++];
106 if ((currentword >> 30) != 0) {
107 // word is a new channel header
108 mMinorDecodingErrors.emplace_back(MinorAltroDecodingError::ErrorType_t::CHANNEL_END_PAYLOAD_UNEXPECT, channelheader, currentword);
109 foundChannelError = true;
110 currentpos--;
111 continue;
112 }
113 bunchwords.push_back((currentword >> 20) & 0x3FF);
114 bunchwords.push_back((currentword >> 10) & 0x3FF);
115 bunchwords.push_back(currentword & 0x3FF);
116 }
117 if (foundChannelError) {
118 // do not decode bunch if channel payload is corrupted
119 continue;
120 }
121 // Payload decoding for channel good - starting a new channel object
122 mChannels.emplace_back(hwaddress, payloadsize);
123 auto& currentchannel = mChannels.back();
124 currentchannel.setBadChannel(badchannel);
125
126 // decode bunches
127 int currentsample = 0;
128 while (currentsample < currentchannel.getPayloadSize() && bunchwords.size() > currentsample + 2) {
129 // Check if bunch word is 0 - if yes skip all following bunches as they can no longer be reliably decoded
130 if (bunchwords[currentsample] == 0) {
131 mMinorDecodingErrors.emplace_back(MinorAltroDecodingError::ErrorType_t::BUNCH_HEADER_NULL, channelheader, 0);
132 break;
133 }
134 int bunchlength = bunchwords[currentsample] - 2, // remove words for bunchlength and starttime
135 starttime = bunchwords[currentsample + 1];
136 // Raise minor decoding error in case the bunch length exceeds the channel payload and skip the bunch
137 if ((unsigned long)bunchlength > bunchwords.size() - currentsample - 2) {
138 mMinorDecodingErrors.emplace_back(MinorAltroDecodingError::ErrorType_t::BUNCH_LENGTH_EXCEED, channelheader, 0);
139 // we must break here as well, the bunch is cut and the pointer would be set to invalid memory
140 break;
141 }
142 // Raise minor decoding error in case the bunch length exceeds the maximum possible amount of samples
143 if ((unsigned int)bunchlength > mMaxBunchLength) {
144 mMinorDecodingErrors.emplace_back(MinorAltroDecodingError::ErrorType_t::BUNCH_LENGTH_ALLOW_EXCEED, channelheader, 0);
145 // Same as above: if the bunch length exceeds the maximum possible bunch length it will for sure conflict with the next bunch
146 break;
147 }
148 // Raise minor decoding error in case the start timne the maximum possible amount of samples (resulting in negative first sample index)
149 if ((unsigned int)starttime > mMaxBunchLength) {
150 mMinorDecodingErrors.emplace_back(MinorAltroDecodingError::ErrorType_t::BUNCH_STARTTIME, channelheader, 0);
151 // Also here we must break, out-of-bounds start time will create troubles in the raw fit
152 break;
153 }
154 if (bunchlength == 0) {
155 // skip bunches with bunch size 0, they don't contain any payload
156 // Map error type to NULL header since header word is null
157 mMinorDecodingErrors.emplace_back(MinorAltroDecodingError::ErrorType_t::BUNCH_HEADER_NULL, channelheader, 0);
158 // Forward position by bunch header size
159 currentsample += bunchlength + 2;
160 continue;
161 }
162 auto& currentbunch = currentchannel.createBunch(bunchlength, starttime);
163 currentbunch.initFromRange(gsl::span<uint16_t>(&bunchwords[currentsample + 2], std::min((unsigned long)bunchlength, bunchwords.size() - currentsample - 2)));
164 currentsample += bunchlength + 2;
165 }
166 }
167 mChannelsInitialized = true;
168}
169
170bool AltroDecoder::checkChannelHWAddress(int hwaddress)
171{
172 unsigned int branch = Channel::getBranchIndexFromHwAddress(hwaddress),
173 fec = Channel::getFecIndexFromHwAddress(hwaddress),
174 altro = Channel::getAltroIndexFromHwAddress(hwaddress);
175 if (branch > 1) {
176 return false;
177 }
178 if (fec > 9) {
179 return false;
180 }
181 if (fec > 0) { // fec == 0 corresponds to trigger, which only has a fake altro information. Hence it's not checked
182 if (!(altro == 0 || altro == 2 || altro == 3 || altro == 4)) {
183 return false;
184 }
185 }
186 return true;
187}
188
190{
191 if (!mRCUTrailer.isInitialized()) {
193 }
194 return mRCUTrailer;
195}
196
197const std::vector<Channel>& AltroDecoder::getChannels() const
198{
199 if (!mChannelsInitialized) {
201 }
202 return mChannels;
203}
204
206
208{
209
210 int errorNumber = -1;
211
212 switch (errortype) {
213 case AltroErrType::RCU_TRAILER_ERROR:
214 errorNumber = 0;
215 break;
216 case AltroErrType::RCU_VERSION_ERROR:
217 errorNumber = 1;
218 break;
219 case AltroErrType::RCU_TRAILER_SIZE_ERROR:
220 errorNumber = 2;
221 break;
222 case AltroErrType::ALTRO_BUNCH_HEADER_ERROR:
223 errorNumber = 3;
224 break;
225 case AltroErrType::ALTRO_BUNCH_LENGTH_ERROR:
226 errorNumber = 4;
227 break;
228 case AltroErrType::ALTRO_PAYLOAD_ERROR:
229 errorNumber = 5;
230 break;
231 case AltroErrType::ALTRO_MAPPING_ERROR:
232 errorNumber = 6;
233 break;
234 case AltroErrType::CHANNEL_ERROR:
235 errorNumber = 7;
236 break;
237
238 default:
239 break;
240 }
241
242 return errorNumber;
243}
244
246{
247 assert(errornumber < getNumberOfErrorTypes());
248
249 AltroErrType errorType;
250
251 switch (errornumber) {
252 case 0:
253 errorType = AltroErrType::RCU_TRAILER_ERROR;
254 break;
255 case 1:
256 errorType = AltroErrType::RCU_VERSION_ERROR;
257 break;
258 case 2:
259 errorType = AltroErrType::RCU_TRAILER_SIZE_ERROR;
260 break;
261 case 3:
262 errorType = AltroErrType::ALTRO_BUNCH_HEADER_ERROR;
263 break;
264 case 4:
265 errorType = AltroErrType::ALTRO_BUNCH_LENGTH_ERROR;
266 break;
267 case 5:
268 errorType = AltroErrType::ALTRO_PAYLOAD_ERROR;
269 break;
270 case 6:
271 errorType = AltroErrType::ALTRO_MAPPING_ERROR;
272 break;
273 case 7:
274 errorType = AltroErrType::CHANNEL_ERROR;
275 break;
276 default:
277 break;
278 }
279
280 return errorType;
281}
282
284{
285 switch (errortype) {
286 case AltroErrType::RCU_TRAILER_ERROR:
287 return "RCUTrailerError";
288 case AltroErrType::RCU_VERSION_ERROR:
289 return "RCUTrailerVersionError";
290 case AltroErrType::RCU_TRAILER_SIZE_ERROR:
291 return "RCUTrailerSizeError";
292 case AltroErrType::ALTRO_BUNCH_HEADER_ERROR:
293 return "BunchHeaderError";
294 case AltroErrType::ALTRO_BUNCH_LENGTH_ERROR:
295 return "BunchLengthError";
296 case AltroErrType::ALTRO_PAYLOAD_ERROR:
297 return "ALTROPayloadError";
298 case AltroErrType::ALTRO_MAPPING_ERROR:
299 return "ALTROMappingError";
300 case AltroErrType::CHANNEL_ERROR:
301 return "ChannelError";
302 };
303 return "";
304}
305
307{
308 switch (errortype) {
309 case AltroErrType::RCU_TRAILER_ERROR:
310 return "RCU Trailer";
311 case AltroErrType::RCU_VERSION_ERROR:
312 return "RCU Version";
313 case AltroErrType::RCU_TRAILER_SIZE_ERROR:
314 return "RCU Trailer Size";
315 case AltroErrType::ALTRO_BUNCH_HEADER_ERROR:
316 return "ALTRO Bunch Header";
317 case AltroErrType::ALTRO_BUNCH_LENGTH_ERROR:
318 return "ALTRO Bunch Length";
319 case AltroErrType::ALTRO_PAYLOAD_ERROR:
320 return "ALTRO Payload";
321 case AltroErrType::ALTRO_MAPPING_ERROR:
322 return "ALTRO Mapping";
323 case AltroErrType::CHANNEL_ERROR:
324 return "Channel";
325 };
326 return "";
327}
328
330{
331 switch (errortype) {
332 case AltroErrType::RCU_TRAILER_ERROR:
333 return "RCU trailer decoding error";
334 case AltroErrType::RCU_VERSION_ERROR:
335 return "Inconsistent RCU trailer version";
336 case AltroErrType::RCU_TRAILER_SIZE_ERROR:
337 return "Invalid RCU trailer size";
338 case AltroErrType::ALTRO_BUNCH_HEADER_ERROR:
339 return "Inconsistent bunch header";
340 case AltroErrType::ALTRO_BUNCH_LENGTH_ERROR:
341 return "Bunch length exceeding payload size";
342 case AltroErrType::ALTRO_PAYLOAD_ERROR:
343 return "Payload could not be decoded";
344 case AltroErrType::ALTRO_MAPPING_ERROR:
345 return "Invalid hardware address in ALTRO mapping";
346 case AltroErrType::CHANNEL_ERROR:
347 return "Channels not initizalized";
348 };
349 return "";
350}
351
352std::string MinorAltroDecodingError::what() const noexcept
353{
354 std::stringstream result;
355 result << getErrorTypeDescription(mErrorType);
356 auto address = mChannelHeader & 0xFFF,
357 payload = (mChannelHeader >> 16) & 0x3FF;
358 bool good = (mChannelHeader >> 29) & 0x1;
359
360 result << " Channel header=0x" << std::hex << mChannelHeader
361 << " (Address=0x" << address << ", payload " << std::dec << payload << ", good " << (good ? "yes" : "no") << ")"
362 << ", word=0x" << std::hex << mPayloadWord << std::dec;
363 return result.str();
364}
365
367
369{
370
371 int errorNumber = -1;
372
373 switch (errortype) {
374 case MinorAltroErrType::CHANNEL_END_PAYLOAD_UNEXPECT:
375 errorNumber = 0;
376 break;
377 case MinorAltroErrType::CHANNEL_PAYLOAD_EXCEED:
378 errorNumber = 1;
379 break;
380 case MinorAltroErrType::CHANNEL_ORDER:
381 errorNumber = 2;
382 break;
383 case MinorAltroErrType::CHANNEL_HEADER:
384 errorNumber = 3;
385 break;
386 case MinorAltroErrType::BUNCH_HEADER_NULL:
387 errorNumber = 4;
388 break;
389 case MinorAltroErrType::BUNCH_LENGTH_EXCEED:
390 errorNumber = 5;
391 break;
392 case MinorAltroErrType::BUNCH_LENGTH_ALLOW_EXCEED:
393 errorNumber = 6;
394 break;
395 case MinorAltroErrType::BUNCH_STARTTIME:
396 errorNumber = 7;
397 break;
398 };
399
400 return errorNumber;
401}
402
404{
405 assert(errornumber < getNumberOfErrorTypes());
406 MinorAltroErrType errorType;
407
408 switch (errornumber) {
409 case 0:
410 errorType = MinorAltroErrType::CHANNEL_END_PAYLOAD_UNEXPECT;
411 break;
412 case 1:
413 errorType = MinorAltroErrType::CHANNEL_PAYLOAD_EXCEED;
414 break;
415 case 2:
416 errorType = MinorAltroErrType::CHANNEL_ORDER;
417 break;
418 case 3:
419 errorType = MinorAltroErrType::CHANNEL_HEADER;
420 break;
421 case 4:
422 errorType = MinorAltroErrType::BUNCH_HEADER_NULL;
423 break;
424 case 5:
425 errorType = MinorAltroErrType::BUNCH_LENGTH_EXCEED;
426 break;
427 case 6:
428 errorType = MinorAltroErrType::BUNCH_LENGTH_ALLOW_EXCEED;
429 break;
430 case 7:
431 errorType = MinorAltroErrType::BUNCH_STARTTIME;
432 break;
433 default:
434 break;
435 }
436
437 return errorType;
438}
439
441{
442 switch (errortype) {
443 case MinorAltroErrType::CHANNEL_END_PAYLOAD_UNEXPECT:
444 return "ChannelEndPayloadUnexpected";
445 case MinorAltroErrType::CHANNEL_PAYLOAD_EXCEED:
446 return "ChannelPayloadExceed";
447 case MinorAltroErrType::CHANNEL_ORDER:
448 return "ChannelOrderError";
449 case MinorAltroErrType::CHANNEL_HEADER:
450 return "ChannelHeader";
451 case MinorAltroErrType::BUNCH_HEADER_NULL:
452 return "BunchHeaderNull";
453 case MinorAltroErrType::BUNCH_LENGTH_EXCEED:
454 return "BunchLengthExceed";
455 case MinorAltroErrType::BUNCH_LENGTH_ALLOW_EXCEED:
456 return "BunchLengthAllowExceed";
457 case MinorAltroErrType::BUNCH_STARTTIME:
458 return "BunchStarttimeExceed";
459 };
460 return "";
461}
462
464{
465 switch (errortype) {
466 case MinorAltroErrType::CHANNEL_END_PAYLOAD_UNEXPECT:
467 return "Channel end unexpected";
468 case MinorAltroErrType::CHANNEL_PAYLOAD_EXCEED:
469 return "Channel exceed";
470 case MinorAltroErrType::CHANNEL_ORDER:
471 return "FEC order";
472 case MinorAltroErrType::CHANNEL_HEADER:
473 return "Channel header invalid";
474 case MinorAltroErrType::BUNCH_HEADER_NULL:
475 return "Bunch header null";
476 case MinorAltroErrType::BUNCH_LENGTH_EXCEED:
477 return "Bunch length exceed";
478 case MinorAltroErrType::BUNCH_LENGTH_ALLOW_EXCEED:
479 return "Bunch length impossible";
480 case MinorAltroErrType::BUNCH_STARTTIME:
481 return "Bunch starttime exceed";
482 };
483 return "";
484}
485
487{
488 switch (errortype) {
489 case MinorAltroErrType::CHANNEL_END_PAYLOAD_UNEXPECT:
490 return "Unexpected end of payload in altro channel payload!";
491 case MinorAltroErrType::CHANNEL_PAYLOAD_EXCEED:
492 return "Trying to access out-of-bound payload!";
493 case MinorAltroErrType::CHANNEL_ORDER:
494 return "Invalid FEC order";
495 case MinorAltroErrType::CHANNEL_HEADER:
496 return "Invalid channel header";
497 case MinorAltroErrType::BUNCH_HEADER_NULL:
498 return "Bunch header 0 or not configured!";
499 case MinorAltroErrType::BUNCH_LENGTH_EXCEED:
500 return "Bunch length exceeding channel payload size!";
501 case MinorAltroErrType::BUNCH_LENGTH_ALLOW_EXCEED:
502 return "Bunch length exceeding max. possible bunch size!";
503 case MinorAltroErrType::BUNCH_STARTTIME:
504 return "Bunch start time outside range!";
505 };
506 return "";
507}
508
509std::ostream& o2::emcal::operator<<(std::ostream& stream, const AltroDecoderError& error)
510{
511 stream << error.what();
512 return stream;
513}
514
515std::ostream& o2::emcal::operator<<(std::ostream& stream, const AltroDecoderError::ErrorType_t& errortype)
516{
518 return stream;
519}
520
521std::ostream& o2::emcal::operator<<(std::ostream& stream, const MinorAltroDecodingError& error)
522{
523 stream << error.what();
524 return stream;
525}
526
527std::ostream& o2::emcal::operator<<(std::ostream& stream, const MinorAltroDecodingError::ErrorType_t& errortype)
528{
530 return stream;
531}
Error handling of the ALTRO Decoder.
ErrorType_t
Error codes connected with the ALTRO decoding.
@ RCU_TRAILER_SIZE_ERROR
RCU trailer size length.
@ CHANNEL_ERROR
Channels not initialized.
@ RCU_TRAILER_ERROR
RCU trailer cannot be decoded or invalid.
static int errorTypeToInt(ErrorType_t errortype)
convert the error type from symoblic constant into int
static ErrorType_t intToErrorType(int errornumber)
convert the error from number into a type (symbolic constant)
static constexpr int getNumberOfErrorTypes() noexcept
Get the number of error types handled by the AltroDecoderError.
static const char * getErrorTypeTitle(ErrorType_t errortype)
Get the title connected to the error type.
const char * what() const noexcept override
Access to error message cnnected to the error.
static const char * getErrorTypeDescription(ErrorType_t errortype)
Get the description connected to the error type.
static const char * getErrorTypeName(ErrorType_t errortype)
Get the name connected to the error type.
void decode()
Decode the ALTRO stream.
const RCUTrailer & getRCUTrailer() const
Get reference to the RCU trailer object.
void readRCUTrailer()
Read RCU trailer for the current event in the raw buffer.
const std::vector< Channel > & getChannels() const
Get the reference to the channel container.
AltroDecoder(RawReaderMemory &reader)
Constructor.
void readChannels()
Read channels for the current event in the raw buffer.
static int getAltroIndexFromHwAddress(int hwaddress)
Extracting ALTRO index from the hardware address.
Definition Channel.h:167
static int getFecIndexFromHwAddress(int hwaddress)
Extracting FEC index in branch from the hardware address.
Definition Channel.h:163
static int getBranchIndexFromHwAddress(int hwaddress)
Extracting branch index from the hardware address.
Definition Channel.h:159
Error handling for the ALTRO decoder for non-crashing errors.
static const char * getErrorTypeTitle(ErrorType_t errortype)
Get the title connected to the error type.
ErrorType_t
Error codes connected with the ALTRO decoding.
@ CHANNEL_ORDER
Channels not in increasing order.
@ BUNCH_LENGTH_ALLOW_EXCEED
Exceeds maximum allowed bunch length.
@ BUNCH_STARTTIME
Bunch start time exceeding.
@ BUNCH_LENGTH_EXCEED
Bunch length exceeding channel payload size.
@ CHANNEL_END_PAYLOAD_UNEXPECT
Unexpected end of payload (channel or trailer word in bunch words)
@ CHANNEL_PAYLOAD_EXCEED
Exceeding channel payload block.
static ErrorType_t intToErrorType(int errornumber)
convert the error from number into a type (symbolic constant)
static int errorTypeToInt(ErrorType_t errortype)
convert the error type from symoblic constant into int
static const char * getErrorTypeDescription(ErrorType_t errortype)
Get the description connected to the error type.
std::string what() const noexcept
Create and return error message for different error types.
static const char * getErrorTypeName(ErrorType_t errortype)
Get the name connected to the error type.
static constexpr int getNumberOfErrorTypes() noexcept
Get the number of error types handled by the AltroDecoderError.
Error handling of the RCU trailer.
Definition RCUTrailer.h:80
const char * what() const noexcept override
Access to the error message.
Definition RCUTrailer.h:104
Information stored in the RCU trailer.
Definition RCUTrailer.h:75
void constructFromRawPayload(const gsl::span< const uint32_t > payloadwords)
Decode RCU trailer from the 32-bit words in the raw buffer.
uint32_t getTrailerSize() const
Get the trailer size in number of DDL (32 bit) words.
Definition RCUTrailer.h:150
bool isInitialized() const
checlks whether the RCU trailer is initialzied
Definition RCUTrailer.h:374
const std::vector< uint32_t > & getPayloadWords() const
Get the payload words (as 32 bit words) contributing to the current payload.
Definition RawPayload.h:67
Reader for raw data produced by the Readout application in in-memory format.
const RawPayload & getPayload() const
access to the full raw payload (single or multiple DMA pages)
GLuint GLuint64EXT address
Definition glcorearb.h:5846
GLuint64EXT * result
Definition glcorearb.h:5662
GLuint buffer
Definition glcorearb.h:655
GLuint GLuint stream
Definition glcorearb.h:1806
std::ostream & operator<<(std::ostream &stream, const Cell &cell)
Stream operator for EMCAL cell.
Definition Cell.cxx:355