Line data Source code
1 : #include "hermesmodules/HermesCoreController.hpp"
2 :
3 : #include <chrono> // std::chrono::seconds
4 : #include <fmt/core.h>
5 : #include <thread> // std::this_thread::sleep_for
6 :
7 : namespace dunedaq {
8 : namespace hermesmodules {
9 :
10 : //-----------------------------------------------------------------------------
11 0 : HermesCoreController::HermesCoreController(uhal::HwInterface hw, std::string readout_id)
12 0 : : m_hw(hw)
13 0 : , m_readout(m_hw.getNode(readout_id))
14 : {
15 :
16 0 : this->load_hw_info();
17 0 : }
18 :
19 : //-----------------------------------------------------------------------------
20 0 : HermesCoreController::~HermesCoreController() {}
21 :
22 : //-----------------------------------------------------------------------------
23 : void
24 0 : HermesCoreController::load_hw_info()
25 : {
26 :
27 : // Check magic number
28 0 : auto magic = m_readout.getNode("info.magic").read();
29 0 : m_readout.getClient().dispatch();
30 0 : if (magic.value() != 0xdeadbeef) {
31 : // TODO: add ERS exception
32 0 : throw MagicNumberError(ERS_HERE, magic.value(), 0xdeadbeef);
33 : }
34 :
35 0 : auto design = m_readout.getNode("info.versions.design").read();
36 0 : auto major = m_readout.getNode("info.versions.major").read();
37 0 : auto minor = m_readout.getNode("info.versions.minor").read();
38 0 : auto patch = m_readout.getNode("info.versions.patch").read();
39 :
40 0 : auto n_mgt = m_readout.getNode("info.generics.n_mgts").read();
41 0 : auto n_src = m_readout.getNode("info.generics.n_srcs").read();
42 0 : auto ref_freq = m_readout.getNode("info.generics.ref_freq").read();
43 0 : m_readout.getClient().dispatch();
44 :
45 : // Version
46 0 : m_core_info.design = design.value();
47 0 : m_core_info.major = major.value();
48 0 : m_core_info.minor = minor.value();
49 0 : m_core_info.patch = patch.value();
50 :
51 : // Generics
52 0 : m_core_info.n_mgt = n_mgt.value();
53 0 : m_core_info.n_src = n_src.value();
54 0 : m_core_info.ref_freq = ref_freq.value();
55 :
56 : // Extra info
57 0 : m_core_info.srcs_per_mux = m_core_info.n_src;
58 :
59 0 : fmt::print("Number of links: {}\n", m_core_info.n_mgt);
60 0 : fmt::print("Number of sources: {}\n", m_core_info.n_src);
61 0 : fmt::print("Reference freq: {}\n", m_core_info.ref_freq);
62 0 : fmt::print("Sources per mux:{}\n", m_core_info.srcs_per_mux);
63 0 : }
64 :
65 : //-----------------------------------------------------------------------------
66 : void
67 0 : HermesCoreController::sel_tx_mux(uint16_t i)
68 : {
69 0 : if (i >= m_core_info.n_mgt) {
70 0 : throw LinkDoesNotExist(ERS_HERE, i);
71 : }
72 :
73 0 : m_readout.getNode("tx_path.csr_tx_mux.ctrl.tx_mux_sel").write(i);
74 0 : m_readout.getClient().dispatch();
75 0 : }
76 :
77 : //-----------------------------------------------------------------------------
78 : void
79 0 : HermesCoreController::sel_tx_mux_buf(uint16_t i)
80 : {
81 0 : if (i >= m_core_info.n_src) {
82 0 : throw InputBufferDoesNotExist(ERS_HERE, i);
83 : }
84 :
85 0 : m_readout.getNode("tx_path.tx_mux.csr.ctrl.sel_buf").write(i);
86 0 : m_readout.getClient().dispatch();
87 0 : }
88 :
89 : //-----------------------------------------------------------------------------
90 : void
91 0 : HermesCoreController::sel_udp_core(uint16_t i)
92 : {
93 0 : if (i >= m_core_info.n_mgt) {
94 0 : throw MgtDoesNotExist(ERS_HERE, i);
95 : }
96 :
97 0 : m_readout.getNode("tx_path.csr_udp_core.ctrl.udp_core_sel").write(i);
98 0 : m_readout.getClient().dispatch();
99 0 : }
100 :
101 : //-----------------------------------------------------------------------------
102 : void
103 0 : HermesCoreController::reset(bool nuke)
104 : {
105 :
106 0 : if (nuke) {
107 0 : m_readout.getNode("csr.ctrl.nuke").write(0x1);
108 0 : m_readout.getClient().dispatch();
109 :
110 : // time.sleep(0.1);
111 0 : std::this_thread::sleep_for(std::chrono::milliseconds(1));
112 :
113 0 : m_readout.getNode("csr.ctrl.nuke").write(0x0);
114 0 : m_readout.getClient().dispatch();
115 : }
116 :
117 0 : m_readout.getNode("csr.ctrl.soft_rst").write(0x1);
118 0 : m_readout.getClient().dispatch();
119 :
120 : // time.sleep(0.1)
121 0 : std::this_thread::sleep_for(std::chrono::milliseconds(1));
122 :
123 0 : m_readout.getNode("csr.ctrl.soft_rst").write(0x0);
124 0 : m_readout.getClient().dispatch();
125 :
126 : // Check the ethernet core status
127 0 : auto eth_rdy = m_readout.getNode("tx_path.tx_mux.csr.stat.eth_rdy").read();
128 0 : m_readout.getClient().dispatch();
129 :
130 : // If the ethernet core is not ready, issue a phy reset
131 0 : if (!eth_rdy) {
132 0 : m_readout.getNode("pcs_pma.debug.csr.ctrl.phy_reset").write(0x1);
133 0 : m_readout.getNode("pcs_pma.debug.csr.ctrl.phy_reset").write(0x0);
134 0 : m_readout.getClient().dispatch();
135 : }
136 0 : }
137 :
138 : //-----------------------------------------------------------------------------
139 : bool
140 0 : HermesCoreController::is_link_in_error(uint16_t link, bool do_throw)
141 : {
142 :
143 0 : this->sel_tx_mux(link);
144 :
145 0 : auto& tx_mux_stat = m_readout.getNode("tx_path.tx_mux.csr.stat");
146 0 : auto err = tx_mux_stat.getNode("err").read();
147 0 : auto eth_rdy = tx_mux_stat.getNode("eth_rdy").read();
148 0 : auto src_rdy = tx_mux_stat.getNode("src_rdy").read();
149 0 : auto udp_rdy = tx_mux_stat.getNode("udp_rdy").read();
150 0 : tx_mux_stat.getClient().dispatch();
151 :
152 0 : bool is_error = (err || !eth_rdy || !src_rdy || !udp_rdy);
153 :
154 0 : if (do_throw && is_error) {
155 0 : throw LinkInError(ERS_HERE, link, err, eth_rdy, src_rdy, udp_rdy);
156 : }
157 :
158 0 : return is_error;
159 0 : }
160 :
161 : //-----------------------------------------------------------------------------
162 : void
163 0 : HermesCoreController::enable(uint16_t link, bool enable)
164 : {
165 :
166 0 : this->sel_tx_mux(link);
167 :
168 0 : auto& tx_mux_ctrl = m_readout.getNode("tx_path.tx_mux.csr.ctrl");
169 :
170 : // Not sure what to do with this
171 0 : auto tx_en = tx_mux_ctrl.getNode("tx_en").read();
172 0 : auto buf_en = tx_mux_ctrl.getNode("en_buf").read();
173 0 : auto ctrl_en = tx_mux_ctrl.getNode("en").read();
174 :
175 0 : if (enable) {
176 :
177 : // Assume that all is off
178 :
179 : // Enable the main logic
180 0 : tx_mux_ctrl.getNode("en").write(0x1);
181 0 : tx_mux_ctrl.getClient().dispatch();
182 :
183 : // Enable transmitter first
184 0 : tx_mux_ctrl.getNode("tx_en").write(0x1);
185 0 : tx_mux_ctrl.getClient().dispatch();
186 :
187 : // Enable buffers last
188 0 : tx_mux_ctrl.getNode("en_buf").write(0x1);
189 0 : tx_mux_ctrl.getClient().dispatch();
190 :
191 : } else {
192 :
193 : // Disable buffers last
194 0 : tx_mux_ctrl.getNode("en_buf").write(0x0);
195 0 : tx_mux_ctrl.getClient().dispatch();
196 :
197 : // Disable transmitter first
198 0 : tx_mux_ctrl.getNode("tx_en").write(0x0);
199 0 : tx_mux_ctrl.getClient().dispatch();
200 :
201 : // Disable the main logic
202 0 : tx_mux_ctrl.getNode("en").write(0x0);
203 0 : tx_mux_ctrl.getClient().dispatch();
204 : }
205 0 : }
206 :
207 : //-----------------------------------------------------------------------------
208 : void
209 0 : HermesCoreController::config_mux(uint16_t link, uint16_t det, uint16_t crate, uint16_t slot)
210 : {
211 0 : this->sel_tx_mux(link);
212 :
213 0 : auto& mux_ctrl = m_readout.getNode("tx_path.tx_mux.mux.ctrl");
214 :
215 0 : mux_ctrl.getNode("detid").write(det);
216 0 : mux_ctrl.getNode("crate").write(crate);
217 0 : mux_ctrl.getNode("slot").write(slot);
218 0 : mux_ctrl.getClient().dispatch();
219 0 : }
220 :
221 : //-----------------------------------------------------------------------------
222 : void
223 0 : HermesCoreController::config_udp(uint16_t link,
224 : uint64_t src_mac,
225 : uint32_t src_ip,
226 : uint16_t src_port,
227 : uint64_t dst_mac,
228 : uint32_t dst_ip,
229 : uint16_t dst_port,
230 : uint32_t filters)
231 : {
232 :
233 0 : if (link >= m_core_info.n_mgt) {
234 0 : throw LinkDoesNotExist(ERS_HERE, link);
235 : }
236 :
237 0 : this->sel_udp_core(link);
238 :
239 : // const std::string udp_ctrl_name = fmt::format("udp.udp_core_{}.udp_core_control.nz_rst_ctrl");
240 0 : const auto& udp_ctrl = m_readout.getNode("tx_path.udp_core.udp_core_control");
241 :
242 0 : udp_ctrl.getNode("src_addr_ctrl.use_external").write(0);
243 :
244 : // Load the source mac address
245 0 : udp_ctrl.getNode("src_addr_ctrl.src_mac_addr_lower").write(src_mac & 0xffffffff);
246 0 : udp_ctrl.getNode("src_addr_ctrl.src_mac_addr_upper").write((src_mac >> 32) & 0xffff);
247 :
248 : // Load the source ip address
249 0 : udp_ctrl.getNode("src_addr_ctrl.src_ip_addr").write(src_ip);
250 :
251 : // Load the dst mac address
252 0 : udp_ctrl.getNode("ctrl.dst_mac_addr_lower").write(dst_mac & 0xffffffff);
253 0 : udp_ctrl.getNode("ctrl.dst_mac_addr_upper").write((dst_mac >> 32) & 0xffff);
254 :
255 : // Load the dst ip address
256 0 : udp_ctrl.getNode("ctrl.dst_ip_addr").write(dst_ip);
257 :
258 : // Ports
259 0 : udp_ctrl.getNode("src_addr_ctrl.src_port").write(src_port);
260 0 : udp_ctrl.getNode("ctrl.dst_port").write(dst_port);
261 :
262 0 : udp_ctrl.getNode("ctrl.filter_control").write(filters);
263 0 : udp_ctrl.getClient().dispatch();
264 0 : }
265 :
266 : //-----------------------------------------------------------------------------
267 : void
268 0 : HermesCoreController::config_fake_src(uint16_t link, uint16_t n_src, uint16_t data_len, uint16_t rate)
269 : {
270 :
271 0 : this->sel_tx_mux(link);
272 :
273 0 : auto was_en_buf = m_readout.getNode("tx_path.tx_mux.csr.ctrl.en_buf").read();
274 0 : m_readout.getNode("tx_path.tx_mux.csr.ctrl.en_buf").write(0x0);
275 0 : m_readout.getClient().dispatch();
276 :
277 0 : for (size_t src_id(0); src_id < m_core_info.srcs_per_mux; ++src_id) {
278 0 : this->sel_tx_mux_buf(src_id);
279 :
280 0 : bool src_en = (src_id < n_src);
281 0 : m_readout.getNode("tx_path.tx_mux.buf.ctrl.fake_en").write(src_en);
282 0 : m_readout.getClient().dispatch();
283 0 : if (!src_en) {
284 0 : continue;
285 : }
286 0 : m_readout.getNode("tx_path.tx_mux.buf.ctrl.dlen").write(data_len);
287 :
288 0 : m_readout.getNode("tx_path.tx_mux.buf.ctrl.rate_rdx").write(rate);
289 0 : m_readout.getClient().dispatch();
290 : }
291 :
292 0 : m_readout.getNode("tx_path.tx_mux.csr.ctrl.en_buf").write(was_en_buf.value());
293 0 : m_readout.getClient().dispatch();
294 0 : }
295 :
296 : //-----------------------------------------------------------------------------
297 : HermesCoreController::LinkGeoInfo
298 0 : HermesCoreController::read_link_geo_info(uint16_t link)
299 : {
300 :
301 0 : this->sel_tx_mux(link);
302 :
303 0 : auto detid = m_readout.getNode("tx_path.tx_mux.mux.ctrl.detid").read();
304 0 : auto crate = m_readout.getNode("tx_path.tx_mux.mux.ctrl.crate").read();
305 0 : auto slot = m_readout.getNode("tx_path.tx_mux.mux.ctrl.slot").read();
306 :
307 0 : m_readout.getClient().dispatch();
308 :
309 0 : return { detid.value(), crate.value(), slot.value() };
310 0 : }
311 :
312 : //-----------------------------------------------------------------------------
313 : opmon::LinkInfo
314 0 : HermesCoreController::read_link_stats(uint16_t link)
315 : {
316 0 : this->sel_tx_mux(link);
317 0 : this->sel_udp_core(link);
318 :
319 0 : opmon::LinkInfo info;
320 :
321 0 : const auto& mux_stats = m_readout.getNode("tx_path.tx_mux.csr.stat");
322 0 : auto err = mux_stats.getNode("err").read();
323 0 : auto eth_rdy = mux_stats.getNode("eth_rdy").read();
324 0 : auto src_rdy = mux_stats.getNode("src_rdy").read();
325 0 : auto udp_rdy = mux_stats.getNode("udp_rdy").read();
326 0 : mux_stats.getClient().dispatch();
327 :
328 0 : const auto& udp_ctrl = m_readout.getNode(fmt::format("tx_path.udp_core.udp_core_control"));
329 0 : const auto& rx_stats = udp_ctrl.getNode("rx_packet_counters");
330 :
331 0 : auto rx_arp_count = rx_stats.getNode("arp_count").read();
332 0 : auto rx_ping_count = rx_stats.getNode("ping_count").read();
333 0 : auto rx_udp_count = rx_stats.getNode("udp_count").read();
334 0 : rx_stats.getClient().dispatch();
335 :
336 0 : const auto& tx_stats = udp_ctrl.getNode("tx_packet_counters");
337 :
338 0 : auto tx_arp_count = tx_stats.getNode("arp_count").read();
339 0 : auto tx_ping_count = tx_stats.getNode("ping_count").read();
340 0 : auto tx_udp_count = tx_stats.getNode("udp_count").read();
341 0 : tx_stats.getClient().dispatch();
342 :
343 0 : info.set_err(err.value());
344 0 : info.set_eth_rdy(eth_rdy.value());
345 0 : info.set_src_rdy(src_rdy.value());
346 0 : info.set_udp_rdy(udp_rdy.value());
347 :
348 0 : info.set_rcvd_arp_count(rx_arp_count.value());
349 0 : info.set_rcvd_ping_count(rx_ping_count.value());
350 0 : info.set_rcvd_udp_count(rx_udp_count.value());
351 :
352 0 : info.set_sent_arp_count(tx_arp_count.value());
353 0 : info.set_sent_ping_count(tx_ping_count.value());
354 0 : info.set_sent_udp_count(tx_udp_count.value());
355 :
356 0 : return info;
357 0 : }
358 :
359 : }
360 : }
|