DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
MasterNode.cpp
Go to the documentation of this file.
1
11
12#include "logging/Logging.hpp"
13
14#include <string>
15
16namespace dunedaq {
17namespace timing {
18
19UHAL_REGISTER_DERIVED_NODE(MasterNode)
20
21//-----------------------------------------------------------------------------
22MasterNode::MasterNode(const uhal::Node& node)
24{}
25//-----------------------------------------------------------------------------
26
27//-----------------------------------------------------------------------------
29//-----------------------------------------------------------------------------
30
31//-----------------------------------------------------------------------------
32std::string
34{
35 std::stringstream status;
36
37 status << getNode<TimestampGeneratorNode>("tstamp").get_status();
38 status << std::endl;
39
40 status << getNode<MasterGlobalNode>("global").get_status();
41 status << std::endl;
42
43 status << getNode<FLCmdGeneratorNode>("scmd_gen").get_cmd_counters_table();
44 status << std::endl;
45
46 getNode("cmd_ctrs.addr").write(0x0);
47 auto counters = getNode("cmd_ctrs.data").readBlock(0xff);
48 getClient().dispatch();
49
50 std::vector<uint32_t> non_zero_counters;
51 std::vector<std::string> counter_labels;
52
53 for (uint i=0; i < counters.size(); ++i)
54 {
55 auto counter = counters.at(i);
56 if (counter > 0)
57 {
58 counter_labels.push_back(format_reg_value(i));
59 non_zero_counters.push_back(counter);
60 }
61 }
62
63 std::vector<std::vector<uint32_t>> counters_container = { non_zero_counters }; // NOLINT(build/unsigned)
64
65 status << format_counters_table(counters_container, { "Sent cmd counters" }, "Master cmd counters (>0)", counter_labels);
66 status << std::endl;
67
68 auto acmd_buf = read_sub_nodes(getNode("acmd_buf.stat"));
69 status << format_reg_table(acmd_buf, "Master acmd buffer");
70
71 return status.str();
72}
73//-----------------------------------------------------------------------------
74
75//-----------------------------------------------------------------------------
76std::string
77MasterNode::get_status(bool print_out) const
78{
79 std::stringstream status;
80 auto raw_timestamp = getNode<TimestampGeneratorNode>("tstamp").read_raw_timestamp();
81 status << "Timestamp: 0x" << std::hex << tstamp2int(raw_timestamp) << std::endl << std::endl;
82 status << get_status_tables();
83
84 if (print_out)
85 TLOG() << status.str();
86 return status.str();
87}
88//-----------------------------------------------------------------------------
89
90//-----------------------------------------------------------------------------
91std::string
92MasterNode::get_status_with_date(uint32_t clock_frequency_hz, bool print_out) const // NOLINT(build/unsigned)
93{
94 std::stringstream status;
95 auto raw_timestamp = getNode<TimestampGeneratorNode>("tstamp").read_raw_timestamp();
96 status << "Timestamp: 0x" << std::hex << tstamp2int(raw_timestamp) << " -> " << format_timestamp(raw_timestamp, clock_frequency_hz) << std::endl
97 << std::endl;
98 status << get_status_tables();
99
100 if (print_out)
101 TLOG() << status.str();
102 return status.str();
103}
104//-----------------------------------------------------------------------------
105
106//-----------------------------------------------------------------------------
107void
108MasterNode::switch_endpoint_sfp(uint32_t address, bool turn_on) const // NOLINT(build/unsigned)
109{
110 uint32_t sequence = 0xab;
111 uint32_t address_mode = 1;
112
113 std::vector<uint32_t> tx_packet = { address & 0xff,
114 address >> 8UL,
115 sequence,
116
117 // packet to reset rx
118 (0x1 << 7UL) | 0x70, // write transaction on 0x70
119 (address_mode << 7UL) | 0x1, // transaction length of 0x1
120 turn_on,
121 };
122 tx_packet.back() = tx_packet.back() | (0x1 << 8UL);
123
124 auto result = transmit_async_packet(tx_packet, -1);
125}
126//-----------------------------------------------------------------------------
127
128//-----------------------------------------------------------------------------
129void
131{
132 auto global = getNode<MasterGlobalNode>("global");
133 global.enable_upstream_endpoint();
134}
135//-----------------------------------------------------------------------------
136
137//-----------------------------------------------------------------------------
138void
139MasterNode::send_fl_cmd(uint32_t command,
140 uint32_t channel, // NOLINT(build/unsigned)
141 uint32_t number_of_commands) const // NOLINT(build/unsigned)
142{
143 for (uint32_t i = 0; i < number_of_commands; i++) { // NOLINT(build/unsigned)
144 getNode<FLCmdGeneratorNode>("scmd_gen").send_fl_cmd(command, channel);
145
146 auto ts_l = getNode("cmd_log.tstamp_l").read();
147 auto ts_h = getNode("cmd_log.tstamp_h").read();
148 auto sent_cmd = getNode("cmd_log.cmd").read();
149 getClient().dispatch();
150
151 if (sent_cmd.value() != command)
152 {
153 TLOG() << "cmd in sent log: 0x" << std::hex << command << ", does not match requested 0x: " << sent_cmd.value();
154 // TODO throw something
155 }
156 uint64_t timestamp = (uint64_t)ts_h.value() << 32 | ts_l.value();
157 TLOG() << "Command sent " << "(" << format_reg_value(command) << ") from generator "
158 << format_reg_value(channel) << " @time " << std::hex << std::showbase << timestamp;
159 }
160}
161//-----------------------------------------------------------------------------
162
163//-----------------------------------------------------------------------------
164uint32_t // NOLINT(build/unsigned)
165MasterNode::measure_endpoint_rtt(uint32_t address, bool control_sfp) const // NOLINT(build/unsigned)
166{
167
168 auto global = getNode<MasterGlobalNode>("global");
169 auto echo = getNode<EchoMonitorNode>("echo_mon");
170
171 if (control_sfp)
172 {
173 // Switch off all TX SFPs
174 //switch_endpoint_sfp(0xffff, false);
175
176 // Turn on the current target
177 switch_endpoint_sfp(address, true);
178
179 millisleep(100);
180
181 try
182 {
183 global.enable_upstream_endpoint();
184 }
185 catch (const timing::ReceiverNotReady& e)
186 {
187 if (control_sfp) {
188 switch_endpoint_sfp(address, false);
189 }
190 throw e;
191 }
192 }
193
194 uint32_t endpoint_rtt = echo.send_echo_and_measure_delay(); // NOLINT(build/unsigned)
195
196 if (control_sfp)
197 switch_endpoint_sfp(address, false);
198
199 return endpoint_rtt;
200}
201//-----------------------------------------------------------------------------
202
203//-----------------------------------------------------------------------------
204void
205MasterNode::apply_endpoint_delay(uint32_t address, // NOLINT(build/unsigned)
206 uint32_t coarse_delay, // NOLINT(build/unsigned)
207 uint32_t fine_delay, // NOLINT(build/unsigned)
208 uint32_t /*phase_delay*/, // NOLINT(build/unsigned)
209 bool measure_rtt,
210 bool control_sfp) const
211{
212
213 auto global = getNode<MasterGlobalNode>("global");
214 auto echo = getNode<EchoMonitorNode>("echo_mon");
215
216 if (measure_rtt) {
217 if (control_sfp) {
218 // Switch off all TX SFPs
219 // switch_endpoint_sfp(0xffff, false);
220
221 // Turn on the current target
223
224 millisleep(100);
225 }
226
227 try
228 {
229 global.enable_upstream_endpoint();
230 }
231 catch (const timing::ReceiverNotReady& e)
232 {
233 if (control_sfp) {
235 }
236 throw e;
237 }
238
239 uint64_t endpoint_rtt = echo.send_echo_and_measure_delay(); // NOLINT(build/unsigned)
240 TLOG() << "Pre delay adjustment RTT: " << format_reg_value(endpoint_rtt, 10);
241 }
242
243 uint32_t sequence = 0xab;
244 uint32_t address_mode = 1;
245
246 std::vector<uint32_t> tx_packet = { address & 0xff,
247 address >> 8UL,
248 sequence,
249
250 // packet to write coarse delay
251 (0x1 << 7UL) | 0x72, // write transaction on 0x72
252 (address_mode << 7UL) | 0x1, // transaction length of 0x1
253 ((fine_delay & 0xf) << 4UL) | (coarse_delay & 0xf),
254
255 // packet to write fine delay
256 (0x1 << 7UL) | 0x73, // write transaction on 0x73
257 (address_mode << 7UL) | 0x1, // transaction length of 0x1
258 (fine_delay >> 4UL) & 0xff,
259
260 // packet to set skew done
261 (0x1 << 7UL) | 0x70, // write transaction on 0x70
262 (address_mode << 7UL) | 0x1, // transaction length of 0x1
263 0x3, // deskew done
264
265 // packet to resync
266 (0x1 << 7UL) | 0x70, // write transaction on 0x70
267 (address_mode << 7UL) | 0x1, // transaction length of 0x1
268 0x4, // resync
269 };
270
271 tx_packet.back() = tx_packet.back() | (0x1 << 8UL);
272
273 transmit_async_packet(tx_packet, -1);
274
275 if (measure_rtt) {
276 try
277 {
278 global.enable_upstream_endpoint();
279 }
280 catch (const timing::ReceiverNotReady& e)
281 {
282 if (control_sfp)
283 {
285 }
286 throw e;
287 }
288
289 uint64_t endpoint_rtt = echo.send_echo_and_measure_delay(); // NOLINT(build/unsigned)
290 TLOG() << "Post delay adjustment RTT: " << format_reg_value(endpoint_rtt, 10);
291
292 if (control_sfp)
294 }
295}
296//-----------------------------------------------------------------------------
297
298//-----------------------------------------------------------------------------
299void
300MasterNode::sync_timestamp(TimestampSource source) const // NOLINT(build/unsigned)
301{
302 set_timestamp(source);
303
304 enable_timestamp_broadcast();
305 TLOG() << "Timestamp broadcast enabled";
306}
307//-----------------------------------------------------------------------------
308
309//-----------------------------------------------------------------------------
310uint64_t // NOLINT(build/unsigned)
312{
313 return getNode<TimestampGeneratorNode>("tstamp").read_timestamp();
314}
315//-----------------------------------------------------------------------------
316
317//-----------------------------------------------------------------------------
318void
319MasterNode::set_timestamp(TimestampSource source) const // NOLINT(build/unsigned)
320{
321 getNode<TimestampGeneratorNode>("tstamp").set_timestamp(source);
322}
323//-----------------------------------------------------------------------------
324
325//-----------------------------------------------------------------------------
326void
328{
329 mon_data.timestamp = read_timestamp();
330
331 auto control = read_sub_nodes(getNode("global.csr.ctrl"), false);
332 auto state = read_sub_nodes(getNode("global.csr.stat"), false);
333 getClient().dispatch();
334
335 mon_data.ts_bcast_enable = control.at("ts_en").value();
336 mon_data.ts_valid = state.at("ts_valid").value();
337 mon_data.ts_tx_err = state.at("ts_tx_err").value();
338 mon_data.tx_err = state.at("tx_err").value();
339 mon_data.ctrs_rdy = state.at("ctrs_rdy").value();
340
341// ic.add(mon_data);
342
343// uint number_of_commands = 0xff;
344
345// getNode("cmd_ctrs.addr").write(0x0);
346// auto counters = getNode("cmd_ctrs.data").readBlock(number_of_commands);
347// getClient().dispatch();
348
349// for (uint i = 0; i < number_of_commands; ++i) { // NOLINT(build/unsigned)
350
351// timingfirmwareinfo::SentCommandCounter cmd_counter;
352// opmonlib::InfoCollector cmd_counter_ic;
353
354// cmd_counter.counts = counters.at(i);
355
356// std::stringstream channel;
357// channel << "cmd_0x" << std::hex << i;
358
359// cmd_counter_ic.add(cmd_counter);
360// ic.add(channel.str(), cmd_counter_ic);
361// }
362
363// getNode<FLCmdGeneratorNode>("scmd_gen").get_info(ic, level);
364}
365//-----------------------------------------------------------------------------
366
367//-----------------------------------------------------------------------------
369{
370 auto global = getNode<MasterGlobalNode>("global");
371 global.reset_command_counters();
372}
373//-----------------------------------------------------------------------------
374
375//-----------------------------------------------------------------------------
376std::vector<uint32_t>
377MasterNode::transmit_async_packet(const std::vector<uint32_t>& packet, int timeout) const
378{
379 // TODO: check for valid packet
380
381 reset_sub_nodes(getNode("acmd_buf.txbuf"));
382
383 TLOG_DEBUG(11) << "tx packet: ";
384 for (auto t : packet)
385 TLOG_DEBUG(11) << std::hex << "0x" << t;
386
387 getNode("acmd_buf.txbuf").writeBlock(packet);
388 getClient().dispatch();
389
390 // we do not expect a reply
391 if (timeout < 0)
392 {
393 std::vector<uint32_t> empty_vector;
394 return empty_vector;
395 }
396
397 uhal::ValWord<uint32_t> buffer_ready; // NOLINT(build/unsigned)
398 uhal::ValWord<uint32_t> buffer_timeout; // NOLINT(build/unsigned)
399
400 // start time counting
401 auto start = std::chrono::high_resolution_clock::now();
402
403 // Wait for the buffer to be happy
404 while (true) {
405
406 buffer_ready = getNode("acmd_buf.stat.ready").read();
407 buffer_timeout = getNode("acmd_buf.stat.timeout").read();
408 getClient().dispatch();
409
410 TLOG_DEBUG(10) << "async buffer ready: 0x" << buffer_ready.value() << ", timeout: " << buffer_timeout.value();
411
412 if (buffer_timeout)
413 throw VLCommandReplyTimeout(ERS_HERE);
414
415 if (buffer_ready)
416 break;
417
418 auto now = std::chrono::high_resolution_clock::now();
419 auto us_since_start = std::chrono::duration_cast<std::chrono::microseconds>(now - start);
420
421 if (us_since_start.count() > timeout)
422 throw VLCommandReplyBufferFlagTimeout(ERS_HERE, timeout);
423
424 std::this_thread::sleep_for(std::chrono::microseconds(50));
425 }
426
427 auto rx_packet = getNode("acmd_buf.rxbuf").readBlock(0x20);
428 getClient().dispatch();
429
430 if (rx_packet.at(0) != 0xff || rx_packet.at(1) != 0xff || rx_packet.at(2) != packet.at(2))
431 {
432 ers::warning(InvalidVLCommandReplyPacket(ERS_HERE, rx_packet.at(0), rx_packet.at(1), rx_packet.at(2)));
433 }
434
435 TLOG_DEBUG(11) << "async result: ";
436 for (auto r : rx_packet)
437 TLOG_DEBUG(11) << std::hex << "0x" << r;
438
439 return rx_packet.value();
440}
441//-----------------------------------------------------------------------------
442
443//-----------------------------------------------------------------------------
444void
445MasterNode::write_endpoint_data(uint16_t endpoint_address, uint8_t reg_address, std::vector<uint8_t> data, bool address_mode) const
446{
447 auto data_length = data.size();
448 if (data_length > 0x3f || data_length == 0)
449 {
450 TLOG() << "invalid data length";
451 }
452
453 // TODO make sequence a function argument?
454 uint32_t sequence = 0xab;
455
456 std::vector<uint32_t> tx_packet = { static_cast<uint32_t>(endpoint_address & 0xff),
457 static_cast<uint32_t>(endpoint_address >> 8UL),
458 sequence,
459 // bit 7 = 1 -> write
460 static_cast<uint32_t>((0x1 << 7UL) | reg_address),
461 static_cast<uint32_t>((address_mode << 7UL) | (0x3f & data_length))
462 };
463 tx_packet.insert(tx_packet.end(), data.begin(), data.end());
464 tx_packet.back() = tx_packet.back() | (0x1 << 8UL);
465
466 auto result = transmit_async_packet(tx_packet);
467}
468//-----------------------------------------------------------------------------
469
470//-----------------------------------------------------------------------------
471std::vector<uint32_t>
472MasterNode::read_endpoint_data(uint16_t endpoint_address, uint8_t reg_address, uint8_t data_length, bool address_mode) const
473{
474 if (data_length > 0x3f || data_length == 0)
475 {
476 TLOG() << "invalid data length";
477 // TODO throw something
478 }
479
480 // TODO make sequence a function argument?
481 uint32_t sequence = 0xab;
482 std::vector<uint32_t> tx_packet = { static_cast<uint32_t>(endpoint_address & 0xff),
483 static_cast<uint32_t>(endpoint_address >> 8UL),
484 sequence,
485 // bit 7 = 0 -> read
486 reg_address,
487 static_cast<uint32_t>((0x1 << 8UL) | (address_mode << 7UL) | (0x3f & data_length))
488 };
489
490 auto result = transmit_async_packet(tx_packet);
491
492 // get parts we actually want
493 std::vector<uint32_t> result_data (result.begin()+3, result.begin()+3+data_length);
494
495 // strip off the bit 8 which is high for last byte
496 result_data.back() = result_data.back() & 0xff;
497
498 return result_data;
499}
500//-----------------------------------------------------------------------------
501
502//-----------------------------------------------------------------------------
504{
505 getNode("global.csr.ctrl.ts_en").write(0x0);
506 getClient().dispatch();
507}
508//-----------------------------------------------------------------------------
509
510//-----------------------------------------------------------------------------
512{
513 getNode("global.csr.ctrl.ts_en").write(0x1);
514 getClient().dispatch();
515}
516//-----------------------------------------------------------------------------
517
518//-----------------------------------------------------------------------------
520MasterNode::scan_endpoint(uint16_t endpoint_address, bool control_sfp) const
521{
523 auto global = getNode<MasterGlobalNode>("global");
524 auto echo = getNode<EchoMonitorNode>("echo_mon");
525
527 endpoint_result.address = endpoint_address;
528
529 // is endpoint sfp switched on?
530 // are any relevant muxes set to correct channel?
531 if (control_sfp)
532 {
533 switch_endpoint_sfp(endpoint_address, true);
534
535 millisleep(100);
536 }
537
538 try
539 {
540 global.enable_upstream_endpoint();
541 }
542 catch (const timing::ReceiverNotReady& e)
543 {
544 switch_endpoint_sfp(endpoint_address, false);
545
546 //ers::error(MonitoredEndpointDead(ERS_HERE, endpoint_address));
547
548 return endpoint_result;
549 }
550
551 endpoint_result.alive = true;
552 endpoint_result.round_trip_time = echo.send_echo_and_measure_delay();
553 TLOG_DEBUG(5) << "Endpoint at address " << endpoint_address << " alive. RTT: " << endpoint_result.round_trip_time;
554
555 auto ept_state = read_endpoint_data(endpoint_address, 0x71, 0x1, 0x1).at(0) & 0xf;
556 TLOG_DEBUG(5) << "Endpoint at address " << endpoint_address << " state: 0x" << std::hex << ept_state;
557 endpoint_result.state = ept_state;
558
559 if (ept_state == 0x6)
560 {
561 TLOG_DEBUG(5) << "Endpoint at address " << endpoint_address << ", applying delays of: " << 0x0;
562 ers::info(MonitoredEndpointDelaySet(ERS_HERE, 0x0, endpoint_address, ept_state));
563 apply_endpoint_delay(endpoint_address, 0x0, 0x0, 0x0, false, false);
564
565 endpoint_result.applied_delay = 0x0;
566
567 auto ept_state_after_delays = read_endpoint_data(endpoint_address, 0x71, 0x1, 0x1).at(0) & 0xf;
568 TLOG_DEBUG(5) << "Endpoint at address " << endpoint_address << ", state after delays apply: " << ept_state_after_delays;
569 endpoint_result.state_after_delay_apply = ept_state_after_delays;
570
571 endpoint_result.round_trip_time_after_delay_apply = echo.send_echo_and_measure_delay();
572 TLOG_DEBUG(5) << "Endpoint at address " << endpoint_address << ", RTT after delays apply: " << endpoint_result.round_trip_time_after_delay_apply;
573 }
574 else if (ept_state == 0x7 || ept_state == 0x8)
575 {
576 TLOG_DEBUG(5) << "Endpoint at address " << endpoint_address << ", delays not needed";
577 }
578 else
579 {
580 ers::error(MonitoredEndpointUnexpectedState(ERS_HERE, endpoint_address, ept_state));
581 }
582
583 if (control_sfp)
584 {
585 switch_endpoint_sfp(endpoint_address, false);
586 }
587
588 return endpoint_result;
589}
590//-----------------------------------------------------------------------------
591
592//-----------------------------------------------------------------------------
593void MasterNode::configure_endpoint_command_decoder(uint16_t endpoint_address, uint8_t slot, uint8_t command) const
594{
595 write_endpoint_data(endpoint_address, 0x60+slot, {command}, true);
596}
597//-----------------------------------------------------------------------------
598} // namespace timing
599} // namespace dunedaq
#define ERS_HERE
Base class for timing IO nodes.
Class for PD-II/DUNE master timing nodes.
std::string get_status_tables() const
Get the status tables.
void set_timestamp(TimestampSource source) const override
Set the timestamp to current time.
std::string get_status(bool print_out=false) const override
Print the status of the timing node.
std::string get_status_with_date(uint32_t clock_frequency_hz, bool print_out=false) const
Print the status of the timing node.
std::vector< uint32_t > transmit_async_packet(const std::vector< uint32_t > &packet, int timeout=500) const
Send an async packet.
void enable_timestamp_broadcast() const
Enable timestamp sending.
uint64_t read_timestamp() const override
Read the current timestamp word.
void apply_endpoint_delay(uint32_t address, uint32_t coarse_delay, uint32_t fine_delay, uint32_t phase_delay, bool measure_rtt=false, bool control_sfp=true) const override
Apply delay to endpoint.
std::vector< uint32_t > read_endpoint_data(uint16_t endpoint_address, uint8_t reg_address, uint8_t data_length, bool address_mode) const
Read some data from endpoint registers.
uint32_t measure_endpoint_rtt(uint32_t address, bool control_sfp=true) const override
Measure the endpoint round trip time.
void switch_endpoint_sfp(uint32_t address, bool turn_on) const override
Control the tx line of endpoint sfp.
void disable_timestamp_broadcast() const
Disable timestamp sending.
timingfirmware::EndpointCheckResult scan_endpoint(uint16_t endpoint_address, bool control_sfp) const override
Scan endpoint.
void enable_upstream_endpoint() const override
Enable RTT endpoint.
void sync_timestamp(TimestampSource source) const override
Set timestamp to current machine time.
void configure_endpoint_command_decoder(uint16_t endpoint_address, uint8_t slot, uint8_t command) const
Configure endpoint command decoder.
void get_info(timingfirmwareinfo::MasterMonitorData &mon_data) const
Fill the PD-I master monitoring structure.
void reset_command_counters() const
Read some data from endpoint registers.
void write_endpoint_data(uint16_t endpoint_address, uint8_t reg_address, std::vector< uint8_t > data, bool address_mode) const
Write some data to endpoint registers.
void send_fl_cmd(uint32_t command, uint32_t channel, uint32_t number_of_commands=1) const override
Send a fixed length command.
void reset_sub_nodes(const uhal::Node &node, uint32_t aValue=0x0, bool dispatch=true) const
Reset subnodes.
std::map< std::string, uhal::ValWord< uint32_t > > read_sub_nodes(const uhal::Node &node, bool dispatch=true) const
Read subnodes.
static int64_t now()
#define TLOG_DEBUG(lvl,...)
Definition Logging.hpp:112
#define TLOG(...)
Definition macro.hpp:22
std::string format_reg_table(T data, std::string title, std::vector< std::string > headers)
Format reg-value table.
Definition toolbox.hxx:166
std::string format_timestamp(uhal::ValVector< uint32_t > raw_timestamp, uint32_t clock_frequency_hz)
Definition toolbox.cpp:233
uint64_t tstamp2int(uhal::ValVector< uint32_t > raw_timestamp)
Definition toolbox.cpp:175
std::string format_counters_table(std::vector< T > counter_nodes, std::vector< std::string > counter_node_titles, std::string table_title, std::vector< std::string > counter_labels, std::string counter_labels_header)
Format reg-value table.
Definition toolbox.hxx:216
std::string format_reg_value(T reg_value, uint32_t base)
Definition toolbox.hxx:117
void millisleep(const double &time_in_milliseconds)
Definition toolbox.cpp:83
Including Qt Headers.
The opmon infrastructure has not been set up in the The control service has been defined multiple times for the application app_name you need to define only one service called control
Definition util.hpp:40
void warning(const Issue &issue)
Definition ers.hpp:115
void info(const Issue &issue)
Definition ers.hpp:95
void error(const Issue &issue)
Definition ers.hpp:81