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