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