1//Dear emacs, this is -*- c++ -*-
4 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
7// Implementation of a LArRODBlockStructure class
8// This version contains LArDigits in fixed gain.
9// See .h file for more details.
11#include "AthenaKernel/getMessageSvc.h"
15#define LARBSDBG(text) logstr<<MSG::DEBUG<<text<<endmsg
20template<class DSPHEADER>
21LArRodBlockTransparentV0<DSPHEADER>::LArRodBlockTransparentV0(IMessageSvc* msgSvc)
22 : LArRodBlockStructure(msgSvc, BlockType())
23{ m_iHeadBlockSize=DSPHEADER::endtag/2; // The implicit cast rounds down to the right size
24 //Fill array of offset to enable for-loops
25 m_BlkOffset=DSPHEADER::RawDataBlkOffset; //RawDataOffset
26 m_fixedGain=CaloGain::LARNGAIN;
27 LArRodBlockTransparentV0::resetPointers();
30// clear temporary block vectors
31template<class DSPHEADER>
32void LArRodBlockTransparentV0<DSPHEADER>::clearBlocks()
34 m_RawDataBlock.clear();
37template<class DSPHEADER>
38void LArRodBlockTransparentV0<DSPHEADER>::resetPointers()
44template<class DSPHEADER>
45void LArRodBlockTransparentV0<DSPHEADER>::setNumberOfSamples(const uint8_t n)
46{ uint16_t value=getVectorHeader16(DSPHEADER::NSamples);
47 setHeader16(DSPHEADER::NSamples, (value & 0xff00) | n);
50template<class DSPHEADER>
51void LArRodBlockTransparentV0<DSPHEADER>::setTDCPhase(const uint8_t n)
52{ uint16_t value=getVectorHeader16(DSPHEADER::NSamples);
53 setHeader16(DSPHEADER::NSamples, (value & 0xff) | ((uint16_t) n<<8));
56template<class DSPHEADER>
57uint8_t LArRodBlockTransparentV0<DSPHEADER>::getTDCPhase() const
59 return (getHeader16(DSPHEADER::NSamples)>>8);
65template<class DSPHEADER>
66void LArRodBlockTransparentV0<DSPHEADER>::setNumberOfGains(const uint8_t n)
68 setHeader16(DSPHEADER::NGains,n);
71template<class DSPHEADER>
73LArRodBlockTransparentV0<DSPHEADER>::initializeFragment(std::vector<uint32_t>& fragment)
74{MsgStream logstr(Athena::getMessageSvc(), BlockType());
75 m_pRODblock=&fragment; //remember pointer to fragment
76 if (fragment.size()>m_iHeadBlockSize) { //Got filled fragment
77 unsigned int sizeRead=0;
78 //Store existing data in the FEB-Map
79 while (sizeRead<fragment.size()) {
80 std::vector<uint32_t>::iterator FebIter;
81 FebIter=fragment.begin()+sizeRead; //Store pointer to current Feb-Header
82 m_FebBlock=&(*FebIter); //Set m_FebBlock in order to use getHeader-functions.
83 uint32_t currFEBid=getHeader32(DSPHEADER::FEBID); //Get this FEB-ID
84 uint16_t currFebSize=getHeader32(DSPHEADER::NWTot); //Size of this FEB-Block
85 if (FebIter+currFebSize>fragment.end()) {
86 fragment.clear(); //Clear existing vector
87 logstr << MSG::ERROR << "initializeFragment: Got inconsistent ROD-Fragment!" << endmsg;
90 m_mFebBlocks[currFEBid].assign(FebIter,FebIter+currFebSize); //Copy data from ROD-fragment into FEB-Block
91 sizeRead+=currFebSize+m_MiddleHeaderSize;
92 LARBSDBG("Found FEB-id "<< currFEBid << "in existing ROD-Fragment");
95 fragment.clear(); //Clear existing vector
99template<class DSPHEADER>
100void LArRodBlockTransparentV0<DSPHEADER>::initializeFEB(const uint32_t id)
101{m_vFragment=&(m_mFebBlocks[id]);
102 //m_FebHeaderIter=m_vFragment->begin();
103 if (m_vFragment->size()<m_iHeadBlockSize) //Got empty or spoiled fragment
104 {m_vFragment->resize(m_iHeadBlockSize,0); //Initialize FEB-Header
105 setHeader32(DSPHEADER::FEBID,id); //Set Feb ID
109template<class DSPHEADER>
110void LArRodBlockTransparentV0<DSPHEADER>::setRawDataFixed(const int channel, const std::vector<short>& samples, const uint32_t gain)
112 MsgStream logstr(Athena::getMessageSvc(), BlockType());
113 if (channel>=m_channelsPerFEB) {
114 logstr << MSG::ERROR << "Attempt to write Raw Data for channel "<< channel << endmsg;
115 return; //Return error
117 // Expected Gain values:
122 {logstr << MSG::ERROR << "Attempt to write raw data with gain "<< gain << endmsg;
125 unsigned int nsamples = getVectorHeader16(DSPHEADER::NSamples) & 0xff;
126 LARBSDBG("Nsamples= " << nsamples);
127 if(samples.size() != nsamples) {
128 logstr << MSG::ERROR << "Number of samples mismatch!\n";
129 logstr << " nsamples =" << nsamples;
130 logstr << " samples.size() =" << samples.size() << endmsg;
134 // Save data as is, we will arrange it later...
135 m_RawDataBlock.push_back(channel);
136 if(channel>=64) { // high channel number on lower 16 bits
137 m_RawDataBlock.push_back(OfflineToRawGain(gain)<<12);
138 for (unsigned int i=0;i<nsamples;i++)
139 m_RawDataBlock.push_back(samples[i]&0xffff);
140 } else { //low channel number
141 m_RawDataBlock.push_back(OfflineToRawGain(gain)<<28);
142 for (unsigned int i=0;i<nsamples;i++)
143 m_RawDataBlock.push_back(samples[i]<<16);
147template<class DSPHEADER>
148void LArRodBlockTransparentV0<DSPHEADER>::finalizeFEB()
151 MsgStream logstr(Athena::getMessageSvc(), BlockType());
154 uint16_t nsamples = getVectorHeader16(DSPHEADER::NSamples) & 0xff;
159 // Set fragment size to FEB raw data + header
160 s_size = 8 + 64 * ngains; // Size of one sample block 16 RADD of 16 bit + 128 channels (16 bit data)
161 size = m_iHeadBlockSize + nsamples*s_size; // Total fragment size;
163 m_vFragment->resize(size,0);
165 LARBSDBG("Size of block (in 32bit words) = " << size);
166 // Now fill the RADD structures
167 for(int i=0; i<nsamples;i++) {
168 uint32_t offset = (m_iHeadBlockSize + i*s_size);
169 for(int j=0;j<8;j++) {
170 // Put a dummy code for RADDs (A | adc nb | sample nb)
171 uint32_t index = offset+j;
172 (*m_vFragment)[index] = 0xA000A000 | ((2*j)<<24) | (i << 16) | ((2*j+1)<<8) | i;
175 // And now the data itself
176 for (int igain=0;igain<ngains;igain++) {
177 int n = m_RawDataBlock.size();
178 for(int j=0; j<n;j+=nsamples+2) {
179 uint32_t ichannel = m_RawDataBlock[j];
180 uint32_t febgain = m_RawDataBlock[j+1];
182 offset=m_iHeadBlockSize + 8 + ((ichannel&0x3F)>>3) + ((ichannel& 0x7)<<3) + 64*igain;
183 LARBSDBG("Processing channel #" << ichannel << ".Writing samples to offset " << offset);
184 for (int s=0;s<nsamples;s++) {
185 // samples are already on the right higher/lower bits of the 32 bit word
186 uint32_t index = offset + s*s_size;
187 uint32_t feb_data = (*m_vFragment)[index];
188 uint32_t sample = m_RawDataBlock[j+2+s];
189 feb_data = feb_data | sample | febgain;
190 (*m_vFragment)[index] = feb_data;
195 LARBSDBG("FINAL Nsamples= " << nsamples);
196 setHeader16(DSPHEADER::NGains,ngains);
197 setHeader32(DSPHEADER::RawDataBlkOffset, m_iHeadBlockSize);
198 setHeader32(DSPHEADER::NWTot,m_vFragment->size());
204template<class DSPHEADER>
205void LArRodBlockTransparentV0<DSPHEADER>::concatinateFEBs( )
207 FEBMAPTYPE::const_iterator feb_it_b=m_mFebBlocks.begin();
208 FEBMAPTYPE::const_iterator feb_it_e=m_mFebBlocks.end();
209 FEBMAPTYPE::const_iterator feb_it;
210 for (feb_it=feb_it_b;feb_it!=feb_it_e;++feb_it) {
211 if (feb_it!=feb_it_b) //Not first Feb
212 m_pRODblock->resize( m_pRODblock->size()+m_MiddleHeaderSize);
214 //Add feb data to rod data block
215 for (uint32_t data : feb_it->second)
216 m_pRODblock->push_back(data);
219 m_mFebBlocks.clear();
223template<class DSPHEADER>
224int LArRodBlockTransparentV0<DSPHEADER>::getNextRawData(int& channelNumber, std::vector<short>& samples, uint32_t& gain)
227 MsgStream logstr(Athena::getMessageSvc(), BlockType());
230 LARBSDBG("GetNextRawData for FEB 0x" << MSG::hex << (uint32_t)getHeader32(DSPHEADER::FEBID) << MSG::dec);
231 LARBSDBG("m_RawDataCounter=" << m_RawDataCounter << " m_RawDataIndex="<< m_RawDataIndex
232 << " m_channelsPerFEB=" << m_channelsPerFEB);
233 LARBSDBG("requested gain= " << m_fixedGain);
234 if (m_RawDataCounter>=m_channelsPerFEB) { //Already beyond maximal number of channels
235 LARBSDBG("Maximum number of channels reached");
238 const uint16_t block = getHeader32(m_BlkOffset);//Position of the raw FEB data block
239 if (!block) { //Block does not exist
240 LARBSDBG("No Raw Data Block in this FEB");
243 //The m_RawDataChannel keeps track of the last read channel
246 channelNumber=m_RawDataCounter;
248 const unsigned int nsamples = getHeader16(DSPHEADER::NSamples) & 0xff;
249 const unsigned int ngains = getHeader16(DSPHEADER::NGains);
250 LARBSDBG("This FEB has " << nsamples << " samples");
251 LARBSDBG("This FEB has " << ngains << " gains");
252 if(ngains==0 || nsamples==0) return 0;
253 // Loop over gains to look for m_fixedGain
254 unsigned int this_gain=0;
256 if (m_fixedGain!=CaloGain::LARNGAIN) { //Fixed gain: Search for gain
257 offset=block + 8 + ((channelNumber&0x3F)>>3) + ((channelNumber & 0x7)<<3);
258 for(this_gain=0;this_gain<ngains;this_gain++) {
259 int index = offset + 64*this_gain;
260 uint32_t x = m_FebBlock[index];
261 if(channelNumber>=64)
262 x = (x & 0x3000) >> 12;
264 x = (x & 0x30000000) >> 28;
265 int data_gain = RawToOfflineGain(x);
266 if(data_gain==m_fixedGain) break;
269 if (this_gain<ngains) { //Gain found in this fragment
270 int s_size = 8 + 64 * ngains; // Size of one sample block 16 RADD of 16 bit + 128 channels (16 bit data)
271 offset = block + 8 + ((channelNumber&0x3F)>>3) + ((channelNumber & 0x7)<<3) + 64*this_gain;
273 uint32_t x = m_FebBlock[index];
274 if(channelNumber>=64) { //low channels on lower bits
276 febgain = (x & 0x3000) >> 12; // gain on bits 12 and 13
278 for(unsigned int s=0;s<nsamples;s++) {
279 index = offset + s*s_size;
280 x = m_FebBlock[index];
281 samples.push_back((short) (x & 0x0fff)); // sample on bits 0 to 11
283 } else { //high channels on higher bits
285 febgain = (x & 0x30000000) >> 28; // gain on bits 12 and 13
287 for(unsigned int s=0;s<nsamples;s++) {
288 index = offset + s*s_size;
289 x = (m_FebBlock[index]) >> 16;
290 samples.push_back((short) (x & 0x0fff)); // sample on bits 0 to 11
293 gain=RawToOfflineGain(febgain);
296 if (m_rearrangeFirstSample && m_rearrangeFirstSample<samples.size()) //FIXME: Very ugly hack! See explanation in LArRodDecoder.h file
297 {//Change e.g. 3 0 1 2 4 to 0 1 2 3 4
298 short movedSample=samples[0];
299 for (unsigned i=1;i<=m_rearrangeFirstSample;i++)
300 samples[i-1]=samples[i];
301 samples[m_rearrangeFirstSample]=movedSample;
306template<class DSPHEADER>
307uint32_t LArRodBlockTransparentV0<DSPHEADER>::getNumberOfSamples() const
309 return getHeader16(DSPHEADER::NSamples);
312template<class DSPHEADER>
313uint32_t LArRodBlockTransparentV0<DSPHEADER>::getNumberOfGains() const
315 return getHeader16(DSPHEADER::NGains);
318template<class DSPHEADER>
319uint32_t LArRodBlockTransparentV0<DSPHEADER>::getRadd(uint32_t adc, uint32_t sample) const
321 int ngain=getHeader16(DSPHEADER::NGains);
322 int index=getHeader32(m_BlkOffset);
323 index+=(8+64*ngain)*sample+adc/2;
324 uint32_t x=m_FebBlock[index];
325 if(adc&0x1) return x>>16;
329template<class DSPHEADER>
330uint16_t LArRodBlockTransparentV0<DSPHEADER>::getCtrl1(uint32_t adc) const
332 int index=getHeader32(m_BlkOffset)-16+adc/2;
333 uint32_t x=m_FebBlock[index];
340template<class DSPHEADER>
341uint16_t LArRodBlockTransparentV0<DSPHEADER>::getCtrl2(uint32_t adc) const
343 int index=getHeader32(m_BlkOffset)-8+adc/2;
344 uint32_t x=m_FebBlock[index];
351template<class DSPHEADER>
352uint16_t LArRodBlockTransparentV0<DSPHEADER>::getCtrl3(uint32_t adc) const
354 int nsamples = getHeader16(DSPHEADER::NSamples);
355 int ngains = getHeader16(DSPHEADER::NGains);
356 int offset=nsamples*(8+64*ngains)+adc/2;
357 int index=getHeader32(m_BlkOffset)+offset;
358 uint32_t x=m_FebBlock[index];
365template<class DSPHEADER>
366uint32_t LArRodBlockTransparentV0<DSPHEADER>::getStatus() const
368 int nsamples = getHeader16(DSPHEADER::NSamples);
369 int ngains = getHeader16(DSPHEADER::NGains);
370 int offset=nsamples*(8+64*ngains)+8;
371 int index=getHeader32(m_BlkOffset)+offset;
372 uint32_t x=m_FebBlock[index];