LDMX Software
HcalRawDecoder.h
1#ifndef HCALRAWDECODER_H
2#define HCALRAWDECODER_H
3
4#include <bitset>
5#include <iomanip>
6#include <optional>
7
8#include "DetDescr/HcalElectronicsID.h"
9#include "DetDescr/HcalID.h"
12#include "Packing/Utility/CRC.h"
13#include "Packing/Utility/Mask.h"
14#include "Packing/Utility/Reader.h"
16namespace hcal {
17
22 int fpga;
26 int spill;
28 int ticks;
30 int bunch;
32 int number;
34 int run;
36 int DD;
38 int MM;
40 int hh;
42 int mm;
44 std::vector<bool> good_bxheader;
46 std::vector<bool> good_trailer;
47
51 void board(framework::Event& event, const std::string& prefix);
52};
53
58 public:
59 HcalRawDecoder(const std::string& name, framework::Process& process)
60 : framework::Producer(name, process) {}
61 virtual ~HcalRawDecoder() = default;
64 void beforeNewRun(ldmx::RunHeader& rh) override;
66 void produce(framework::Event& event) override;
67
68 private:
78 template <typename ReaderType>
80 std::vector<ldmx::HgcrocDigiCollection::Sample>>
81 read(ReaderType& reader, PolarfireEventHeader& eh) {
85 static const unsigned int common_mode_channel = roc_version_ == 2 ? 19 : 1;
86 static const unsigned int calib_channel = 20;
88 static uint32_t head1, head2, w;
89
90 // special header words not counted in event length
91 do {
92 reader >> head1;
93 } while (head1 != 0xbeef2021 and head1 != 0xbeef2022);
94
98 long int eventlen;
99 long int i_event{0};
100 /* whole event header word looks like
101 *
102 * VERSION (4) | FPGA ID (8) | NSAMPLES (4) | LEN (16)
103 */
104 reader >> head1;
105 i_event++;
106
107 eh.version = (head1 >> 28) & packing::utility::mask<4>;
108 eh.fpga = (head1 >> 20) & packing::utility::mask<8>;
109 eh.nsamples = (head1 >> 16) & packing::utility::mask<4>;
110 eventlen = head1 & packing::utility::mask<16>;
111 if (eh.version == 1u) {
112 // eventlen is 32-bit words in event
113 // do nothing here
114 } else if (eh.version == 2u) {
115 // eventlen is 64-bit words in event,
116 // need to multiply by 2 to get actual 32-bit event length
117 eventlen *= 2;
118 // and subtract off the special header word above
119 eventlen -= 1;
120 } else {
121 EXCEPTION_RAISE(
122 "VersMis",
123 "HcalRawDecoder only knows version 1 and 2 of DAQ format.");
124 }
125 // sample counters
126 int n_words{0};
127 std::vector<uint32_t> length_per_sample(eh.nsamples, 0);
128 for (uint32_t i_sample{0}; i_sample < eh.nsamples; i_sample++) {
129 if (i_sample % 2 == 0) {
130 n_words++;
131 reader >> w;
132 i_event++;
133 }
134 uint32_t shift_in_word = 16 * (i_sample % 2);
135 length_per_sample[i_sample] =
136 (w >> shift_in_word) & packing::utility::mask<12>;
137 }
138
139 if (eh.version == 2) {
145 for (int i_word{n_words}; i_word < 8; i_word++) {
146 reader >> head1;
147 i_event++;
148 }
149
153 reader >> head1;
154 i_event++;
155 eh.spill = ((head1 >> 12) & 0xfff);
156 eh.bunch = (head1 & 0xfff);
157 reader >> head1;
158 i_event++;
159 eh.ticks = head1;
160 reader >> head1;
161 i_event++;
162 eh.number = head1;
163 reader >> head1;
164 i_event++;
165 eh.run = (head1 & 0xFFF);
166 eh.DD = (head1 >> 23) & 0x1F;
167 eh.MM = (head1 >> 28) & 0xF;
168 eh.hh = (head1 >> 18) & 0x1F;
169 eh.mm = (head1 >> 12) & 0x3F;
170 }
171
179 // fill map of **electronic** IDs to the digis that were read out
181 std::vector<ldmx::HgcrocDigiCollection::Sample>>
182 eid_to_samples;
183 std::size_t i_sample{0};
184 while (i_event < eventlen) {
185 reader >> head1 >> head2;
186 i_event += 2;
202 packing::utility::CRC fpga_crc;
203 fpga_crc << head1;
204
205 [[maybe_unused]] uint32_t hgcroc_version =
206 (head1 >> 28) & packing::utility::mask<4>;
207 uint32_t fpga = (head1 >> 20) & packing::utility::mask<8>;
208 uint32_t nlinks = (head1 >> 14) & packing::utility::mask<6>;
209 [[maybe_unused]] uint32_t len = head1 & packing::utility::mask<12>;
210
211 fpga_crc << head2;
212
213 [[maybe_unused]] uint32_t bx_id =
214 (head2 >> 20) & packing::utility::mask<12>;
215 [[maybe_unused]] uint32_t rreq =
216 (head2 >> 10) & packing::utility::mask<10>;
217 [[maybe_unused]] uint32_t orbit = head2 & packing::utility::mask<10>;
218
219 std::vector<uint32_t> length_per_link(nlinks, 0);
220 for (uint32_t i_link{0}; i_link < nlinks; i_link++) {
221 if (i_link % 4 == 0) {
222 i_event++;
223 reader >> w;
224 fpga_crc << w;
225 }
226 uint32_t shift_in_word = 8 * (i_link % 4);
227 [[maybe_unused]] bool rid_ok =
228 ((w >> (shift_in_word + 7)) & packing::utility::mask<1>) == 1;
229 [[maybe_unused]] bool cdc_ok =
230 ((w >> (shift_in_word + 6)) & packing::utility::mask<1>) == 1;
231 length_per_link[i_link] =
232 (w >> shift_in_word) & packing::utility::mask<6>;
233 }
234
243 eh.good_bxheader.resize(nlinks);
244 eh.good_trailer.resize(nlinks);
245 for (uint32_t i_link{0}; i_link < nlinks; i_link++) {
250 if (length_per_link.at(i_link) < 2) {
251 continue;
252 }
253 // move on from last word counting links or previous link
254 packing::utility::CRC link_crc;
255 i_event++;
256 reader >> w;
257 fpga_crc << w;
258 link_crc << w;
259 [[maybe_unused]] uint32_t roc_id =
260 (w >> 16) & packing::utility::mask<16>;
261 [[maybe_unused]] bool crc_ok =
262 ((w >> 15) & packing::utility::mask<1>) == 1;
263
264 // get readout map from the last 8 bits of this word
265 // and the entire next word
266 std::bitset<40> ro_map = w & packing::utility::mask<8>;
267 ro_map <<= 32;
268 i_event++;
269 reader >> w;
270 fpga_crc << w;
271 link_crc << w;
272 ro_map |= w;
273 // loop through channels on this link,
274 // since some channels may have been suppressed because of low
275 // amplitude the channel ID is not the same as the index it
276 // is listed in.
277 int j{-1};
278 for (uint32_t i_word{2}; i_word < length_per_link.at(i_link);
279 i_word++) {
280 // skip zero-suppressed channel IDs
281 do {
282 j++;
283 } while (j < 40 and not ro_map.test(j));
284
285 // next word is this channel
286 i_event++;
287 reader >> w;
288 fpga_crc << w;
289
290 if (j == 0) {
299 link_crc << w;
300 // v2
301 eh.good_bxheader[i_link] = ((w & 0xff000000) == 0xaa000000);
302 // v3
303 //
304 // Shadows a previous declaration but is never used so renamed here
305 [[maybe_unused]] uint32_t v3_bx_id =
306 (w >> 16) & packing::utility::mask<12>;
307 [[maybe_unused]] uint32_t short_event =
308 (w >> 10) & packing::utility::mask<6>;
309 [[maybe_unused]] uint32_t short_orbit =
310 (w >> 7) & packing::utility::mask<3>;
311 [[maybe_unused]] uint32_t hamming_errs =
312 (w >> 4) & packing::utility::mask<3>;
313 } else if (j == common_mode_channel) {
317 link_crc << w;
318 } else if (j == calib_channel) {
319 // calib channel
320 link_crc << w;
321 } else if (j == 39) {
322 // trailer on each link added by ROC
323 // ROC v2 - IDLE word
324 // ROC v3 - CRC checksum
325 if (roc_version_ == 2) {
326 bool good_idle = (w == 0xaccccccc);
327 eh.good_trailer[i_link] = good_idle;
328 } else {
329 bool good_crc = (link_crc.get() == w);
330 eh.good_trailer[i_link] = good_crc;
331 }
332 /*
333 if (roc_version_ > 2 and link_crc.get() != w) {
334 EXCEPTION_RAISE("BadCRC",
335 "Our calculated link checksum doesn't match the "
336 "one from raw data.");
337 }
338 */
339 } else {
341
342 link_crc << w;
358 ldmx::HcalElectronicsID eid(fpga, i_link,
359 j - 1 - 1 * (j > common_mode_channel) -
360 1 * (j > calib_channel));
361 // copy data into EID->sample map
362 eid_to_samples[eid].emplace_back(w);
363 } // type of channel
364 } // loop over channels (j in Table 4)
365 } // loop over links
366
367 // another CRC checksum from FPGA
368 i_event++;
369 reader >> w;
370 [[maybe_unused]] uint32_t crc = w;
371 /* TODO
372 * fix calculation of FPGA checksum
373 * I can't figure out why it isn't matching, but there
374 * is definitely a word here where the FPGA checksum would be.
375 if (fpga_crc.get() != crc) {
376 EXCEPTION_RAISE(
377 "BadCRC",
378 "Our calculated FPGA checksum doesn't match the one read in.");
379 }
380 */
381 // padding to reach 64-bit boundary in version 2
382 if (eh.version == 2u and length_per_sample.at(i_sample) % 2 == 1) {
383 i_event++;
384 reader >> head1;
385 }
386 i_sample++;
387 }
388
389 if (eh.version == 1u) {
390 // special footer words
391 reader >> head1 >> head2;
392 }
393
394 return eid_to_samples;
395 }
396
397 private:
399 std::string input_file_;
401 std::vector<std::string> input_names_;
403 std::string input_pass_;
405 std::string output_name_;
407 std::string detector_name_;
414
415 private:
418};
419} // namespace hcal
420#endif /* HCALRAWDECODER_H */
Base classes for all user event processing components to extend.
Class which contains logic for how the detector items connect to and relate with the reconstruction c...
Class that defines an HCal sensitive detector.
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:41
Class which represents the process under execution.
Definition Process.h:36
Base class for a module which produces a data product.
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:27
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:54
The HGC ROC and FPGA use a CRC checksum to double check that the data transfer has been done correctl...
Definition CRC.h:50
uint32_t get()
Get the calculate checksum from the calculator.
Definition CRC.h:110
Reading a raw data file.
Definition Reader.h:19
int hh
hour run started
int version
version of daq format
std::vector< bool > good_bxheader
quality of link headers
int mm
minute run started
int number
event number according to this polarfire
void board(framework::Event &event, const std::string &prefix)
board us onto the bus with the input prefix
int ticks
number of 5MHz ticks since spill
int DD
day of month run started
std::vector< bool > good_trailer
quality of link trailers
int fpga
id for polarfire
int nsamples
number of samples
int run
run number according to this polarfire
int MM
month run started
int bunch
bunch number according to this polarfire