ATLAS Offline Software
Loading...
Searching...
No Matches
L1CaloBsDecoderRun3.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
4#include <algorithm>
5#include <bitset>
6#include <iostream>
7#include <iomanip>
8#include <map>
9#include <vector>
10
11#include "eformat/ROBFragment.h"
12
21#include "defsL1Calo/EfexDefs.h"
23#ifndef OFFLINE_DECODER
24#include "bytestreamDecoder/L1CaloRdoGfexTob.h"
25#include "bytestreamDecoder/L1CaloRdoGfexTower.h"
26#include "bytestreamDecoder/L1CaloRdoJfexTob.h"
27#include "bytestreamDecoder/L1CaloRdoJfexTower.h"
28#include "bytestreamDecoder/L1CaloRdoMuonTob.h" // **FIXME** Different class for run 3?
29#include "bytestreamDecoder/L1CaloRdoPh1TopoHit.h"
30#include "channelMappings/GfexCellMapping.h"
31#include "channelMappings/JfexCellMapping.h"
32#include "defsL1Calo/FexDefs.h"
33#include "infraL1Calo/GfexLatomeCentralFibrePacker.h"
34#include "infraL1Calo/GfexLatomeForwardFibrePacker.h"
35#include "infraL1Calo/GfexTrexFibrePacker.h"
36#include "infraL1Calo/JfexLatomeFibrePacker.h"
37#include "infraL1Calo/JfexTrexFibrePacker.h"
38#endif
39
40#define LOG_ERROR(location,title,detail) { if(m_logger) { std::stringstream s; s << location; std::stringstream s2; s2<<title; std::stringstream s3; s3<<detail; m_logger->err(s.str(),s2.str(),s3.str().empty() ? s2.str() : s3.str()); } }
41
47
49: m_verbosity(0), m_logger(std::make_unique<Logging>())
50{
51
52 // Force initialisation of mapping tables.
53 EfexCellMapping dummyEfexMapping(0,0,0,0,0,0);
54 if (!dummyEfexMapping.getDetectorRegion().getValidity()) {
55 LOG_ERROR("ctor", "unexpected invalid eFEX mapping!?","");
56 }
57#ifndef OFFLINE_DECODER
58 JfexCellMapping dummyJfexMapping(0,1,0,0); // Processor number 1-4
59 if (!dummyJfexMapping.getDetectorRegion().getValidity()) {
60 LOG_ERROR("ctor", "unexpected invalid jFEX mapping!?","");
61 }
62 GfexCellMapping dummyGfexMapping(0,0,0,0); // Processor number 0-2?
63 if (!dummyGfexMapping.getDetectorRegion().getValidity()) {
64 LOG_ERROR("ctor","unexpected invalid gFEX mapping!?","");
65 }
66#endif
67}
68
84void
85L1CaloBsDecoderRun3::decodeEfexData( const uint32_t* beg, const uint32_t* end,
86 std::list<L1CaloRdoEfexTower>& tower,
87 std::list<L1CaloRdoRodInfo>::const_iterator rodInfo ) const
88{
89 const uint32_t* payload( beg );
90 const size_t fragmentSize = end - beg;
91
92 // The data block is optimised for production by firmware with the length
93 // in a trailer at the end. The SWROD concatenates a number of such blocks
94 // (removing the 2 word header used to fill the ROD fragment header).
95 // So we need to find the end and work backwards.
96
97 size_t numTowers = tower.size();
98 size_t index = fragmentSize;
99
100 // Loop looking backwards for eFEX processor input data blocks.
101 while ( index > 0 ) {
102 if ( index < 4 ) {
103 LOG_ERROR("decodeEfexData", "block size error",
104 "remaining block size " << index
105 << " is too small for the eFEX FPGA trailer");
106 return;
107 }
108 const uint32_t ctrlTrailer2 = payload[--index];
109 const uint32_t ctrlTrailer1 = payload[--index];
110 const uint32_t fpgaTrailer2 = payload[--index];
111 const uint32_t fpgaTrailer1 = payload[--index];
112
113 const uint32_t ctrlErrors = ctrlTrailer2 & 0x3f;
114 const uint32_t efexNumber = (ctrlTrailer1 >> 12) & 0xf;
115 const uint32_t shelfNumber = (ctrlTrailer1 >> 16) & 0x1; // Just use 1 bit from 4 bit field
116 const size_t payloadSize = (ctrlTrailer1 & 0xfff) - 2;
117
118 if ( payloadSize > index ) {
119 LOG_ERROR("decodeEfexData", "block size error","remaining eFEX block size "
120 << index << " is too small for the claimed payload size "
121 << payloadSize);
122 return;
123 }
124
125 if (efexNumber >= CrateDefs::numAtcaFexSlots() ) {
126 LOG_ERROR("decodeEfexData","invalid eFEX number " << efexNumber,
127 " (out of range 0-" << CrateDefs::numAtcaFexSlots()-1 << ")");
128 return;
129 }
130
131 // We can now work forwards from the start of this block
132 // decoding each set of 8 words per input fibre channel.
133 // The payloadSize has had two trailer words subtracted.
134 index -= payloadSize;
135 size_t chanIndex = 0;
136 uint32_t chanErrorOR = 0;
137 std::bitset<49> chansWithError;
138 bool anyErrorBit = false;
139 while ( chanIndex < payloadSize ) {
140 if ( (payloadSize - chanIndex) < 8 ) {
141 LOG_ERROR("decodeEfexData s" << shelfNumber << " e" << efexNumber,"block size error",
142 (payloadSize - chanIndex)<< " is too small for one eFEX input fibre block (8)");
143 return;
144 }
145 const uint32_t chanNumber = payload[index+chanIndex+7] & 0xff;
146 const uint32_t chanErrors = this->decodeEfexDataChan ( &payload[index+chanIndex], efexNumber, shelfNumber,
147 ctrlErrors, tower, rodInfo );
148 if ( chanErrors ) {
149 chanErrorOR |= ( chanErrors & 0x7 ); // Only three lowest bits get ORed
150 chansWithError[chanNumber] = 1;
151 anyErrorBit = true;
152 }
153 chanIndex += 8;
154 }
155 if ( anyErrorBit ) {
156 chanErrorOR |= 0x8; // Extra bit set if any of the three lower bits are set
157 }
158 const uint64_t fpgaErrorBits = ( (uint64_t)(fpgaTrailer2 & 0x1ffff) << 32 ) | fpgaTrailer1;
159 const uint64_t chanErrorBits = chansWithError.to_ullong();
160 const uint32_t fpgaErrorOR = ( fpgaTrailer2 >> 28 ) & 0xf;
161 if ( fpgaErrorBits != chanErrorBits || fpgaErrorOR != chanErrorOR ) {
162 LOG_ERROR("decodeEfexData: s" << shelfNumber << " e" << efexNumber,"errorbit mismatch",
163 "mismatch between errors in FPGA trailer: "
164 << std::hex << fpgaErrorBits << " " << fpgaErrorOR
165 << " and those derived from channels: " << chanErrorBits << " " << chanErrorOR
166 << std::dec);
167 }
168 }
169 if ( m_verbosity > 0 )
170 {
171 std::cout << "L1CaloBsDecoderRun3::decodeEfexData: n.towers added="
172 << tower.size() - numTowers << std::endl;
173 }
174}
175
186uint32_t
188 const uint32_t efexNumber, const uint32_t shelfNumber,
189 const uint32_t errorMask,
190 std::list<L1CaloRdoEfexTower>& tower,
191 std::list<L1CaloRdoRodInfo>::const_iterator rodInfo ) const
192{
193 // The EM and hadronic fibres have different encoding and cover
194 // different numbers of towers with more or less granularity.
195 // Channel numbers 0-39 are EM, 40-48 are hadronic.
196 const uint32_t chanNumber = ( payload[7] ) & 0xff;
197 const uint32_t fpgaNumber = ( payload[7] >> 8 ) & 0x3;
198 const uint32_t errorBits = ( payload[7] >> 28 ) & 0x7;
199 const uint32_t disabled = ( payload[7] >> 31 ) & 0x1;
200 if ((int)chanNumber >= EfexDefs::numInputFibresPerFpga()) {
201 LOG_ERROR("decodeEfexDataChan s" << shelfNumber << "e" << efexNumber << "f" << fpgaNumber, "invalid channel",
202 chanNumber << " (out of range 0-" << EfexDefs::numInputFibresPerFpga()-1 << ")");
203 return 0xffffffff;
204 }
205
206 // Some endcap channels are inactive and have the disabled bit set
207 // if the full data is being read out. Just skip these.
208 if (disabled) {
209 return 0;
210 }
211
212 // The EfexCellMapping returns global coordinates but the RDO objects
213 // expect local eta,phi within the module. So prepare these here.
214 // Find local eta,phi from global EfexCellMapping and module offset.
215 // There is no good way of handling the localEta. Below we add one
216 // so the barrel eta has core towers in localEta 1-16 with 0 and 17
217 // being core towers on C and A sides. Overlap towers extend further
218 // and both localEta and localPhi may be negative.
219 int moduleEta = -24 + (efexNumber % 3) * 16;
220 int modulePhi = 2 + (shelfNumber * 32) + (efexNumber / 3) * 8;
221
222 // The fibre packer decoder methods expect a vector of seven words.
223 std::vector<FibrePackerBase::myDataWord> encodedData;
224 for ( size_t i = 0; i < 7; i++ ) {
225 encodedData.push_back( payload[i] );
226 }
228
229 // Build up error flag for towers on this fibre.
230 // Bits 0-5 from ROD block trailer
231 // Bit 7 fibre CRC error flag
232 // Bits 8-10 from fibre trailer
233 bool rightCRC = this->checkFibreCRC( encodedData );
234 const uint32_t errorField = ( errorMask & 0x3f )
235 | ( rightCRC ? 0 : 0x80 )
236 | ( errorBits << 8 );
237
238 if (chanNumber < 40) {
239 // Each EM fibre has 10 supercells for each of two 0.1*0.1 trigger towers.
240 // The EfexLatomeFibrePacker returns the complete set of 20 supercells.
242 std::vector<FibrePackerBase::myDataWord> cells = packer.getUnpackedData( encodedData, frameType );
243
244 // Create two tower RDOs, each containing half the supercells.
245 // NB all the middle layer supercells come first, then the rest
246 // for each tower: 4xM0, 4xM1, P0,4xF0,B0, P1,4xF1,B1.
247 // Hard code this to avoid too many calls to EfexCellMapping.
248 // We just call it with the first supercell word for each tower.
249 const std::vector<uint32_t> cellIndex = { 0, 1, 2, 3, 8, 9,10,11,12,13, // Tower0: MMMMPFFFFB
250 4, 5, 6, 7,14,15,16,17,18,19 }; // Tower1: MMMMPFFFFB
251 for ( size_t k = 0; k < 2; k++ ) {
252 std::vector<uint32_t> towerCells( 10, 0 );
253 uint32_t towerSumEt( 0 );
254 uint32_t wordNumber = 0;
255 for (size_t i = 0; i < 10; i++) {
256 uint32_t iCell = cellIndex[i+k*10];
257 if (i == 0) {
258 wordNumber = iCell;
259 }
260 towerCells[i] = cells[iCell];
261 towerSumEt += towerCells[i];
262 }
263
264 // **FIXME** Fibre packer does not yet return quality bits!
265 // There should be one per middle layer supercell.
266 // We can OR those with error bits for this fibre.
267 uint32_t towerFlag = errorField;
268
269 if ( true/*towerSumEt || towerFlag*/ ) { // commented out zero suppression of towers, so that we can recognise case when we do not have a tower
270 EfexCellMapping mapping( shelfNumber, efexNumber, fpgaNumber, chanNumber, wordNumber );
271 L1CaloDetectorRegion region = mapping.getDetectorRegion();
272 EfexHardwareInfo hwInfo( mapping.getHardwareInfo() );
273 if ( region.getValidity() && hwInfo.getValidity() ) {
274 int localEta = region.getEtaIndex() - moduleEta + 1;
275 int localPhi = region.getPhiIndex() - modulePhi;
276
277 const uint32_t layer = 0; // EM
278 L1CaloRdoEfexTower newOne( shelfNumber, efexNumber, localEta, localPhi, layer, region );
279 newOne.setRodInfo( rodInfo );
280 L1CaloRdoEfexTower& rdo = L1CaloBsDecoderUtil::findRdo( newOne, tower );
281
282 rdo.setHardwareInfo( fpgaNumber, chanNumber, wordNumber,
283 hwInfo.getMpodNumber(), hwInfo.getFibreNumber(),
284 hwInfo.getOverlap() );
285 rdo.setValue( towerSumEt );
286 rdo.setFlag( towerFlag );
287 rdo.setSupercells( towerCells );
288 if ( m_verbosity > 0 )
289 {
290 std::cout << "L1CaloBsDecoderRun3::decodeEfexDataChan: EM"
291 << ", shelf=" << shelfNumber << ", module=" << efexNumber
292 << std::hex << ", Et=0x" << towerSumEt << ", flag=0x" << towerFlag
293 << std::dec << std::endl;
294 }
295 }
296 }
297 }
298 }
299
300 else {
301 // Each hadronic fibre has a 4*4 array of 16 towers.
302 EfexTrexFibrePacker packer;
303 std::vector<FibrePackerBase::myDataWord> towerVals = packer.getUnpackedData( encodedData, frameType );
304 size_t numHadTowers = std::min(towerVals.size(),(size_t)16);
305
306 // Create an RDO for each tower.
307 for ( size_t wordNumber = 0; wordNumber < numHadTowers; wordNumber++ ) {
308 const uint32_t towerEt = ( towerVals[wordNumber] == 0x3fe ) ? 0 : towerVals[wordNumber];
309 const uint32_t invalid = ( towerVals[wordNumber] == 0x3fe ) ? 1 : 0;
310 const uint32_t towerFlag = errorMask | ( invalid << 31 );
311
312 if ( true/*towerEt || towerFlag*/ ) { // commented out zero suppression of towers, so that we can recognise case when we do not have a tower
313 EfexCellMapping mapping( shelfNumber, efexNumber, fpgaNumber, chanNumber, wordNumber );
314 L1CaloDetectorRegion region = mapping.getDetectorRegion();
315 EfexHardwareInfo hwInfo( mapping.getHardwareInfo() );
316 if ( region.getValidity() && hwInfo.getValidity() ) {
317 // Need to decide if data is Tile/TREX or HEC/LATOME as TREX tower Et is still
318 // limited to 8 bits, at least for the start of Run 3, as in Runs 1 & 2.
319 // After the legacy CP/JEP system is decommissioned this may change to enable
320 // use of the full 10 bit field.
321 if ( (region.getEtaIndex() >= -15) && (region.getEtaIndex() < 15) ) { // Tile/TREX
322 towerVals[wordNumber] &= 0xff;
323 }
324
325 int localEta = region.getEtaIndex() - moduleEta + 1;
326 int localPhi = region.getPhiIndex() - modulePhi;
327
328 const uint32_t layer = 1; // Hadronic
329 L1CaloRdoEfexTower newOne( shelfNumber, efexNumber, localEta, localPhi, layer, region );
330 newOne.setRodInfo( rodInfo );
331 L1CaloRdoEfexTower& rdo = L1CaloBsDecoderUtil::findRdo( newOne, tower );
332
333 rdo.setHardwareInfo( fpgaNumber, chanNumber, wordNumber,
334 hwInfo.getMpodNumber(), hwInfo.getFibreNumber(),
335 hwInfo.getOverlap() );
336 rdo.setValue( towerEt );
337 rdo.setFlag( towerFlag );
338 if ( m_verbosity > 0 )
339 {
340 std::cout << "L1CaloBsDecoderRun3::decodeEfexDataChan: Had"
341 << ", shelf=" << shelfNumber << ", module=" << efexNumber
342 << std::hex << ", Et=0x" << towerEt << ", flag=0x" << towerFlag
343 << std::dec << std::endl;
344 }
345 }
346 }
347 }
348 }
349
350 return errorBits;
351}
352
362void
363L1CaloBsDecoderRun3::decodeEfexTobs( const uint32_t* beg, const uint32_t* end,
364 std::list<L1CaloRdoEfexTob>& tob,
365 std::list<L1CaloRdoRodInfo>::const_iterator rodInfo ) const
366{
367 const uint32_t* payload( beg );
368 const size_t fragmentSize = end - beg;
369
370 // The data block is optimised for production by firmware as a set
371 // of nested blocks with the lengths at the end. So we need to find
372 // the end and work backwards.
373
374 if ( fragmentSize < 2 ) {
375 LOG_ERROR("decodeEfexTobs", "ROD trailer fragment size", fragmentSize
376 << " is too small for the ROD trailer");
377 return;
378 }
379
380 size_t index = fragmentSize;
381 const uint32_t rodTrailer2 = payload[--index];
382 const uint32_t rodTrailer1 = payload[--index];
383
384 const uint32_t rodErrors = rodTrailer2 & 0x7f;
385 const size_t payloadSize = rodTrailer1 & 0xffff;
386 if ( (rodErrors >> 6) & 0x1 ) {
387 LOG_ERROR("decodeEfexTobs","Unknown corrective trailer " << std::hex << rodErrors << std::dec,"");
388 return;
389 }
390 if ( (payloadSize + 2) != fragmentSize ) {
391 // Actual ROD fragment payload size does not match that claimed in the trailer.
392 LOG_ERROR("decodeEfexTobs","inconsistent ROD fragment size","payload size " << payloadSize
393 << " vs ROD fragment size " << fragmentSize);
394 return;
395 }
396
397 // Loop looking backwards for eFEX module blocks.
398 while ( index > 0 ) {
399 if ( index < 2 ) {
400 LOG_ERROR("decodeEfexTobs","block size error", index
401 << " is too small for the eFEX trailer");
402 return;
403 }
404 size_t efexIndex = index;
405 const uint32_t efexTrailer2 = payload[--efexIndex];
406 const uint32_t efexTrailer1 = payload[--efexIndex];
407
408 // check if this is actually a ROD corrective trailer instead of
409 // a control trailer
410 const uint32_t corrective = (efexTrailer2 >> 5) & 0x1;
411 if ( corrective ) {
412 // Corrective ROD trailer
413 size_t corrBlockSize = (efexTrailer1) & 0xffff;
414 const uint32_t efexNumber = (efexTrailer1 >> 16) & 0xf;
415 const uint32_t shelfNumber = (efexTrailer1 >> 20) & 0x1;
416 const uint32_t ctrlErr = efexTrailer2 & 0x3f;
417
418 LOG_ERROR("decodeEfexTobs s" << shelfNumber << "e" << efexNumber,
419 "rod corrective trailer " << std::hex << ctrlErr << std::dec,"");
420
421 if (corrBlockSize > index) {
422 LOG_ERROR("decodeEfexTobs s" << shelfNumber << "e" << efexNumber, "excessive rod corrective blocksize",
423 "rod corrective blocksize " << corrBlockSize <<
424 " > remaining blocksize ");
425 return;
426 }
427
428 index -= corrBlockSize; // Ought to be 2
429 continue;
430 }
431
432
433 const size_t efexBlockSize = efexTrailer1 & 0xfff;
434 const uint32_t efexNumber = (efexTrailer1 >> 12) & 0xf;
435 const uint32_t shelfNumber = (efexTrailer1 >> 16) & 0x1; // 4 bit field, but only 1 but used
436 //??const uint32_t procErrMap = (efexTrailer1 >> 20) & 0xf; // Currently unused
437 const uint32_t numSlices = (efexTrailer1 >> 24) & 0xf;
438 //??const uint32_t l1aSlice = (efexTrailer1 >> 28) & 0xf; // Currently unused
439 const uint32_t efexErrors = efexTrailer2 & 0x3f;
440 if ( efexBlockSize > index ) {
441 LOG_ERROR("decodeEfexTobs s" << shelfNumber << "e" << efexNumber,"excessive block size", efexBlockSize
442 << " exceeds remaining data size " << index);
443 return;
444 }
445 // Update index to previous eFEX block (if any).
446 index = efexIndex - efexBlockSize;
447
448 // Combine rod and efex error fields.
449 const uint32_t errorMask = efexErrors | (rodErrors << 6);
450
451 // Loop looking backwards for eFEX processor blocks.
452 // There should be one block per slice per FPGA
453 // (except for errors giving corrective trailers).
454 while ( efexIndex > index ) {
455 if ( (efexIndex - index) < 2 ) {
456 LOG_ERROR("decodeEfexTobs s"<< shelfNumber << "e" << efexNumber,
457 "blocksize deficit",
458 (efexIndex - index) << " is too small for the eFEX slice trailer");
459 return;
460 }
461 size_t procIndex = efexIndex;
462 bool ret = this->decodeEfexTobSlice ( payload, procIndex, efexNumber, shelfNumber,
463 numSlices, errorMask, tob, rodInfo );
464 if ( ! ret ) {
465 return;
466 }
467 efexIndex = procIndex;
468 }
469 }
470}
471
486bool
487L1CaloBsDecoderRun3::decodeEfexTobSlice( const uint32_t payload[], size_t& index,
488 const uint32_t efexNumber, const uint32_t shelfNumber,
489 const uint32_t numSlices, const uint32_t errorMask,
490 std::list<L1CaloRdoEfexTob>& tob,
491 std::list<L1CaloRdoRodInfo>::const_iterator rodInfo ) const
492{
493 if ( index < 1 ) {
494 return false;
495 }
496
497 const uint32_t sliceTrailer = payload[index-1];
498 const uint32_t corrective = (sliceTrailer >> 31) & 0x01;
499
500
501 if ( corrective ) {
502 // Corrective trailer: no data from this processor FPGA.
503 // Not much we can do so just report it and carry on.
504 size_t corrBlockSize = sliceTrailer & 0xfff;
505 //const uint32_t failingBCN = (sliceTrailer >> 12) & 0xfff; - don't print this to avoid too many different error messages
506 const uint32_t fpgaNumber = (sliceTrailer >> 24) & 0x3;
507 const uint32_t plErr = (sliceTrailer >> 30) & 0x01;
508 const uint32_t bcnErr = (sliceTrailer >> 29) & 0x01;
509 LOG_ERROR("decodeEfexTobSlice s" << shelfNumber << "e" << efexNumber << "f" << fpgaNumber,
510 "ctrl corrective trailer " << std::hex << (plErr*2+bcnErr) << std::dec,"error bits: PacketLength=" << plErr << ", BCNMismatch=" << bcnErr);
511 // corrective trailer blockSize doesn't include the trailer itself (length of one)
512 // and also doesn't include padding word (which occurs if the blockSize is even
513 // because the corrective trailer adds one more word and then a padding word is needed
514 corrBlockSize += ((corrBlockSize % 2) == 1) ? 1 : 2;
515
516 if (corrBlockSize > index) {
517 LOG_ERROR("decodeEfexTobSlice s" << shelfNumber << "e" << efexNumber << "f" << fpgaNumber, "excessive ctrl corrective blocksize",
518 "corrective blocksize " << corrBlockSize <<
519 " > remaining blocksize ");
520 return false;
521 }
522
523 index -= corrBlockSize; // Ought to be 2
524 }
525 else {
526 // October 2021: New format implemented! K.Char in lowest 8 bits.
527 const uint32_t tobType = (sliceTrailer >> 8) & 0x1;
528 const uint32_t numTobs = (sliceTrailer >> 9) & 0x7;
529 const uint32_t numEmXtobs = (sliceTrailer >> 12) & 0x3f;
530 const uint32_t numTauXtobs = (sliceTrailer >> 18) & 0x3f;
531 const uint32_t sliceNumber = (sliceTrailer >> 24) & 0x7;
532 const uint32_t safeMode = (sliceTrailer >> 27) & 0x1;
533 const uint32_t fpgaNumber = (sliceTrailer >> 28) & 0x3;
534
535 // Work out how long this block should be. Each TOB is one word,
536 // each XTOB is two words. If the total is odd (including one word
537 // for the trailer) there should be an extra zero padding word.
538 // However in safe mode all the TOBs and XTOBs are suppressed
539 // and we only have the trailer and padding word.
540 size_t tobSize = (safeMode == 0)
541 ? (1 + numTobs + 2 * (numEmXtobs + numTauXtobs))
542 : 2;
543 tobSize += (tobSize % 2);
544
545 // Move index to start of this block.
546 if (tobSize > index) {
547 LOG_ERROR( "decodeEfexTobSlice s" << shelfNumber << "e" << efexNumber << "f" << fpgaNumber,
548 "excessive blocksize",
549 "TOB blocksize " << tobSize << " > remaining blocksize " << index);
550 return false;
551 }
552 index -= tobSize;
553
554 if ( safeMode ) {
555 LOG_ERROR( "decodeEfexTobSlice s" << shelfNumber << "e" << efexNumber << "f" << fpgaNumber,
556 "safe mode",
557 "missed " << numTobs << " TOBs, " << numEmXtobs << " EM XTOBs, "
558 << numTauXtobs << " Tau XTOBs" );
559 }
560 else {
561 // Luxury, we can now work forwards inside the slice block!
562 // We expect first TOBs (if any) then EM xTOBs, then Tau xTOBs.
563 const size_t totalTobs = numTobs + numEmXtobs + numTauXtobs;
564 L1CaloRdoFexTob::TobType fexTobType = (tobType == 0)
568 size_t sliceIndex = index;
569 for (size_t iTOB = 0; iTOB < totalTobs; iTOB++) {
570 if (iTOB >= numTobs) {
572 fexTobType = (iTOB < (numTobs + numEmXtobs))
575 }
576 this->decodeOneEfexTob ( &payload[sliceIndex], shelfNumber, efexNumber, fpgaNumber,
577 errorMask, numSlices, sliceNumber, fexTobType, fexTobSource,
578 tob, rodInfo );
579 // One or two words per TOB or xTOB.
580 sliceIndex += (fexTobSource == L1CaloRdoFexTob::TobSource::EfexTob) ? 1 : 2;
581 }
582 }
583 }
584 return true;
585}
586
593void
594L1CaloBsDecoderRun3::decodeOneEfexTob( const uint32_t word[], const uint32_t shelfNumber,
595 const uint32_t efexNumber, const uint32_t fpgaNumber,
596 const uint32_t errorMask,
597 const uint32_t numSlices, const uint32_t sliceNum,
600 std::list<L1CaloRdoEfexTob>& tob,
601 std::list<L1CaloRdoRodInfo>::const_iterator rodInfo ) const
602{
603 const uint32_t tobWord = word[0];
604 const uint32_t isolInfo = (tobWord ) & 0xffc000;
605 const uint32_t tobPhi = (tobWord >> 24) & 0x7;
606 const uint32_t tobEta = (tobWord >> 27) & 0x7;
607 const uint32_t tobFpga = (tobWord >> 30) & 0x3;
608
609 uint32_t etValue(0);
610 if (tobSource == L1CaloRdoFexTob::TobSource::EfexXtob) {
611 // XTOB: Et from second TOB word.
612 etValue = word[1] & 0xffff;
613 }
614 else { // EfexTob or Ph1Topo
615 // TOB: Et from single TOB word.
616 etValue = tobWord & 0xfff;
617 }
618
619 if ( sliceNum >= numSlices ) {
620 LOG_ERROR("decodeOneEfexTob s" << shelfNumber << "e" << efexNumber << "f" << fpgaNumber,
621 "excessive sliceNum",
622 "TOB slice " << sliceNum << " exceeds number of slices " << numSlices << " in processor trailer");
623 }
624 else if ( etValue ) {
625 // Should already be zero suppressed in the readout
626 // but no harm in making doubly sure.
627 // Add the error bits from the eFEX control FPGA (low 6 bits)
628 // and the error bits from the ROD output packet (low 7 bits)
629 // to the isolation bits (which have the low 14 bits unused).
630 // This probably needs more sophisticated treatment.
631 // The internal eta within one FPGA is in the range 0-5
632 // where 1-4 are the standard values and 0 & 5 are only
633 // used at the extreme eta, ie |eta| > 2.4.
634 // To get an eta within the module we use the range 0-17
635 // where 0 & 17 are only used at the extremes.
636 const uint32_t moduleEta = 1 + (tobEta - 1) + 4 * tobFpga;
637 const uint32_t flagMask = isolInfo | errorMask;
638 L1CaloRdoEfexTob newOne( shelfNumber, efexNumber, moduleEta, tobPhi,
639 numSlices, tobType, tobSource );
640 newOne.setRodInfo( rodInfo );
642 rdo.setValue( etValue, sliceNum );
643 rdo.setFlag( flagMask, sliceNum );
644#ifdef OFFLINE_DECODER
645 // store the raw words - used in offline to construct the EDM objects
646 rdo.setWord0( word[0], sliceNum );
647 if(tobSource == L1CaloRdoFexTob::TobSource::EfexXtob) rdo.setWord1(word[1], sliceNum);
648#endif
649 if ( m_verbosity > 0 )
650 {
651 std::cout << "L1CaloBsDecoderRun3::decodeOneEfexTob: tobType=" << tobType
652 << ", tobSource=" << tobSource << ", slice=" << sliceNum
653 << ", shelf=" << shelfNumber << ", module=" << efexNumber
654 << ", eta=" << moduleEta << ", phi=" << tobPhi
655 << std::hex << ", Et=0x" << etValue << ", flag=0x" << flagMask
656 << std::dec << ", numSlices=" << numSlices << std::endl;
657 }
658 }
659}
660
668bool
669L1CaloBsDecoderRun3::checkFibreCRC( std::vector<uint32_t>& data ) const
670{
671 const size_t numWords = FexDefs::num32BitWordsPerFibre();
672 if ( data.size() != numWords ) {
673 return false;
674 }
675 GenericCrc crc;
676 const size_t numPayloadBits = ( 32 * numWords ) - 9;
677 unsigned int actualCRC = ( data[numWords-1] >> 23 ) & 0x1ff;
678 data[0] &= 0xffffff00; // Zero the K character
679 unsigned int expectCRC = crc.crc9fibre( data, numPayloadBits );
680
681 return (actualCRC == expectCRC);
682}
683
684#ifndef OFFLINE_DECODER
694void
695L1CaloBsDecoderRun3::decodeJfexData( const uint32_t* beg, const uint32_t* end,
696 std::list<L1CaloRdoJfexTower>& tower,
697 std::list<L1CaloRdoRodInfo>::const_iterator rodInfo )
698{
699 const uint32_t* payload( beg );
700 const size_t fragmentSize = end - beg;
701
702 // The data block is optimised for production by firmware with the length
703 // in a trailer at the end. The SWROD concatenates a number of such blocks
704 // (removing the 2 word header used to fill the ROD fragment header).
705 // So we need to find the end and work backwards.
706
707 size_t numTowers = tower.size();
708 size_t index = fragmentSize;
709
710 // Loop looking backwards for jFEX processor input data blocks.
711 while ( index > 0 ) {
712 if ( index < 2 ) {
713 LOG_ERROR("decodeJfexData","","remaining block size " << index
714 << " is too small for the jFEX FPGA trailer");
715 return;
716 }
717 const uint32_t fpgaTrailer2 = payload[--index];
718 const uint32_t fpgaTrailer1 = payload[--index];
719
720 const uint32_t fpgaErrors = fpgaTrailer2 & 0x3f;
721 const uint32_t jfexNumber = (fpgaTrailer1 >> 20) & 0x7;
722 const uint32_t fpgaNumber = (fpgaTrailer1 >> 18) & 0x3;
723 const size_t payloadSize = (fpgaTrailer1 & 0xffff);
724
725 if ( payloadSize > index ) {
726 LOG_ERROR("decodeJfexData","","remaining jFEX block size "
727 << index << " is too small for the claimed payload size "
728 << payloadSize);
729 return;
730 }
731
732 // We can now work forwards from the start of this block
733 // decoding each set of 8 words per input fibre channel.
734 index -= payloadSize;
735 size_t chanIndex = 0;
736 while ( chanIndex < payloadSize ) {
737 if ( (payloadSize - chanIndex) < 8 ) {
738 LOG_ERROR("decodeJfexData","","decodeJfexData: remaining jFEX block size "
739 << (payloadSize - chanIndex)
740 << " is too small for one jFEX input fibre block (8)");
741 return;
742 }
743 this->decodeJfexDataChan ( &payload[index+chanIndex], jfexNumber, fpgaNumber,
744 fpgaErrors, tower, rodInfo );
745 chanIndex += 8;
746 }
747 }
748 if ( m_verbosity > 0 )
749 {
750 std::cout << "L1CaloBsDecoderRun3::decodeJfexData: n.towers added="
751 << tower.size() - numTowers << std::endl;
752 }
753}
754
765uint32_t
767 const uint32_t jfexNumber, const uint32_t fpgaNumber,
768 const uint32_t errorMask,
769 std::list<L1CaloRdoJfexTower>& tower,
770 std::list<L1CaloRdoRodInfo>::const_iterator rodInfo )
771{
772 const uint32_t shelfNumber = 0x22; // Hard code to P1 value (34)
773
774 // The LATOME and TREX fibres have slightly different encoding.
775 // Towards the forward regions and especially FCAL they cover
776 // different numbers of towers with more or less granularity.
777 // Channels 0-23 & 36-59 are standard inputs, 24-35 are overlap.
778 // The HEC overlap minipod (AVR) is #3 of 1-5 in each FPGA.
779 const uint32_t chanNumber = ( payload[7] ) & 0xff;
780 const uint32_t errorBits = ( payload[7] >> 28 ) & 0xf;
781
782 // **FIXME** Ignore overlap for the moment.
783 if (chanNumber >= 24 && // **FIXME** Remove this!
784 chanNumber < 36) { // **FIXME** Remove this!
785 return 0; // **FIXME** Remove this!
786 } // **FIXME** Remove this!
787 // **FIXME** Ignore end jFEX modules for now.
788 if (jfexNumber == 0 || // **FIXME** Remove this!
789 jfexNumber == 5) { // **FIXME** Remove this!
790 return 0; // **FIXME** Remove this!
791 } // **FIXME** Remove this!
792
793 // The JfexCellMapping returns global coordinates but the RDO objects
794 // expect local eta within the module. So prepare this here.
795 // **FIXME** Not sure how to handle internal eta for FCAL (esp C side).
796 int moduleEta = -24 + (jfexNumber % 6) * 8;
797
798 // The fibre packer decoder methods expect a vector of seven words.
799 std::vector<FibrePackerBase::myDataWord> encodedData;
800 for ( size_t i = 0; i < 7; i++ ) {
801 encodedData.push_back( payload[i] );
802 }
804
805 // **FIXME** Need mapping to decide when to use Latome vs TREX decoders.
806 // **FIXME** But they are identical apart from handling of saturation
807 // **FIXME** so for the moment always use Latome.
808
809 bool trex = false; // **FIXME**
810
811 // Unpack sixteen 0.1*0.1 trigger towers.
812 std::vector<FibrePackerBase::myDataWord> towers;
813 if (trex) {
814 JfexTrexFibrePacker packer;
815 towers = packer.getUnpackedData( encodedData, frameType );
816 }
817 else {
818 // Unpack sixteen 0.1*0.1 trigger towers.
819 JfexLatomeFibrePacker packer;
820 towers = packer.getUnpackedData( encodedData, frameType );
821 }
822
823 // Create RDO per tower.
824 for ( size_t iTower = 0; iTower < towers.size(); iTower++ ) {
825 const uint32_t towerEt = towers[iTower];
826
827 if ( towerEt || errorMask ) {
828 // The JfexCellMapping needs the "unit number", ie U1-U4 which
829 // is the FPGA "processor" number in the readout+1. Additionally
830 // the readout uses 0-3 whereas JfexCellMapping expects 1-4.
831 // We also want the fibre number. The (FPGA,chan) JfexCellMapping
832 // constructor returns that (numbered with the whole module).
833 // NB per FPGA minipod (AVR) 1, 2, 4 & 5 are full input data.
834 // Minipod 3 is the overlap one, also used for TTC, IPbus, etc.
835 // The channel (MGT) numbering in the readout is 0-59 which are
836 // the direct fibres. But in firmware and mappings 0-59 are PMA
837 // loopback channels. The direct fibres are actually 60-119.
838 // But for the moment the PMA loopback inputs are not read out
839 // so, except for the mapping lookup, we use 0-59.
840 // The mapping tool prefers zero based FPGA numbers which increment
841 // with increasing phi, so convert back to that style in procNumber.
842 int unitNumber = fpgaNumber + 1;
843 int procNumber = JfexDefs::processorNumberToUnitNumber(unitNumber) - 1;
844 JfexHardwareInfo hwInfoFpga( JfexCellMapping( unitNumber, chanNumber+60 ).getHardwareInfo() );
845 int mgtFibreNumber = hwInfoFpga.getFibreNumber();
846 JfexCellMapping mapping( jfexNumber, unitNumber, mgtFibreNumber, iTower );
847 L1CaloDetectorRegion region = mapping.getDetectorRegion();
848 JfexHardwareInfo hwInfo( mapping.getHardwareInfo() );
849 JfexTriggerTowerInfo ttInfo( mapping.getTriggerTowerInfo() );
850
851 if ( region.getValidity() && hwInfo.getValidity() ) {
852 int layer = (region.getLayer() == L1CaloDetectorRegion::Electromagnetic) ? 0 : 1;
853 int localEta = region.getEtaIndex() - moduleEta;
854 int localPhi = region.getPhiIndex();
855
856 L1CaloRdoJfexTower newOne( shelfNumber, jfexNumber, localEta, localPhi, layer, region );
857 newOne.setRodInfo( rodInfo );
858 L1CaloRdoJfexTower& rdo = L1CaloBsDecoderUtil::findRdo( newOne, tower );
859
860 rdo.setHardwareInfo( procNumber, chanNumber, iTower,
861 hwInfo.getAvr(), hwInfo.getFibreNumber(),
862 ttInfo.isCore() );
863 rdo.setValue( towerEt );
864 rdo.setFlag( errorMask );
865
866 if ( m_verbosity > 0 )
867 {
868 std::cout << "L1CaloBsDecoderRun3::decodeJfexDataChan: "
869 << "module=" << jfexNumber
870 << std::hex << ", Et=0x" << towerEt << ", flag=0x" << errorMask
871 << std::dec << std::endl;
872 }
873 //std::cout << "L1CaloBsDecoderRun3::addJfexTower: fpga=" << fpgaNumber
874 // << ", chan=" << chanNumber << ", word=" << iTower
875 // << ", unit=" << unitNumber
876 // << ", mpod=" << hwInfo.getAvr()
877 // << ", modFibre=" << hwInfo.getFibreNumber()
878 // << ", mgtFibre=" << mgtFibreNumber
879 // << ", regionEta=" << localEta
880 // << ", regionPhi=" << localPhi
881 // << ", layer=" << layer
882 // << ", phiFpga=" << (localPhi/16)
883 // << ", hwFpga=" << hwInfo.getFpgaNumber()
884 // << ", validity=" << region.getValidity()
885 // << ", Et=" << towerEt
886 // << ", errors=0x" << std::hex << errorMask << std::dec
887 // << std::endl;
888 }
889 }
890 }
891
892 return errorBits;
893}
894
904void
905L1CaloBsDecoderRun3::decodeJfexTobs( const uint32_t* beg, const uint32_t* end,
906 std::list<L1CaloRdoJfexTob>& tob,
907 std::list<L1CaloRdoRodInfo>::const_iterator rodInfo )
908{
909 const uint32_t* payload( beg );
910 const size_t fragmentSize = end - beg;
911
912 // The data block is optimised for production by firmware as a set
913 // of nested blocks with the lengths at the end. So we need to find
914 // the end and work backwards.
915
916 if ( fragmentSize < 2 ) {
917 LOG_ERROR("decodeJfexTobs","",": fragment size " << fragmentSize
918 << " is too small for the ROD trailer");
919 return;
920 }
921
922 size_t index = fragmentSize;
923 const uint32_t rodTrailer2 = payload[--index];
924 const uint32_t rodTrailer1 = payload[--index];
925
926 const uint32_t rodErrors = rodTrailer2 & 0x7f;
927 const size_t payloadSize = rodTrailer1 & 0xffff;
928 if ( (payloadSize + 2) != fragmentSize ) {
929 // Actual ROD fragment payload size does not match that claimed in the trailer.
930 LOG_ERROR("decodeJfexTobs","","payload size " << payloadSize
931 << " inconsistent with ROD fragment size " << fragmentSize);
932 return;
933 }
934 //??const uint32_t rodShelfNumber = (rodTrailer1 >> 18) & 0x3;
935
936 // Loop looking backwards for jFEX FPGA blocks.
937 while ( index > 0 ) {
938 if ( index < 2 ) {
939 LOG_ERROR("decodeJfexTobs","","remaining block size " << index
940 << " is too small for the jFEX trailer");
941 return;
942 }
943 size_t fpgaIndex = index;
944 const uint32_t fpgaTrailer2 = payload[--fpgaIndex];
945 const uint32_t fpgaTrailer1 = payload[--fpgaIndex];
946 const size_t fpgaBlockSize = fpgaTrailer1 & 0xffff;
947 const uint32_t jfexNumber = (fpgaTrailer1 >> 20) & 0x7;
948 const uint32_t fpgaNumber = (fpgaTrailer1 >> 18) & 0x3;
949 const uint32_t numSlices = (fpgaTrailer1 >> 24) & 0xf;
950 const uint32_t sliceNumber = (fpgaTrailer1 >> 28) & 0xf;
951 const uint32_t fpgaErrors = fpgaTrailer2 & 0x3f;
952 if ( fpgaBlockSize > index ) {
953 LOG_ERROR("decodeJfexTobs","","jFEX FPGA block size " <<
954 fpgaBlockSize << " exceeds remaining data size " << index
955 << " (jFEX " << jfexNumber << " FPGA " << fpgaNumber << ")");
956 return;
957 }
958 // Update index to previous jFEX FPGA block (if any).
959 index = fpgaIndex - fpgaBlockSize;
960
961 // Combine rod and jfex error fields.
962 const uint32_t errorMask = fpgaErrors | (rodErrors << 6);
963
964 bool ret = this->decodeJfexTobSlice ( payload, fpgaBlockSize, fpgaIndex, jfexNumber, fpgaNumber,
965 sliceNumber, numSlices, errorMask, tob, rodInfo );
966 if ( ! ret ) {
967 return;
968 }
969 }
970}
971
987bool
988L1CaloBsDecoderRun3::decodeJfexTobSlice( const uint32_t payload[], size_t blockSize, size_t& index,
989 const uint32_t jfexNumber, const uint32_t fpgaNumber,
990 const uint32_t sliceNumber, const uint32_t numSlices,
991 const uint32_t errorMask,
992 std::list<L1CaloRdoJfexTob>& tob,
993 std::list<L1CaloRdoRodInfo>::const_iterator rodInfo )
994{
995 if ( index < 2 ) {
996 return false;
997 }
998
999 // **FIXME** TEMP Ignore jfex00 and jfex05 due to data corruption.
1000 if ( jfexNumber == 0 || jfexNumber == 5 ) {
1001 return true;
1002 }
1003
1004 const uint32_t countTrailer1 = payload[index-2];
1005 const uint32_t countTrailer2 = payload[index-1];
1006
1007 // **FIXME** Not sure if jFEX will send corrective trailers?
1008 const uint32_t corrective = 0;
1009 if ( corrective ) {
1010 // **FIXME** To be implemented if required.
1011 }
1012 else {
1013 const uint32_t safeMode = (countTrailer1 ) & 0x1;
1014 const uint32_t numSJetTobs = (countTrailer1 >> 1) & 0x3f;
1015 const uint32_t numLJetTobs = (countTrailer1 >> 7) & 0x3f;
1016 const uint32_t numTauTobs = (countTrailer1 >> 13) & 0x3f;
1017 const uint32_t numElecTobs = (countTrailer1 >> 19) & 0x3f;
1018 const uint32_t numSumEtTobs = (countTrailer1 >> 25) & 0x1;
1019 const uint32_t numMissEtTobs = (countTrailer1 >> 26) & 0x1;
1020 const uint32_t numSJetXtobs = (countTrailer2 >> 1) & 0x3f;
1021 const uint32_t numLJetXtobs = (countTrailer2 >> 7) & 0x3f;
1022 const uint32_t numTauXtobs = (countTrailer2 >> 13) & 0x3f;
1023 const uint32_t numElecXtobs = (countTrailer2 >> 19) & 0x3f;
1024
1025 // Work out how long this block should be. For jFEX both TOBs
1026 // and XTOBs are one word. Apart from the counts of small jets,
1027 // large jets, taus and (forward) electrons there are two TOBs
1028 // for SumEt and MissingEt.
1029 // If the total is odd there should be an extra zero padding word.
1030 // However in safe mode all the TOBs and XTOBs are suppressed
1031 // and we only have the trailer with the counts.
1032
1033 // For ease of later decoding, fill a vector with the end index
1034 // of each type of TOB/XTOB word.
1035 std::vector<size_t> end;
1036 end.push_back( 0 ) ;
1037 if ( !safeMode ) {
1038 end.push_back( end.back() + numSJetTobs );
1039 end.push_back( end.back() + numLJetTobs );
1040 end.push_back( end.back() + numTauTobs );
1041 end.push_back( end.back() + numElecTobs );
1042 end.push_back( end.back() + numSumEtTobs );
1043 end.push_back( end.back() + numMissEtTobs );
1044 end.push_back( end.back() + numSJetXtobs );
1045 end.push_back( end.back() + numLJetXtobs );
1046 end.push_back( end.back() + numTauXtobs );
1047 end.push_back( end.back() + numElecXtobs );
1048 }
1049
1050 size_t tobSize = end.back(); // End of TOBs/XTOBs
1051 tobSize += (tobSize % 2); // Possible padding
1052 tobSize += 2; // Two count words
1053
1054 if ( tobSize != blockSize ) {
1055 LOG_ERROR("decodeJfexTobSlice","",": TOB slice " << sliceNumber
1056 << " has block size " << blockSize << " expected TOBs+counts " << tobSize
1057 << " (jFEX " << jfexNumber << " FPGA " << fpgaNumber << ")");
1058 }
1059 if ( tobSize > index ) {
1060 LOG_ERROR("decodeJfexTobSlice","",": TOB size " << tobSize
1061 << " is larger than index " << index);
1062 return false;
1063 }
1064
1065 size_t numTobs = (safeMode) ? 0 : end[6]; // End index of MissEt TOBs
1066 size_t totalTobs = (safeMode) ? 0 : end.back(); // End index of TOBs+XTOBs
1067
1068 // Move index to start of this block.
1069 index -= tobSize;
1070
1071 // Luxury, we can now work forwards inside the slice block!
1072 size_t sliceIndex = index;
1073 L1CaloRdoFexTob::TobType fexTobType;
1074 L1CaloRdoFexTob::TobSource fexTobSource;
1075 for (size_t iTOB = 0; iTOB < totalTobs; iTOB++) {
1076 // Small jets, taus and electron TOBs and XTOBs
1077 // all have similar structure so extract common
1078 // values and override for other TOB types.
1079 // TOBs and xTOBs now have identical formats
1080 // so first find the TOB type, then process
1081 // the values afterwards.
1082 const uint32_t tobWord = payload[sliceIndex++];
1083 uint32_t flagInfo = (tobWord >> 21) & 0xfff;
1084 uint32_t etValue = (tobWord >> 10) & 0x7ff;
1085 uint32_t tobPhi = (tobWord >> 1) & 0xf;
1086 uint32_t tobEta = (tobWord >> 5) & 0x1f;
1087 fexTobSource = (iTOB < numTobs)
1090 if (iTOB < end[1]) {
1092 } else if (iTOB < end[2]) {
1094 } else if (iTOB < end[3]) {
1095 fexTobType = L1CaloRdoFexTob::TobType::Tau;
1096 } else if (iTOB < end[4]) {
1097 fexTobType = L1CaloRdoFexTob::TobType::EM;
1098 } else if (iTOB < end[6]) {
1100 } else if (iTOB < end[7]) {
1102 } else if (iTOB < end[8]) {
1104 } else if (iTOB < end[9]) {
1105 fexTobType = L1CaloRdoFexTob::TobType::Tau;
1106 } else if (iTOB < end[10]) {
1107 fexTobType = L1CaloRdoFexTob::TobType::EM;
1108 } else {
1109 // Padding word: skip.
1110 continue;
1111 }
1112
1113 if (fexTobType == L1CaloRdoFexTob::TobType::SmallJet) {
1114 flagInfo = 0; // None defined
1115 } else if (fexTobType == L1CaloRdoFexTob::TobType::LargeJet) {
1116 flagInfo = 0; // None defined
1117 etValue = (tobWord >> 10) & 0x1fff;
1118 } else if (fexTobType == L1CaloRdoFexTob::TobType::Energy) {
1119 // **FIXME** SumEt and MissEt to be implemented!
1120 flagInfo = (tobWord & 0x1) | (tobWord & 0x1000) >> 15;
1121 etValue = (tobWord & 0x7ffffffe) >> 1;
1122 tobPhi = 0;
1123 tobEta = 0;
1124 }
1125
1126 // **FIXME** REMOVE THIS TEMPORARY HACK ASAP!!
1127 // **FIXME** Ignore & fix wrong slice numbers.
1128 uint32_t sliceNumberHacked = sliceNumber;
1129 if (numSlices == 1 && sliceNumber == 2) {
1130 sliceNumberHacked = 0;
1131 }
1132 //>>if ( sliceNumber >= numSlices ) {
1133 if ( sliceNumberHacked >= numSlices ) {
1134 LOG_ERROR("decodeJfexTobSlice","",": TOB slice " << sliceNumber
1135 << " exceeds number of slices " << numSlices << " in processor trailer");
1136 }
1137 else if ( etValue || flagInfo ) {
1138 // Should already be zero suppressed in the readout
1139 // but no harm in making doubly sure.
1140 // Add the error bits from the jFEX control FPGA (low 6 bits)
1141 // and the error bits from the ROD output packet (low 7 bits)
1142 // to the isolation bits (shifted up 16 bits).
1143 // This probably needs more sophisticated treatment.
1144 // The reported fpgaNumber is in the U1-U4 order but
1145 // we need the FPGAs ordered by increasing phi.
1146 // **FIXME** Check use of tobEta and adjusted tobPhi by FPGA.
1147 const uint32_t procNumber = JfexDefs::processorNumberToUnitNumber(fpgaNumber+1) - 1;
1148 const uint32_t modulePhi = tobPhi + 16 * procNumber;
1149 const uint32_t flagMask = (flagInfo << 16) | errorMask;
1150 const uint32_t shelfNumber = 0x22; // Hard code to P1 value (34)
1151 L1CaloRdoJfexTob newOne( shelfNumber, jfexNumber, tobEta, modulePhi,
1152 numSlices, fexTobType, fexTobSource );
1153 newOne.setRodInfo( rodInfo );
1154 L1CaloRdoJfexTob& rdo = L1CaloBsDecoderUtil::findRdo( newOne, tob );
1155 //>>rdo.setValue( etValue, sliceNumber );
1156 //>>rdo.setFlag( flagMask, sliceNumber );
1157 rdo.setValue( etValue, sliceNumberHacked );
1158 rdo.setFlag( flagMask, sliceNumberHacked );
1159 if ( m_verbosity > 0 )
1160 {
1161 std::cout << "L1CaloBsDecoderRun3::decodeJfexTobSlice: tobType=" << fexTobType
1162 << ", tobSource=" << fexTobSource << ", slice=" << sliceNumberHacked
1163 << ", module=" << jfexNumber << ", fpga=" << fpgaNumber
1164 << ", proc=" << procNumber << ", eta=" << tobEta << ", phi=" << modulePhi
1165 << std::hex << ", Et=0x" << etValue << ", flag=0x" << flagMask
1166 << std::dec << ", numSlices=" << numSlices << std::endl;
1167 }
1168 }
1169 }
1170 }
1171 return true;
1172}
1173
1183void
1184L1CaloBsDecoderRun3::decodeGfexData( const uint32_t* beg, const uint32_t* end,
1185 std::list<L1CaloRdoGfexTower>& tower,
1186 std::list<L1CaloRdoRodInfo>::const_iterator rodInfo )
1187{
1188 const uint32_t* payload( beg );
1189
1190 // The data block consists of up to three sections, one per processor FPGA.
1191 // Each block starts with a one word header that identifies the FPGA and has
1192 // the block length and a few other fields.
1193
1194 size_t numTowers = tower.size();
1195
1196 // Loop looking backwards for jFEX processor input data blocks.
1197 while ( payload < end ) {
1198 const uint32_t word = *payload++;
1199
1200 // The first word must be the header.
1201
1202 const uint32_t fpgaCode = ( word >> 28 ) & 0xf;
1203 if ( fpgaCode < 0xa || fpgaCode > 0xc ) {
1204 LOG_ERROR("decodeGfexData","","invalid FPGA code 0x"
1205 << std::hex << fpgaCode << std::dec);
1206 return;
1207 }
1208 const uint32_t fpgaNumber = fpgaCode - 0xa; // A=0, B=1, C=2
1209 const uint32_t headerVer = ( word >> 24 ) & 0xf;
1210 const uint32_t headerLen = ( word >> 22 ) & 0x3;
1211 if ( headerVer > 1 || headerLen > 1 ) {
1212 LOG_ERROR("decodeGfexData","",": header version " << headerVer
1213 << " or length " << headerLen << " is not yet supported");
1214 return;
1215 }
1216 const uint32_t truncatedFlag = (word >> 12) & 0x1;
1217 if ( truncatedFlag ) {
1218 LOG_ERROR("decodeGfexData","","WARNING data truncated");
1219 }
1220 const uint32_t numFpgaWords = word & 0xfff;
1221 if ( ( numFpgaWords % 7 ) != 0 ) {
1222 LOG_ERROR("decodeGfexData","","input data size " << numFpgaWords
1223 << " is not a multiple of 7");
1224 return;
1225 }
1226 const uint32_t numInputFibres = numFpgaWords / 7;
1227
1228 // Loop over the input fibres and decode each block of 7 words.
1229 // **FIXME** Not sure if gFEX data will have error flags?
1230 // **FIXME** For the moment hard code to zero.
1231
1232 const uint32_t fpgaErrors = 0;
1233
1234 for ( size_t chanNumber = 0; chanNumber < numInputFibres; chanNumber++ ) {
1235 // Ignore the spare fibres for the moment.
1236 if ( chanNumber < 48 || chanNumber >= 52 ) {
1237 this->decodeGfexDataChan ( payload, fpgaNumber, chanNumber,
1238 fpgaErrors, tower, rodInfo );
1239 }
1240 payload += 7;
1241 }
1242 }
1243 if ( m_verbosity > 0 )
1244 {
1245 std::cout << "L1CaloBsDecoderRun3::decodeGfexData: n.towers added="
1246 << tower.size() - numTowers << std::endl;
1247 }
1248}
1249
1259uint32_t
1261 const uint32_t fpgaNumber,
1262 const uint32_t chanNumber,
1263 const uint32_t errorMask,
1264 std::list<L1CaloRdoGfexTower>& tower,
1265 std::list<L1CaloRdoRodInfo>::const_iterator rodInfo )
1266{
1267 const uint32_t shelfNumber = 0x23; // Hard code to P1 value (35)
1268 const uint32_t gfexNumber = 0; // **CHECK** What is used in COOL/OKS?
1269
1270 // Ignore the spare fibres for the moment.
1271 if ( chanNumber >= 48 && chanNumber < 52 ) {
1272 return 0;
1273 }
1274
1275 // Ignore FPGA C for the moment (different format).
1276 if ( fpgaNumber >= 2 ) {
1277 return 0;
1278 }
1279
1280 // The fibre packer decoder methods expect a vector of seven words.
1281 std::vector<FibrePackerBase::myDataWord> encodedData;
1282 for ( size_t i = 0; i < 7; i++ ) {
1283 encodedData.push_back( payload[i] );
1284 }
1286
1287 // Unpack up to sixteen gCaloTowers. NB central FPGAs only have eight
1288 // Et values per EM fibre but additionally have eight fine positions.
1289 // For the moment we ignore the latter.
1290 // We need the central Latome decoder for FPGAs A&B for both EM layer
1291 // and hadronic layer outside the central eight 0.2 eta bins (to 1.6).
1292 // The hadronic fibres within |eta|<1.6 are TREX.
1293 // However due to overlaps and potentially unused words on fibres
1294 // its safer to decode in all possible ways and work out which one
1295 // to use afterwards.
1296 GfexTrexFibrePacker trexPacker;
1297 GfexLatomeCentralFibrePacker clarPacker;
1298 GfexLatomeForwardFibrePacker flarPacker;
1299 std::vector<FibrePackerBase::myDataWord> trexTowers = trexPacker.getUnpackedData( encodedData, frameType );
1300 std::vector<FibrePackerBase::myDataWord> clarTowers = clarPacker.getUnpackedData( encodedData, frameType );
1301 std::vector<FibrePackerBase::myDataWord> flarTowers = flarPacker.getUnpackedData( encodedData, frameType );
1302 size_t numTowers = GfexDefs::maxGTowersPerFibre();
1303 size_t numCentral = numTowers / 2; // 8
1304
1305 // Create RDO per tower.
1306 for ( size_t iTower = 0; iTower < numTowers; iTower++ ) {
1307 GfexCellMapping mapping( 0, fpgaNumber, chanNumber, iTower );
1308 L1CaloDetectorRegion region = mapping.getDetectorRegion();
1309 GfexHardwareInfo hwInfo( mapping.getHardwareInfo() );
1310 if ( !region.getValidity() || !hwInfo.getValidity() ) {
1311 continue;
1312 }
1313 // Currently GfexCellMapping sets local eta,phi within each FPGA.
1314 // We want to convert to global values (whole module or system).
1315 int globalPhi = region.getPhiIndex() * 2;
1316 int globalEta = GfexDefs::localToGlobalEta(fpgaNumber,region.getEtaIndex());
1317 if (globalEta < -49 || globalEta >= 49) {
1318 continue; // Invalid or not yet implemented
1319 }
1320 int layer = (region.getLayer() == L1CaloDetectorRegion::Electromagnetic) ? 0 : 1;
1321
1322 // Work out which decoding we ought to use.
1323 // For the moment avoid regions of potential confusion, eg Tile/HEC
1324 // overlap, anything outside |eta|>2.4, etc.
1325 // **FIXME** Ideally this should definitively come from the mapping.
1326 int towerEt = 0;
1327 if ( layer == 1 && std::abs(globalEta) < 14 ) {
1328 // TREX within Tile/HEC overlap.
1329 towerEt = trexTowers[iTower];
1330 }
1331 else if ( layer == 1 && std::abs(globalEta) >= 16 && std::abs(globalEta) < 24 ) {
1332 // HEC outside Tile/HEC overlap.
1333 towerEt = flarTowers[iTower];
1334 }
1335 else if ( layer == 0 && std::abs(globalEta) < 14 && iTower < numCentral ) {
1336 // EM layer within barrel/endcap overlap.
1337 towerEt = clarTowers[iTower];
1338 }
1339 else if ( layer == 0 && std::abs(globalEta) >= 16 && std::abs(globalEta) < 24 && iTower < numCentral ) {
1340 // EM layer outside barrel/endcap overlap.
1341 towerEt = clarTowers[iTower];
1342 }
1343 else {
1344 continue;
1345 }
1346
1347 if ( towerEt || errorMask ) {
1348
1349 L1CaloRdoGfexTower newOne( shelfNumber, gfexNumber, globalEta, globalPhi, layer, region );
1350 newOne.setRodInfo( rodInfo );
1351 L1CaloRdoGfexTower& rdo = L1CaloBsDecoderUtil::findRdo( newOne, tower );
1352
1353 rdo.setHardwareInfo( hwInfo.getFpgaNumber(), chanNumber, iTower,
1354 GfexDefs::minipodNumFromName(hwInfo.getMpodName()),
1355 hwInfo.getMpodChannel() );
1356 rdo.setValue( towerEt );
1357 rdo.setFlag( errorMask );
1358
1359 if ( m_verbosity > 0 )
1360 {
1361 std::cout << "L1CaloBsDecoderRun3::decodeGfexDataChan: "
1362 << "FPGA=" << fpgaNumber
1363 << std::hex << ", Et=0x" << towerEt << ", flag=0x" << errorMask
1364 << std::dec << std::endl;
1365 }
1366 //std::cout << "L1CaloBsDecoderRun3::decodeGfexDataChan: fpga=" << fpgaNumber
1367 // << ", chan=" << chanNumber << ", word=" << iTower
1368 // << ", mpod=" << GfexDefs::minipodNumFromName(hwInfo.getMpodName())
1369 // << ", mpodFibre=" << hwInfo.getMpodChannel()
1370 // << ", globalEta=" << globalEta
1371 // << ", globalPhi=" << globalPhi
1372 // << ", layer=" << layer
1373 // << ", Et=" << towerEt
1374 // << ", errors=0x" << std::hex << errorMask << std::dec
1375 // << std::endl;
1376 }
1377 }
1378
1379 return 0; // No error bits yet
1380}
1381
1392void
1393L1CaloBsDecoderRun3::decodeGfexTobs( const uint32_t* beg, const uint32_t* end,
1394 std::list<L1CaloRdoGfexTob>& tob,
1395 std::list<L1CaloRdoRodInfo>::const_iterator rodInfo )
1396{
1397 // **FIXME** To be implemented!
1398 const uint32_t* payload( beg );
1399 const size_t fragmentSize = end - beg;
1400
1401 // The data block is constructed by the SWROD. It consists of up to six
1402 // subblocks for Jets and MET TOBs from each of the three FPGAs.
1403 // Each subblock starts with a 1 word header which identifies the block
1404 // type and gives its length.
1405 // Each subblock contains two sets of seven data words that are (or for
1406 // MET could be) transmitted to Ph1Topo on the fibres. If multiple slices
1407 // are read out, each subblock should have multiples of 14 words.
1408
1409 size_t index = 0;
1410 while ( index < fragmentSize ) {
1411 const uint32_t headerWord = payload[index];
1412 const uint32_t blockType = (headerWord >> 28) & 0xf;
1413 //const uint32_t version = (headerWord >> 24) & 0xf; // Currently unused (1)
1414 const uint32_t headerSize = (headerWord >> 22) & 0x3;
1415 const uint32_t errorFlags = (headerWord >> 12) & 0x1;
1416 const uint32_t dataSize = headerWord & 0xfff;
1417
1418 const uint32_t blockSize = headerSize + dataSize;
1419 if ( (index + blockSize) > fragmentSize ) {
1420 LOG_ERROR("decodeGfexTobs","","remaining block size "
1421 << (fragmentSize - index)
1422 << " is too small for subblock of type " << blockType
1423 << " with headerSize " << headerSize
1424 << " and dataSize " << dataSize);
1425 return;
1426 }
1427 index += headerSize;
1428
1429 const uint32_t wordsPerSlice = 2 * FexDefs::num32BitWordsPerFibre();
1430 const uint32_t numSlices = dataSize / wordsPerSlice;
1431 if ( numSlices * wordsPerSlice != dataSize ) {
1432 LOG_ERROR("decodeGfexTobs","","subblock type " << blockType
1433 << " with dataSize " << dataSize
1434 << " is not a multiple of " << wordsPerSlice << " words");
1435 return;
1436 }
1437
1438 // Create TOB RDOs for each slice.
1439 for (size_t sliceNumber = 0; sliceNumber < numSlices; sliceNumber++) {
1440 bool ret = this->decodeGfexTobSlice( &payload[index], blockType, sliceNumber, numSlices,
1441 errorFlags, tob, rodInfo );
1442 if ( ! ret ) {
1443 return;
1444 }
1445 index += wordsPerSlice;
1446 }
1447 }
1448}
1449
1462bool
1463L1CaloBsDecoderRun3::decodeGfexTobSlice( const uint32_t payload[], uint32_t blockType,
1464 const uint32_t sliceNumber, const uint32_t numSlices,
1465 const uint32_t errorMask,
1466 std::list<L1CaloRdoGfexTob>& tob,
1467 std::list<L1CaloRdoRodInfo>::const_iterator rodInfo )
1468{
1469 // The subblock type is 0xA,B,C for jet TOBs from FPGA A,B,C
1470 // and 0x1,2,3 for global (MET) TOBs.
1471 bool isMet = (blockType >= 0x1 && blockType <= 0x3);
1472 bool isJet = (blockType >= 0xA && blockType <= 0xC);
1473 if ( !isJet && !isMet ) {
1474 LOG_ERROR("decodeGfexTobSlice","",": invalid block type "
1475 << blockType);
1476 return false;
1477 }
1478 const uint32_t fpgaNumber = (isJet) ? (blockType - 0x1) : (blockType - 0xA);
1479
1480 // We expect two fibres each of 7 words.
1481 size_t index = 0;
1482 for ( size_t iFibre = 0; iFibre < 2; iFibre++ ) {
1483 for ( size_t iWord = 0; iWord < (size_t)FexDefs::num32BitWordsPerFibre(); iWord++, index++ ) {
1484 // Jet TOBs.
1485 if (isJet) {
1486 const uint32_t tobID = payload[index] & 0x1f;
1487 const uint32_t status = (payload[index] >> 7) & 0x1;
1488 const uint32_t etValue = (payload[index] >> 8) & 0xfff;
1489 const uint32_t tobEta = (payload[index] >> 20) & 0x3f;
1490 const uint32_t tobPhi = (payload[index] >> 26) & 0x1f;
1491 const uint32_t saturated = (payload[index] >> 31) & 0x1;
1492
1495 if ( tobID >= 1 && tobID <= 4 ) {
1497 }
1498 else if ( tobID >= 5 && tobID <= 6 ) {
1500 }
1501
1502 if ( ( etValue || saturated || errorMask ) && tobID ) {
1503 // Zero suppress (as gFEX always sends something).
1504 // **FIXME** Not sure what to do with status or satured bits.
1505 // **FIXME** For the moment set them in the error flags
1506 // **FIXME** Check use of tobEta and tobPhi (is it per FPGA?).
1507 const uint32_t flagMask = errorMask | (saturated << 31) | (status << 30);
1508 const uint32_t shelfNumber = 0x23; // Hard code to P1 value (35)
1509 const uint32_t moduleNumber = 0; // Hard code to P1 value (0) **FIXME** CHECK!
1510 L1CaloRdoGfexTob newOne( shelfNumber, moduleNumber, tobEta, tobPhi,
1511 numSlices, fexTobType, fexTobSource );
1512 newOne.setRodInfo( rodInfo );
1513 L1CaloRdoGfexTob& rdo = L1CaloBsDecoderUtil::findRdo( newOne, tob );
1514 rdo.setValue( etValue, sliceNumber );
1515 rdo.setFlag( flagMask, sliceNumber );
1516 if ( m_verbosity > 0 )
1517 {
1518 std::cout << "L1CaloBsDecoderRun3::decodeGfexTobSlice: tobType=" << fexTobType
1519 << ", tobSource=" << fexTobSource << ", slice=" << sliceNumber
1520 << ", fpga=" << fpgaNumber << ", eta=" << tobEta << ", phi=" << tobPhi
1521 << std::hex << ", Et=0x" << etValue << ", flag=0x" << flagMask
1522 << std::dec << ", numSlices=" << numSlices << std::endl;
1523 }
1524 }
1525 }
1526
1527 // MET TOBs. **FIXME** To be implemented!
1528 else if (isMet) {
1529 }
1530 }
1531 }
1532
1533 return true;
1534}
1535
1548void
1549L1CaloBsDecoderRun3::decodePh1TopoData( const uint32_t* beg, const uint32_t* end,
1550 std::list<L1CaloRdoEfexTob>& etob,
1551 std::list<L1CaloRdoJfexTob>& jtob,
1552 std::list<L1CaloRdoGfexTob>& gtob,
1553 std::list<L1CaloRdoMuonTob>& mtob,
1554 std::list<L1CaloRdoRodInfo>::const_iterator rodInfo )
1555{
1556 const uint32_t* payload( beg );
1557 const size_t fragmentSize = end - beg;
1558
1559 // Fibre types of Ph1Topo inputs. These are defined in the VHDL at:
1560 // https://gitlab.cern.ch/atlas-l1calo/l1topo/ph1topo/-/blob/master/src/infr/topo_mapping_pkg.vhd#L27
1561 // For our purposes we only need to distinguish different formats
1562 // and ignore those that do not appear in the readout.
1563 enum TopoInputFibreTypes { Unknown=0x00, IPB=0x01, TTC=0x02, EM1=0x03, EM2=0x04,
1564 G1=0x05, G2=0x06, J1=0x07, J2=0x08, JF=0x09, JFXE=0x0a,
1565 M0A=0x0b, M0C=0x0c, M1A=0x0d, M1C=0x0e, M2A=0x0f, M2C=0x10,
1566 TAU1=0x11, TAU2=0x12, gJ1=0x13, gJ2=0x14 };
1567
1568 // The data block is optimised for production by firmware with the length
1569 // in a trailer at the end. The SWROD concatenates a number of such blocks
1570 // (removing the 2 word header used to fill the ROD fragment header).
1571 // So we need to find the end and work backwards.
1572
1573 //??size_t numTobs = tower.size();
1574 size_t index = fragmentSize;
1575
1576 // Loop looking backwards for Ph1Topo processor input data blocks.
1577 while ( index > 0 ) {
1578 if ( index < 2 ) {
1579 LOG_ERROR("decodePh1TopoData","","remaining block size " << index
1580 << " is too small for the Ph1Topo FPGA trailer");
1581 return;
1582 }
1583 const uint32_t fpgaTrailer2 = payload[--index];
1584 const uint32_t fpgaTrailer1 = payload[--index];
1585
1586 const uint32_t fpgaErrors = fpgaTrailer2 & 0x3f;
1587 //??const uint32_t sliceNum = (fpgaTrailer1 >> 28) & 0xf;
1588 //??const uint32_t numSlices = (fpgaTrailer1 >> 24) & 0xf;
1589 const uint32_t sliceNum = 0; // **FIXME** Temporarily hard code until set properly
1590 const uint32_t numSlices = 1; // **FIXME** Temporarily hard code until set properly
1591 //>>const uint32_t topoNumber = (fpgaTrailer1 >> 22) & 0x3;
1592 //>>const uint32_t fpgaNumber = (fpgaTrailer1 >> 21) & 0x1;
1593 //>>const uint32_t fwType = (fpgaTrailer1 >> 19) & 0x3; // 0: Mult, 1: Algo, 2: Beta
1594 const size_t payloadSize = (fpgaTrailer1 & 0xffff);
1595
1596 if ( payloadSize > index ) {
1597 LOG_ERROR("decodePh1TopoData","","remaining Ph1Topo block size "
1598 << index << " is too small for the claimed payload size "
1599 << payloadSize);
1600 return;
1601 }
1602
1603 // We can now work forwards from the start of this block
1604 // decoding each set of 8 words per input fibre channel.
1605 // In Ph1Topo the input data channels can be TOBs of many
1606 // different types. The type is identifed in the 8th word.
1607 // We then need the appropriate mapping to give us which
1608 // P1 FEX crate and module number is the source.
1609 // NB this may be incorrect for test rig setups.
1610 index -= payloadSize;
1611 size_t chanIndex = 0;
1612 uint32_t fexShelf = 0;
1613 uint32_t fexModule = 0;
1614 uint32_t fexFpga = 0;
1615 while ( chanIndex < payloadSize ) {
1616 if ( (payloadSize - chanIndex) < 8 ) {
1617 LOG_ERROR("decodePh1TopoData","","remaining Ph1Topo block size "
1618 << (payloadSize - chanIndex)
1619 << " is too small for one Ph1Topo input fibre block (8)");
1620 return;
1621 }
1622 //>>const uint32_t chanNumber = ( payload[7] ) & 0xff;
1623 const uint32_t fibreType = ( payload[7] >> 8 ) & 0x1f;
1624 //>>const uint32_t errorBits = ( payload[7] >> 30 ) & 0x3;
1625
1628
1629 // Most fibres have up to six TOBs, but jFEX fibres have seven.
1630 size_t numTobs = 6;
1631 if (fibreType == TopoInputFibreTypes::J1 || fibreType == TopoInputFibreTypes::JF ||
1632 fibreType == TopoInputFibreTypes::J2 || fibreType == TopoInputFibreTypes::JFXE) {
1633 numTobs = 7;
1634 }
1635
1636 for (size_t iTob = 0; iTob < numTobs; iTob++) {
1637 // TOBs from eFEX.
1638 if (fibreType == TopoInputFibreTypes::EM1 || fibreType == TopoInputFibreTypes::TAU1 ||
1639 fibreType == TopoInputFibreTypes::EM2 || fibreType == TopoInputFibreTypes::TAU2) {
1640 tobType = (fibreType <= TopoInputFibreTypes::EM2) // Assumes enum order!
1643 // Need mapping!
1644 this->decodeOneEfexTob( &payload[index+chanIndex+iTob], fexShelf, fexModule, fexFpga,
1645 fpgaErrors, numSlices, sliceNum, tobType, tobSource,
1646 etob, rodInfo );
1647 }
1648 // Fibres from jFEX.
1649 /*
1650 else if () {
1651 }
1652 */
1653 }
1654 chanIndex += 8;
1655 }
1656 }
1657 //??if ( m_verbosity > 0 )
1658 //??{
1659 //?? std::cout << "L1CaloBsDecoderRun3::decodeJfexData: n.towers added="
1660 //?? << tower.size() - numTowers << std::endl;
1661 //??}
1662}
1663
1673void
1674L1CaloBsDecoderRun3::decodePh1TopoHits( const uint32_t* beg, const uint32_t* end,
1675 std::list<L1CaloRdoPh1TopoHit>& hit,
1676 std::list<L1CaloRdoRodInfo>::const_iterator rodInfo )
1677{
1678 const uint32_t* payload( beg );
1679 const size_t fragmentSize = end - beg;
1680
1681 // The data block is optimised for production by firmware as a set
1682 // of nested blocks with the lengths at the end. So we need to find
1683 // the end and work backwards.
1684
1685 if ( fragmentSize < 2 ) {
1686 LOG_ERROR("decodePh1TopoHits","","fragment size " << fragmentSize
1687 << " is too small for the ROD trailer");
1688 return;
1689 }
1690
1691 size_t index = fragmentSize;
1692 const uint32_t rodTrailer2 = payload[--index];
1693 const uint32_t rodTrailer1 = payload[--index];
1694
1695 const uint32_t rodErrors = rodTrailer2 & 0x7f;
1696 const size_t payloadSize = rodTrailer1 & 0xffff;
1697 if ( (payloadSize + 2) != fragmentSize ) {
1698 // Actual ROD fragment payload size does not match that claimed in the trailer.
1699 LOG_ERROR("decodePh1TopoHits","","payload size " << payloadSize
1700 << " inconsistent with ROD fragment size " << fragmentSize);
1701 return;
1702 }
1703
1704 // Loop looking backwards for Ph1Topo FPGA blocks.
1705 while ( index > 0 ) {
1706 if ( index < 2 ) {
1707 LOG_ERROR("decodePh1TopoHits","","remaining block size " << index
1708 << " is too small for the Ph1Topo trailer");
1709 return;
1710 }
1711 size_t fpgaIndex = index;
1712 const uint32_t fpgaTrailer2 = payload[--fpgaIndex];
1713 const uint32_t fpgaTrailer1 = payload[--fpgaIndex];
1714 const size_t fpgaBlockSize = fpgaTrailer1 & 0xffff;
1715 const uint32_t topoNumber = (fpgaTrailer1 >> 20) & 0x7;
1716 const uint32_t fpgaNumber = (fpgaTrailer1 >> 18) & 0x3;
1717 const uint32_t numSlices = (fpgaTrailer1 >> 24) & 0xf;
1718 const uint32_t sliceNumber = (fpgaTrailer1 >> 28) & 0xf;
1719 const uint32_t fpgaErrors = fpgaTrailer2 & 0x3f;
1720 if ( fpgaBlockSize > index ) {
1721 LOG_ERROR("decodePh1TopoHits","","Ph1Topo FPGA block size "
1722 << fpgaBlockSize << " exceeds remaining data size " << index
1723 << " (Ph1Topo " << topoNumber << " FPGA " << fpgaNumber << ")");
1724 return;
1725 }
1726 // Update index to previous Ph1Topo FPGA block (if any).
1727 index = fpgaIndex - fpgaBlockSize;
1728
1729 // Combine rod and topo error fields.
1730 const uint32_t errorMask = fpgaErrors | (rodErrors << 6);
1731
1732 // There should always be six words.
1733 // All six are only used by Topo1 and they are all CTP hits.
1734 // Topo2 and Topo3 modules just use two words of the block,
1735 // one for the hits sent to CTP and one for the overflow flags.
1736 const size_t expectedBlockSize = 6;
1737 if ( fpgaBlockSize != expectedBlockSize ) {
1738 LOG_ERROR("decodePh1TopoHits","","Ph1Topo FPGA block size "
1739 << fpgaBlockSize << " is not the expected " << expectedBlockSize);
1740 return;
1741 }
1742 const uint32_t shelfNumber = 0x24; // Hard code to P1 value (36)
1743 const int idFlag = 0; // Not used for Ph1Topo
1744 L1CaloRdoHit::HitSource hitSource( L1CaloRdoHit::Result );
1745 size_t numWordsUsedPerFPGA = (topoNumber == 1) ? 6 : 2;
1746 size_t numHitWordsPerFPGA = (topoNumber == 1) ? 6 : 1;
1747 size_t numHitWordsPerModule = numHitWordsPerFPGA * 2;
1748
1749 L1CaloRdoPh1TopoHit newOne( shelfNumber, topoNumber, idFlag, hitSource, numHitWordsPerModule, numSlices );
1750 newOne.setRodInfo( rodInfo );
1751 L1CaloRdoPh1TopoHit& rdo = L1CaloBsDecoderUtil::findRdo( newOne, hit );
1752 rdo.setFlag( errorMask, sliceNumber );
1753
1754 size_t sliceIndex = index;
1755 for ( size_t k = 0; k < numWordsUsedPerFPGA; k++ ) {
1756 const uint32_t resultWord = payload[sliceIndex++];
1757 size_t wordNum = ( topoNumber == 1 ) ? k : 0;
1758 wordNum += fpgaNumber * numHitWordsPerFPGA;
1759 // Interpret this as hit or overflow?
1760 bool isOverflow = ( topoNumber != 1 ) && ( k != 0 );
1761 if ( isOverflow ) {
1762 rdo.setOverflows( resultWord, wordNum, sliceNumber );
1763 }
1764 else {
1765 rdo.setHits( resultWord, wordNum, sliceNumber );
1766 }
1767
1768 if ( m_verbosity > 0 )
1769 {
1770 std::cout << "L1CaloBsDecoderRun3::decodePh1TopoHits: slice=" << sliceNumber
1771 << ", module=" << topoNumber << ", fpga=" << fpgaNumber
1772 << std::hex << ", result=0x" << resultWord << ", errors=0x" << errorMask
1773 << std::dec << ", numSlices=" << numSlices << ", numWords=" << numHitWordsPerModule
1774 << ", isOverflow=" << isOverflow << std::endl;
1775 }
1776 }
1777 }
1778}
1779
1780
1781
1782
1783#endif // ndef OFFLINE_DECODER
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
#define LOG_ERROR(location, title, detail)
@ Unknown
Definition TruthClasses.h:9
static unsigned int numAtcaFexSlots()
Definition CrateDefs.h:42
New class for Efex Cell Mappings, constructs either from shared CSVTables instance.
L1CaloDetectorRegion getDetectorRegion() const
static int numInputFibresPerFpga()
Definition EfexDefs.h:35
bool getValidity() const
int getMpodNumber() const
int getFibreNumber() const
virtual std::vector< myDataWord > getUnpackedData(const std::vector< myDataWord > &encodedData, InputDataFrameType frameType) const override
Function unpacking the data from LATOME format, either standard or alignement frame.
virtual std::vector< myDataWord > getUnpackedData(const std::vector< myDataWord > &encodedData, InputDataFrameType frameType) const override
Function unpacking the data from LATOME format, either standard or alignement frame.
static int num32BitWordsPerFibre()
Definition FexDefs.h:17
InputDataFrameType
type of input data frame
uint32_t crc9fibre(const std::vector< uint32_t > &inwords, size_t num_bits) const
Functions calculating CRC over input data.
Definition GenericCrc.cxx:5
Interface class for logging, can be overriden to e.g.
bool decodeEfexTobSlice(const uint32_t payload[], size_t &index, const uint32_t efexNumber, const uint32_t shelfNumber, const uint32_t numSlices, const uint32_t errorMask, std::list< L1CaloRdoEfexTob > &tob, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo) const
Decode one eFEX FPGA block of TOBs and XTOBs for one slice.
uint32_t decodeGfexDataChan(const uint32_t payload[], const uint32_t fpgaNumber, const uint32_t chanNumber, const uint32_t errorMask, std::list< L1CaloRdoGfexTower > &dat, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo)
Decode the data from one gFEX input fibre (only ever one slice).
uint32_t decodeEfexDataChan(const uint32_t payload[], const uint32_t efexNumber, const uint32_t shelfNumber, const uint32_t errorMask, std::list< L1CaloRdoEfexTower > &dat, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo) const
Decode the data from one eFEX input fibre (only ever one slice).
void decodeJfexTobs(const uint32_t *beg, const uint32_t *end, std::list< L1CaloRdoJfexTob > &tob, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo)
Decode jFEX TOBs and XTOBs.
void decodePh1TopoHits(const uint32_t *beg, const uint32_t *end, std::list< L1CaloRdoPh1TopoHit > &hit, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo)
Decode Ph1Topo hit results.
void decodePh1TopoData(const uint32_t *beg, const uint32_t *end, std::list< L1CaloRdoEfexTob > &etob, std::list< L1CaloRdoJfexTob > &jtob, std::list< L1CaloRdoGfexTob > &gtob, std::list< L1CaloRdoMuonTob > &mtob, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo)
Decode Ph1Topo input data: these are TOBs from FEXes and MuCTPI.
void decodeGfexData(const uint32_t *beg, const uint32_t *end, std::list< L1CaloRdoGfexTower > &dat, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo)
Decode gFEX input fibre data.
bool checkFibreCRC(std::vector< uint32_t > &data) const
Check the CRC in an input fibre block of words.
void decodeOneEfexTob(const uint32_t word[], const uint32_t shelfNumber, const uint32_t efexNumber, const uint32_t fpgaNumber, const uint32_t errorMask, const uint32_t numSlices, const uint32_t sliceNum, L1CaloRdoFexTob::TobType tobType, L1CaloRdoFexTob::TobSource tobSource, std::list< L1CaloRdoEfexTob > &tob, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo) const
Decode word(s) for one eFEX TOB (or xTOB) and create one RDO.
void decodeGfexTobs(const uint32_t *beg, const uint32_t *end, std::list< L1CaloRdoGfexTob > &dat, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo)
Decode gFEX TOBs.
void decodeJfexData(const uint32_t *beg, const uint32_t *end, std::list< L1CaloRdoJfexTower > &dat, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo)
Decode jFEX input fibre data.
bool decodeJfexTobSlice(const uint32_t payload[], size_t blockSize, size_t &index, const uint32_t jfexNumber, const uint32_t fpgaNumber, const uint32_t sliceNumber, const uint32_t numSlices, const uint32_t errorMask, std::list< L1CaloRdoJfexTob > &tob, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo)
Decode one jFEX FPGA block of TOBs and XTOBs for one slice.
void decodeEfexData(const uint32_t *beg, const uint32_t *end, std::list< L1CaloRdoEfexTower > &dat, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo) const
Decode eFEX input fibre data.
uint32_t decodeJfexDataChan(const uint32_t payload[], const uint32_t jfexNumber, const uint32_t fpgaNumber, const uint32_t errorMask, std::list< L1CaloRdoJfexTower > &dat, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo)
Decode the data from one jFEX input fibre (only ever one slice).
std::unique_ptr< Logging > m_logger
void decodeEfexTobs(const uint32_t *beg, const uint32_t *end, std::list< L1CaloRdoEfexTob > &tob, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo) const
Decode eFEX TOBs and XTOBs.
bool decodeGfexTobSlice(const uint32_t payload[], const uint32_t blockType, const uint32_t sliceNumber, const uint32_t numSlices, const uint32_t errorMask, std::list< L1CaloRdoGfexTob > &tob, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo)
Decode one gFEX FPGA block of TOBs for one slice.
static Tar & findRdo(const Tar &target, Dat &data, Iter begin, Iter end)
Simple class to mainly store eta/phi information (indices, granularity, trigger tower coordinates) as...
LayerTypeEnum getLayer() const
L1CaloRdoFexTob subclass for eFEX EM/Tau TOBs or XTOBs.
void setSupercells(std::vector< uint32_t > &supercells)
void setHardwareInfo(uint32_t fpga, uint32_t mgt, uint32_t word, uint32_t mpod, uint32_t fibre, uint32_t overlap)
void setRodInfo(std::list< L1CaloRdoRodInfo >::const_iterator &rodInfo)
void setFlag(int flag, size_t slice)
void setValue(int val, size_t slice)
Definition index.py:1
STL namespace.