LDMX Software
ecal::EcalRawDecoder Class Reference

Public Member Functions

 EcalRawDecoder (const std::string &n, framework::Process &p)
 Constructor.
 
virtual ~EcalRawDecoder ()=default
 Destructor.
 
virtual void configure (framework::config::Parameters &)
 Callback for the EventProcessor to configure itself from the given set of parameters.
 
virtual void produce (framework::Event &event)
 Process the event and put new data products into it.
 
- Public Member Functions inherited from framework::Producer
 Producer (const std::string &name, Process &process)
 Class constructor.
 
virtual void process (Event &event) final
 Processing an event for a Producer is calling produce.
 
- Public Member Functions inherited from framework::EventProcessor
 DECLARE_FACTORY (EventProcessor, EventProcessor *, const std::string &, Process &)
 declare that we have a factory for this class
 
 EventProcessor (const std::string &name, Process &process)
 Class constructor.
 
virtual ~EventProcessor ()=default
 Class destructor.
 
virtual void beforeNewRun (ldmx::RunHeader &run_header)
 Callback for Producers to add parameters to the run header before conditions are initialized.
 
virtual void onNewRun (const ldmx::RunHeader &run_header)
 Callback for the EventProcessor to take any necessary action when the run being processed changes.
 
virtual void onFileOpen (EventFile &event_file)
 Callback for the EventProcessor to take any necessary action when a new event input ROOT file is opened.
 
virtual void onFileClose (EventFile &event_file)
 Callback for the EventProcessor to take any necessary action when a event input ROOT file is closed.
 
virtual void onProcessStart ()
 Callback for the EventProcessor to take any necessary action when the processing of events starts, such as creating histograms.
 
virtual void onProcessEnd ()
 Callback for the EventProcessor to take any necessary action when the processing of events finishes, such as calculating job-summary quantities.
 
template<class T >
const T & getCondition (const std::string &condition_name)
 Access a conditions object for the current event.
 
TDirectory * getHistoDirectory ()
 Access/create a directory in the histogram file for this event processor to create histograms and analysis tuples.
 
void setStorageHint (framework::StorageControl::Hint hint)
 Mark the current event as having the given storage control hint from this module_.
 
void setStorageHint (framework::StorageControl::Hint hint, const std::string &purposeString)
 Mark the current event as having the given storage control hint from this module and the given purpose string.
 
int getLogFrequency () const
 Get the current logging frequency from the process.
 
int getRunNumber () const
 Get the run number from the process.
 
std::string getName () const
 Get the processor name.
 
void createHistograms (const std::vector< framework::config::Parameters > &histos)
 Internal function which is used to create histograms passed from the python configuration @parma histos vector of Parameters that configure histograms to create.
 

Private Attributes

std::string input_name_
 input object of encoded data
 
std::string input_pass_
 input pass of creating encoded data
 
std::string output_name_
 output object to put onto event bus
 
int roc_version_
 version of HGC ROC we are decoding
 
bool translate_eid_
 should we translate electronic IDs to detector IDs
 

Additional Inherited Members

- Protected Member Functions inherited from framework::EventProcessor
void abortEvent ()
 Abort the event immediately.
 
- Protected Attributes inherited from framework::EventProcessor
HistogramPool histograms_
 helper object for making and filling histograms
 
NtupleManager & ntuple_ {NtupleManager::getInstance()}
 Manager for any ntuples.
 
logging::logger the_log_
 The logger for this EventProcessor.
 

Detailed Description

Definition at line 14 of file EcalRawDecoder.h.

Constructor & Destructor Documentation

◆ EcalRawDecoder()

ecal::EcalRawDecoder::EcalRawDecoder ( const std::string & n,
framework::Process & p )
inline

Constructor.

Definition at line 19 of file EcalRawDecoder.h.

20 : framework::Producer(n, p) {}
Base class for a module which produces a data product.

Member Function Documentation

◆ configure()

void ecal::EcalRawDecoder::configure ( framework::config::Parameters & parameters)
virtual

Callback for the EventProcessor to configure itself from the given set of parameters.

The parameters a processor has access to are the member variables of the python class in the sequence that has class_name equal to the EventProcessor class name.

For an example, look at MyProcessor.

Parameters
parametersParameters for configuration.

Reimplemented from framework::EventProcessor.

Definition at line 20 of file EcalRawDecoder.cxx.

20 {
21 input_name_ = ps.get<std::string>("input_name");
22 input_pass_ = ps.get<std::string>("input_pass");
23 output_name_ = ps.get<std::string>("output_name");
24 roc_version_ = ps.get<int>("roc_version");
25 translate_eid_ = ps.get<bool>("translate_eid");
26}
std::string input_pass_
input pass of creating encoded data
int roc_version_
version of HGC ROC we are decoding
bool translate_eid_
should we translate electronic IDs to detector IDs
std::string input_name_
input object of encoded data
std::string output_name_
output object to put onto event bus

References framework::config::Parameters::get(), input_name_, input_pass_, output_name_, roc_version_, and translate_eid_.

◆ produce()

void ecal::EcalRawDecoder::produce ( framework::Event & event)
virtual

Process the event and put new data products into it.

Parameters
eventThe Event to process.

Static parameters depending on ROC version

words for reading and decoding

Re-sort the data from grouped by bunch to by channel

The readout cip streams the data off of it, so it doesn't have time to re-group the signals across multiple bunches (samples) by their channel ID. We need to do that here.

are we reading a buffer from multi-sample per event?

Decode Bunch Header We have a few words of header material before the actual data. This header material is assumed to be encoded as in Table 3 of the DAQ specs.

<name> (bits)

VERSION (4) | FPGA_ID (8) | NLINKS (6) | 00 | LEN (12) BX ID (12) | RREQ (10) | OR (10) RID ok (1) | CRC ok (1) | LEN3 (6) | RID ok (1) | CRC ok (1) | LEN2 (6) | RID ok (1) | CRC ok (1) | LEN1 (6) | RID ok (1) | CRC ok (1) | LEN0 (6) ... other listing of links ...

Decode Each Link in Sequence Now we should be decoding each link serially where each link was encoded as in Table 4 of the DAQ specs

ROC_ID (16) | CRC ok (1) | 0 (7) | RO Map (8) RO Map (32)

Special "Header" Word from ROC

version 3: 0101 | BXID (12) | RREQ (6) | OR (3) | HE (3) | 0101

version 2: 10101010 | BXID (12) | WADD (9) | 1010

Common Mode Channels 10 | 0000000000 | Common Mode ADC 0 (10) | Common Mode ADC 1 (10)

DAQ Channels

Generate Packed Electronics ID Link Index i_link Channel ID channel_id ROC ID roc_id FPGA ID fpga are all available. For now, we just generate a dummy mapping using the link and channel indices.

The subfields for the electronics ID infrastructure need to start from 0 and count up. This means we need to subtract some of the fields by their lowest value before inputting them into the EID.

TODO fix hardcoded starting value

roc_id-256 is the ssame as i_link = is this a coincidence? or should we change the second input to be the link index_

Translation

Now the HgcrocDigiCollection::Sample class handles the unpacking of individual samples; however, we still need to translate electronic IDs into detector IDs.

DO NOTHING skip hits_ where the EID aren't in the detector mapping no zero supp during test beam on the front-end, so channels that aren't connected to anything are still being readout. std::cout << "EID(" << eid.fiber() << "," << eid.elink() << "," << eid.channel() << ") "; for (auto& s : digi) std::cout << hex(s.raw()) << " "; std::cout << std::endl;

no EID translation, just add the digis to the digi collection with their raw electronic ID TODO: remove this, we shouldn't be able to get past the decoding stage without translating the EID into a detector ID to avoid confusion in recon

Implements framework::Producer.

Definition at line 28 of file EcalRawDecoder.cxx.

28 {
32 static const unsigned int common_mode_channel = roc_version_ == 2 ? 19 : 1;
34 static uint32_t head1, head2, w;
35
36 BufferReader reader{event.getCollection<uint8_t>(input_name_, input_pass_)};
37
44 // fill map of **electronic** IDs to the digis that were read out
46 std::vector<ldmx::HgcrocDigiCollection::Sample>>
47 eid_to_samples;
48 while (reader >> head1 >> head2) {
50 if (head1 == 0x11111111 and head2 == 0xbeef2021) {
51 /* whole event header word looks like
52 *
53 * VERSION (4) | FPGA ID (8) | NSAMPLES (4) | LEN (16)
54 */
55 uint32_t whole_event_header;
56 reader >> whole_event_header;
57 /* event length not currently used but is stored in header as defined by
58 the spec uint32_t version = (whole_event_header >> 28) &
59 packing::utility::MASK<4>; uint32_t fpga = (whole_event_header >> 20) &
60 packing::utility::MASK<8>; uint32_t eventlen = whole_event_header &
61 packing::utility::MASK<16>;
62 */
63 uint32_t nsamples =
64 (whole_event_header >> 16) & packing::utility::MASK<4>;
65 // sample counters
66 std::vector<uint32_t> length_per_sample(nsamples, 0);
67 for (uint32_t i_sample{0}; i_sample < nsamples; i_sample++) {
68 if (i_sample % 2 == 0) {
69 reader >> w;
70 }
71 uint32_t shift_in_word = 16 * (i_sample % 2);
72 length_per_sample[i_sample] =
73 (w >> shift_in_word) & packing::utility::MASK<12>;
74 }
75
76 // read first sample headers
77 reader >> head1 >> head2;
78 } else if (head1 == 0xd07e2021 and head2 == 0x12345678) {
79 // these are the special footer words at the end,
80 // done with event
81 break;
82 }
83
99 packing::utility::CRC fpga_crc;
100 fpga_crc << head1;
101 std::cout << hex(head1) << " : ";
102 uint32_t version = (head1 >> 28) & packing::utility::MASK<4>;
103 // std::cout << "version " << version << std::flush;
104 uint32_t one{1};
105 if (version != one)
106 EXCEPTION_RAISE("VersMis",
107 "EcalRawDecoder only knows version 1 of DAQ format.");
108
109 uint32_t fpga = (head1 >> 20) & packing::utility::MASK<8>;
110 uint32_t nlinks = (head1 >> 14) & packing::utility::MASK<6>;
111 // total length not used but is available in header as defined by spec
112 // uint32_t len = head1 & packing::utility::MASK<12>;
113
114 // std::cout << ", fpga: " << fpga << ", nlinks: " << nlinks << ", len: " <<
115 // len << std::endl;
116 fpga_crc << head2;
117 // std::cout << hex(head2) << " : ";
118
119 // bunch ID (bx), read request (rreq) and orbit counter (orbit) are defined
120 // in header but not used right now uint32_t bx_id = (head2 >> 20) &
121 // packing::utility::MASK<12>; uint32_t rreq = (head2 >> 10) &
122 // packing::utility::MASK<10>; uint32_t orbit = head2 &
123 // packing::utility::MASK<10>;
124
125 // std::cout << "bx_id: " << bx_id << ", rreq: " << rreq << ", orbit: " <<
126 // orbit << std::endl;
127
128 std::vector<uint32_t> length_per_link(nlinks, 0);
129 for (uint32_t i_link{0}; i_link < nlinks; i_link++) {
130 if (i_link % 4 == 0) {
131 reader >> w;
132 fpga_crc << w;
133 // std::cout << hex(w) << " : Four Link Pack " << std::endl;
134 }
135 uint32_t shift_in_word = 8 * (i_link % 4);
136 // the check sums performed by the HGCROC and downstream chips can
137 // confirm the validity of the data, not used here (yet)
138 // bool rid_ok = ((w >> (shift_in_word + 7)) & packing::utility::MASK<1>)
139 // == 1; bool cdc_ok = ((w >> (shift_in_word + 6)) &
140 // packing::utility::MASK<1>) == 1;
141 length_per_link[i_link] =
142 (w >> shift_in_word) & packing::utility::MASK<6>;
143 // std::cout << " Link " << i_link << " readout " <<
144 // length_per_link.at(i_link) << " channels" << std::endl;
145 }
146
156 for (uint32_t i_link{0}; i_link < nlinks; i_link++) {
157 // move on from last word counting links or previous link
158 // std::cout << "RO Link " << i_link << std::endl;
159 packing::utility::CRC link_crc;
160 reader >> w;
161 fpga_crc << w;
162 link_crc << w;
163 uint32_t roc_id = (w >> 16) & packing::utility::MASK<16>;
164 // checksum for this chunk of data can be used to confirm data validity
165 // bool crc_ok = (w >> 15) & packing::utility::MASK<1> == 1;
166 // std::cout << hex(w) << " : roc_id " << roc_id << ", crc_ok (v2
167 // always false) " << std::boolalpha << crc_ok << std::endl;
168
169 // get readout map from the last 8 bits of this word
170 // and the entire next word
171 std::bitset<40> ro_map = w & packing::utility::MASK<8>;
172 ro_map <<= 32;
173 reader >> w;
174 fpga_crc << w;
175 link_crc << w;
176 ro_map |= w;
177
178 // std::cout << "Start looping through channels..." << std::endl;
179 // loop through channels on this link,
180 // since some channels may have been suppressed because of low
181 // amplitude the channel ID is not the same as the index_ it
182 // is listed in.
183 int channel_id{-1};
184 for (uint32_t j{0}; j < length_per_link.at(i_link) - 2; j++) {
185 // skip zero-suppressed channel IDs
186 do {
187 channel_id++;
188 } while (channel_id < 40 and not ro_map.test(channel_id));
189
190 // next word is this channel
191 reader >> w;
192 fpga_crc << w;
193 // std::cout << hex(w) << " " << channel_id;
194
195 if (channel_id == 0) {
204 // std::cout << " : ROC Header";
205 /*
206 * These are unused, but are available as defined by the spec
207 * additionally, we are calculating our own copy of the link checksum
208 for later comparison
209 * if the data packet has readout its own checksum
210 link_crc << w;
211 uint32_t bx_id = (w >> 16) & packing::utility::MASK<12>;
212 uint32_t short_event = (w >> 10) & packing::utility::MASK<6>;
213 uint32_t short_orbit = (w >> 7) & packing::utility::MASK<3>;
214 uint32_t hamming_errs = (w >> 4) & packing::utility::MASK<3>;
215 */
216 } else if (channel_id == common_mode_channel) {
220 link_crc << w;
221 // std::cout << " : Common Mode";
222 } else if (channel_id == 39) {
223 /*
224 // CRC checksum from ROC
225 uint32_t crc = w;
226 // std::cout << " : CRC checksum : " << hex(link_crc.get()) << " =? "
227 << hex(crc);
228 // keeping this there in comment is helpful when the HGCROC is sending
229 along its own CRC checksum of the data for us to compare against.
230 // We had to comment it out because the v2 HGCROC we were using was
231 not sending a checksum and thus the check would always fail. if
232 (link_crc.get() != crc) { EXCEPTION_RAISE("BadCRC", "Our calculated
233 link checksum doesn't match the " "one from raw data.");
234 }
235 */
236 } else {
238
239 link_crc << w;
250 // std::cout << " : DAQ Channel ";
251
252 // std::cout << fpga << " " << roc_id-256 << " " << channel_id << " ";
263 ldmx::EcalElectronicsID eid(fpga - 1, roc_id - 256, channel_id);
264 // std::cout << eid.index();
265
266 // copy data into EID->sample map
267 eid_to_samples[eid].emplace_back(w);
268 } // type of channel
269 // std::cout << std::endl;
270 } // loop over channels (j in Table 4)
271 // std::cout << "done looping through channels" << std::endl;
272 } // loop over links
273
274 // another CRC checksum from FPGA
275 reader >> w;
276 // this word would be the CRC checksum as deteremined by the chip
277 // uint32_t crc = w;
278 // std::cout << "FPGA Checksum : " << hex(fpga_crc.get()) << " =? "
279 // << hex(crc) << std::endl;
280 /* TODO
281 * fix calculation of FPGA checksum
282 * I can't figure out why it isn't matching, but there
283 * is definitely a word here where the FPGA checksum would be.
284 if (fpga_crc.get() != crc) {
285 EXCEPTION_RAISE(
286 "BadCRC",
287 "Our calculated FPGA checksum doesn't match the one read in.");
288 }
289 */
290 }
291
293 // assume all channels have same number of samples
294 digis.setNumSamplesPerDigi(eid_to_samples.begin()->second.size());
295 digis.setSampleOfInterestIndex(0); // TODO configurable
297 if (translate_eid_) {
305 auto detmap{
307 for (auto const& [eid, digi] : eid_to_samples) {
308 // The electronics map returns an empty ID of the correct
309 // type when the electronics ID is not found.
310 // need to check if the electronics ID exists
311 // TODO: do we want to end processing if this happens?
312 if (detmap.exists(eid)) {
313 uint32_t did_raw = detmap.get(eid).raw();
314 digis.addDigi(did_raw, digi);
315 } else {
325 }
326 }
327 } else {
335 for (auto const& [eid, digi] : eid_to_samples) {
336 digis.addDigi(eid.raw(), digi);
337 }
338 }
339
340 // std::cout << "adding " << digis.getNumDigis() << " digis each with " <<
341 // digis.getNumSamplesPerDigi() << " samples to event bus" << std::endl;
342 event.add(output_name_, digis);
343 return;
344} // produce
static constexpr const char * CONDITIONS_OBJECT_NAME
The name of the EID <-> DetID map for the ECal.
const T & getCondition(const std::string &condition_name)
Access a conditions object for the current event.
Identifies a location in the Ecal readout chain.
Represents a collection of the digi hits readout by an HGCROC.
void setNumSamplesPerDigi(unsigned int n)
Set number of samples for each digi.
void setSampleOfInterestIndex(unsigned int n)
Set index of sample of interest.
void setVersion(int v)
Set the version of the ROC we have read.
void addDigi(unsigned int id, const std::vector< Sample > &digi)
Add samples to collection.
The HGC ROC and FPGA use a CRC checksum to double check that the data transfer has been done correctl...
Definition CRC.h:51
A very simple wrapper enabling us to more easily tell the output stream to style the input word in he...

References ldmx::HgcrocDigiCollection::addDigi(), ecal::EcalDetectorMap::CONDITIONS_OBJECT_NAME, framework::EventProcessor::getCondition(), input_name_, input_pass_, output_name_, roc_version_, ldmx::HgcrocDigiCollection::setNumSamplesPerDigi(), ldmx::HgcrocDigiCollection::setSampleOfInterestIndex(), ldmx::HgcrocDigiCollection::setVersion(), and translate_eid_.

Member Data Documentation

◆ input_name_

std::string ecal::EcalRawDecoder::input_name_
private

input object of encoded data

Definition at line 37 of file EcalRawDecoder.h.

Referenced by configure(), and produce().

◆ input_pass_

std::string ecal::EcalRawDecoder::input_pass_
private

input pass of creating encoded data

Definition at line 39 of file EcalRawDecoder.h.

Referenced by configure(), and produce().

◆ output_name_

std::string ecal::EcalRawDecoder::output_name_
private

output object to put onto event bus

Definition at line 41 of file EcalRawDecoder.h.

Referenced by configure(), and produce().

◆ roc_version_

int ecal::EcalRawDecoder::roc_version_
private

version of HGC ROC we are decoding

Definition at line 43 of file EcalRawDecoder.h.

Referenced by configure(), and produce().

◆ translate_eid_

bool ecal::EcalRawDecoder::translate_eid_
private

should we translate electronic IDs to detector IDs

Definition at line 45 of file EcalRawDecoder.h.

Referenced by configure(), and produce().


The documentation for this class was generated from the following files: