12#ifndef ALICEO2_ITSMFT_ALPIDE_CODER_H
13#define ALICEO2_ITSMFT_ALPIDE_CODER_H
23#include <fmt/format.h>
30#define ALPIDE_DECODING_STAT
77 static constexpr int NRows = 512;
79 static constexpr int NCols = 1024;
113 static bool isData(uint16_t
v) {
return (
v & (0x1 << 15)) == 0; }
114 static bool isData(uint8_t
v) {
return (
v & (0x1 << 7)) == 0; }
127 template <
class T,
typename CG>
133 bool needSorting =
false;
134 auto roErrHandler = [&chipData](uint8_t roErr) {
135#ifdef ALPIDE_DECODING_STAT
150 uint8_t dataC = 0, timestamp = 0;
151 uint16_t dataS = 0, region = 0;
152#ifdef ALPIDE_DECODING_STAT
153 uint16_t rowPrev = 0xffff;
157 std::uint16_t rightColHits[
NRows];
158 std::uint16_t colDPrev = 0xffff;
164 while (
buffer.next(dataC)) {
166 LOGP(
debug,
"dataC: {:#x} expect {:#b}",
int(dataC),
int(expectInp));
170#ifdef ALPIDE_DECODING_STAT
176#ifdef ALPIDE_DECODING_STAT
183 uint16_t chipIDGlo = cidGetter(dataC &
MaskChipID);
184 if (chipIDGlo == 0xffff) {
186#ifdef ALPIDE_DECODING_STAT
191 return unexpectedEOF(
"CHIP_EMPTY:WrongChipID");
194 if (!
buffer.next(timestamp)) {
195#ifdef ALPIDE_DECODING_STAT
198 return unexpectedEOF(
"CHIP_EMPTY:Timestamp");
200 seenChips.push_back(chipIDGlo);
207 uint16_t chipIDGlo = cidGetter(dataC &
MaskChipID);
208 if (chipIDGlo == 0xffff) {
210#ifdef ALPIDE_DECODING_STAT
215 return unexpectedEOF(
"CHIP_EMPTY:WrongChipID");
218 if (!
buffer.next(timestamp)) {
219#ifdef ALPIDE_DECODING_STAT
222 return unexpectedEOF(
"CHIP_HEADER");
238#ifdef ALPIDE_DECODING_STAT
247 for (
int ihr = 0; ihr < nRightCHits; ihr++) {
248 addHit(chipData, rightColHits[ihr], colDPrev);
259 if (!
buffer.next(dataC)) {
260#ifdef ALPIDE_DECODING_STAT
263 return unexpectedEOF(
"CHIPDATA");
266 LOGP(
debug,
"dataC: {:#x} dataS: {:#x} expect {:#b} in ExpectData",
int(dataC),
int(dataS),
int(expectInp));
273 uint16_t
row = pixID >> 1;
275 uint16_t colD = (region *
NDColInReg + dColID) << 1;
276 bool rightC = (
row & 0x1) ? !(pixID & 0x1) : (pixID & 0x1);
278 if (colD == colDPrev) {
280 if (
row == rowPrev) {
282#ifdef ALPIDE_DECODING_STAT
284 chipData.
addErrorInfo((uint64_t(colD + rightC) << 16) | uint64_t(
row));
286 }
else if (rowPrev < 0xffff &&
row < rowPrev) {
287#ifdef ALPIDE_DECODING_STAT
289 chipData.
addErrorInfo((uint64_t(colD + rightC) << 16) | uint64_t(
row));
291 return unexpectedEOF(
"DECREASING_ROW");
295 uint8_t hitsPattern = 0;
296 if (!
buffer.next(hitsPattern)) {
297#ifdef ALPIDE_DECODING_STAT
300 return unexpectedEOF(
"CHIP_DATA_LONG:Pattern");
303#ifdef ALPIDE_DECODING_STAT
306 return unexpectedEOF(
"CHIP_DATA_LONG:Pattern");
308 LOGP(
debug,
"hitsPattern: {:#b} expect {:#b}",
int(hitsPattern),
int(expectInp));
315 if (colD < colDPrev && colDPrev != 0xffff) {
316#ifdef ALPIDE_DECODING_STAT
319 return unexpectedEOF(
"Wrong column order");
323 for (
int ihr = 0; ihr < nRightCHits; ihr++) {
324 addHit(chipData, rightColHits[ihr], colDPrev);
335 rightColHits[nRightCHits++] =
row;
337 addHit(chipData,
row, colD);
341 uint8_t hitsPattern = 0;
342 if (!
buffer.next(hitsPattern)) {
343#ifdef ALPIDE_DECODING_STAT
346 return unexpectedEOF(
"CHIP_DATA_LONG:Pattern");
348 LOGP(
debug,
"hitsPattern: {:#b} expect {:#b}",
int(hitsPattern),
int(expectInp));
350#ifdef ALPIDE_DECODING_STAT
353 return unexpectedEOF(
"CHIP_DATA_LONG:Pattern");
356 if (hitsPattern & (0x1 << ip)) {
357 uint16_t addr = pixID + ip + 1, rowE = addr >> 1;
359#ifdef ALPIDE_DECODING_STAT
362 return unexpectedEOF(fmt::format(
"Non-existing encoder {} decoded, DataLong was {:x}", pixID, dataS));
364 rightC = ((rowE & 0x1) ? !(addr & 0x1) : (addr & 0x1));
367 rightColHits[nRightCHits++] = rowE;
369 addHit(chipData, rowE, colD);
375#ifdef ALPIDE_DECODING_STAT
379#ifdef ALPIDE_DECODING_STAT
382 return unexpectedEOF(fmt::format(
"Expected DataShort or DataLong mask, got {:x}", dataS));
393 return unexpectedEOF(
"Abandon on 0-padding");
404#ifdef ALPIDE_DECODING_STAT
407 return unexpectedEOF(
"Trailer after header");
412 bool fatalAPE =
false;
415#ifdef ALPIDE_DECODING_STAT
419 return unexpectedEOF(fmt::format(
"APE error {:#02x} [expectation = {:#02x}]",
int(dataC),
int(expectInp)));
421 LOGP(error,
"Code should not have entered here, APE: {:#02x}, expectation: {:#02x}", codeAPE,
int(expectInp));
422 return unexpectedEOF(fmt::format(
"APE error {:#02x} [expectation = {:#02x}]",
int(dataC),
int(expectInp)));
425#ifdef ALPIDE_DECODING_STAT
428 const uint8_t* begPtr =
buffer.data();
429 const uint8_t* endPtr =
buffer.getEnd();
430 const uint8_t* curPtr =
buffer.getPtr();
433 std::memcpy(chipData.
getRawErrBuff().data(), curPtr - offsBack, offsBack + offsAfter);
436 return unexpectedEOF(fmt::format(
"Unknown word 0x{:x} [expectation = 0x{:x}]",
int(dataC),
int(expectInp)));
440#ifdef ALPIDE_DECODING_STAT
443 return unexpectedEOF(
"Missing CHIP_TRAILER");
446 if (needSorting && chipData.
getData().size()) {
447 LOGP(error,
"This code path should have been disabled");
448 auto& pixData = chipData.
getData();
449 std::sort(pixData.begin(), pixData.end(),
450 [](
PixelData&
a,
PixelData&
b) { return a.getCol() < b.getCol() || (a.getCol() == b.getCol() && a.getRowDirect() < b.getRowDirect()); });
452 auto currPix = pixData.begin(), prevPix = currPix++;
453 while (currPix != pixData.end()) {
454 if (prevPix->getCol() == currPix->getCol() && prevPix->getRowDirect() == currPix->getRowDirect()) {
455 currPix = pixData.erase(prevPix);
460 if (chipData.
getData().size()) {
461 seenChips.push_back(chipData.
getChipID());
463 return chipData.
getData().size();
468 template <
typename LG,
typename CG>
471 std::vector<uint16_t>& seenChipIDs, LG lidGetter, CG cidGetter)
476 int bufferLength = 0;
477 for (
auto it = seenChips.begin(); it != seenChips.end(); ++it) {
478 bufferLength += it->second->getData().size();
480 bufferLength += seenChipIDs.size() * 2;
484 for (
int ID : seenChipIDs) {
486 int localID = lidGetter(
ID);
487 if (seenChips.count(
ID)) {
488 currentChip = *seenChips[
ID];
491 encoder.
encodeChip(reconstructedData, currentChip, localID,
497 reconstructedData.
fill(0x00,
500 auto hexToString = [](uint8_t
v) {
501 std::stringstream ss;
502 ss <<
"0x" << std::setfill(
'0') << std::setw(2) << std::hex
503 << std::uppercase << (0xFF &
v);
507 auto reportError = [&](std::string
message) {
508 LOG(error) <<
"Error during decoder verification: " <<
message;
513 while (
buffer.next(dataC)) {
516 LOG(
debug) <<
"Reconstructed Data:";
517 reconstructedData.
rewind();
519 while (reconstructedData.
next(dataC)) {
534 if (seenChipIDs.size())
535 currentChip = seenChips[seenChipIDs[0]];
551 while (nonEmptyBuffer.
next(dataC)) {
553 reportError(
"Buffer sizes mismatch.");
560 reconstructedData.
current(dataRec);
562 if (dataRaw == dataRec) {
565 if (seenChips.count(
ID)) {
566 currentChip = seenChips[
ID];
568 currentChip =
nullptr;
573 reconstructedData.
next(dataRec);
576 reconstructedData.
next(dataRec);
591 LOG(
debug) <<
"Mismatch " << hexToString(dataRaw) <<
" / "
592 << hexToString(dataRec)
593 <<
" was resolved, able to continue verification";
596 LOG(
debug) <<
"Mismatch " << hexToString(dataRaw) <<
" / "
597 << hexToString(dataRec)
598 <<
" was expected, aborting the verification";
603 std::stringstream errorStream;
605 <<
"Unexpected byte mismatch during decoder verification. "
607 << hexToString(dataRaw)
608 <<
", Reconstructed: " << hexToString(dataRec);
609 reportError(errorStream.str());
630 reconstructedData.
current(dataRec);
632 auto inner = [&](
int errIdx) {
634 dataRaw == dataRec) {
686 if (dataRaw == errorByte) {
691 while (
buffer.next(dataRaw)) {
692 if (dataRaw != 0x00) {
728 LOG(error) <<
"Unknown error set by chip during verifier mismatch";
752 uint16_t chipInModule, uint16_t
bc, uint16_t roflags = 0);
757 buffer.addFast(makeChipEmpty(chipInMod,
bc));
778 void addPixel(
short row,
short col)
780 int last = mPix2Encode.size();
781 mPix2Encode.emplace_back(
row,
col);
782 if (last &&
row == mPix2Encode[last - 1].
row) {
783 mPix2Encode[
last - 1].nextInRow =
last;
785 mFirstInRow.push_back(last);
790 static uint16_t makeChipHeader(
short chipID,
short bc)
798 static uint8_t makeChipTrailer(
short roflags)
805 static uint16_t makeChipEmpty(
short chipID,
short bc)
813 static uint8_t makeRegion(
short reg)
820 static uint16_t makeDataShort(
short encoder,
short address)
827 static uint16_t makeDataLong(
short encoder,
short address)
834 int procDoubleCol(PayLoadCont&
buffer,
short reg,
short dcol);
837 int procRegion(PayLoadCont&
buffer,
short reg)
841 nfound += procDoubleCol(
buffer, reg, idc);
849 static int unexpectedEOF(
const std::string&
message)
858 static const NoiseMap* mNoisyPixels;
861 std::vector<int> mFirstInRow;
862 std::vector<PixLink> mPix2Encode;
Alpide Chip and GBT link decoding statistics.
Definition of the ITSMFT NoiseMap.
Declaration of class for continuos buffer of ALPIDE data.
Transient data classes for single pixel and set of pixels from current chip.
static constexpr int RowMask
static bool isData(uint8_t v)
static constexpr uint32_t MaskReserved
static constexpr uint32_t ERROR_MASK
static constexpr uint32_t DATASHORT
static constexpr uint32_t MaskEncoder
static constexpr uint32_t CHIPEMPTY
static bool verifyDecodedCable(std::map< int, ChipPixelData * > &seenChips, PayLoadCont &buffer, std::vector< uint16_t > &seenChipIDs, LG lidGetter, CG cidGetter)
static uint8_t bc2TimeStamp(int bc)
static uint16_t timeStamp2BC(uint8_t ts)
static constexpr uint32_t BUSYOFF
static constexpr uint32_t MaskChipID
static constexpr int NDColInReg
static constexpr int NCols
static bool isData(uint16_t v)
static bool isChipHeader(uint8_t v)
static constexpr uint8_t MaskErrFatal
static constexpr uint32_t BUSYON
static constexpr uint32_t REGION_MASK
int encodeChip(PayLoadCont &buffer, const o2::itsmft::ChipPixelData &chipData, uint16_t chipInModule, uint16_t bc, uint16_t roflags=0)
static VerifierMismatchResult handleVerifierMismatch(PayLoadCont &buffer, PayLoadCont &reconstructedData, ChipPixelData *currentChip)
static constexpr int EOFFlag
static constexpr uint32_t ExpectChipEmpty
static constexpr uint32_t MaskROFlags
static constexpr uint8_t MaskErrDataOverrun
static bool isEmptyChip(uint8_t b)
static constexpr uint32_t ExpectBUSY
static constexpr uint32_t MaskHitMap
static constexpr uint32_t REGION
static constexpr uint8_t MaskErrBusyViolation
static constexpr uint32_t CHIPHEADER
static constexpr uint32_t CHIPTRAILER
static void setNoisyPixels(const NoiseMap *noise)
static bool isChipEmpty(uint8_t v)
static constexpr uint8_t MaskErrStrobeExtended
static constexpr uint32_t ExpectChipHeader
static constexpr uint32_t ExpectRegion
static constexpr uint32_t DATALONG
static constexpr uint32_t ExpectData
static constexpr uint32_t MaskTimeStamp
void addEmptyChip(PayLoadCont &buffer, int chipInMod, int bc)
static constexpr int HitMapSize
static constexpr uint32_t MaskDColID
static constexpr uint32_t MaskRegion
static constexpr uint32_t MaskPixID
static constexpr uint8_t MaskErrFlushedIncomplete
static constexpr int NRegions
static constexpr uint32_t ExpectNextChip
static int decodeChip(ChipPixelData &chipData, T &buffer, std::vector< uint16_t > &seenChips, CG cidGetter)
decode alpide data for the next non-empty chip from the buffer
static constexpr int NRows
static constexpr uint32_t ExpectChipTrailer
static constexpr int Error
static bool isChipTrailer(uint8_t v)
static bool isChipHeaderOrEmpty(uint8_t v)
check if the byte corresponds to chip_header or chip_empty flag
static constexpr size_t MAXDATAERRBYTES
uint8_t getROFlags() const
void setError(ChipStat::DecErrors i)
void setErrorInfo(uint64_t b)
void setNBytesInRawBuff(int n)
void setChipID(uint16_t id)
void setROFlags(uint8_t f=0)
void addErrorInfo(uint64_t b)
static constexpr size_t MAXDATAERRBYTES_AFTER
uint16_t getChipID() const
const std::vector< PixelData > & getData() const
void forEachSetError(Func f) const
NoiseMap class for the ITS and MFT.
bool isNoisy(int chip, int row, int col) const
void ensureFreeCapacity(size_t n)
fill n bytes with given symbol w/o checking for the size
void rewind()
move all data between the mPtr and mEnd to the head of the buffer
size_t getSize() const
get offset of the current ptr from the head
void fill(const uint8_t c, size_t n)
add n bytes to the buffer, expand if needed. no check for overlap
bool next(uint8_t &v)
read short value from buffer
bool isEmpty() const
make buffer empty w/o deallocating it
bool current(uint8_t &v) const
read character value from buffer
< single pixel datum, with possibility to set a flag of pixel being masked out
GLuint GLuint64EXT address
GLboolean GLboolean GLboolean b
GLuint GLsizei const GLchar * message
GLboolean GLboolean GLboolean GLboolean a
uint8_t itsSharedClusterMap uint8_t
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
HitsRecord(uint8_t r, uint8_t dc, uint16_t adr, uint8_t hmap)
ClassDefNV(HitsRecord, 1)
PixLink(short r=0, short c=0, int next=-1)
static int getAPENonCritical(uint8_t c)
static int getAPECode(uint8_t c, bool &ft)
static uint8_t getAPEByte(DecErrors c)
@ APE_RATE_MISSING_TRG_ERROR
@ APE_PENDING_LANE_EVENT_LIMIT
@ APE_LANE_FIFO_OVERFLOW_ERROR
@ APE_PENDING_DETECTOR_EVENT_LIMIT
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"