DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
DAPHNEFrame.hpp
Go to the documentation of this file.
1
14#ifndef FDDETDATAFORMATS_INCLUDE_FDDATAFORMATS_DAPHNE_DAPHNEFRAME_HPP_
15#define FDDETDATAFORMATS_INCLUDE_FDDATAFORMATS_DAPHNE_DAPHNEFRAME_HPP_
16
18#include <algorithm> // For std::min
19#include <cassert> // For assert()
20#include <cstdio>
21#include <cstdlib>
22#include <stdexcept> // For std::out_of_range
23#include <cstdint> // For uint32_t etc
24
25namespace dunedaq {
26namespace fddetdataformats {
27
29{
30public:
31 // ===============================================================
32 // Preliminaries
33 // ===============================================================
34
35 // The definition of the format is in terms of 32-bit words
36 typedef uint32_t word_t; // NOLINT
37
38 // Dataframe format version
39 static constexpr uint8_t version = 2;
40
41 static constexpr int s_bits_per_adc = 14;
42 static constexpr int s_bits_per_word = 8 * sizeof(word_t);
43 static constexpr int s_num_adcs = 1024;
45
46 struct Header
47 {
51 };
52
53
55
56 // Word 1: peak 0 odd
57 // Declared in reverse order (LSB first) so that:
58 // - num_subpeaks_0 occupies bits [3:0]
59 // - reserved_0 occupies bits [7:4]
60 // - adc_integral_0 occupies bits [30:8]
61 // - found_0 occupies bit [31]
62 word_t num_subpeaks_0 : 4; // Num_SubPeaks [3:0]
63 word_t reserved_0 : 4; // Reserved [7:4]
64 word_t adc_integral_0 : 23; // ADC_Integral [30:8]
65 word_t found_0 : 1; // Found [31]
66
67 // Word 2: peak 0 even
68 // Declared (LSB first) so that:
69 // - adc_max_0 occupies bits [13:0]
70 // - sample_max_0 occupies bits [22:14]
71 // - samples_over_baseline_0 occupies bits [31:23]
72 word_t adc_max_0 : 14; // ADC Max [13:0]
73 word_t sample_max_0 : 9; // Time_Peak [22:14]
74 word_t samples_over_baseline_0 : 9; // Time_Over_Baseline [31:23]
75
76 // Word 3: peak 1 odd
77 word_t num_subpeaks_1 : 4; // Num_SubPeaks [3:0]
78 word_t reserved_1 : 4; // Reserved [7:4]
79 word_t adc_integral_1 : 23; // ADC_Integral [30:8]
80 word_t found_1 : 1; // Found [31]
81
82 // Word 4: peak 1 even
83 word_t adc_max_1 : 14; // ADC Max [13:0]
84 word_t sample_max_1 : 9; // Time_Peak [22:14]
85 word_t samples_over_baseline_1 : 9;// Time_Over_Baseline [31:23]
86
87 // Word 5: peak 2 odd
88 word_t num_subpeaks_2 : 4; // Num_SubPeaks [3:0]
89 word_t reserved_2 : 4; // Reserved [7:4]
90 word_t adc_integral_2 : 23; // ADC_Integral [30:8]
91 word_t found_2 : 1; // Found [31]
92
93 // Word 6: peak 2 even
94 word_t adc_max_2 : 14; // ADC Max [13:0]
95 word_t sample_max_2 : 9; // Time_Peak [22:14]
96 word_t samples_over_baseline_2 : 9;// Time_Over_Baseline [31:23]
97
98 // Word 7: peak 3 odd
99 word_t num_subpeaks_3 : 4; // Num_SubPeaks [3:0]
100 word_t reserved_3 : 4; // Reserved [7:4]
101 word_t adc_integral_3 : 23; // ADC_Integral [30:8]
102 word_t found_3 : 1; // Found [31]
103
104 // Word 8: peak 3 even
105 word_t adc_max_3 : 14; // ADC Max [13:0]
106 word_t sample_max_3 : 9; // Time_Peak [22:14]
107 word_t samples_over_baseline_3 : 9;// Time_Over_Baseline [31:23]
108
109 // Word 9: peak 4 odd
110 word_t num_subpeaks_4 : 4; // Num_SubPeaks [3:0]
111 word_t reserved_4 : 4; // Reserved [7:4]
112 word_t adc_integral_4 : 23; // ADC_Integral [30:8]
113 word_t found_4 : 1; // Found [31]
114
115 // Word 10: peak 4 even
116 word_t adc_max_4 : 14; // ADC Max [13:0]
117 word_t sample_max_4 : 9; // Time_Peak [22:14]
118 word_t samples_over_baseline_4 : 9;// Time_Over_Baseline [31:23]
119
120 // Word 11: Time_Start fields for indices 0,1,2 and Reserved
121 // Declared in LSB-first order:
122 // - samples_start_2 occupies bits [11:2]
123 // - samples_start_1 occupies bits [21:12]
124 // - samples_start_0 occupies bits [31:22]
125 // - reserved_5 occupies bits [1:0]
126 word_t samples_start_2 : 10; // Time_Start(2) [11:2]
127 word_t samples_start_1 : 10; // Time_Start(1) [21:12]
128 word_t samples_start_0 : 10; // Time_Start(0) [31:22]
129 word_t reserved_5 : 2; // Reserved [1:0]
130
131 // Word 12: Time_Start fields for indices 3,4 and Reserved
132 // Declared in LSB-first order:
133 // - reserved_6 occupies bits [11:0]
134 // - samples_start_4 occupies bits [21:12]
135 // - samples_start_3 occupies bits [31:22]
136 word_t reserved_6 : 12; // Reserved [11:0]
137 word_t samples_start_4 : 10; // Time_Start(4) [21:12]
138 word_t samples_start_3 : 10; // Time_Start(3) [31:22]
139
140 // Word 13: Trailer word (all 32 bits), typically 0xFFFFFFFF.
142
143 static const uint8_t max_peaks = 5;
144
145 inline bool is_found( int idx ) const;
146 inline void set_found( uint8_t val, int idx );
147
148 inline uint32_t get_adc_integral(int idx) const;
149 inline void set_adc_integral(uint32_t val, int idx);
150
151 inline uint8_t get_num_subpeaks(int idx) const;
152 inline void set_num_subpeaks(uint8_t val, int idx);
153
154 inline uint16_t get_samples_over_baseline(int idx) const;
155 inline void set_samples_over_baseline(uint16_t val, int idx);
156
157 inline uint16_t get_sample_max(int idx) const;
158 inline void set_sample_max(uint16_t val, int idx);
159
160 inline uint16_t get_adc_max(int idx) const;
161 inline void set_adc_max(uint16_t val, int idx);
162
163 inline uint16_t get_sample_start(int idx) const;
164 inline void set_sample_start(uint16_t val, int idx);
165
166
167 // ===============================================================
168 // Private Helper: Reinterpret Trailer as an array of word_t
169 // ===============================================================
170 inline const word_t* as_words() const {
171 return reinterpret_cast<const word_t*>(this);
172 }
173 inline word_t* as_words() {
174 return reinterpret_cast<word_t*>(this);
175 }
176
177
178
179 };
180
181 // ===============================================================
182 // Data members
183 // ===============================================================
188
189 // ===============================================================
190 // Private Helper: Reinterpret Trailer as an array of word_t
191 // ===============================================================
192 // inline const word_t* as_words() const {
193 // return reinterpret_cast<const word_t*>(&trailer);
194 // }
195 // inline word_t* as_words() {
196 // return reinterpret_cast<word_t*>(&trailer);
197 // }
198
199
200 inline uint16_t get_adc(int i) const; // NOLINT;
201 inline void set_adc(int i, uint16_t val); // NOLINT;
202
203 uint8_t get_channel() const { return header.channel; } // NOLINT(build/unsigned)
204 void set_channel( uint8_t val) { header.channel = val & 0x3Fu; } // NOLINT(build/unsigned)
205
208 uint64_t get_timestamp() const // NOLINT(build/unsigned)
209 {
210 return daq_header.get_timestamp();
211 }
212};
213
214
215// ===============================================================
216// Accessors
217// ===============================================================
218
226uint16_t
227DAPHNEFrame::get_adc(int i) const // NOLINT
228{
229 if (i < 0 || i >= s_num_adcs)
230 throw std::out_of_range("ADC index out of range");
231
232 // The index of the first (and sometimes only) word containing the required ADC value
233 int word_index = s_bits_per_adc * i / s_bits_per_word;
234 assert(word_index < s_num_adc_words);
235 // Where in the word the lowest bit of our ADC value is located
236 int first_bit_position = (s_bits_per_adc * i) % s_bits_per_word;
237 // How many bits of our desired ADC are located in the `word_index`th word
238 int bits_from_first_word = std::min(s_bits_per_adc, s_bits_per_word - first_bit_position);
239 uint16_t adc = adc_words[word_index] >> first_bit_position; // NOLINT
240 // If we didn't get the full 14 bits from this word, we need the rest from the next word
241 if (bits_from_first_word < s_bits_per_adc) {
242 assert(word_index + 1 < s_num_adc_words);
243 adc |= adc_words[word_index + 1] << bits_from_first_word;
244 }
245 // Mask out all but the lowest 14 bits;
246 return adc & 0x3FFFu;
247}
248
252void
253DAPHNEFrame::set_adc(int i, uint16_t val) // NOLINT
254{
255 if (i < 0 || i >= s_num_adcs)
256 throw std::out_of_range("ADC index out of range");
257 if (val >= (1 << s_bits_per_adc))
258 throw std::out_of_range("ADC value out of range");
259
260 // The index of the first (and sometimes only) word containing the required ADC value
261 int word_index = s_bits_per_adc * i / s_bits_per_word;
262 assert(word_index < s_num_adc_words);
263 // Where in the word the lowest bit of our ADC value is located
264 int first_bit_position = (s_bits_per_adc * i) % s_bits_per_word;
265 // How many bits of our desired ADC are located in the `word_index`th word
266 int bits_in_first_word = std::min(s_bits_per_adc, s_bits_per_word - first_bit_position);
267 uint32_t mask = (1 << (first_bit_position)) - 1;
268 adc_words[word_index] = ((val << first_bit_position) & ~mask) | (adc_words[word_index] & mask);
269 // If we didn't put the full 14 bits in this word, we need to put the rest in the next word
270 if (bits_in_first_word < s_bits_per_adc) {
271 assert(word_index + 1 < s_num_adc_words);
272 mask = (1 << (s_bits_per_adc - bits_in_first_word)) - 1;
273 adc_words[word_index + 1] = ((val >> bits_in_first_word) & mask) | (adc_words[word_index + 1] & ~mask);
274 }
275}
276
277// --- Trailer Accessors (Manual Shift–Mask Extraction) ---
278
283inline bool
284DAPHNEFrame::PeakDescriptorData::is_found(int idx) const // idx index 0 to 4
285{
286 if (idx < 0 || idx > 4)
287 throw std::out_of_range("Peak index out of range (must be 0-4)");
288 const word_t* tw = as_words();
289 // In odd word, Found is in bit 31.
290 return static_cast<uint8_t>((tw[2*idx] >> 31) & 0x1);
291}
292
296inline void
298{
299 if (idx < 0 || idx > 4)
300 throw std::out_of_range("peak index out of range (must be 0-4)");
301 if (val > 1)
302 throw std::out_of_range("Found value out of range (must be 0-1)");
303 word_t* tw = as_words();
304 tw[2*idx] = (tw[2*idx] & ~(1u << 31)) | ((val & 0x1) << 31);
305}
306
311inline uint32_t
313{
314 if (idx < 0 || idx > 4)
315 throw std::out_of_range("Peak index out of range (must be 0-4)");
316 const word_t* tw = as_words();
317 return (tw[2*idx] >> 8) & 0x7FFFFF; // Mask 23 bits
318}
319
323inline void
325{
326 if (idx < 0 || idx > 4)
327 throw std::out_of_range("Peak index out of range (must be 0-4)");
328 if (val > 0x7FFFFF)
329 throw std::out_of_range("ADC_Integral value out of range (must be 0-8388607)");
330 word_t* tw = as_words();
331 tw[2*idx] = (tw[2*idx] & ~(0x7FFFFFu << 8)) | ((val & 0x7FFFFF) << 8);
332}
333
338inline uint8_t
340{
341 if (idx < 0 || idx > 4)
342 throw std::out_of_range("Peak index out of range (must be 0-4)");
343 const word_t* tw = as_words();
344 return static_cast<uint8_t>(tw[2*idx] & 0xF);
345}
346
350inline void
352{
353 if (idx < 0 || idx > 4)
354 throw std::out_of_range("Peak index out of range (must be 0-4)");
355 if (val > 0xF)
356 throw std::out_of_range("Num_SubPeaks value out of range (must be 0-15)");
357 word_t* tw = as_words();
358 tw[2*idx] = (tw[2*idx] & ~0xF) | (val & 0xF);
359}
360
365inline uint16_t
367{
368 if (idx < 0 || idx > 4)
369 throw std::out_of_range("Peak index out of range (must be 0-4)");
370 const word_t* tw = as_words();
371 return static_cast<uint16_t>((tw[2*idx+1] >> 23) & 0x1FF);
372}
373
377inline void
379{
380 if (idx < 0 || idx > 4)
381 throw std::out_of_range("Peak index out of range (must be 0-4)");
382 if (val > 0x1FF)
383 throw std::out_of_range("Time_Over_Baseline value out of range (must be 0-511)");
384 word_t* tw = as_words();
385 tw[2*idx+1] = (tw[2*idx+1] & ~(0x1FFu << 23)) | ((val & 0x1FF) << 23);
386}
387
392inline uint16_t
394{
395 if (idx < 0 || idx > 4)
396 throw std::out_of_range("Peak index out of range (must be 0-4)");
397 const word_t* tw = as_words();
398 return static_cast<uint16_t>((tw[2*idx+1] >> 14) & 0x1FF);
399}
400
401
405inline void
407{
408 if (idx < 0 || idx > 4)
409 throw std::out_of_range("Peak index out of range (must be 0-4)");
410 if (val > 0x1FF)
411 throw std::out_of_range("Time_Peak value out of range (must be 0-511)");
412 word_t* tw = as_words();
413 tw[2*idx+1] = (tw[2*idx+1] & ~(0x1FFu << 14)) | ((val & 0x1FF) << 14);
414}
415
420inline uint16_t
422{
423 if (idx < 0 || idx > 4)
424 throw std::out_of_range("Peak index out of range (must be 0-4)");
425 const word_t* tw = as_words();
426 // Even word for idx is at index 2*idx+1; ADC Max is in bits 13:0.
427 return static_cast<uint16_t>(tw[2*idx+1] & 0x3FFF);
428}
429
433inline void
435{
436 if (idx < 0 || idx > 4)
437 throw std::out_of_range("Peak index out of range (must be 0-4)");
438 if (val > 0x3FFF)
439 throw std::out_of_range("ADC Max value out of range (must be 0-16383)");
440 word_t* tw = as_words();
441 tw[2*idx+1] = (tw[2*idx+1] & ~0x3FFFu) | (val & 0x3FFF);
442}
443
456inline uint16_t
458{
459 if (idx < 0 || idx > 4)
460 throw std::out_of_range("Time_Start index out of range (must be 0-4)");
461
462 const word_t* tw = as_words();
463 if (idx < 3) {
464 int shift = 22 - 10 * idx;
465 return static_cast<uint16_t>((tw[10] >> shift) & 0x3FF);
466 } else {
467 int shift = 22 - 10 * (idx - 3);
468 return static_cast<uint16_t>((tw[11] >> shift) & 0x3FF);
469 }
470}
471
483inline void
485{
486 if (idx < 0 || idx > 4)
487 throw std::out_of_range("Time_Start index out of range (must be 0–4)");
488 if (val > 0x3FF)
489 throw std::out_of_range("Time_Start value out of range (must be 0–1023)");
490
491 word_t* tw = as_words();
492 word_t mask = 0x3FFu;
493
494 if (idx < 3) {
495 int shift = 22 - 10 * idx;
496 tw[10] = (tw[10] & ~(mask << shift)) | ((val & mask) << shift);
497 } else {
498 int shift = 22 - 10 * (idx - 3);
499 tw[11] = (tw[11] & ~(mask << shift)) | ((val & mask) << shift);
500 }
501}
502
503
504} // namespace fddetdataformats
505} // namespace dunedaq
506
507#endif // FDDETDATAFORMATS_INCLUDE_FDDATAFORMATS_DAPHNE_DAPHNEFRAME_HPP_
detdataformats::DAQHeader daq_header
void set_adc(int i, uint16_t val)
Set the ith ADC value in the frame to val.
uint64_t get_timestamp() const
Get the 64-bit timestamp of the frame.
uint16_t get_adc(int i) const
Get the ith ADC value in the frame.
Including Qt Headers.
DAQHeader is a versioned and unified structure for every FE electronics.
Definition DAQHeader.hpp:22
bool is_found(int idx) const
Get the Found value for a specific peak (channel) from the trailer. (Word 2*idx, bit 31)
void set_adc_integral(uint32_t val, int idx)
Set the ADC_Integral value for a specific peak.
uint16_t get_adc_max(int idx) const
Get the ADC Max value for a specific peak. (Word 2*idx+1, bits [31:18])
void set_num_subpeaks(uint8_t val, int idx)
Set the Num_SubPeaks value for a specific peak.
uint16_t get_sample_start(int idx) const
Get the Time_Start value for a given index (0-4).
uint16_t get_sample_max(int idx) const
Get the Time_Peak value for a specific peak. (Word 2*idx+1, bits [17:9])
void set_sample_max(uint16_t val, int idx)
Set the Time_Peak value for a specific peak.
void set_found(uint8_t val, int idx)
Set the Found value for a specific peak (channel) in the trailer.
uint32_t get_adc_integral(int idx) const
Get the ADC_Integral value for a specific peak. (Word 2*idx, bits [30:8])
void set_sample_start(uint16_t val, int idx)
Set the time_start field for Peak index 0–4 using bit shifts.
void set_adc_max(uint16_t val, int idx)
Set the ADC Max value for a specific peak.
uint8_t get_num_subpeaks(int idx) const
Get the Num_SubPeaks value for a specific peak. (Word 2*idx, bits [3:0])
void set_samples_over_baseline(uint16_t val, int idx)
Set the Time_Over_Baseline value for a specific peak.
uint16_t get_samples_over_baseline(int idx) const
Get the Time_Over_Baseline value for a specific peak. (Word 2*idx+1, bits [8:0])