ATLAS Offline Software
Loading...
Searching...
No Matches
PpmByteStreamReadV1V2Tool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5// ===========================================================================
6// Includes
7// ===========================================================================
8// STD:
9// ===========================================================================
10#include <stdexcept>
11#include <bitset>
12// ===========================================================================
13#include "eformat/SourceIdentifier.h"
17
18#include "CaloUserHeader.h"
19#include "SubBlockHeader.h"
20#include "SubBlockStatus.h"
21#include "WordDecoder.h"
22
23#include "../L1CaloSubBlock.h" // Only for error codes
24#include "../L1CaloSrcIdMap.h"
25
27
29// ===========================================================================
30
31namespace {
32uint32_t bitFieldSize(uint32_t word, uint8_t offset, uint8_t size) {
33 return (word >> offset) & ((1U << size) - 1);
34}
35
36uint32_t crateModuleMask(uint8_t crate, uint8_t module) {
37 return (crate << 8) | (1 << 4) | module;
38}
39
40uint32_t coolId(uint8_t crate, uint8_t module, uint8_t channel) {
41 const uint8_t pin = channel % 16;
42 const uint8_t asic = channel / 16;
43 return (crateModuleMask(crate, module) << 16) | (pin << 8) | asic;
44}
45
46int16_t pedCorrection(uint16_t twoBytePedCor) {
47 return twoBytePedCor > 511? (twoBytePedCor - 1024): twoBytePedCor;
48}
49
50#if 0
51std::string noAuxSuffix(const std::string& name) {
52 if ((name.size() > 4) && (name.substr(name.size()-4, 4) == "Aux.")) {
53 return name.substr(0, name.size() - 4);
54 }
55 return name;
56}
57#endif
58}
59// ===========================================================================
60namespace LVL1BS {
61// ===========================================================================
62// Constructor
64 "PpmByteStreamxAODReadTool"*/) :
65 AsgTool(name),
66 m_errorTool("LVL1BS::L1CaloErrorByteStreamTool/L1CaloErrorByteStreamTool"),
67 m_ppmMaps("LVL1::PpmMappingTool/PpmMappingTool"),
68 m_robDataProvider("ROBDataProviderSvc", name),
69 m_srcIdMap(nullptr),
71{
72 declareInterface<PpmByteStreamReadV1V2Tool>(this);
73 declareProperty("UseSWROD",m_useSWROD = false, "Use SWROD readout instead of legacy (which was removed in 2024)");
74 declareProperty("PpmMappingTool", m_ppmMaps,
75 "Crate/Module/Channel to Eta/Phi/Layer mapping tool");
76 declareProperty("ROBDataProviderSvc", m_robDataProvider,
77 "Get ROB source IDs service");
78}
79
80// ===========================================================================
81// Initialize
82
83
85 ATH_MSG_DEBUG("Initializing " << name());
86
88 m_srcIdMap->useSWROD(m_useSWROD);
89 CHECK(m_errorTool.retrieve());
90 CHECK(m_ppmMaps.retrieve());
91 CHECK(m_robDataProvider.retrieve());
92
94
95 return StatusCode::SUCCESS;
96}
97// ===========================================================================
98// Finalize
99
101 delete m_srcIdMap;
102
103 return StatusCode::SUCCESS;
104}
105
106// Conversion bytestream to trigger towers
108 State& state,
109 const IROBDataProviderSvc::VROBFRAG& robFrags) const
110{
111 if (m_maxSizeSeen > state.m_triggerTowers->capacity()){
113 }
114
115 state.m_subDetectorID = eformat::TDAQ_CALO_PREPROC;
116
117 ROBIterator rob = robFrags.begin();
118 ROBIterator robEnd = robFrags.end();
119
120 for (; rob != robEnd; ++rob) {
121
122 StatusCode sc = processRobFragment_(state, rob, RequestType::PPM);
123 if (!sc.isSuccess()) {
124
125 }
126 }
127
129 return StatusCode::SUCCESS;
130}
131
132
134 const EventContext& ctx,
135 xAOD::TriggerTowerContainer* const ttCollection) const
136{
138}
139
141 const EventContext& ctx,
142 const std::string& sgKey,
143 xAOD::TriggerTowerContainer* const ttCollection) const
144{
145 State state;
146 state.m_triggerTowers = ttCollection;
147 const std::vector<uint32_t>& vID(ppmSourceIDs(state, sgKey));
148 // // get ROB fragments
150 m_robDataProvider->getROBData(ctx, vID, robFrags, "PpmByteStreamxAODReadTool");
151 ATH_MSG_DEBUG("Number of ROB fragments:" << robFrags.size());
152
153 CHECK(convert(state, robFrags));
154 return StatusCode::SUCCESS;
155}
156
157// ===========================================================================
159 State& state,
160 const ROBIterator& robIter, const RequestType& /*requestedType*/) const
161{
162 auto rob = **robIter;
163
165 "Treating ROB fragment source id #" << MSG::hex << rob.rob_source_id());
166
167
168 state.m_rodSourceId = rob.rod_source_id();
169 state.m_robSourceId = rob.source_id();
170 const auto sourceID = (state.m_rodSourceId >> 16) & 0xff;
171 const auto rodCrate = m_srcIdMap->crate(state.m_rodSourceId);
172 const auto rodSlink = m_srcIdMap->slink(state.m_rodSourceId);
173 // -------------------------------------------------------------------------
174 // Check Rob status
175 if (rob.nstatus() > 0) {
176 ROBPointer robData;
177 rob.status(robData);
178 if (*robData != 0) {
179 ATH_MSG_WARNING("ROB status error - skipping fragment");
180 m_errorTool->robError(state.m_rodSourceId, *robData);
181 return StatusCode::FAILURE;
182 }
183 }
184 // -------------------------------------------------------------------------
185 RODPointer payloadBeg;
186 RODPointer payloadEnd;
187 RODPointer payload;
188
189 rob.rod_data(payloadBeg);
190 payloadEnd = payloadBeg + rob.rod_ndata();
191 payload = payloadBeg;
192 // -------------------------------------------------------------------------
193 if (payload == payloadEnd) {
194 ATH_MSG_DEBUG("ROB fragment empty");
195 return StatusCode::FAILURE;
196 }
197 // -------------------------------------------------------------------------
198
199
200 uint16_t rodVer = rob.rod_version() & 0xffff;
201 uint32_t rodRunNumber = rob.rod_run_no() & 0xffffff;
202 state.m_verCode = ((rodVer & 0xfff) << 4) | 1;
203
204
205 if (sourceID != state.m_subDetectorID) {
206 ATH_MSG_ERROR("Wrong subdetector source id for requested objects: " << state.m_rodSourceId);
207 return StatusCode::FAILURE;
208 }
209
210 ATH_MSG_DEBUG("Treating crate " << rodCrate << " slink " << rodSlink);
211 state.m_caloUserHeader = CaloUserHeader(*payload);
212 if (!state.m_caloUserHeader.isValid()) {
213 ATH_MSG_ERROR("Invalid or missing user header");
214 return StatusCode::FAILURE;
215 }
216
218 "Run number: " << MSG::dec << rodRunNumber << endmsg
219 << "Version code: 0x" << MSG::hex << int(state.m_verCode) << MSG::dec
220 << endmsg << "LUT triggered slice offset: "
221 << int(state.m_caloUserHeader.lut()) << endmsg
222 << "FADC triggered slice offset: " << int(state.m_caloUserHeader.ppFadc())
223 << endmsg << "FADC baseline lower bound: "
224 << int(state.m_caloUserHeader.ppLowerBound()));
225
226 int indata = 0;
227 uint8_t blockType = 0;
228 int subBlock = 0;
229
230 for (; payload != payloadEnd; ++payload) {
231 if (CaloUserHeader::isValid(*payload) && (subBlock == 0)) {
232
233 } else if (SubBlockHeader::isSubBlockHeader(*payload)) {
234 indata = 0;
235 CHECK(processPpmBlock_(state));
236
237 state.m_ppLuts.clear();
238 state.m_ppFadcs.clear();
239 state.m_ppBlock.clear();
240
241 blockType = (*payload >> 28) & 0xf;
242
243 if ((blockType & 0xd) == 0xc) {
244 state.m_subBlockHeader = SubBlockHeader(*payload);
246 "SubBlock version #" << int(state.m_subBlockHeader.version())
247 << " format #" << int(state.m_subBlockHeader.format())
248 << " seqNum (compVer) #" << int(state.m_subBlockHeader.seqNum())
249 << " nslice1 #" << int(state.m_subBlockHeader.nSlice1())
250 << " nslice2 #" << int(state.m_subBlockHeader.nSlice2())
251 );
252 subBlock = blockType & 0xe;
253 } else if (blockType == (subBlock | 1)) {
254 processSubBlockStatus_(state, state.m_subBlockHeader.crate(), state.m_subBlockHeader.module(), *payload);
255 subBlock = 0;
256 }
257 } else {
258 switch(state.m_subDetectorID){
259 case eformat::TDAQ_CALO_PREPROC:
260 CHECK(processPpmWord_(state, *payload, indata));
261 break;
262 default:
263 break;
264 }
265 indata++;
266 }
267 }
268 CHECK(processPpmBlock_(state));
269 state.m_ppLuts.clear();
270 state.m_ppFadcs.clear();
271 state.m_ppBlock.clear();
272 return StatusCode::SUCCESS;
273}
274
276 uint32_t word,
277 int indata) const
278{
279 if ( (state.m_subBlockHeader.format() == 0)
280 || (state.m_subBlockHeader.format() >= 2)
281 || (state.m_verCode >= 0x41)) {
282 state.m_ppBlock.push_back(word);
283 } else if ((state.m_verCode == 0x21) || (state.m_verCode == 0x31)) {
284 return processPpmStandardR3V1_(state, word, indata);
285 } else {
286 ATH_MSG_ERROR("Unsupported PPM version:format ("
287 << state.m_verCode << ":" << state.m_subBlockHeader.format()
288 <<") combination");
289 return StatusCode::FAILURE;
290 }
291 return StatusCode::SUCCESS;
292}
293
294
296{
297 if (state.m_ppBlock.size() > 0) {
298 if (state.m_subBlockHeader.format() == 0) {
299 StatusCode sc = processPpmNeutral_(state);
300 CHECK(sc);
301 return sc;
302 }
303
304 if (state.m_verCode == 0x31) {
305 StatusCode sc = processPpmCompressedR3V1_(state);
306 CHECK(sc);
307 return sc;
308 }
309
310 if (state.m_verCode == 0x41 || state.m_verCode == 0x42) {
311 StatusCode sc = processPpmBlockR4V1_(state);
312 CHECK(sc);
313 return sc;
314 }
315 }
316
317 if (state.m_ppLuts.size() > 0) {
318 if (state.m_verCode == 0x21 || state.m_verCode == 0x31) {
319 StatusCode sc = processPpmBlockR3V1_(state);
320 CHECK(sc);
321 return sc;
322 }
323 ATH_MSG_ERROR("Unknown PPM subheader format '"
324 << int(state.m_subBlockHeader.format())
325 << "' for rob version '"
326 << MSG::hex << int(state.m_verCode)
327 << MSG::dec << "'" );
328 return StatusCode::FAILURE;
329 }
330 return StatusCode::SUCCESS;
331}
332
334{
335 uint8_t numLut = state.m_subBlockHeader.nSlice1();
336 uint8_t numFadc = state.m_subBlockHeader.nSlice2();
337 uint8_t totSlice = 3 * numLut + numFadc;
338
339 uint8_t channel = 0;
340 for ( int asic = 0 ; asic < 4 ; ++asic ) {
341 for ( int mcm = 0 ; mcm < 16 ; ++mcm ) {
342 // ----------------------------------------------------------------------
343 std::vector<uint32_t> rotated(totSlice);
344
345 for ( uint8_t slice = 0 ; slice < totSlice ; ++slice ) {
346 for ( uint8_t bit = 0 ; bit < 11 ; ++bit ) {
347 if ( state.m_ppBlock[slice * 11 + asic * (11 * totSlice) + bit + 1] & (1 << mcm))
348 rotated[slice] |= (1 << bit);
349 }
350 }
351
352 bool nonZeroData = false;
353 for (uint8_t slice = 0; slice < numLut; ++slice) {
354 if (rotated[slice]
355 || rotated[slice + numLut]
356 || rotated[slice + 2 * numLut + numFadc]) { // CP, JET
357 nonZeroData = true;
358 break;
359 }
360 }
361
362 std::vector<uint8_t> lcpVal;
363 std::vector<uint8_t> lcpBcidVec;
364 std::vector<uint8_t> ljeVal;
365 std::vector<uint8_t> ljeSat80Vec;
366 std::vector<int16_t> pedCor;
367 std::vector<uint8_t> pedEn;
368
369 std::vector<uint16_t> adcVal;
370 std::vector<uint8_t> adcExt;
371
372 if (nonZeroData) {
373 for (uint8_t slice = 0; slice < numLut; ++slice) {
374 lcpVal.push_back(rotated[slice] & 0xff);
375 ljeVal.push_back(rotated[slice + numLut] & 0xff);
376 pedCor.push_back(::pedCorrection(rotated[slice + 2 * numLut + numFadc] & 0x3ff));
377
378 lcpBcidVec.push_back((rotated[slice] >> 8) & 0x7);
379 ljeSat80Vec.push_back((rotated[slice + numLut] >> 8) & 0x7);
380 pedEn.push_back((rotated[slice + 2 * numLut + numFadc] >> 10) & 0x1);
381 }
382 }
383
384 for (uint8_t slice = 0; slice < numFadc; ++slice) {
385 if (rotated[slice + numLut]) { // CP, JET
386 nonZeroData = true;
387 break;
388 }
389 }
390
391 if (nonZeroData) {
392 for (uint8_t slice = 0; slice < numFadc; ++ slice) {
393 adcVal.push_back(rotated[slice + 2 * numLut] & 0x3ff);
394 adcExt.push_back((rotated[slice + 2 * numLut] >> 10 & 0x1) & 0x3ff);
395 }
396 }
397
399 state,
400 state.m_subBlockHeader.crate(),
401 state.m_subBlockHeader.module(),
402 channel,
403 std::move(lcpVal),
404 std::move(lcpBcidVec),
405 std::move(ljeVal),
406 std::move(ljeSat80Vec),
407 std::move(adcVal),
408 std::move(adcExt),
409 std::move(pedCor),
410 std::move(pedEn)));
411 // ---------------------------------------------------------------------
412 channel++;
413 }
414 }
415 return StatusCode::SUCCESS;
416}
417
419{
420 BitReader br (state.m_ppBlock);
421 uint8_t chan = 0;
422 try{
423 while (chan < 64) {
424 uint8_t present = 1;
425 if (state.m_subBlockHeader.format() == 3) {
426 present = br.getField(1);
427 }
428
429 if (present == 1) {
430 uint8_t lutVal = 0;
431 uint8_t fmt = 6;
432 uint8_t lutSat=0;
433 uint8_t lutExt=0;
434 uint8_t lutPeak=0;
435
436 std::vector<uint16_t> adcVal = {0 , 0, 0, 0, 0};
437 std::vector<uint8_t> adcExt = {0 , 0, 0, 0, 0};
438
439 uint8_t minHeader = br.getField(4);
440 uint8_t minIndex = minHeader % 5;
441 if (minHeader < 15) { // Formats 0-5
442 if (minHeader < 10) { // Formats 0-1
443 fmt = minHeader / 5;
444 } else { // Formats 2-5
445 fmt = 2 + br.getField( 2);
446 uint8_t haveLut = br.getField(1);
447 if (fmt == 2) {
448 if (haveLut == 1) {
449 lutVal = br.getField(3);
450 lutPeak = 1; // Even if LutVal==0 it seems
451 }
452 } else {
453 uint8_t haveExt = br.getField(1);
454 if (haveLut == 1) {
455 lutVal = br.getField(8);
456 lutExt = br.getField(1);
457 lutSat = br.getField(1);
458 lutPeak = br.getField(1);
459 }
460
461 if (haveExt == 1){
462 for(uint8_t i = 0; i < 5; ++i) {
463 adcExt[i] = br.getField(1);
464 }
465 } else {
466 adcExt[2] = lutExt;
467 }
468 }
469 }
470 adcVal = getPpmAdcSamplesR3_(state, br, fmt, minIndex);
471 } else {
472 uint8_t haveAdc = br.getField(1);
473 if (haveAdc == 1) {
474 uint16_t val = br.getField(10);
475 for(uint8_t i = 0; i < 5; ++i) {
476 adcVal[i] = val;
477 }
478 }
479 }
480 // Add Trigger Tower
481 //std::vector<uint8_t> luts = {lutVal};
483 state,
484 state.m_subBlockHeader.crate(),
485 state.m_subBlockHeader.module(),
486 chan,
487 std::vector<uint8_t> {lutVal},
488 std::vector<uint8_t> {uint8_t(lutExt | (lutSat << 1) | (lutPeak << 2))},
489 std::move(adcVal),
490 std::move(adcExt)
491 ));
492 }
493 chan++;
494 }
495 }catch (const std::out_of_range& ex) {
496 ATH_MSG_WARNING("Excess Data in Sub-block");
498 }
499 return StatusCode::SUCCESS;
500}
501
503 State& state,
504 BitReader& br, uint8_t format, uint8_t minIndex) const
505{
506 std::vector<uint16_t> adc = {0, 0, 0, 0, 0};
507 uint8_t minAdc = 0;
508
509 for(uint8_t i = 0; i <5; ++i) {
510 uint8_t longField = 0;
511 uint8_t numBits = 0;
512 if (format > 2) {
513 longField = br.getField(1);
514 numBits = longField == 0? 4: (format * 2);
515 } else {
516 numBits = i == 0? 4: (format + 2);
517 }
518
519 if (i == 0) {
520 minAdc = br.getField(numBits);
521 if (longField == 0) {
522 minAdc += state.m_caloUserHeader.ppLowerBound();
523 }
524 } else {
525 adc[i] = minAdc + br.getField(numBits);
526 }
527 }
528
529 if (minIndex == 0) {
530 adc[0] = minAdc;
531 } else {
532 adc[0] = adc[minIndex];
533 adc[minIndex] = minAdc;
534 }
535 return adc;
536}
537
538
539
541 uint32_t word,
542 int inData) const
543{
544
545 StatusCode sc = StatusCode::SUCCESS;
546 if (state.m_subBlockHeader.seqNum() == 63) { // Error block
547 ATH_MSG_DEBUG("Error PPM subblock");
548 //TODO: errorTool
549 } else {
550 const uint8_t numAdc = state.m_subBlockHeader.nSlice2();
551 const uint8_t numLut = state.m_subBlockHeader.nSlice1();
552 const uint8_t nTotal = numAdc + numLut;
553 const uint8_t wordsPerBlock = 8; // 16 towers (4 MCMs) / 2 per word
554 const uint8_t iBlk = inData / wordsPerBlock;
555 uint8_t iChan = state.m_subBlockHeader.seqNum() + 2 * (inData % wordsPerBlock);
556
557 if (iBlk < numLut) { // First all LUT values
558 for(uint8_t i = 0; i < 2; ++i) {
559 uint16_t subword = (word >> 16 * i) & 0x7ff;
560 state.m_ppLuts[iChan].push_back(subword);
561 iChan++;
562 }
563 } else if (iBlk < nTotal) { // Next all FADC values
564 for(uint8_t i = 0; i < 2; ++i) {
565 uint16_t subword = (word >> (16 * i)) & 0x7ff;
566 state.m_ppFadcs[iChan].push_back(subword);
567 iChan++;
568 }
569
570 } else{
571 ATH_MSG_WARNING("Error decoding Ppm word (run1)");
572 sc = StatusCode::FAILURE;
573 }
574
575 }
576 return sc;
577}
578
580{
581 if (state.m_subBlockHeader.format() == 1) {
583 return StatusCode::SUCCESS;
584 } else if (state.m_subBlockHeader.format() >= 2) {
586 return StatusCode::SUCCESS;
587 }
588 return StatusCode::FAILURE;
589}
590
592{
593 BitReader br (state.m_ppBlock);
594 uint8_t numAdc = state.m_subBlockHeader.nSlice2();
595 uint8_t numLut = state.m_subBlockHeader.nSlice1();
596 int16_t pedCorBase = -20;
597
598
599 try{
600 for(uint8_t chan = 0; chan < s_channels; ++chan) {
601 uint8_t present = 1;
602
603 std::vector<uint8_t> haveLut(numLut, 0);
604 std::vector<uint8_t> lcpVal(numLut, 0);
605
606 std::vector<uint8_t> lcpExt(numLut, 0);
607 std::vector<uint8_t> lcpSat(numLut, 0);
608 std::vector<uint8_t> lcpPeak(numLut, 0);
609 std::vector<uint8_t> lcpBcidVec(numLut, 0);
610
611 std::vector<uint8_t> ljeVal(numLut, 0);
612
613 std::vector<uint8_t> ljeLow(numLut, 0);
614 std::vector<uint8_t> ljeHigh(numLut, 0);
615 std::vector<uint8_t> ljeRes(numLut, 0);
616 std::vector<uint8_t> ljeSat80Vec(numLut, 0);
617
618 std::vector<uint16_t> adcVal(numAdc, 0);
619 std::vector<uint8_t> adcExt(numAdc, 0);
620 std::vector<int16_t> pedCor(numLut, 0);
621 std::vector<uint8_t> pedEn(numLut, 0);
622
623 int8_t encoding = -1;
624 int8_t minIndex = -1;
625
626 if (state.m_subBlockHeader.format() == 3) {
627 present = br.getField(1);
628 }
629 if (present == 1) {
630 interpretPpmHeaderR4V1_(br, numAdc, encoding, minIndex);
631 CHECK((encoding != -1) && (minIndex != -1));
632 // First get the LUT related quantities
633 if (encoding < 3) {
634 // Get the peak finder bits
635 for(uint i=0; i < numLut; ++i) {
636 lcpPeak[i] = br.getField(1);
637 }
638 // Get Sat80 low bits
639 if (encoding > 0) {
640 for (uint8_t i = 0; i < numLut; ++i) {
641 ljeLow[i] = br.getField(1);
642 }
643 }
644 // Get LutCP and LutJEP values (these are
645 // only present if the peak finder is set).
646 if (encoding == 2) {
647 for (uint8_t i = 0; i < numLut; ++i) {
648 if (lcpPeak[i] == 1) {
649 lcpVal[i] = br.getField(4);
650 }
651 }
652 for(uint8_t i = 0; i < numLut; ++i) {
653 if (lcpPeak[i] == 1){
654 ljeVal[i] = br.getField(3);
655 }
656 }
657 }
658 } else if (encoding < 6) {
659 // Get LUT presence flag for each LUT slice.
660 for(uint8_t i = 0; i < numLut; ++i){
661 haveLut[i] = br.getField(1);
662 }
663
664 // Get external BCID bits (if block is present).
665 uint8_t haveExt = br.getField(1);
666
667 if (haveExt == 1) {
668 for (uint8_t i = 0; i < numAdc; ++i) {
669 adcExt[i] = br.getField(1);
670 }
671 }
672
673 for(uint8_t i = 0; i < numLut; ++i){
674 if (haveLut[i] == 1) {
675 lcpVal[i] = br.getField(8);
676 lcpExt[i] = br.getField(1);
677 lcpSat[i] = br.getField(1);
678 lcpPeak[i] = br.getField(1);
679 }
680 }
681 // Get JEP LUT values and corresponding bits.
682 for(uint8_t i = 0; i < numLut; ++i){
683 if (haveLut[i] == 1) {
684 ljeVal[i] = br.getField(8);
685 ljeLow[i] = br.getField(1);
686 ljeHigh[i] = br.getField(1);
687 ljeRes[i] = br.getField(1);
688 }
689 }
690
691 }
692
693 }
694 // Next get the ADC related quantities (all encodings).
695 if (minIndex <0) return StatusCode::FAILURE;
696 adcVal = getPpmAdcSamplesR4_(state, br, encoding, minIndex);
697 // Finally get the pedestal correction.
698 if ((encoding < 3) || (encoding == 6)) {
699 for (uint8_t i = 0; i < numLut; ++i)
700 {
701 pedCor[i] = br.getField(6) + pedCorBase;
702 if (state.m_subBlockHeader.compVer() > 0) {
703 pedEn[i] = 1;
704 }
705 }
706 } else {
707 // At the moment there is an enabled bit for every LUT slice
708 // (even though its really a global flag).
709 // The correction values is a twos complement signed value.
710 for (uint8_t i = 0; i < numLut; ++i)
711 {
712 uint16_t val = br.getField(10);
713 pedCor[i] = ::pedCorrection(val);
714 pedEn[i] = br.getField(1);
715 }
716 }
717
718 for(uint8_t i=0; i < numLut; ++i){
719 lcpBcidVec[i] = uint8_t((lcpPeak[i] << 2) | (lcpSat[i] << 1) | lcpExt[i]);
720 ljeSat80Vec[i] = uint8_t((ljeRes[i] << 2) | (ljeHigh[i] << 1) | ljeLow[i]);
721 }
724 chan,
725 std::move(lcpVal), std::move(lcpBcidVec),
726 std::move(ljeVal), std::move(ljeSat80Vec),
727 std::move(adcVal), std::move(adcExt),
728 std::move(pedCor), std::move(pedEn)));
729 } // End for loop: done with that channel, move on to the next one.
730 // Finally decode the error and status blocks (if any).
732 state.m_subBlockHeader.crate(), state.m_subBlockHeader.module(), br);
733 } catch (const std::out_of_range& ex) {
734 ATH_MSG_WARNING("Excess Data in Sub-block");
736 }
737 //Check status word
738 return StatusCode::SUCCESS;
739
740}
741
743 uint8_t numAdc,
744 int8_t& encoding, int8_t& minIndex) const
745{
746 uint8_t minHeader = 0;
747
748 if (numAdc == 5) {
749 minHeader = br.getField(4);
750
751 minIndex = minHeader % 5;
752 if (minHeader < 15){ // Encodings 0-5
753 if (minHeader < 10) {
754 encoding = minHeader / 5;
755 } else {
756 encoding = 2 + br.getField(2);
757 }
758 } else {
759 encoding = 6;
760 }
761 } else {
762 uint8_t numBits = 0;
763 if (numAdc ==3 ) {
764 numBits = 2;
765 } else if (numAdc == 7) {
766 numBits = 3;
767 } else if (numAdc < 16) {
768 numBits = 4;
769 }
770
771 if (numBits > 0) {
772 uint8_t fieldSize = 1 << numBits;
773 minHeader = br.getField(numBits);
774 uint8_t encValue = fieldSize - 1;
775 if (minHeader == encValue) { // Encoding 6
776 encoding = 6;
777 minIndex = 0;
778 } else {
779 minHeader += br.getField(2) << numBits;
780 minIndex = minHeader % fieldSize;
781 encValue = 3 * fieldSize;
782
783 if (minHeader < encValue) { // Encodings 0-2
784 encoding = minHeader / fieldSize;
785 } else {
786 encoding = 3 + br.getField(2);
787 }
788 }
789 }
790 }
791}
792
794 State& state,
795 BitReader& br,
796 uint8_t encoding, uint8_t minIndex) const
797{
798 uint8_t numAdc = state.m_subBlockHeader.nSlice2();
799
800 if (encoding == 6) {
801 uint16_t val = br.getField(6);
802 return std::vector<uint16_t>(numAdc, val);
803 } else if ( encoding < 3) {
804 std::vector<uint16_t> adc(numAdc, 0);
805 uint16_t minAdc = br.getField(5) + state.m_caloUserHeader.ppLowerBound();
806 adc[minIndex] = minAdc;
807 for(uint8_t i = 1; i < numAdc; ++i) {
808 adc[i == minIndex? 0: i] = br.getField(encoding + 2) + minAdc;
809 }
810 return adc;
811 } else {
812 std::vector<uint16_t> adc(numAdc, 0);
813 uint16_t minAdc = br.getField(1)
814 ? br.getField(encoding * 2)
815 : (br.getField(5) +
817
818 adc[minIndex] = minAdc;
819 for (uint8_t i = 1; i < numAdc; ++i) {
820 adc[minIndex == i? 0: i] = br.getField(
821 br.getField(1)? encoding * 2: 4
822 ) + minAdc;
823 }
824 return adc;
825 }
826}
827
829{
830 if (state.m_subBlockHeader.format() == 1) {
832 return StatusCode::SUCCESS;
833 } else if (state.m_subBlockHeader.format() >= 2) {
834 // TODO: convert compressed
835 return StatusCode::FAILURE;
836 }
837 return StatusCode::FAILURE;
838}
839
841{
842 BitReader br (state.m_ppBlock);
843 uint8_t numAdc = state.m_subBlockHeader.nSlice2();
844 uint8_t numLut = state.m_subBlockHeader.nSlice1();
845 uint8_t crate = state.m_subBlockHeader.crate();
846 uint8_t module = state.m_subBlockHeader.module();
847
848 for (uint8_t chan = 0; chan < 64; ++chan) {
849
850 //for (uint8_t k = 0; k < 4; ++k) {
851 std::vector<uint8_t> lcpVal;
852 std::vector<uint8_t> lcpBcidVec;
853
854 std::vector<uint8_t> ljeVal;
855 std::vector<uint8_t> ljeSat80Vec;
856
857
858
859 std::vector<uint16_t> adcVal;
860 std::vector<uint8_t> adcExt;
861 std::vector<int16_t> pedCor;
862 std::vector<uint8_t> pedEn;
863 try {
864 for (int i = 0; i < numLut; ++i) {
865 lcpVal.push_back(br.getField(8));
866 lcpBcidVec.push_back(br.getField(3));
867 }
868
869 for (int i = 0; i < numLut; ++i) {
870 ljeVal.push_back(br.getField(8));
871 ljeSat80Vec.push_back(br.getField(3));
872 }
873
874 for (int i = 0; i < numAdc; ++i) {
875 adcVal.push_back(br.getField(10));
876 adcExt.push_back(br.getField(1));
877 }
878
879 for (int i = 0; i < numLut; ++i) {
880 uint16_t pc = br.getField(10);
881 pedCor.push_back(pedCorrection(pc));
882 pedEn.push_back(br.getField(1));
883 }
884 } catch (const std::out_of_range& ex) {
885 ATH_MSG_WARNING("Excess Data in Sub-block");
887 }
888 CHECK(
889 addTriggerTowerV2_(state,
890 crate, module, chan,
891 std::move(lcpVal), std::move(lcpBcidVec),
892 std::move(ljeVal), std::move(ljeSat80Vec),
893 std::move(adcVal), std::move(adcExt),
894 std::move(pedCor), std::move(pedEn)));
895 }
896
897 return StatusCode::SUCCESS;
898}
899
901{
902 for(const auto & lut : state.m_ppLuts) {
904 state,
905 state.m_subBlockHeader.crate(),
906 state.m_subBlockHeader.module(),
907 lut.first,
908 lut.second,
909 state.m_ppFadcs[lut.first]));
910 }
911 return StatusCode::SUCCESS;
912}
913
915 uint8_t crate, uint8_t module, uint32_t payload) const
916{
917 int curr = state.m_triggerTowers->size() - 1;
918 for(int i=0; i < s_channels; ++i){
919 if (curr < 0){
920 break;
921 }
922 auto tt = (*state.m_triggerTowers)[curr--];
923 if (tt->coolId() >> 16 & crateModuleMask(crate, module)){
924 LVL1::DataError errorBits( tt->errorWord() );
925 errorBits.set(LVL1::DataError::SubStatusWord, payload);
926 tt->setErrorWord( errorBits.error() );
927 }else{
928 break;
929 }
930 }
931}
932
933
935 uint8_t crate, uint8_t module, BitReader& br) const
936{
937 // These bits come at the end of a PPM block. This code assumes the main part of the block
938 // has already been decoded and the pointer is set to the start of the error bits.
939 uint8_t haveStatus = br.getField(1);
940 uint8_t haveErrors = br.getField(1);
941
942 // If either or both of these bits is set, then follows a single 16 bit map to indicate the MCM
943 if (haveStatus || haveErrors) {
944 uint16_t mcmMap = br.getField(s_submodules);
945 std::vector<uint16_t> mcmErrors(s_submodules);
946 uint16_t errorWord = 0;
947
948 // For each so indicated MCM, there is either the 5 bit status block, or the 6 bit error block, or both
949 for(int i=0; i < s_submodules; ++i){
950 errorWord = 0;
951 if ((mcmMap & (1 << i)) != 0) {
952 uint16_t blockStatus = 0;
953 uint16_t blockErrors = 0;
954
955 if (haveStatus) {
956 blockStatus = br.getField(5);
957 errorWord |= blockStatus;
958 }
959 if (haveErrors) {
960 blockErrors = br.getField(6);
961 errorWord |= (blockErrors<<5);
962 }
963 }
964 mcmErrors.at(i)=errorWord;
965 }
966
967 int curr = state.m_triggerTowers->size() - 1;
968 for(int i=0; i < s_channels; ++i){
969 if (curr < 0){
970 break;
971 }
972 auto tt = (*state.m_triggerTowers)[curr--];
973 if (tt->coolId() >> 16 & crateModuleMask(crate, module)){
974 uint16_t mcmID = (tt->coolId() >> 8) & 0xff;
975 uint16_t chnID = tt->coolId() & 0xff;
976 uint16_t error = mcmErrors.at(mcmID);
977
978 // Now translate the error into Athena language
979 LVL1::DataError errorBits( tt->errorWord() );
980 if ( error & (1<<chnID) ) { errorBits.set(LVL1::DataError::ChannelDisabled); }
981 if ( error & (1<<4) ) { errorBits.set(LVL1::DataError::MCMAbsent); }
982 if ( error & (1<<5) ) { errorBits.set(LVL1::DataError::Timeout); }
983 if ( error & (1<<6) ) { errorBits.set(LVL1::DataError::ASICFull); }
984 if ( error & (1<<7) ) { errorBits.set(LVL1::DataError::EventMismatch); }
985 if ( error & (1<<8) ) { errorBits.set(LVL1::DataError::BunchMismatch); }
986 if ( error & (1<<9) ) { errorBits.set(LVL1::DataError::FIFOCorrupt); }
987 if ( error & (1<<10) ) { errorBits.set(LVL1::DataError::PinParity); }
988
989 // Set the modified error word for this channel
990 tt->setErrorWord( errorBits.error() );
991 }else{
992 break;
993 }
994 }
995 }
996}
997
998
1000 State& state,
1001 uint8_t crate,
1002 uint8_t module,
1003 uint8_t channel,
1004 std::vector<uint8_t>&& lcpVal,
1005 std::vector<uint8_t>&& lcpBcidVec,
1006 std::vector<uint8_t>&& ljeVal,
1007 std::vector<uint8_t>&& ljeSat80Vec,
1008 std::vector<uint16_t>&& adcVal,
1009 std::vector<uint8_t>&& adcExt,
1010 std::vector<int16_t>&& pedCor,
1011 std::vector<uint8_t>&& pedEn) const
1012{
1013 uint32_t coolId = ::coolId(crate, module, channel);
1014
1015 int layer = 0;
1016 double eta = 0.;
1017 double phi = 0.;
1018
1019 bool isData = m_ppmMaps->mapping(crate, module, channel, eta, phi, layer);
1020
1021 if (!isData && !state.m_ppmIsRetSpare && !state.m_ppmIsRetMuon){
1022 return StatusCode::SUCCESS;
1023 }
1024
1025 if (!isData) {
1026 const int pin = channel % 16;
1027 const int asic = channel / 16;
1028 eta = 16 * crate + module;
1029 phi = 4 * pin + asic;
1030 }
1031
1033 state.m_triggerTowers->push_back(tt);
1034
1035 tt->initialize(coolId, eta, phi,
1036 std::move(lcpVal), std::move(ljeVal),
1037 std::move(pedCor), std::move(pedEn),
1038 std::move(lcpBcidVec), std::move(adcVal),
1039 std::move(adcExt), std::move(ljeSat80Vec),
1040 0, state.m_caloUserHeader.lut(),
1041 state.m_caloUserHeader.ppFadc());
1042 return StatusCode::SUCCESS;
1043}
1044
1046 State& state,
1047 uint8_t crate,
1048 uint8_t module,
1049 uint8_t channel,
1050 std::vector<uint8_t>&& luts,
1051 std::vector<uint8_t>&& lcpBcidVec,
1052 std::vector<uint16_t>&& fadc,
1053 std::vector<uint8_t>&& bcidExt
1054 ) const
1055{
1056 std::vector<uint8_t> ljeSat80Vec;
1057
1058 std::vector<int16_t> pedCor;
1059 std::vector<uint8_t> pedEn;
1060 std::vector<uint8_t> luts_copy =luts;
1061
1063 crate, module, channel,
1064 std::move(luts), std::move(lcpBcidVec),
1065 std::move(luts_copy) , std::move(ljeSat80Vec),
1066 std::move(fadc), std::move(bcidExt),
1067 std::move(pedCor), std::move(pedEn))
1068 );
1069
1070 return StatusCode::SUCCESS;
1071}
1072
1074 State& state,
1075 uint8_t crate,
1076 uint8_t module,
1077 uint8_t channel,
1078 const std::vector<uint16_t>& luts,
1079 const std::vector<uint16_t>& fadc
1080 ) const
1081{
1082 std::vector<uint8_t> lcpVal;
1083 std::vector<uint8_t> lcpBcidVec;
1084
1085 std::vector<uint16_t> adcVal;
1086 std::vector<uint8_t> adcExt;
1087
1088 for(auto lut: luts) {
1089 lcpVal.push_back(BitField::get<uint8_t>(lut, 0, 8));
1090 lcpBcidVec.push_back(BitField::get<uint8_t>(lut, 8, 3));
1091 }
1092
1093 for(auto f: fadc) {
1094 adcExt.push_back(BitField::get<uint8_t>(f, 0, 1));
1095 adcVal.push_back(BitField::get<uint16_t>(f, 1, 10));
1096 }
1097
1099 crate, module, channel,
1100 std::move(lcpVal), std::move(lcpBcidVec),
1101 std::move(adcVal), std::move(adcExt)));
1102
1103 return StatusCode::SUCCESS;
1104}
1105
1106
1107// Return reference to vector with all possible Source Identifiers
1108
1110{
1111 const int crates = 8;
1112
1113 m_ppmSourceIDs.clear();
1114 m_ppmSourceIDsSpare.clear();
1115 m_ppmSourceIDsMuon.clear();
1116
1117 for (int crate = 0; crate < crates; ++crate) {
1118 for (int slink = 0; slink < m_srcIdMap->maxSlinks(); ++slink) {
1119 const uint32_t rodId = m_srcIdMap->getRodID(crate, slink, 0,
1120 eformat::TDAQ_CALO_PREPROC);
1121 const uint32_t robId = m_srcIdMap->getRobID(rodId);
1122 m_ppmSourceIDs.push_back(robId);
1123 if (crate > 1 && crate < 6) {
1124 m_ppmSourceIDsSpare.push_back(robId);
1125 if (crate < 4 && slink == 0) {
1126 m_ppmSourceIDsMuon.push_back(robId);
1127 }
1128 }
1129 }
1130 }
1131}
1132
1133
1134
1135const std::vector<uint32_t>& PpmByteStreamReadV1V2Tool::ppmSourceIDs(
1136 State& state,
1137 const std::string& sgKey) const
1138{
1139 state.m_ppmIsRetMuon = false;
1140 state.m_ppmIsRetSpare = false;
1141
1142 if (sgKey.find("Muon") != std::string::npos) {
1143 state.m_ppmIsRetMuon = true;
1144 } else if (sgKey.find("Spare") != std::string::npos) {
1145 state.m_ppmIsRetSpare = true;
1146 }
1147
1148 if (state.m_ppmIsRetSpare) {
1149 return m_ppmSourceIDsSpare;
1150 }
1151
1152 if (state.m_ppmIsRetMuon) {
1153 return m_ppmSourceIDsMuon;
1154 }
1155
1156 return m_ppmSourceIDs;
1157}
1158
1159
1160
1162 (const uint8_t numBits)
1163{
1164 if ((m_ppPointer + numBits) <= m_ppMaxBit) {
1165 uint32_t iWord = m_ppPointer / 31;
1166 uint8_t iBit = m_ppPointer % 31;
1167 m_ppPointer += numBits;
1168
1169 uint32_t result;
1170 if ((iBit + numBits) <= 31) {
1171 result = ::bitFieldSize(m_ppBlock[iWord], iBit, numBits);
1172 } else {
1173 uint8_t nb1 = 31 - iBit;
1174 uint8_t nb2 = numBits - nb1;
1175 uint32_t field1 = ::bitFieldSize(m_ppBlock[iWord], iBit, nb1);
1176 uint32_t field2 = ::bitFieldSize(m_ppBlock[iWord + 1], 0, nb2);
1177 result = field1 | (field2 << nb1);
1178 }
1179
1180 return result;
1181 }
1182
1183 throw std::out_of_range("Requested too much bits from ppm block");
1184}
1185// ===========================================================================
1186} // end namespace
1187// ===========================================================================
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#define endmsg
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define CHECK(...)
Evaluate an expression and check for errors.
unsigned int uint
static Double_t sc
size_t size() const
Number of registered mappings.
const char *const fmt
Atomic min/max functions.
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
void reserve(size_type n)
Attempt to preallocate enough memory for a specified number of elements.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
size_type size() const noexcept
Returns the number of elements in the collection.
size_type capacity() const noexcept
Returns the total number of elements that the collection can hold before needing to allocate more mem...
std::vector< const ROBF * > VROBFRAG
T get(const uint32_t &word) const
Definition WordDecoder.h:22
L1Calo User Header class.
uint8_t ppLowerBound() const
This class provides conversion between Lower level Source ID to higher level source ID for L1Calo Byt...
StatusCode addTriggerTowerV2_(State &state, uint8_t crate, uint8_t module, uint8_t channel, std::vector< uint8_t > &&lcpVal, std::vector< uint8_t > &&lcpBcidVec, std::vector< uint8_t > &&ljeVal, std::vector< uint8_t > &&ljeSat80Vec, std::vector< uint16_t > &&adcVal, std::vector< uint8_t > &&adcExt, std::vector< int16_t > &&pedCor, std::vector< uint8_t > &&pedEn) const
std::vector< uint16_t > getPpmAdcSamplesR3_(State &state, BitReader &br, uint8_t format, uint8_t minIndex) const
StatusCode processPpmBlockR3V1_(State &state) const
OFFLINE_FRAGMENTS_NAMESPACE::PointerType RODPointer
StatusCode processPpmCompressedR3V1_(State &state) const
StatusCode convert(const EventContext &ctx, xAOD::TriggerTowerContainer *const ttCollection) const
Convert ROB fragments to trigger towers.
ToolHandle< LVL1::IL1CaloMappingTool > m_ppmMaps
Channel mapping tool.
StatusCode processPpmBlockR4V1_(State &state) const
StatusCode processPpmNeutral_(State &state) const
void processPpmErrorBits_(State &state, uint8_t crate, uint8_t module, BitReader &br) const
StatusCode processPpmBlock_(State &state) const
ServiceHandle< IROBDataProviderSvc > m_robDataProvider
Service for reading bytestream.
StatusCode processPpmStandardR4V1_(State &state) const
StatusCode processPpmCompressedR4V1_(State &state) const
StatusCode processPpmWord_(State &state, uint32_t word, int indata) const
const std::vector< uint32_t > & ppmSourceIDs(State &state, const std::string &sgKey) const
Return reference to vector with all possible Source Identifiers.
void processSubBlockStatus_(State &state, uint8_t crate, uint8_t module, uint32_t word) const
IROBDataProviderSvc::VROBFRAG::const_iterator ROBIterator
ToolHandle< LVL1BS::L1CaloErrorByteStreamTool > m_errorTool
virtual StatusCode initialize() override
Dummy implementation of the initialisation function.
StatusCode processRobFragment_(State &state, const ROBIterator &robFrag, const RequestType &requestedType) const
OFFLINE_FRAGMENTS_NAMESPACE::PointerType ROBPointer
void interpretPpmHeaderR4V1_(BitReader &br, uint8_t numAdc, int8_t &encoding, int8_t &minIndex) const
std::vector< uint16_t > getPpmAdcSamplesR4_(State &state, BitReader &br, uint8_t encoding, uint8_t minIndex) const
StatusCode addTriggerTowerV1_(State &state, uint8_t crate, uint8_t module, uint8_t channel, const std::vector< uint16_t > &luts, const std::vector< uint16_t > &fadc) const
StatusCode processPpmStandardR3V1_(State &state) const
L1Calo User Header class.
uint8_t compVer() const
Error data.
Definition DataError.h:27
int error() const
Return the full error word.
Definition DataError.h:78
void set(ErrorBit bit, int value=1)
Set an error bit or data.
Definition DataError.cxx:28
static const std::string xAODTriggerTowerLocation
AsgTool(const std::string &name)
Constructor specifying the tool instance's name.
Definition AsgTool.cxx:58
T atomic_fetch_max(std::atomic< T > *a, T v, std::memory_order memorder=std::memory_order_seq_cst)
Atomically calculate maximum.
TriggerTowerContainer_v2 TriggerTowerContainer
Define the latest version of the TriggerTower container.
setScaleOne setStatusOne setSaturated int16_t
TriggerTower_v2 TriggerTower
Define the latest version of the TriggerTower class.
setEventNumber uint32_t