/
DAPHNEFrame.hpp
146 lines (125 loc) · 5.14 KB
/
DAPHNEFrame.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/**
* @file DAPHNEFrame.hpp
*
* Contains declaration of DAPHNEFrame, a class for accessing raw DAPHNE frames, as produced by the DAPHNE boards
*
* The canonical definition of the PDS DAPHNE format is given in EDMS document 2088726:
* https://edms.cern.ch/document/2088726/3
*
* This is part of the DUNE DAQ Application Framework, copyright 2020.
* Licensing/copyright details are in the COPYING file that you should have
* received with this code.
*/
#ifndef FDDETDATAFORMATS_INCLUDE_FDDATAFORMATS_DAPHNE_DAPHNEFRAME_HPP_
#define FDDETDATAFORMATS_INCLUDE_FDDATAFORMATS_DAPHNE_DAPHNEFRAME_HPP_
#include "detdataformats/DAQHeader.hpp"
#include <algorithm> // For std::min
#include <cassert> // For assert()
#include <cstdio>
#include <cstdlib>
#include <stdexcept> // For std::out_of_range
#include <cstdint> // For uint32_t etc
namespace dunedaq {
namespace fddetdataformats {
class DAPHNEFrame
{
public:
// ===============================================================
// Preliminaries
// ===============================================================
// The definition of the format is in terms of 32-bit words
typedef uint32_t word_t; // NOLINT
static constexpr int s_bits_per_adc = 14;
static constexpr int s_bits_per_word = 8 * sizeof(word_t);
static constexpr int s_num_adcs = 1024;
static constexpr int s_num_adc_words = s_num_adcs * s_bits_per_adc / s_bits_per_word;
struct Header
{
word_t channel : 6, pds_reserved_1 : 10, trigger_sample_value : 16;
word_t threshold : 16, baseline : 16;
};
struct Trailer
{
word_t trailer;
};
// ===============================================================
// Data members
// ===============================================================
detdataformats::DAQHeader daq_header;
Header header;
word_t adc_words[s_num_adc_words]; // NOLINT
Trailer trailer;
// ===============================================================
// Accessors
// ===============================================================
/**
* @brief Get the ith ADC value in the frame
*
* The ADC words are 14 bits long, stored packed in the data structure. The order is:
*
* - 1024 adc values from one daphne channels
*/
uint16_t get_adc(int i) const // NOLINT
{
if (i < 0 || i >= s_num_adcs)
throw std::out_of_range("ADC index out of range");
// The index of the first (and sometimes only) word containing the required ADC value
int word_index = s_bits_per_adc * i / s_bits_per_word;
assert(word_index < s_num_adc_words);
// Where in the word the lowest bit of our ADC value is located
int first_bit_position = (s_bits_per_adc * i) % s_bits_per_word;
// How many bits of our desired ADC are located in the `word_index`th word
int bits_from_first_word = std::min(s_bits_per_adc, s_bits_per_word - first_bit_position);
uint16_t adc = adc_words[word_index] >> first_bit_position; // NOLINT
// If we didn't get the full 14 bits from this word, we need the rest from the next word
if (bits_from_first_word < s_bits_per_adc) {
assert(word_index + 1 < s_num_adc_words);
adc |= adc_words[word_index + 1] << bits_from_first_word;
}
// Mask out all but the lowest 14 bits;
return adc & 0x3FFFu;
}
/**
* @brief Set the ith ADC value in the frame to @p val
*/
void set_adc(int i, uint16_t val) // NOLINT
{
if (i < 0 || i >= s_num_adcs)
throw std::out_of_range("ADC index out of range");
if (val >= (1 << s_bits_per_adc))
throw std::out_of_range("ADC value out of range");
// The index of the first (and sometimes only) word containing the required ADC value
int word_index = s_bits_per_adc * i / s_bits_per_word;
assert(word_index < s_num_adc_words);
// Where in the word the lowest bit of our ADC value is located
int first_bit_position = (s_bits_per_adc * i) % s_bits_per_word;
// How many bits of our desired ADC are located in the `word_index`th word
int bits_in_first_word = std::min(s_bits_per_adc, s_bits_per_word - first_bit_position);
uint32_t mask = (1 << (first_bit_position)) - 1;
adc_words[word_index] = ((val << first_bit_position) & ~mask) | (adc_words[word_index] & mask);
// If we didn't put the full 14 bits in this word, we need to put the rest in the next word
if (bits_in_first_word < s_bits_per_adc) {
assert(word_index + 1 < s_num_adc_words);
mask = (1 << (s_bits_per_adc - bits_in_first_word)) - 1;
adc_words[word_index + 1] = ((val >> bits_in_first_word) & mask) | (adc_words[word_index + 1] & ~mask);
}
}
/** @brief Get the channel from the DAPHNE frame
*/
uint8_t get_channel() const { return header.channel; } // NOLINT(build/unsigned)
/** @brief Set the channel of the DAPHNE frame
*/
void set_channel( uint8_t val) { header.channel = val& 0x3Fu; } // NOLINT(build/unsigned)
/** @brief Get the 64-bit timestamp of the frame
*/
uint64_t get_timestamp() const // NOLINT(build/unsigned)
{
return daq_header.get_timestamp();
}
};
} // namespace detdataformats
} // namespace dunedaq
#endif // FDDETDATAFORMATS_INCLUDE_FDDATAFORMATS_DAPHNE_DAPHNEFRAME_HPP_
// Local Variables:
// c-basic-offset: 2
// End: