ATLAS Offline Software
Loading...
Searching...
No Matches
L1CaloBsDecoderRun3 Class Reference

Decoder for Run 3 data formats: eFEX, jFEX, gFEX and phase 1 Topo. More...

#include <L1CaloBsDecoderRun3.h>

Collaboration diagram for L1CaloBsDecoderRun3:

Classes

class  Logging
 Interface class for logging, can be overriden to e.g. More...

Public Member Functions

 L1CaloBsDecoderRun3 ()
void setVerbosity (bool verbosity)
void setLogger (std::unique_ptr< Logging > &&logger)
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.
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.
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.
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 decodeGfexData (const uint32_t *beg, const uint32_t *end, std::list< L1CaloRdoGfexTower > &dat, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo)
 Decode gFEX input fibre data.
void decodeGfexTobs (const uint32_t *beg, const uint32_t *end, std::list< L1CaloRdoGfexTob > &dat, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo)
 Decode gFEX TOBs.
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 decodePh1TopoHits (const uint32_t *beg, const uint32_t *end, std::list< L1CaloRdoPh1TopoHit > &hit, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo)
 Decode Ph1Topo hit results.

Private Member Functions

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.
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).
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 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).
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.
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).
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.
bool checkFibreCRC (std::vector< uint32_t > &data) const
 Check the CRC in an input fibre block of words.

Private Attributes

int m_verbosity
std::unique_ptr< Loggingm_logger

Detailed Description

Decoder for Run 3 data formats: eFEX, jFEX, gFEX and phase 1 Topo.

Utility methods shared with Runs 1 & 2 are now in L1CaloBsDecoderUtil.

Definition at line 22 of file L1CaloBsDecoderRun3.h.

Constructor & Destructor Documentation

◆ L1CaloBsDecoderRun3()

L1CaloBsDecoderRun3::L1CaloBsDecoderRun3 ( )

Definition at line 48 of file L1CaloBsDecoderRun3.cxx.

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}
#define LOG_ERROR(location, title, detail)
std::unique_ptr< Logging > m_logger

Member Function Documentation

◆ checkFibreCRC()

bool L1CaloBsDecoderRun3::checkFibreCRC ( std::vector< uint32_t > & data) const
private

Check the CRC in an input fibre block of words.

The CRC field should be the top 9 bits in the 7 word block. This means we calculate the CRC over the remaining 215 bits.

Parameters
datavector of 7 input fibre words
Returns
true if the CRC is valid

Definition at line 669 of file L1CaloBsDecoderRun3.cxx.

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}
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
static int num32BitWordsPerFibre()
Definition FexDefs.h:17
uint32_t crc9fibre(const std::vector< uint32_t > &inwords, size_t num_bits) const
Functions calculating CRC over input data.
Definition GenericCrc.cxx:5

◆ decodeEfexData()

void L1CaloBsDecoderRun3::decodeEfexData ( const uint32_t * beg,
const uint32_t * end,
std::list< L1CaloRdoEfexTower > & tower,
std::list< L1CaloRdoRodInfo >::const_iterator rodInfo ) const

Decode eFEX input fibre data.

For the EM layer we have up to 10 supercell values per tower though there is still just a single hadronic value. It seemed overkill to have an RDO per supercell, so instead the main RDO "Value" is set to the sum of 10 EM supercells with the individual supercell Ets saved in a separate vector. These are always stored in 1441 order (PS, F0-F3, M0-M3, BK) even in regions where some supercells are missing. The flag field is used for status/error bits.

Parameters
begpointer to start of rod data payload
endpointer to end of rod data payload
towerlist of RDO to be filled
rodInfoiterator to ROD information for this block

Definition at line 85 of file L1CaloBsDecoderRun3.cxx.

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}
static unsigned int numAtcaFexSlots()
Definition CrateDefs.h:42
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).
str index
Definition DeMoScan.py:362
setEventNumber uint32_t

◆ decodeEfexDataChan()

uint32_t L1CaloBsDecoderRun3::decodeEfexDataChan ( const uint32_t payload[],
const uint32_t efexNumber,
const uint32_t shelfNumber,
const uint32_t errorMask,
std::list< L1CaloRdoEfexTower > & tower,
std::list< L1CaloRdoRodInfo >::const_iterator rodInfo ) const
private

Decode the data from one eFEX input fibre (only ever one slice).

Parameters
payloadpayload vector starting at this 8 word block
efexNumbernumber of this eFEX in its shelf
shelfNumbershelf number (here 0 or 1)
errorMaskglobal error bits set for this ROD fragment
towerlist of RDO to be filled
rodInfoiterator to ROD information for this block
Returns
whether decoding succeeded (false to abort decoding)

Definition at line 187 of file L1CaloBsDecoderRun3.cxx.

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.
241 EfexLatomeFibrePacker packer;
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}
static int numInputFibresPerFpga()
Definition EfexDefs.h:35
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.
InputDataFrameType
type of input data frame
bool checkFibreCRC(std::vector< uint32_t > &data) const
Check the CRC in an input fibre block of words.
static Tar & findRdo(const Tar &target, Dat &data, Iter begin, Iter end)
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 setFlag(int flag, size_t slice)
void setValue(int val, size_t slice)
@ layer
Definition HitInfo.h:79

◆ decodeEfexTobs()

void L1CaloBsDecoderRun3::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.

The RDO value encodes the cluster Et in the value field and the isolation bits and other information in the flag.

Parameters
begpointer to start of rod data payload
endpointer to end of rod data payload
toblist of RDO to be filled
rodInfoiterator to ROD information for this block

Definition at line 363 of file L1CaloBsDecoderRun3.cxx.

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}
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.

◆ decodeEfexTobSlice()

bool L1CaloBsDecoderRun3::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
private

Decode one eFEX FPGA block of TOBs and XTOBs for one slice.

Parameters
payloadentire ROD fragment payload vector
indexjust past end of block for this slice (this method updates it to the start of the block)
efexNumbernumber of this eFEX in its shelf
shelfNumbershelf number
numSlicesnumber of TOB slices read out in this event
errorMaskglobal error bits set for this ROD fragment
toblist of RDO to be filled
rodInfoiterator to ROD information for this block
Returns
whether decoding succeeded (false to abort decoding in which case the returned index is not valid)

Definition at line 487 of file L1CaloBsDecoderRun3.cxx.

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)
566 : L1CaloRdoFexTob::TobType::Tau;
568 size_t sliceIndex = index;
569 for (size_t iTOB = 0; iTOB < totalTobs; iTOB++) {
570 if (iTOB >= numTobs) {
572 fexTobType = (iTOB < (numTobs + numEmXtobs))
574 : L1CaloRdoFexTob::TobType::Tau;
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}
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.
@ Tau
The object is a tau (jet)
Definition ObjectType.h:49

◆ decodeGfexData()

void L1CaloBsDecoderRun3::decodeGfexData ( const uint32_t * beg,
const uint32_t * end,
std::list< L1CaloRdoGfexTower > & tower,
std::list< L1CaloRdoRodInfo >::const_iterator rodInfo )

Decode gFEX input fibre data.

We create one RDO per tower using the value field for its Et. The flag field is used for status/error bits.

Parameters
begpointer to start of rod data payload
endpointer to end of rod data payload
towerlist of RDO to be filled
rodInfoiterator to ROD information for this block

Definition at line 1184 of file L1CaloBsDecoderRun3.cxx.

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}
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).

◆ decodeGfexDataChan()

uint32_t L1CaloBsDecoderRun3::decodeGfexDataChan ( const uint32_t payload[],
const uint32_t fpgaNumber,
const uint32_t chanNumber,
const uint32_t errorMask,
std::list< L1CaloRdoGfexTower > & tower,
std::list< L1CaloRdoRodInfo >::const_iterator rodInfo )
private

Decode the data from one gFEX input fibre (only ever one slice).

Parameters
payloadpayload vector starting at this 7 word block
fpgaNumberFPGA number (0-2 for A-C)
errorMaskglobal error bits set for this ROD fragment
towerlist of RDO to be filled
rodInfoiterator to ROD information for this block
Returns
whether decoding succeeded (false to abort decoding)

Definition at line 1260 of file L1CaloBsDecoderRun3.cxx.

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}
LayerTypeEnum getLayer() const
@ globalPhi
Definition HitInfo.h:38

◆ decodeGfexTobs()

void L1CaloBsDecoderRun3::decodeGfexTobs ( const uint32_t * beg,
const uint32_t * end,
std::list< L1CaloRdoGfexTob > & tob,
std::list< L1CaloRdoRodInfo >::const_iterator rodInfo )

Decode gFEX TOBs.

We create one RDO per TOB using the value field for its Et. The flag field is used for status/error bits. FIXME We also create one RDO for the energy TOBs.

Parameters
begpointer to start of rod data payload
endpointer to end of rod data payload
toblist of RDO to be filled
rodInfoiterator to ROD information for this block

Definition at line 1393 of file L1CaloBsDecoderRun3.cxx.

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}
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.
L1Topo::BlockTypes blockType(const uint32_t word, uint32_t offset=28, uint32_t size=0x0f)
Function to return the block type of a data word from L1Topo.
Definition BlockTypes.cxx:9
size_t dataSize(TDA::PayloadIterator start)
Size in bytes of the buffer that is needed to decode next fragment data content.

◆ decodeGfexTobSlice()

bool L1CaloBsDecoderRun3::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 )
private

Decode one gFEX FPGA block of TOBs for one slice.

See https://edms.cern.ch/ui/file/1492098/1/L1CaloTOBFormats_v010.pdf

Parameters
payloadpointer to this slice in ROD fragment payload
blockTypecode for Jet or MET TOB
sliceNumbernumber of this readout slice
numSlicestotal number of TOB slices read out in this event
errorFlagsglobal error bits set for this subblock (or ROD fragment?)
toblist of RDO to be filled
rodInfoiterator to ROD information for this block
Returns
whether decoding succeeded (false to abort decoding)

Definition at line 1463 of file L1CaloBsDecoderRun3.cxx.

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}
status
Definition merge.py:16
setScaleOne setStatusOne saturated

◆ decodeJfexData()

void L1CaloBsDecoderRun3::decodeJfexData ( const uint32_t * beg,
const uint32_t * end,
std::list< L1CaloRdoJfexTower > & tower,
std::list< L1CaloRdoRodInfo >::const_iterator rodInfo )

Decode jFEX input fibre data.

We create one RDO per tower using the value field for its Et. The flag field is used for status/error bits.

Parameters
begpointer to start of rod data payload
endpointer to end of rod data payload
towerlist of RDO to be filled
rodInfoiterator to ROD information for this block

Definition at line 695 of file L1CaloBsDecoderRun3.cxx.

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}
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).

◆ decodeJfexDataChan()

uint32_t L1CaloBsDecoderRun3::decodeJfexDataChan ( const uint32_t payload[],
const uint32_t jfexNumber,
const uint32_t fpgaNumber,
const uint32_t errorMask,
std::list< L1CaloRdoJfexTower > & tower,
std::list< L1CaloRdoRodInfo >::const_iterator rodInfo )
private

Decode the data from one jFEX input fibre (only ever one slice).

Parameters
payloadpayload vector starting at this 8 word block
jfexNumbernumber of this jFEX in its shelf
fpgaNumberFPGA number
errorMaskglobal error bits set for this ROD fragment
towerlist of RDO to be filled
rodInfoiterator to ROD information for this block
Returns
whether decoding succeeded (false to abort decoding)

Definition at line 766 of file L1CaloBsDecoderRun3.cxx.

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}

◆ decodeJfexTobs()

void L1CaloBsDecoderRun3::decodeJfexTobs ( const uint32_t * beg,
const uint32_t * end,
std::list< L1CaloRdoJfexTob > & tob,
std::list< L1CaloRdoRodInfo >::const_iterator rodInfo )

Decode jFEX TOBs and XTOBs.

The RDO value encodes the cluster Et in the value field and the isolation bits and other information in the flag.

Parameters
begpointer to start of rod data payload
endpointer to end of rod data payload
toblist of RDO to be filled
rodInfoiterator to ROD information for this block

Definition at line 905 of file L1CaloBsDecoderRun3.cxx.

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}
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.

◆ decodeJfexTobSlice()

bool L1CaloBsDecoderRun3::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 )
private

Decode one jFEX FPGA block of TOBs and XTOBs for one slice.

Parameters
payloadentire ROD fragment payload vector
indexjust past end of block for this slice (this method updates it to the start of the block)
jfexNumbernumber of this jFEX in its shelf
fpgaNumberFPGA number
sliceNumbernumber of this readout slice
numSlicestotal number of TOB slices read out in this event
errorMaskglobal error bits set for this ROD fragment
toblist of RDO to be filled
rodInfoiterator to ROD information for this block
Returns
whether decoding succeeded (false to abort decoding in which case the returned index is not valid)

Definition at line 988 of file L1CaloBsDecoderRun3.cxx.

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)
1089 : L1CaloRdoFexTob::TobSource::JfexXtob;
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}

◆ decodeOneEfexTob()

void L1CaloBsDecoderRun3::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
private

Decode word(s) for one eFEX TOB (or xTOB) and create one RDO.

FIXME Document other parameters when stable!

Parameters
toblist of RDO to be filled
rodInfoiterator to ROD information for this block

Definition at line 594 of file L1CaloBsDecoderRun3.cxx.

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 );
641 L1CaloRdoEfexTob& rdo = L1CaloBsDecoderUtil::findRdo( newOne, tob );
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}

◆ decodePh1TopoData()

void L1CaloBsDecoderRun3::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.

We create one RDO per TOB using the value field for its Et. The flag field is used for status/error bits.

Parameters
begpointer to start of rod data payload
endpointer to end of rod data payload
etoblist of eFEX TOB RDOs to be filled
jtoblist of jFEX TOB RDOs to be filled
gtoblist of gFEX TOB RDOs to be filled
mtoblist of muon TOB RDOs to be filled
rodInfoiterator to ROD information for this block

Definition at line 1549 of file L1CaloBsDecoderRun3.cxx.

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!
1642 : L1CaloRdoFexTob::TobType::Tau;
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}
@ Unknown
Definition TruthClasses.h:9

◆ decodePh1TopoHits()

void L1CaloBsDecoderRun3::decodePh1TopoHits ( const uint32_t * beg,
const uint32_t * end,
std::list< L1CaloRdoPh1TopoHit > & hit,
std::list< L1CaloRdoRodInfo >::const_iterator rodInfo )

Decode Ph1Topo hit results.

The format is common to jFEX TOBs (and much like eFEX TOBs). So there could be better code reuse than this cut & paste job.

Parameters
begpointer to start of rod data payload
endpointer to end of rod data payload
toblist of RDO to be filled
rodInfoiterator to ROD information for this block

Definition at line 1674 of file L1CaloBsDecoderRun3.cxx.

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}

◆ setLogger()

void L1CaloBsDecoderRun3::setLogger ( std::unique_ptr< Logging > && logger)
inline

Definition at line 40 of file L1CaloBsDecoderRun3.h.

40{ m_logger = std::move(logger); }
static Root::TMsgLogger logger("iLumiCalc")

◆ setVerbosity()

void L1CaloBsDecoderRun3::setVerbosity ( bool verbosity)

Member Data Documentation

◆ m_logger

std::unique_ptr<Logging> L1CaloBsDecoderRun3::m_logger
private

Definition at line 136 of file L1CaloBsDecoderRun3.h.

◆ m_verbosity

int L1CaloBsDecoderRun3::m_verbosity
private

Definition at line 135 of file L1CaloBsDecoderRun3.h.


The documentation for this class was generated from the following files: