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