Line data Source code
1 : /**
2 : * @file HSINode.cpp
3 : *
4 : * This is part of the DUNE DAQ Software Suite, copyright 2020.
5 : * Licensing/copyright details are in the COPYING file that you should have
6 : * received with this code.
7 : */
8 :
9 : #include "timing/HSINode.hpp"
10 :
11 : #include "timing/FLCmdGeneratorNode.hpp"
12 : #include "timing/toolbox.hpp"
13 : #include "logging/Logging.hpp"
14 :
15 : #include <string>
16 : #include <utility>
17 : #include <vector>
18 :
19 : namespace dunedaq {
20 : namespace timing {
21 :
22 0 : UHAL_REGISTER_DERIVED_NODE(HSINode)
23 :
24 : //-----------------------------------------------------------------------------
25 0 : HSINode::HSINode(const uhal::Node& node)
26 0 : : TimingNode(node)
27 0 : {}
28 : //-----------------------------------------------------------------------------
29 :
30 : //-----------------------------------------------------------------------------
31 0 : HSINode::~HSINode() {}
32 : //-----------------------------------------------------------------------------
33 :
34 : //-----------------------------------------------------------------------------
35 : std::string
36 0 : HSINode::get_status(bool print_out) const
37 : {
38 :
39 0 : std::stringstream status;
40 :
41 0 : std::vector<std::pair<std::string, std::string>> ept_summary;
42 0 : std::vector<std::pair<std::string, std::string>> hsi_summary;
43 :
44 : // auto lEPTimestamp = getNode("tstamp").readBlock(2);
45 :
46 0 : auto hsi_control = read_sub_nodes(getNode("csr.ctrl"), false);
47 0 : auto hsi_state = read_sub_nodes(getNode("csr.stat"), false);
48 :
49 0 : auto hsi_buffer_count = getNode("buf.count").read();
50 :
51 0 : auto hsi_re_mask = getNode("csr.re_mask").read();
52 0 : auto hsi_fe_mask = getNode("csr.fe_mask").read();
53 0 : auto hsi_inv_mask = getNode("csr.inv_mask").read();
54 :
55 0 : getClient().dispatch();
56 :
57 0 : hsi_summary.push_back(std::make_pair("Source", format_reg_value(hsi_control.find("src")->second.value(), 16)));
58 0 : hsi_summary.push_back(std::make_pair("Enabled", format_reg_value(hsi_control.find("en")->second.value(), 16)));
59 0 : hsi_summary.push_back(std::make_pair("Rising edge mask", format_reg_value(hsi_re_mask.value(), 16)));
60 0 : hsi_summary.push_back(std::make_pair("Falling edge mask", format_reg_value(hsi_fe_mask.value(), 16)));
61 0 : hsi_summary.push_back(std::make_pair("Invert mask", format_reg_value(hsi_inv_mask.value(), 16)));
62 0 : hsi_summary.push_back(
63 0 : std::make_pair("Buffer enabled", format_reg_value(hsi_control.find("buf_en")->second.value(), 16)));
64 0 : hsi_summary.push_back(
65 0 : std::make_pair("Buffer error", format_reg_value(hsi_state.find("buf_err")->second.value(), 16)));
66 0 : hsi_summary.push_back(
67 0 : std::make_pair("Buffer warning", format_reg_value(hsi_state.find("buf_warn")->second.value(), 16)));
68 0 : hsi_summary.push_back(std::make_pair("Buffer occupancy", to_string(hsi_buffer_count.value())));
69 :
70 0 : status << format_reg_table(hsi_summary, "HSI summary", { "", "" }) << std::endl;
71 :
72 0 : if (print_out)
73 0 : TLOG() << status.str();
74 0 : return status.str();
75 0 : }
76 : //-----------------------------------------------------------------------------
77 :
78 : //-----------------------------------------------------------------------------
79 : uint32_t // NOLINT(build/unsigned)
80 0 : HSINode::read_buffer_count() const
81 : {
82 0 : auto buffer_count = getNode("buf.count").read();
83 0 : getClient().dispatch();
84 0 : return buffer_count.value();
85 0 : }
86 : //-----------------------------------------------------------------------------
87 :
88 : //-----------------------------------------------------------------------------
89 : uhal::ValVector<uint32_t> // NOLINT(build/unsigned)
90 0 : HSINode::read_data_buffer(uint16_t& n_words, bool read_all, bool fail_on_error) const // NOLINT(build/unsigned)
91 : {
92 :
93 0 : uint32_t buffer_state = read_buffer_state(); // NOLINT(build/unsigned)
94 :
95 0 : uint16_t n_hsi_words = buffer_state >> 0x10; // NOLINT(build/unsigned)
96 :
97 0 : n_words = n_hsi_words;
98 :
99 0 : TLOG_DEBUG(5) << "Words available in readout buffer: " << format_reg_value(n_hsi_words);
100 :
101 0 : uhal::ValVector<uint32_t> buffer_data; // NOLINT(build/unsigned)
102 :
103 0 : if (buffer_state & 0x2) {
104 0 : ers::warning(HSIBufferIssue(ERS_HERE, "WARNING"));
105 : }
106 :
107 0 : if (buffer_state & 0x1) {
108 0 : ers::error(HSIBufferIssue(ERS_HERE, "ERROR"));
109 0 : if (fail_on_error)
110 : return buffer_data;
111 : }
112 :
113 : // this is bad
114 0 : if (n_hsi_words > 1024) {
115 0 : ers::error(HSIBufferIssue(ERS_HERE, "OVERFLOW"));
116 0 : if (fail_on_error)
117 : return buffer_data;
118 : n_hsi_words = 1024;
119 : }
120 :
121 0 : uint32_t events_to_read = n_hsi_words / hsi_buffer_event_words_number; // NOLINT(build/unsigned)
122 :
123 0 : TLOG_DEBUG(5) << "Events available in readout buffer: " << format_reg_value(events_to_read);
124 :
125 0 : uint32_t words_to_read = read_all ? n_hsi_words : events_to_read * hsi_buffer_event_words_number; // NOLINT(build/unsigned)
126 :
127 0 : TLOG_DEBUG(5) << "Words to be read out in readout buffer: " << format_reg_value(words_to_read);
128 :
129 0 : if (!words_to_read) {
130 0 : TLOG_DEBUG(5) << "No words to be read out.";
131 : }
132 :
133 0 : buffer_data = getNode("buf.data").readBlock(words_to_read);
134 0 : getClient().dispatch();
135 :
136 : return buffer_data;
137 0 : }
138 : //-----------------------------------------------------------------------------
139 :
140 : //-----------------------------------------------------------------------------
141 : uhal::ValVector<uint32_t> // NOLINT(build/unsigned)
142 0 : HSINode::read_data_buffer(bool read_all, bool fail_on_error) const
143 : {
144 0 : uint16_t words; // NOLINT(build/unsigned)
145 0 : return read_data_buffer(words, read_all, fail_on_error);
146 : }
147 :
148 : //-----------------------------------------------------------------------------
149 : std::string
150 0 : HSINode::get_data_buffer_table(bool read_all, bool print_out) const
151 : {
152 :
153 0 : std::stringstream table;
154 0 : auto buffer_data = read_data_buffer(read_all);
155 :
156 0 : std::vector<std::pair<std::string, uint32_t>> buffer_table; // NOLINT(build/unsigned)
157 :
158 0 : uint32_t i = 0; // NOLINT(build/unsigned)
159 0 : for (auto it = buffer_data.begin(); it != buffer_data.end(); ++it, ++i) {
160 0 : std::stringstream index_stream;
161 0 : index_stream << std::setfill('0') << std::setw(4) << i;
162 0 : buffer_table.push_back(std::make_pair(index_stream.str(), *it));
163 0 : }
164 0 : table << format_reg_table(buffer_table, "HSI buffer", { "Word", "Data" });
165 :
166 0 : if (print_out)
167 0 : TLOG() << table.str();
168 0 : return table.str();
169 0 : }
170 : //-----------------------------------------------------------------------------
171 :
172 : //-----------------------------------------------------------------------------
173 : void
174 0 : HSINode::configure_hsi(uint32_t src, // NOLINT(build/unsigned)
175 : uint32_t re_mask, // NOLINT(build/unsigned)
176 : uint32_t fe_mask, // NOLINT(build/unsigned)
177 : uint32_t inv_mask, // NOLINT(build/unsigned)
178 : double rate,
179 : uint32_t clock_frequency_hz, // NOLINT(build/unsigned)
180 : bool dispatch) const
181 : {
182 :
183 0 : getNode("csr.ctrl.src").write(src);
184 0 : getNode("csr.re_mask").write(re_mask);
185 0 : getNode("csr.fe_mask").write(fe_mask);
186 0 : getNode("csr.inv_mask").write(inv_mask);
187 :
188 : // Configures the internal hsi signal generator to produce triggers at a defined frequency.
189 : // Rate = (clock_frequency_hz / 2^(d+8)) / p where n in [0,15] and p in [1,256]
190 :
191 : // DIVIDER (int): Frequency divider.
192 :
193 : // The division from clock_frequency_hz to the desired rate is done in three steps:
194 : // a) A pre-division by 256
195 : // b) Division by a power of two set by n = 2 ^ rate_div_d (ranging from 2^0 -> 2^15)
196 : // c) 1-in-n prescaling set by n = rate_div_p
197 :
198 0 : try
199 : {
200 0 : uint32_t divisor;
201 0 : uint32_t prescale;
202 0 : double actual_rate;
203 :
204 0 : FLCmdGeneratorNode::parse_periodic_fl_cmd_rate(rate, clock_frequency_hz, actual_rate, divisor, prescale);
205 :
206 0 : TLOG() << "Requested rate, actual rate: " << rate << ", " << actual_rate;
207 0 : TLOG() << "prescale, divisor: " << prescale << ", " << divisor;
208 :
209 0 : std::stringstream trig_stream;
210 0 : trig_stream << "> Random trigger rate for HSI set to " << std::setprecision(3) << std::scientific << actual_rate << " Hz. d: " << divisor << " p: " << prescale;
211 0 : TLOG() << trig_stream.str();
212 :
213 0 : getNode("csr.ctrl.rate_div_p").write(prescale);
214 0 : getNode("csr.ctrl.rate_div_d").write(divisor);
215 0 : }
216 0 : catch (const timing::BadRequestedFakeTriggerRate& e)
217 : {
218 0 : ers::error(FailedToUpdateHSIRandomRate(ERS_HERE,e));
219 0 : }
220 :
221 0 : if (dispatch)
222 0 : getClient().dispatch();
223 0 : }
224 : //-----------------------------------------------------------------------------
225 :
226 : //-----------------------------------------------------------------------------
227 : void
228 0 : HSINode::start_hsi(bool dispatch) const
229 : {
230 0 : getNode("csr.ctrl.en").write(0x1);
231 0 : if (dispatch)
232 0 : getClient().dispatch();
233 0 : }
234 : //-----------------------------------------------------------------------------
235 :
236 : //-----------------------------------------------------------------------------
237 : void
238 0 : HSINode::stop_hsi(bool dispatch) const
239 : {
240 0 : getNode("csr.ctrl.en").write(0x0);
241 0 : if (dispatch)
242 0 : getClient().dispatch();
243 0 : }
244 : //-----------------------------------------------------------------------------
245 :
246 : //-----------------------------------------------------------------------------
247 : void
248 0 : HSINode::reset_hsi(bool dispatch) const
249 : {
250 0 : getNode("csr.ctrl.en").write(0x0);
251 :
252 0 : getNode("csr.ctrl.buf_en").write(0x0);
253 0 : getNode("csr.ctrl.buf_en").write(0x1);
254 :
255 0 : getNode("csr.re_mask").write(0x0);
256 0 : getNode("csr.fe_mask").write(0x0);
257 0 : getNode("csr.inv_mask").write(0x0);
258 0 : getNode("csr.ctrl.src").write(0x0);
259 :
260 0 : if (dispatch)
261 0 : getClient().dispatch();
262 0 : }
263 : //-----------------------------------------------------------------------------
264 :
265 : //-----------------------------------------------------------------------------
266 : bool
267 0 : HSINode::read_buffer_warning() const
268 : {
269 0 : auto buf_warning = getNode("csr.stat.buf_warn").read();
270 0 : getClient().dispatch();
271 0 : return buf_warning.value();
272 0 : }
273 : //-----------------------------------------------------------------------------
274 :
275 : //-----------------------------------------------------------------------------
276 : bool
277 0 : HSINode::read_buffer_error() const
278 : {
279 0 : auto buf_error = getNode("csr.stat.buf_err").read();
280 0 : getClient().dispatch();
281 0 : return buf_error.value();
282 0 : }
283 : //-----------------------------------------------------------------------------
284 :
285 : //-----------------------------------------------------------------------------
286 : uint32_t // NOLINT(build/unsigned)
287 0 : HSINode::read_buffer_state() const
288 : {
289 :
290 0 : auto buf_state = read_sub_nodes(getNode("csr.stat"), false);
291 0 : auto hsi_buffer_count = getNode("buf.count").read();
292 0 : getClient().dispatch();
293 :
294 0 : uint8_t buffer_error = static_cast<uint8_t>(buf_state.find("buf_err")->second.value()); // NOLINT(build/unsigned)
295 0 : uint8_t buffer_warning = static_cast<uint8_t>(buf_state.find("buf_warn")->second.value()); // NOLINT(build/unsigned)
296 :
297 0 : uint32_t buffer_state = buffer_error | (buffer_warning << 1); // NOLINT(build/unsigned)
298 0 : buffer_state = buffer_state | static_cast<uint32_t>(hsi_buffer_count.value()) << 0x10; // NOLINT(build/unsigned)
299 0 : return buffer_state;
300 0 : }
301 : //-----------------------------------------------------------------------------
302 :
303 : //-----------------------------------------------------------------------------
304 : uint32_t // NOLINT(build/unsigned)
305 0 : HSINode::read_signal_source_mode() const
306 : {
307 0 : auto source = getNode("csr.ctrl.src").read();
308 0 : getClient().dispatch();
309 0 : return source.value();
310 0 : }
311 : //-----------------------------------------------------------------------------
312 :
313 : //-----------------------------------------------------------------------------
314 : void
315 0 : HSINode::get_info(timingfirmwareinfo::HSIFirmwareMonitorData& mon_data) const
316 : {
317 0 : auto hsi_control = read_sub_nodes(getNode("csr.ctrl"), false);
318 0 : auto hsi_state = read_sub_nodes(getNode("csr.stat"), false);
319 :
320 0 : auto hsi_buffer_count = getNode("buf.count").read();
321 :
322 0 : auto hsi_re_mask = getNode("csr.re_mask").read();
323 0 : auto hsi_fe_mask = getNode("csr.fe_mask").read();
324 0 : auto hsi_inv_mask = getNode("csr.inv_mask").read();
325 :
326 0 : getClient().dispatch();
327 :
328 0 : mon_data.source = hsi_control.find("src")->second.value();
329 0 : mon_data.re_mask = hsi_re_mask.value();
330 0 : mon_data.fe_mask = hsi_fe_mask.value();
331 0 : mon_data.inv_mask = hsi_inv_mask.value();
332 0 : mon_data.buffer_enabled = hsi_control.find("buf_en")->second.value();
333 0 : mon_data.buffer_error = hsi_state.find("buf_err")->second.value();
334 0 : mon_data.buffer_warning = hsi_state.find("buf_warn")->second.value();
335 0 : mon_data.buffer_occupancy = hsi_buffer_count.value();
336 0 : mon_data.enabled = hsi_control.find("en")->second.value();
337 0 : }
338 : // //-----------------------------------------------------------------------------
339 :
340 : } // namespace timing
341 : } // namespace dunedaq
|