LDMX Software
HcalRawDecoder.h
1#ifndef HCALRAWDECODER_H
2#define HCALRAWDECODER_H
3
4#include <bitset>
5
6#include "DetDescr/HcalElectronicsID.h"
8#include "Packing/Utility/CRC.h"
9#include "Packing/Utility/Mask.h"
10#include "Packing/Utility/Reader.h"
12namespace hcal {
13
18 int fpga_;
22 int spill_;
24 int ticks_;
26 int bunch_;
30 int run_;
32 int dd_;
34 int month_;
36 int hh_;
38 int mm_;
40 std::vector<bool> good_bxheader_;
42 std::vector<bool> good_trailer_;
43
47 void board(framework::Event& event, const std::string& prefix);
48};
49
54 public:
55 HcalRawDecoder(const std::string& name, framework::Process& process)
57 virtual ~HcalRawDecoder() = default;
60 void beforeNewRun(ldmx::RunHeader& rh) override;
62 void produce(framework::Event& event) override;
63
64 private:
74 template <typename ReaderType>
76 std::vector<ldmx::HgcrocDigiCollection::Sample>>
77 read(ReaderType& reader, PolarfireEventHeader& eh) {
81 static const unsigned int common_mode_channel = roc_version_ == 2 ? 19 : 1;
82 static const unsigned int calib_channel = 20;
84 static uint32_t head1, head2, w;
85
86 // special header words not counted in event length
87 do {
88 reader >> head1;
89 } while (head1 != 0xbeef2021 and head1 != 0xbeef2022);
90
94 long int eventlen;
95 long int i_event{0};
96 /* whole event header word looks like
97 *
98 * VERSION (4) | FPGA ID (8) | NSAMPLES (4) | LEN (16)
99 */
100 reader >> head1;
101 i_event++;
102
103 eh.version_ = (head1 >> 28) & packing::utility::MASK<4>;
104 eh.fpga_ = (head1 >> 20) & packing::utility::MASK<8>;
105 eh.nsamples_ = (head1 >> 16) & packing::utility::MASK<4>;
106 eventlen = head1 & packing::utility::MASK<16>;
107 if (eh.version_ == 1u) {
108 // eventlen is 32-bit words in event
109 // do nothing here
110 } else if (eh.version_ == 2u) {
111 // eventlen is 64-bit words in event,
112 // need to multiply by 2 to get actual 32-bit event length
113 eventlen *= 2;
114 // and subtract off the special header word above
115 eventlen -= 1;
116 } else {
117 EXCEPTION_RAISE(
118 "VersMis",
119 "HcalRawDecoder only knows version 1 and 2 of DAQ format.");
120 }
121 // sample counters
122 int n_words{0};
123 std::vector<uint32_t> length_per_sample(eh.nsamples_, 0);
124 for (uint32_t i_sample{0}; i_sample < eh.nsamples_; i_sample++) {
125 if (i_sample % 2 == 0) {
126 n_words++;
127 reader >> w;
128 i_event++;
129 }
130 uint32_t shift_in_word = 16 * (i_sample % 2);
131 length_per_sample[i_sample] =
132 (w >> shift_in_word) & packing::utility::MASK<12>;
133 }
134
135 if (eh.version_ == 2) {
141 for (int i_word{n_words}; i_word < 8; i_word++) {
142 reader >> head1;
143 i_event++;
144 }
145
149 reader >> head1;
150 i_event++;
151 eh.spill_ = ((head1 >> 12) & 0xfff);
152 eh.bunch_ = (head1 & 0xfff);
153 reader >> head1;
154 i_event++;
155 eh.ticks_ = head1;
156 reader >> head1;
157 i_event++;
158 eh.number_ = head1;
159 reader >> head1;
160 i_event++;
161 eh.run_ = (head1 & 0xFFF);
162 eh.dd_ = (head1 >> 23) & 0x1F;
163 eh.mm_ = (head1 >> 28) & 0xF;
164 eh.hh_ = (head1 >> 18) & 0x1F;
165 eh.mm_ = (head1 >> 12) & 0x3F;
166 }
167
175 // fill map of **electronic** IDs to the digis that were read out
177 std::vector<ldmx::HgcrocDigiCollection::Sample>>
178 eid_to_samples;
179 std::size_t i_sample{0};
180 while (i_event < eventlen) {
181 reader >> head1 >> head2;
182 i_event += 2;
198 packing::utility::CRC fpga_crc;
199 fpga_crc << head1;
200
201 [[maybe_unused]] uint32_t hgcroc_version =
202 (head1 >> 28) & packing::utility::MASK<4>;
203 uint32_t fpga = (head1 >> 20) & packing::utility::MASK<8>;
204 uint32_t nlinks = (head1 >> 14) & packing::utility::MASK<6>;
205 [[maybe_unused]] uint32_t len = head1 & packing::utility::MASK<12>;
206
207 fpga_crc << head2;
208
209 [[maybe_unused]] uint32_t bx_id =
210 (head2 >> 20) & packing::utility::MASK<12>;
211 [[maybe_unused]] uint32_t rreq =
212 (head2 >> 10) & packing::utility::MASK<10>;
213 [[maybe_unused]] uint32_t orbit = head2 & packing::utility::MASK<10>;
214
215 std::vector<uint32_t> length_per_link(nlinks, 0);
216 for (uint32_t i_link{0}; i_link < nlinks; i_link++) {
217 if (i_link % 4 == 0) {
218 i_event++;
219 reader >> w;
220 fpga_crc << w;
221 }
222 uint32_t shift_in_word = 8 * (i_link % 4);
223 [[maybe_unused]] bool rid_ok =
224 ((w >> (shift_in_word + 7)) & packing::utility::MASK<1>) == 1;
225 [[maybe_unused]] bool cdc_ok =
226 ((w >> (shift_in_word + 6)) & packing::utility::MASK<1>) == 1;
227 length_per_link[i_link] =
228 (w >> shift_in_word) & packing::utility::MASK<6>;
229 }
230
239 eh.good_bxheader_.resize(nlinks);
240 eh.good_trailer_.resize(nlinks);
241 for (uint32_t i_link{0}; i_link < nlinks; i_link++) {
246 if (length_per_link.at(i_link) < 2) {
247 continue;
248 }
249 // move on from last word counting links or previous link
250 packing::utility::CRC link_crc;
251 i_event++;
252 reader >> w;
253 fpga_crc << w;
254 link_crc << w;
255 [[maybe_unused]] uint32_t roc_id =
256 (w >> 16) & packing::utility::MASK<16>;
257 [[maybe_unused]] bool crc_ok =
258 ((w >> 15) & packing::utility::MASK<1>) == 1;
259
260 // get readout map from the last 8 bits of this word
261 // and the entire next word
262 std::bitset<40> ro_map = w & packing::utility::MASK<8>;
263 ro_map <<= 32;
264 i_event++;
265 reader >> w;
266 fpga_crc << w;
267 link_crc << w;
268 ro_map |= w;
269 // loop through channels on this link,
270 // since some channels may have been suppressed because of low
271 // amplitude the channel ID is not the same as the index it
272 // is listed in.
273 int j{-1};
274 for (uint32_t i_word{2}; i_word < length_per_link.at(i_link);
275 i_word++) {
276 // skip zero-suppressed channel IDs
277 do {
278 j++;
279 } while (j < 40 and not ro_map.test(j));
280
281 // next word is this channel
282 i_event++;
283 reader >> w;
284 fpga_crc << w;
285
286 if (j == 0) {
295 link_crc << w;
296 // v2
297 eh.good_bxheader_[i_link] = ((w & 0xff000000) == 0xaa000000);
298 // v3
299 //
300 // Shadows a previous declaration but is never used so renamed here
301 [[maybe_unused]] uint32_t v3_bx_id =
302 (w >> 16) & packing::utility::MASK<12>;
303 [[maybe_unused]] uint32_t short_event =
304 (w >> 10) & packing::utility::MASK<6>;
305 [[maybe_unused]] uint32_t short_orbit =
306 (w >> 7) & packing::utility::MASK<3>;
307 [[maybe_unused]] uint32_t hamming_errs =
308 (w >> 4) & packing::utility::MASK<3>;
309 } else if (j == common_mode_channel) {
313 link_crc << w;
314 } else if (j == calib_channel) {
315 // calib channel
316 link_crc << w;
317 } else if (j == 39) {
318 // trailer on each link added by ROC
319 // ROC v2 - IDLE word
320 // ROC v3 - CRC checksum
321 if (roc_version_ == 2) {
322 bool good_idle = (w == 0xaccccccc);
323 eh.good_trailer_[i_link] = good_idle;
324 } else {
325 bool good_crc = (link_crc.get() == w);
326 eh.good_trailer_[i_link] = good_crc;
327 }
328 /*
329 if (roc_version_ > 2 and link_crc.get() != w) {
330 EXCEPTION_RAISE("BadCRC",
331 "Our calculated link checksum doesn't match the "
332 "one from raw data.");
333 }
334 */
335 } else {
337
338 link_crc << w;
354 ldmx::HcalElectronicsID eid(fpga, i_link,
355 j - 1 - 1 * (j > common_mode_channel) -
356 1 * (j > calib_channel));
357 // copy data into EID->sample map
358 eid_to_samples[eid].emplace_back(w);
359 } // type of channel
360 } // loop over channels (j in Table 4)
361 } // loop over links
362
363 // another CRC checksum from FPGA
364 i_event++;
365 reader >> w;
366 [[maybe_unused]] uint32_t crc = w;
367 /* TODO
368 * fix calculation of FPGA checksum
369 * I can't figure out why it isn't matching, but there
370 * is definitely a word here where the FPGA checksum would be.
371 if (fpga_crc.get() != crc) {
372 EXCEPTION_RAISE(
373 "BadCRC",
374 "Our calculated FPGA checksum doesn't match the one read in.");
375 }
376 */
377 // padding to reach 64-bit boundary in version 2
378 if (eh.version_ == 2u and length_per_sample.at(i_sample) % 2 == 1) {
379 i_event++;
380 reader >> head1;
381 }
382 i_sample++;
383 }
384
385 if (eh.version_ == 1u) {
386 // special footer words
387 reader >> head1 >> head2;
388 }
389
390 return eid_to_samples;
391 }
392
393 private:
395 std::string input_file_;
397 std::vector<std::string> input_names_;
399 std::string input_pass_;
401 std::string output_name_;
403 std::string detector_name_;
410
411 private:
414};
415} // namespace hcal
416#endif /* HCALRAWDECODER_H */
Base classes for all user event processing components to extend.
Class that represents a digitized hit in a calorimeter cell readout by an HGCROC.
Implements an event buffer system for storing event data.
Definition Event.h:40
Class which represents the process under execution.
Definition Process.h:34
Base class for a module which produces a data product.
virtual void process(Event &event) final
Processing an event for a Producer is calling produce.
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:26
std::string detector_name_
the detector name if we are reading from a file
bool read_from_file_
is the input_name a file or an event object
std::string output_name_
output object to put onto event bus
std::string input_file_
input file of encoded data
void beforeNewRun(ldmx::RunHeader &rh) override
add detector name if we are reading from file
packing::utility::Reader file_reader_
the file reader (if we are doing that)
void configure(framework::config::Parameters &) override
Callback for the EventProcessor to configure itself from the given set of parameters.
std::vector< std::string > input_names_
input object of encoded data
std::map< ldmx::HcalElectronicsID, std::vector< ldmx::HgcrocDigiCollection::Sample > > read(ReaderType &reader, PolarfireEventHeader &eh)
Assume input reader behaves like a binary data input stream where we can "pop" individual 32-bit word...
bool translate_eid_
are get translating electronic IDs?
int roc_version_
version of HGC ROC we are decoding
std::string input_pass_
input pass of creating encoded data
void produce(framework::Event &event) override
use read function to decode data, then translate EIDs into DetIDs
Identifies a location in the Hcal readout chain.
Run-specific configuration and data stored in its own output TTree alongside the event TTree in the o...
Definition RunHeader.h:68
The HGC ROC and FPGA use a CRC checksum to double check that the data transfer has been done correctl...
Definition CRC.h:51
uint32_t get()
Get the calculate checksum from the calculator.
Definition CRC.h:111
Reading a raw data file.
Definition Reader.h:20
int ticks_
number of 5MHz ticks since spill
int version_
version of daq format
std::vector< bool > good_trailer_
quality of link trailers
int dd_
day of month run started
int number_
event number according to this polarfire
int mm_
minute run started
int fpga_
id for polarfire
int nsamples_
number of samples
int bunch_
bunch number according to this polarfire
void board(framework::Event &event, const std::string &prefix)
board us onto the bus with the input prefix
int hh_
hour run started
int month_
month run started
int run_
run number according to this polarfire
std::vector< bool > good_bxheader_
quality of link headers