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 <cstring>
12#include <cstdint>
13#include <boost/format.hpp>
14#include "InfoLogger/InfoLogger.hxx"
16#include "PHOSBase/Geometry.h"
21#include <fairlogger/Logger.h>
22
23using namespace o2::phos;
24
26 std::vector<o2::phos::Cell>& currentCellContainer, std::vector<o2::phos::Cell>& currentTRUContainer)
27{
28 mOutputHWErrors.clear();
29 mOutputFitChi.clear();
30
31 try {
32 auto& header = rawreader.getRawHeader();
33 mddl = o2::raw::RDHUtils::getFEEID(header);
34 } catch (...) {
36 }
37 const std::vector<uint32_t>& payloadwords = rawreader.getPayload().getPayloadWords();
38
39 if (payloadwords.size() == 0) {
41 }
42
43 try {
44 gsl::span<const uint32_t> tmp(payloadwords.data(), payloadwords.size());
45 mRCUTrailer.constructFromRawPayload(tmp);
46 } catch (RCUTrailer::Error& e) {
47 mOutputHWErrors.emplace_back(mddl, kGeneralSRUErr, static_cast<char>(e.getErrorType())); // assign general SRU header errors to non-existing FEE 15
49 }
50
51 try {
52 readChannels(payloadwords, rawFitter, currentCellContainer, currentTRUContainer);
54 mOutputHWErrors.emplace_back(mddl, kGeneralTRUErr, static_cast<char>(e)); // assign general SRU header errors to non-existing FEE 16
55 return e;
56 }
58}
59
60void AltroDecoder::readChannels(const std::vector<uint32_t>& buffer, CaloRawFitter* rawFitter,
61 std::vector<o2::phos::Cell>& currentCellContainer, std::vector<o2::phos::Cell>& currentTRUContainer)
62{
63 int currentpos = 0;
64 mTRUFlags.clear();
65 mTRUDigits.fill(0);
66 mFlag4x4Bitset.reset();
67 mFlag2x2Bitset.reset();
68
69 int payloadend = buffer.size() - mRCUTrailer.getTrailerSize(); // mRCUTrailer.getPayloadSize() was not updated in case of merged pages.
70 // Extract offset from fee configuration
71 short value = mRCUTrailer.getAltroCFGReg1();
72 short offset = (value >> 10) & 0xf;
73 while (currentpos < payloadend) {
74 auto currentword = buffer[currentpos++];
75 ChannelHeader header = {currentword};
76 if (header.mMark != 1) {
77 if (currentword != 0) {
78 short fec = header.mHardwareAddress >> 7 & 0xf; // try to extract FEE number from header
79 short branch = header.mHardwareAddress >> 11 & 0x1;
80 if (fec > 14) {
81 fec = kGeneralSRUErr;
82 }
83 fec += kGeneralTRUErr * branch;
84 mOutputHWErrors.emplace_back(mddl, fec, 5); // 5: channel header error
85 }
86 continue;
87 }
89 int numberofwords = (header.mPayloadSize + 2) / 3;
90 if (numberofwords > payloadend - currentpos) {
91 short fec = header.mHardwareAddress >> 7 & 0xf; // try to extract FEE number from header
92 short branch = header.mHardwareAddress >> 11 & 0x1;
93 if (fec > 14) {
94 fec = kGeneralSRUErr;
95 }
96 fec += kGeneralTRUErr * branch;
97 mOutputHWErrors.emplace_back(mddl, fec, 6); // 6: channel payload error
98 continue;
99 }
100 mBunchwords.clear();
101 int isample = 0;
102 while (isample < header.mPayloadSize) {
103 currentword = buffer[currentpos++];
104 if ((currentword >> 30) != 0) {
105 currentpos--;
106 short fec = header.mHardwareAddress >> 7 & 0xf; // try to extract FEE number from header
107 short branch = header.mHardwareAddress >> 11 & 0x1;
108 if (fec > 14) {
109 fec = kGeneralSRUErr;
110 }
111 fec += kGeneralTRUErr * branch;
112 mOutputHWErrors.emplace_back(mddl, fec, 6); // 6: channel payload error
113 break;
114 }
115 mBunchwords.push_back((currentword >> 20) & 0x3FF);
116 isample++;
117 if (isample < header.mPayloadSize) {
118 mBunchwords.push_back((currentword >> 10) & 0x3FF);
119 isample++;
120 if (isample < header.mPayloadSize) {
121 mBunchwords.push_back(currentword & 0x3FF);
122 isample++;
123 } else {
124 break;
125 }
126 } else {
127 break;
128 }
129 }
130 short absId;
131 Mapping::CaloFlag caloFlag;
132 if (!hwToAbsAddress(header.mHardwareAddress, absId, caloFlag)) {
133 // do not decode, skip to hext channel
134 short fec = header.mHardwareAddress >> 7 & 0xf; // try to extract FEE number from header
135 short branch = header.mHardwareAddress >> 11 & 0x1;
136 if (fec > 14) {
137 fec = kGeneralSRUErr;
138 }
139 fec += kGeneralTRUErr * branch;
140 mOutputHWErrors.emplace_back(mddl, fec, 7); // 7: wrong hw address
141 continue;
142 }
143
144 // Get time and amplitude
145 if (caloFlag != Mapping::kTRU) { // HighGain or LowGain
146 // decode bunches
147 int currentsample = 0;
148 while (currentsample < header.mPayloadSize) {
149 int bunchlength = mBunchwords[currentsample] - 2, // remove words for bunchlength and starttime
150 starttime = mBunchwords[currentsample + 1];
151 if (bunchlength < 0) { // corrupted data,
152 short fec = header.mHardwareAddress >> 7 & 0xf; // try to extract FEE number from header
153 short branch = header.mHardwareAddress >> 11 & 0x1;
154 fec += kGeneralTRUErr * branch;
155 mOutputHWErrors.emplace_back(mddl, fec, 6); // 6: channel payload error
156 break;
157 }
158 // extract sample properties
159 CaloRawFitter::FitStatus fitResult = rawFitter->evaluate(gsl::span<uint16_t>(&mBunchwords[currentsample + 2], std::min((unsigned long)bunchlength, mBunchwords.size() - currentsample - 2)));
160 currentsample += bunchlength + 2;
161 if (!rawFitter->isOverflow() && rawFitter->getChi2() > 0) { // Overflow is will show wrong chi2
162 short chiAddr = absId;
163 chiAddr |= caloFlag << 14;
164 mOutputFitChi.emplace_back(chiAddr);
165 mOutputFitChi.emplace_back(short(std::min(5.f * rawFitter->getChi2(), float(SHRT_MAX - 1)))); // 0.2 accuracy
166 }
167 if (fitResult == CaloRawFitter::FitStatus::kOK || fitResult == CaloRawFitter::FitStatus::kNoTime) {
168 if (!mPedestalRun) {
169 if (caloFlag == Mapping::kHighGain && !rawFitter->isOverflow()) {
170 currentCellContainer.emplace_back(absId, std::max(rawFitter->getAmp() - offset, float(0)),
171 (rawFitter->getTime() + starttime - bunchlength - mPreSamples) * o2::phos::PHOSSimParams::Instance().mTimeTick * 1.e-9, (ChannelType_t)caloFlag);
172 }
173 if (caloFlag == Mapping::kLowGain) {
174 currentCellContainer.emplace_back(absId, std::max(rawFitter->getAmp() - offset, float(0)),
175 (rawFitter->getTime() + starttime - bunchlength - mPreSamples) * o2::phos::PHOSSimParams::Instance().mTimeTick * 1.e-9, (ChannelType_t)caloFlag);
176 }
177 } else { // pedestal, to store RMS, scale in by 1.e-7 to fit range
178 currentCellContainer.emplace_back(absId, std::max(rawFitter->getAmp() - offset, float(0)), 1.e-7 * rawFitter->getTime(), (ChannelType_t)caloFlag);
179 }
180 } // Successful fit
181 } // Bunched of a channel
182 } // HG or LG channel
183 else { // TRU channel
184 // Channels in TRU:
185 // There are 112 readout channels and 12 channels reserved for production flags:
186 // Channels 0-111: channel data readout
187 // Channels 112-123: production flags
189 Mapping::Instance()->hwToAbsId(mddl, header.mHardwareAddress, absId, caloFlag);
190 readTRUDigits(absId, header.mPayloadSize);
191 } else {
192 readTRUFlags(header.mHardwareAddress, header.mPayloadSize);
193 }
194 } // TRU channel
195 }
196
197 if (mKeepTruNoise) { // copy all TRU digits and TRU flags for noise scan
198 // TRU flags are copied with 4x4 mark
199 for (const Cell cFlag : mTRUFlags) {
200 currentTRUContainer.emplace_back(cFlag);
201 currentTRUContainer.back().setType(TRU4x4);
202 }
203 // Copy digits with 2x2 mark
204 for (int itru = 0; itru < 224; itru++) {
205 if (mTRUDigits[itru] > 0) {
206 short absId = Mapping::NCHANNELS + 224 * mddl + itru + 1;
207 truDigitPack dp = {mTRUDigits[itru]};
208 float a = dp.mAmp, t = dp.mTime;
209 currentTRUContainer.emplace_back(absId, a, t, TRU2x2);
210 }
211 }
212 } else {
213 // Find matching of Flags and truDigits and create output
214 // if trigger cell exists and the trigger flag true -add it
215 // Normally we have few ~2-4 digits and flags per event
216 // no need for clever algoritm here
217 // One 2x2 tru digit can contribute several 4x4 TRU flags
218 for (const Cell cFlag : mTRUFlags) {
219 float sum = 0;
220 if (matchTruDigits(cFlag, sum)) {
221 currentTRUContainer.emplace_back(cFlag);
222 currentTRUContainer.back().setEnergy(sum);
223 }
224 }
225 }
226}
227
228bool AltroDecoder::hwToAbsAddress(short hwAddr, short& absId, Mapping::CaloFlag& caloFlag)
229{
230 // check hardware address and convert to absId and caloFlag
231
232 if (mddl < 0 || mddl > o2::phos::Mapping::NDDL) {
233 return (char)4;
234 }
235 // short chan = hwAddr & 0xf;
236 short chip = hwAddr >> 4 & 0x7;
237 short fec = hwAddr >> 7 & 0xf;
238 short branch = hwAddr >> 11 & 0x1;
239
240 short e2 = 0;
241 if (fec > 14) {
242 e2 = 2;
243 fec = kGeneralSRUErr;
244 mOutputHWErrors.emplace_back(mddl, fec + branch * kGeneralTRUErr, 2);
245 } else {
246 if (fec != 0 && (chip < 0 || chip > 4 || chip == 1)) { // Do not check for TRU (fec=0)
247 e2 = 3;
248 mOutputHWErrors.emplace_back(mddl, fec + branch * kGeneralTRUErr, 3);
249 }
250 }
251
252 if (e2) {
253 return false;
254 }
255 // correct hw address, try to convert
256 Mapping::ErrorStatus s = Mapping::Instance()->hwToAbsId(mddl, hwAddr, absId, caloFlag);
257 if (s != Mapping::ErrorStatus::kOK) {
258 mOutputHWErrors.emplace_back(mddl, branch * kGeneralTRUErr + kGeneralSRUErr, 4); // 4: error in mapping
259 return false;
260 }
261 return true;
262}
263
264void AltroDecoder::readTRUDigits(short absId, int payloadSize)
265{
266 int currentsample = 0;
267 short maxAmp = 0;
268 int timeBin = 0;
269 while (currentsample < payloadSize) {
270 int bunchlength = mBunchwords[currentsample] - 2; // remove words for bunchlength and starttime
271 if (bunchlength < 0) { // corrupted sample: add error and ignore the reast of bunchwords
272 // 1: wrong TRU header
273 mOutputHWErrors.emplace_back(mddl, kGeneralTRUErr, static_cast<char>(1));
274 return;
275 }
276 timeBin = mBunchwords[currentsample + 1] - bunchlength;
277 int istart = currentsample + 2;
278 int iend = std::min(istart + bunchlength - 2, static_cast<int>(mBunchwords.size()));
279 for (int i = istart; i < iend; i++) {
280 if (maxAmp < mBunchwords[i]) {
281 maxAmp = mBunchwords[i];
282 }
283 }
284 currentsample += bunchlength + 2;
285 }
286 truDigitPack dp = {0};
287 dp.mHeader = -1;
288 dp.mAmp = maxAmp;
289 dp.mTime = timeBin;
290 int chId = (absId - Mapping::NCHANNELS - 1) % 224;
291 mTRUDigits[chId] = dp.mDataWord;
292}
293void AltroDecoder::readTRUFlags(short hwAddress, int payloadSize)
294{
295 // Production flags:
296 // Production flags are supplied in channels 112 - 123
297 // Each of the channels is 10 bit wide
298 // The bits inside the channel (indexing starting from the first bit of channel 112) is as follows:
299 // Bits 0-111: Trigger flags for corresponding channel index
300 // If using 4x4 algorithm, only 91 first bits are used of these
301 // information about used trigger is stored in channel 123
302 // Bit 112: Marker for 4x4 algorithm (1 active, 0 not active)
303 // Bit 113: Marker for 2x2 algorithm (1 active, 0 not active)
304 // Bit 114: Global L0 OR of all patches in the TRU
305 const int kWordLength = 10; // Length of one data word in TRU raw data
306 int currentsample = 0;
307 while (currentsample < payloadSize) {
308 int bunchlength = mBunchwords[currentsample] - 2; // remove words for bunchlength and starttime
309 if (bunchlength < 1) { // corrupted sample: add error and ignore the rest of bunchwords
310 // 1: wrong TRU header
311 mOutputHWErrors.emplace_back(mddl, kGeneralTRUErr, static_cast<char>(1));
312 return;
313 }
314 int timeBin = mBunchwords[currentsample + 1] + 1; // +1 for further convenience
315 int istart = currentsample + 2;
316 int iend = istart + std::min(bunchlength, static_cast<int>(mBunchwords.size()) - currentsample - 2);
317 currentsample += bunchlength + 2;
318
319 if (timeBin >= 128 || timeBin < 1) { // corrupted sample: add error and try to read next
320 // 2: wrong TRU payload
321 mOutputHWErrors.emplace_back(mddl, kGeneralTRUErr, static_cast<char>(2)); // PAYLOAD_DECODING
322 continue;
323 }
324
325 if (timeBin <= iend - istart) {
326 // 2: wrong TRU payload
327 mOutputHWErrors.emplace_back(mddl, kGeneralTRUErr, static_cast<char>(2)); // PAYLOAD_DECODING
328 continue;
329 }
330
331 for (int i = iend - 1; i >= istart; i--) {
332 --timeBin;
333 short a = mBunchwords[i];
334
335 // Assign the bits in the words to corresponding channels
336 for (Int_t bitIndex = 0; bitIndex < kWordLength; bitIndex++) {
337 // Find the correct channel number assuming that
338 // hwAddress 112 = bits 0-9 corresponding trigger flags in channels 0-9
339 // hwAddress 113 = bits 10-19 corresponding trigger flags in channels 10-19
340 // and so on
341 short channel;
342 if (hwAddress < 128) {
343 channel = (hwAddress - Mapping::NTRUBranchReadoutChannels) * kWordLength + bitIndex;
344 } else {
345 channel = 112 + (hwAddress - 2048 - Mapping::NTRUBranchReadoutChannels) * kWordLength + bitIndex; // branch 0
346 }
347 if (hwAddress == Mapping::TRUFinalProductionChannel || hwAddress == Mapping::TRUFinalProductionChannel + 2048) {
348 // fill 4x4 or 2x2 flags
349 if ((a & (1 << 2)) > 0) {
350 mFlag4x4Bitset[timeBin] = 1;
351 }
352 if ((a & (1 << 3)) > 0) { // bit 113 2x2 trigger
353 mFlag2x2Bitset[timeBin] = 1;
354 }
355 } else {
356 short absId;
358 if (a & (1 << bitIndex)) {
359 ChannelType_t trFlag = TRU4x4;
360 if (mFlag4x4Bitset[timeBin]) {
361 trFlag = TRU4x4;
362 if ((channel > 90 && channel < 112) || channel > 202) { // no such channels in 4x4 trigger
363 continue;
364 }
365 } else {
366 if (mFlag2x2Bitset[timeBin]) {
367 trFlag = TRU2x2;
368 } else { // trigger was not fired at all at this time bin
369 continue;
370 }
371 }
372 Mapping::Instance()->hwToAbsId(mddl, channel, absId, fl);
373 // Prepare TRU cell with zero yet amplitude
374 if (mTRUFlags.size() > 0 && mTRUFlags.back().getTRUId() == absId) { // Just added, set earliest time
375 mTRUFlags.back().setTime(timeBin * o2::phos::PHOSSimParams::Instance().mTRUTimeTick * 1.e-9);
376 } else {
377 mTRUFlags.emplace_back(absId, timeBin * o2::phos::PHOSSimParams::Instance().mTRUTimeTick * 1.e-9, 0., trFlag);
378 }
379 }
380 }
381 } // Bits in one word
382 } // Length of signal
383 }
384}
385bool AltroDecoder::matchTruDigits(const Cell& cTruFlag, float& sumAmp)
386{
387 // Check if TRU digit matches with TRU flag
388 // return true if at least one matched
389 // and sum of amplitudes
390 // TODO Should we check time as well? So far keep time of summary table mark
391 if (cTruFlag.getType() == TRU2x2) { // direct match of channel ID
392 short ch = (cTruFlag.getTRUId() - Mapping::NCHANNELS - 1) % 224;
393 if (mTRUDigits[ch] > 0) {
394 truDigitPack dp = {mTRUDigits[ch]};
395 sumAmp = dp.mAmp;
396 return true;
397 } else {
398 sumAmp = 0.;
399 return false;
400 }
401 }
402 if (cTruFlag.getType() == TRU4x4) { // direct match of channel ID
403 char relid[3];
404 Geometry::truAbsToRelNumbering(cTruFlag.getTRUId(), 1, relid); // 1 for 4x4 trigger
405 bool found = false;
406 sumAmp = 0.;
407 short ch = Geometry::truRelToAbsNumbering(relid, 0); // first 2x2 tile
408 ch = (ch - Mapping::NCHANNELS - 1) % 224;
409 if (mTRUDigits[ch] != 0) {
410 truDigitPack dp = {mTRUDigits[ch]};
411 sumAmp += dp.mAmp;
412 found = true;
413 }
414 relid[1] += 2;
415 ch = Geometry::truRelToAbsNumbering(relid, 0); // another 2x2 tile
416 ch = (ch - Mapping::NCHANNELS - 1) % 224;
417 if (mTRUDigits[ch] != 0) {
418 truDigitPack dp = {mTRUDigits[ch]};
419 sumAmp += dp.mAmp;
420 found = true;
421 }
422 relid[2] += 2;
423 ch = Geometry::truRelToAbsNumbering(relid, 0); // another 2x2 tile
424 ch = (ch - Mapping::NCHANNELS - 1) % 224;
425 if (mTRUDigits[ch] != 0) {
426 truDigitPack dp = {mTRUDigits[ch]};
427 sumAmp += dp.mAmp;
428 found = true;
429 }
430 relid[1] -= 2;
431 ch = Geometry::truRelToAbsNumbering(relid, 0); // another 2x2 tile
432 ch = (ch - Mapping::NCHANNELS - 1) % 224;
433 if (mTRUDigits[ch] != 0) {
434 truDigitPack dp = {mTRUDigits[ch]};
435 sumAmp += dp.mAmp;
436 found = true;
437 }
438 return found;
439 }
440 // Not applicable for non-TRU cells
441 return false;
442}
int32_t i
@ RCU_TRAILER_ERROR
RCU trailer cannot be decoded or invalid.
AltroDecoderError::ErrorType_t decode(RawReaderMemory &rawreader, CaloRawFitter *rawFitter, std::vector< o2::phos::Cell > &cellContainer, std::vector< o2::phos::Cell > &truContainer)
Decode the ALTRO stream.
void readChannels(const std::vector< uint32_t > &payloadwords, CaloRawFitter *rawFitter, std::vector< o2::phos::Cell > &cellContainer, std::vector< o2::phos::Cell > &truContainer)
Read channels for the current event in the raw buffer.
bool isOverflow() const
is last fitted sample has overflow
virtual FitStatus evaluate(gsl::span< short unsigned int > signal)
Evaluation Amplitude and TOF return status -1: not evaluated/empty bunch; 0: OK; 1: overflow; 4: sing...
float getChi2() const
Chi2/NDF of last performed fit.
float getTime() const
time in last fitted sample
float getAmp() const
amplitude in last fitted sample
short getTRUId() const
Definition Cell.cxx:55
ChannelType_t getType() const
Definition Cell.cxx:174
static short truRelToAbsNumbering(const char *relId, short trigType)
Definition Geometry.cxx:118
static bool truAbsToRelNumbering(short truId, short trigType, char *relid)
Definition Geometry.cxx:83
static constexpr short NDDL
Total number of DDLs.
Definition Mapping.h:45
static Mapping * Instance()
Definition Mapping.cxx:29
static constexpr short NTRUBranchReadoutChannels
Number of TRU readout channels per branch.
Definition Mapping.h:46
static bool isTRUReadoutchannel(short hwAddress)
Definition Mapping.h:112
static constexpr short NCHANNELS
Number of channels starting from 1.
Definition Mapping.h:42
static constexpr short TRUFinalProductionChannel
Definition Mapping.h:48
ErrorStatus hwToAbsId(short ddl, short hw, short &absId, CaloFlag &caloFlag) const
convert hardware address to absId and caloFlag
Definition Mapping.cxx:54
Error handling of the.
Definition RCUTrailer.h:61
ErrorType_t getErrorType() const noexcept
Access to error code.
Definition RCUTrailer.h:89
void constructFromRawPayload(const gsl::span< const uint32_t > payloadwords)
Decode RCU trailer from the 32-bit words in the raw buffer.
unsigned int getTrailerSize() const
Definition RCUTrailer.h:129
unsigned int getAltroCFGReg1() const
Definition RCUTrailer.h:126
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 o2::header::RDHAny & getRawHeader() const
access to the raw header of the current page
const RawPayload & getPayload() const
access to the full raw payload (single or multiple DMA pages)
float sum(float s, o2::dcs::DataPointValue v)
Definition dcs-ccdb.cxx:39
GLuint buffer
Definition glcorearb.h:655
GLsizei const GLfloat * value
Definition glcorearb.h:819
GLintptr offset
Definition glcorearb.h:660
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
ChannelType_t
Definition Cell.h:51
@ TRU4x4
TRU channel, 4x4 trigger.
Definition Cell.h:55
@ TRU2x2
TRU channel, 2x2 trigger.
Definition Cell.h:54
float mTimeTick
ns to PHOS digitization step conversion
uint32_t mMark
Bits 30 - 30: Mark header.
Definition RCUTrailer.h:34
uint32_t mHardwareAddress
Bits 0 - 15: Hardware address.
Definition RCUTrailer.h:30
uint32_t mPayloadSize
Bits 16 - 25: Payload size.
Definition RCUTrailer.h:31