LDMX Software
Public Member Functions | Private Attributes | List of all members
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 beforeNewRun (ldmx::RunHeader &header)
 Handle allowing producers to modify run headers before the run begins.
 
- Public Member Functions inherited from framework::EventProcessor
 EventProcessor (const std::string &name, Process &process)
 Class constructor.
 
virtual ~EventProcessor ()
 Class destructor.
 
virtual void onNewRun (const ldmx::RunHeader &runHeader)
 Callback for the EventProcessor to take any necessary action when the run being processed changes.
 
virtual void onFileOpen (EventFile &eventFile)
 Callback for the EventProcessor to take any necessary action when a new event input ROOT file is opened.
 
virtual void onFileClose (EventFile &eventFile)
 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

- Static Public Member Functions inherited from framework::EventProcessor
static void declare (const std::string &classname, int classtype, EventProcessorMaker *)
 Internal function which is part of the PluginFactory machinery.
 
- Static Public Attributes inherited from framework::Producer
static const int CLASSTYPE {1}
 Constant used to track EventProcessor types by the PluginFactory.
 
- Protected Member Functions inherited from framework::EventProcessor
void abortEvent ()
 Abort the event immediately.
 
- Protected Attributes inherited from framework::EventProcessor
HistogramHelper histograms_
 Interface class for making and filling histograms.
 
NtupleManagerntuple_ {NtupleManager::getInstance()}
 Manager for any ntuples.
 
logging::logger theLog_
 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 className equal to the EventProcessor class name.

For an example, look at MyProcessor.

Parameters
parametersParameters for configuration.

Reimplemented from framework::EventProcessor.

Definition at line 22 of file EcalRawDecoder.cxx.

22 {
23 input_name_ = ps.getParameter<std::string>("input_name");
24 input_pass_ = ps.getParameter<std::string>("input_pass");
25 output_name_ = ps.getParameter<std::string>("output_name");
26 roc_version_ = ps.getParameter<int>("roc_version");
27 translate_eid_ = ps.getParameter<bool>("translate_eid");
28}
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::getParameter(), 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 30 of file EcalRawDecoder.cxx.

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

References ldmx::HgcrocDigiCollection::addDigi(), ecal::EcalDetectorMap::CONDITIONS_OBJECT_NAME, 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: