Line data Source code
1 : /**
2 : * @file TimestampGeneratorNode.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/TimestampGeneratorNode.hpp"
10 :
11 : #include "timing/toolbox.hpp"
12 : #include "logging/Logging.hpp"
13 :
14 : #include <string>
15 :
16 : namespace dunedaq {
17 : namespace timing {
18 :
19 0 : UHAL_REGISTER_DERIVED_NODE(TimestampGeneratorNode)
20 :
21 : //-----------------------------------------------------------------------------
22 0 : TimestampGeneratorNode::TimestampGeneratorNode(const uhal::Node& node)
23 0 : : TimingNode(node)
24 0 : {}
25 : //-----------------------------------------------------------------------------
26 :
27 : //-----------------------------------------------------------------------------
28 0 : TimestampGeneratorNode::~TimestampGeneratorNode() {}
29 : //-----------------------------------------------------------------------------
30 :
31 : //-----------------------------------------------------------------------------
32 : std::string
33 0 : TimestampGeneratorNode::get_status(bool print_out) const
34 : {
35 0 : std::stringstream status;
36 0 : status << "Current timestamp: 0x" << std::hex << read_timestamp() << std::endl;
37 0 : status << "Start timestamp: 0x" << std::hex << read_start_timestamp() << std::endl;
38 0 : status << "SW init timestamp: 0x" << std::hex << read_sw_init_timestamp() << std::endl;
39 :
40 0 : auto ctrl_subnodes = read_sub_nodes(getNode("csr.ctrl"));
41 0 : status << format_reg_table(ctrl_subnodes, "TS gen ctrl");
42 :
43 0 : auto stat_subnodes = read_sub_nodes(getNode("csr.stat"));
44 0 : status << format_reg_table(stat_subnodes, "TS gen state");
45 :
46 :
47 0 : if (print_out)
48 0 : TLOG() << status.str();
49 0 : return status.str();
50 0 : }
51 : //-----------------------------------------------------------------------------
52 :
53 : //-----------------------------------------------------------------------------
54 : uhal::ValVector<uint32_t> // NOLINT(build/unsigned)
55 0 : TimestampGeneratorNode::read_raw_timestamp(bool dispatch) const
56 : {
57 0 : auto timestamp = getNode("ctr").readBlock(2);
58 0 : if (dispatch)
59 0 : getClient().dispatch();
60 0 : return timestamp;
61 0 : }
62 : //-----------------------------------------------------------------------------
63 :
64 : //-----------------------------------------------------------------------------
65 : uint64_t // NOLINT(build/unsigned)
66 0 : TimestampGeneratorNode::read_timestamp() const
67 : {
68 0 : return tstamp2int(read_raw_timestamp());
69 : }
70 : //-----------------------------------------------------------------------------
71 :
72 : //-----------------------------------------------------------------------------
73 : uint64_t // NOLINT(build/unsigned)
74 0 : TimestampGeneratorNode::read_start_timestamp() const
75 : {
76 0 : auto start_ts_l = getNode("csr.tstamp_start_l").read();
77 0 : auto start_ts_h = getNode("csr.tstamp_start_h").read();
78 0 : getClient().dispatch();
79 0 : return (uint64_t)start_ts_l.value() + ((uint64_t)start_ts_h.value() << 32);
80 0 : }
81 : //-----------------------------------------------------------------------------
82 :
83 : //-----------------------------------------------------------------------------
84 : uint64_t // NOLINT(build/unsigned)
85 0 : TimestampGeneratorNode::read_sw_init_timestamp() const
86 : {
87 0 : auto sw_init_ts_l = getNode("csr.tstamp_sw_init_l").read();
88 0 : auto sw_init_ts_h = getNode("csr.tstamp_sw_init_h").read();
89 0 : getClient().dispatch();
90 0 : return (uint64_t)sw_init_ts_l.value() + ((uint64_t)sw_init_ts_h.value() << 32);
91 0 : }
92 : //-----------------------------------------------------------------------------
93 :
94 : //-----------------------------------------------------------------------------
95 : void
96 0 : TimestampGeneratorNode::set_timestamp(TimestampSource source) const // NOLINT(build/unsigned)
97 : {
98 : // TODO put somewhere more accessible
99 0 : const uint clock_frequency_hz = 62500000;
100 :
101 0 : const uint64_t old_timestamp = read_timestamp(); // NOLINT(build/unsigned)
102 0 : TLOG() << "Reading old timestamp: " << format_reg_value(old_timestamp) << ", " << format_timestamp(old_timestamp, clock_frequency_hz);
103 :
104 0 : getNode("csr.ctrl.rst").write(0x1);
105 0 : getNode("csr.ctrl.tstamp_source_sel").write(source);
106 0 : getClient().dispatch();
107 :
108 0 : uint64_t now_timestamp;
109 0 : if (source == kSoftware)
110 : {
111 0 : now_timestamp = get_milliseconds_since_epoch() * (clock_frequency_hz / 1000); // NOLINT(build/unsigned)
112 : }
113 0 : else if (source == kMixed)
114 : {
115 0 : now_timestamp = get_seconds_since_epoch() * clock_frequency_hz ; // NOLINT(build/unsigned)
116 : }
117 0 : else if (source != kUpstream)
118 : {
119 0 : throw UnknownTimestampSource(ERS_HERE, source);
120 : }
121 :
122 0 : if (source != kUpstream)
123 : {
124 0 : TLOG() << "New software timestamp: " << format_reg_value(now_timestamp) << ", " << format_timestamp(now_timestamp, clock_frequency_hz);
125 : // Take the timestamp and split it up
126 0 : uint32_t now_ts_low = (now_timestamp >> 0) & ((1UL << 32) - 1); // NOLINT(build/unsigned)
127 0 : uint32_t now_ts_high = (now_timestamp >> 32) & ((1UL << 32) - 1); // NOLINT(build/unsigned)
128 :
129 0 : getNode("csr.tstamp_sw_init_l").write(now_ts_low);
130 0 : getNode("csr.tstamp_sw_init_h").write(now_ts_high);
131 : }
132 :
133 0 : getNode("csr.ctrl.rst").write(0x0);
134 0 : getNode("csr.ctrl.load").write(0x1);
135 0 : getNode("csr.ctrl.load").write(0x0);
136 0 : getClient().dispatch();
137 :
138 0 : auto start = std::chrono::high_resolution_clock::now();
139 0 : while (true) {
140 0 : auto ts_loaded = getNode("csr.stat.tstamp_loaded").read();
141 0 : auto ts_error = getNode("csr.stat.tstamp_error").read();
142 0 : getClient().dispatch();
143 :
144 0 : TLOG_DEBUG(6) << std::hex << "ts loaded: 0x" << ts_loaded.value() << ", ts error: " << ts_error.value();
145 :
146 0 : if (ts_loaded.value() && !ts_error.value())
147 : {
148 0 : const uint64_t start_ts = read_start_timestamp();
149 0 : TLOG() << "Timestamp initialised with: " << format_reg_value(start_ts) << ", " << format_timestamp(start_ts, clock_frequency_hz);
150 0 : break;
151 : }
152 :
153 0 : auto now = std::chrono::high_resolution_clock::now();
154 0 : auto ms_since_start = std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
155 :
156 0 : if (ms_since_start.count() > 1000)
157 0 : throw TimestampNotReady(ERS_HERE, ts_loaded.value(), ts_error.value());
158 :
159 0 : std::this_thread::sleep_for(std::chrono::microseconds(10));
160 0 : }
161 :
162 0 : const uint64_t new_timestamp = read_timestamp(); // NOLINT(build/unsigned)
163 0 : TLOG() << "Reading new timestamp: " << format_reg_value(new_timestamp) << ", " << format_timestamp(new_timestamp, clock_frequency_hz);
164 :
165 0 : getClient().dispatch();
166 0 : }
167 : //-----------------------------------------------------------------------------
168 :
169 : } // namespace timing
170 : } // namespace dunedaq
|