LDMX Software
EcalRawDecoder.cxx
1#include "Ecal/EcalRawDecoder.h"
2
3#include <bitset>
4
6#include "DetDescr/EcalID.h"
8#include "Packing/Utility/BufferReader.h"
9#include "Packing/Utility/CRC.h"
10#include "Packing/Utility/Hex.h"
11#include "Packing/Utility/Mask.h"
13
14namespace ecal {
15
16// we are using 32-bit words here
19
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}
27
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
345
346} // namespace ecal
347
Class which contains logic for how the detector items connect to and relate with the reconstruction c...
Class that identifies a location in the Ecal readout chain.
Class that defines an ECal detector ID with a cell number.
#define DECLARE_PRODUCER(CLASS)
Macro which allows the framework to construct a producer given its name during configuration.
Class that represents a digitized hit in a calorimeter cell readout by an HGCROC.
static constexpr const char * CONDITIONS_OBJECT_NAME
The name of the EID <-> DetID map for the ECal.
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
virtual void produce(framework::Event &event)
Process the event and put new data products into it.
std::string input_name_
input object of encoded data
std::string output_name_
output object to put onto event bus
virtual void configure(framework::config::Parameters &)
Callback for the EventProcessor to configure itself from the given set of parameters.
const T & getCondition(const std::string &condition_name)
Access a conditions object for the current event.
Implements an event buffer system for storing event data.
Definition Event.h:40
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:26
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:75
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.
This class is a helper class for reading the buffer stored in the raw data format.
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...