ATLAS Offline Software
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 
20 #include "defsL1Calo/CrateDefs.h"
21 #include "defsL1Calo/EfexDefs.h"
22 #include "infraL1Calo/GenericCrc.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 
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 
84 void
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 
186 uint32_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.
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 ( towerSumEt || towerFlag ) {
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 ( towerEt || towerFlag ) {
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 
362 void
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 
486 bool
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)
567  L1CaloRdoFexTob::TobSource fexTobSource = L1CaloRdoFexTob::TobSource::EfexTob;
568  size_t sliceIndex = index;
569  for (size_t iTOB = 0; iTOB < totalTobs; iTOB++) {
570  if (iTOB >= numTobs) {
571  fexTobSource = L1CaloRdoFexTob::TobSource::EfexXtob;
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 
593 void
594 L1CaloBsDecoderRun3::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,
598  L1CaloRdoFexTob::TobType tobType,
599  L1CaloRdoFexTob::TobSource tobSource,
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 );
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 }
660 
668 bool
669 L1CaloBsDecoderRun3::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
685 
694 void
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 
765 uint32_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 
904 void
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 
987 bool
988 L1CaloBsDecoderRun3::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)
1088  ? L1CaloRdoFexTob::TobSource::JfexTob
1089  : L1CaloRdoFexTob::TobSource::JfexXtob;
1090  if (iTOB < end[1]) {
1091  fexTobType = L1CaloRdoFexTob::TobType::SmallJet;
1092  } else if (iTOB < end[2]) {
1093  fexTobType = L1CaloRdoFexTob::TobType::LargeJet;
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]) {
1099  fexTobType = L1CaloRdoFexTob::TobType::Energy;
1100  } else if (iTOB < end[7]) {
1101  fexTobType = L1CaloRdoFexTob::TobType::SmallJet;
1102  } else if (iTOB < end[8]) {
1103  fexTobType = L1CaloRdoFexTob::TobType::LargeJet;
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 
1183 void
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 
1259 uint32_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 
1392 void
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 
1462 bool
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 
1493  L1CaloRdoFexTob::TobType fexTobType( L1CaloRdoFexTob::TobType::Invalid );
1494  L1CaloRdoFexTob::TobSource fexTobSource( L1CaloRdoFexTob::TobSource::GfexTob );
1495  if ( tobID >= 1 && tobID <= 4 ) {
1496  fexTobType = L1CaloRdoFexTob::TobType::SmallJet;
1497  }
1498  else if ( tobID >= 5 && tobID <= 6 ) {
1499  fexTobType = L1CaloRdoFexTob::TobType::LargeJet;
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 
1548 void
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 
1626  L1CaloRdoFexTob::TobType tobType(L1CaloRdoFexTob::TobType::Invalid);
1627  L1CaloRdoFexTob::TobSource tobSource(L1CaloRdoFexTob::TobSource::Ph1Topo);
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 
1673 void
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
L1CaloBsDecoderRun3::decodeEfexData
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.
Definition: L1CaloBsDecoderRun3.cxx:85
FexDefs::num32BitWordsPerFibre
static int num32BitWordsPerFibre()
Definition: FexDefs.h:17
L1CaloRdoEfexTower
Definition: L1CaloRdoEfexTower.h:10
L1CaloBsDecoderRun3::decodeGfexData
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.
Definition: L1CaloBsDecoderRun3.cxx:1184
EfexTrexFibrePacker.h
EfexLatomeFibrePacker.h
RunTileCalibRec.cells
cells
Definition: RunTileCalibRec.py:271
GetLCDefs::Unknown
@ Unknown
Definition: GetLCDefs.h:21
plotBeamSpotCompare.x1
x1
Definition: plotBeamSpotCompare.py:216
data
char data[hepevt_bytes_allocation_ATLAS]
Definition: HepEvt.cxx:11
L1CaloBsDecoderRun3::Logging
Interface class for logging, can be overriden to e.g.
Definition: L1CaloBsDecoderRun3.h:31
EfexHardwareInfo::getMpodNumber
int getMpodNumber() const
Definition: EfexHardwareInfo.cxx:33
FexDefs.h
L1CaloDetectorRegion::getLayer
LayerTypeEnum getLayer() const
Definition: L1CaloDetectorRegion.h:52
L1CaloRdo::setRodInfo
void setRodInfo(std::list< L1CaloRdoRodInfo >::const_iterator &rodInfo)
Definition: L1CaloRdo.cxx:252
xAOD::uint32_t
setEventNumber uint32_t
Definition: EventInfo_v1.cxx:127
make_unique
std::unique_ptr< T > make_unique(Args &&... args)
Definition: SkimmingToolEXOT5.cxx:23
index
Definition: index.py:1
Energy
std::vector< double > Energy
Definition: CalibHitToCaloCell.h:23
L1CaloDetectorRegion::getValidity
bool getValidity() const
Definition: L1CaloDetectorRegion.h:50
L1CaloBsDecoderRun3::decodeJfexDataChan
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).
Definition: L1CaloBsDecoderRun3.cxx:766
EfexCellMapping::getDetectorRegion
L1CaloDetectorRegion getDetectorRegion() const
Definition: EfexCellMapping.cxx:73
Ringer::EM2
@ EM2
Definition: CaloRingsDefs.h:48
L1Topo::blockType
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
LOG_ERROR
#define LOG_ERROR(location, title, detail)
Definition: L1CaloBsDecoderRun3.cxx:40
L1CaloBsDecoderRun3::m_verbosity
int m_verbosity
Definition: L1CaloBsDecoderRun3.h:135
L1CaloRdoEfexTower::setSupercells
void setSupercells(std::vector< uint32_t > &supercells)
Definition: L1CaloRdoEfexTower.cxx:83
L1CaloRdo::setValue
void setValue(int val, size_t slice)
Definition: L1CaloRdo.cxx:226
L1CaloBsDecoderRun3::decodeOneEfexTob
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.
Definition: L1CaloBsDecoderRun3.cxx:594
find_tgc_unfilled_channelids.mapping
mapping
Definition: find_tgc_unfilled_channelids.py:17
L1CaloBsDecoderRun3::decodeGfexTobs
void decodeGfexTobs(const uint32_t *beg, const uint32_t *end, std::list< L1CaloRdoGfexTob > &dat, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo)
Decode gFEX TOBs.
Definition: L1CaloBsDecoderRun3.cxx:1393
EfexHardwareInfo
Definition: EfexHardwareInfo.h:4
mergePhysValFiles.end
end
Definition: DataQuality/DataQualityUtils/scripts/mergePhysValFiles.py:93
GenericCrc
Definition: GenericCrc.h:9
L1CaloRdoEfexTob
Definition: L1CaloRdoEfexTob.h:10
xAOD::saturated
setScaleOne setStatusOne saturated
Definition: gFexGlobalRoI_v1.cxx:51
L1CaloDetectorRegion::Electromagnetic
@ Electromagnetic
Definition: L1CaloDetectorRegion.h:23
L1CaloRdoEfexTower::setHardwareInfo
void setHardwareInfo(uint32_t fpga, uint32_t mgt, uint32_t word, uint32_t mpod, uint32_t fibre, uint32_t overlap)
Definition: L1CaloRdoEfexTower.cxx:89
Ringer::EM
@ EM
Definition: CaloRingsDefs.h:19
lumiFormat.i
int i
Definition: lumiFormat.py:92
ret
T ret(T t)
Definition: rootspy.cxx:260
Result
ICscStripFitter::Result Result
Definition: CalibCscStripFitter.cxx:13
EfexHardwareInfo::getFibreNumber
int getFibreNumber() const
Definition: EfexHardwareInfo.cxx:21
TRT::Hit::layer
@ layer
Definition: HitInfo.h:79
L1CaloRdoEfexTower.h
L1CaloBsDecoderRun3::decodeGfexTobSlice
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.
Definition: L1CaloBsDecoderRun3.cxx:1463
CrateDefs.h
xAOD::uint64_t
uint64_t
Definition: EventInfo_v1.cxx:123
EfexTrexFibrePacker
Definition: EfexTrexFibrePacker.h:10
SCT_Monitoring::disabled
@ disabled
Definition: SCT_MonitoringNumbers.h:60
EfexLatomeFibrePacker::getUnpackedData
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.
Definition: EfexLatomeFibrePacker.cxx:168
L1CaloBsDecoderRun3::decodeJfexTobSlice
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.
Definition: L1CaloBsDecoderRun3.cxx:988
L1CaloBsDecoderRun3::decodeJfexData
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.
Definition: L1CaloBsDecoderRun3.cxx:695
L1CaloRdoFexTob::TobSource
TobSource
Definition: L1CaloRdoFexTob.h:15
L1CaloDetectorRegion::getEtaIndex
int getEtaIndex() const
Definition: L1CaloDetectorRegion.h:44
EfexTrexFibrePacker::getUnpackedData
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.
Definition: EfexTrexFibrePacker.cxx:127
TRT::Hit::globalPhi
@ globalPhi
Definition: HitInfo.h:38
L1CaloBsDecoderRun3.h
min
#define min(a, b)
Definition: cfImp.cxx:40
WriteBchToCool.beg
beg
Definition: WriteBchToCool.py:69
L1CaloBsDecoderRun3::decodePh1TopoData
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.
Definition: L1CaloBsDecoderRun3.cxx:1549
PayloadHelpers::dataSize
size_t dataSize(TDA::PayloadIterator start)
Size in bytes of the buffer that is needed to decode next fragment data content.
Definition: TriggerEDMDeserialiserAlg.cxx:188
L1CaloDetectorRegion
Definition: L1CaloDetectorRegion.h:8
EfexCellMapping.h
L1CaloBsDecoderRun3::decodeJfexTobs
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.
Definition: L1CaloBsDecoderRun3.cxx:905
PixelModuleFeMask_create_db.payload
string payload
Definition: PixelModuleFeMask_create_db.py:69
FibrePackerBase::InputDataFrameType
InputDataFrameType
type of input data frame
Definition: FibrePackerBase.h:37
L1CaloDetectorRegion::getPhiIndex
int getPhiIndex() const
Definition: L1CaloDetectorRegion.h:45
DeMoScan.index
string index
Definition: DeMoScan.py:362
GenericCrc.h
RunTileMonitoring.towers
towers
Definition: RunTileMonitoring.py:133
EfexHardwareInfo::getValidity
bool getValidity() const
Definition: EfexHardwareInfo.cxx:43
L1CaloBsDecoderRun3::checkFibreCRC
bool checkFibreCRC(std::vector< uint32_t > &data) const
Check the CRC in an input fibre block of words.
Definition: L1CaloBsDecoderRun3.cxx:669
L1CaloBsDecoderRun3::decodeGfexDataChan
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).
Definition: L1CaloBsDecoderRun3.cxx:1260
L1CaloRdoEfexTob.h
EfexDefs.h
EfexLatomeFibrePacker
Definition: EfexLatomeFibrePacker.h:10
GenericCrc::crc9fibre
uint32_t crc9fibre(const std::vector< uint32_t > &inwords, size_t num_bits) const
Functions calculating CRC over input data.
Definition: GenericCrc.cxx:5
L1CaloRdo::setFlag
void setFlag(int flag, size_t slice)
Definition: L1CaloRdo.cxx:239
xAODType::Tau
@ Tau
The object is a tau (jet)
Definition: ObjectType.h:49
L1CaloBsDecoderUtil::findRdo
static Tar & findRdo(const Tar &target, Dat &data, Iter begin, Iter end)
Definition: L1CaloBsDecoderUtil.h:33
L1CaloBsDecoderRun3::decodeEfexDataChan
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).
Definition: L1CaloBsDecoderRun3.cxx:187
EfexCellMapping
Definition: EfexCellMapping.h:14
merge.status
status
Definition: merge.py:17
CrateDefs::numAtcaFexSlots
static unsigned int numAtcaFexSlots()
Definition: CrateDefs.h:42
L1CaloBsDecoderUtil.h
L1CaloBsDecoderRun3::L1CaloBsDecoderRun3
L1CaloBsDecoderRun3()
Definition: L1CaloBsDecoderRun3.cxx:48
Ringer::EM1
@ EM1
Definition: CaloRingsDefs.h:47
L1CaloBsDecoderRun3::decodeEfexTobSlice
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.
Definition: L1CaloBsDecoderRun3.cxx:487
L1CaloBsDecoderRun3::decodePh1TopoHits
void decodePh1TopoHits(const uint32_t *beg, const uint32_t *end, std::list< L1CaloRdoPh1TopoHit > &hit, std::list< L1CaloRdoRodInfo >::const_iterator rodInfo)
Decode Ph1Topo hit results.
Definition: L1CaloBsDecoderRun3.cxx:1674
FibrePackerBase::InputDataFrameType::Normal
@ Normal
Standard data frame.
EfexDefs::numInputFibresPerFpga
static int numInputFibresPerFpga()
Definition: EfexDefs.h:35
fitman.k
k
Definition: fitman.py:528
L1CaloRdoFexTob::TobType
TobType
Definition: L1CaloRdoFexTob.h:14
EfexHardwareInfo::getOverlap
int getOverlap() const
Definition: EfexHardwareInfo.cxx:51
L1CaloBsDecoderRun3::decodeEfexTobs
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.
Definition: L1CaloBsDecoderRun3.cxx:363