Line data Source code
1 : /**
2 : * @file HermesModule.cpp
3 : *
4 : * Implementations of HermesModule's functions
5 : *
6 : * This is part of the DUNE DAQ Software Suite, copyright 2020.
7 : * Licensing/copyright details are in the COPYING file that you should have
8 : * received with this code.
9 : */
10 :
11 : #include "appmodel/HermesModule.hpp"
12 : #include "appmodel/HermesDataSender.hpp"
13 : #include "appmodel/IpbusAddressTable.hpp"
14 : #include "appmodel/appmodelIssues.hpp"
15 : #include "confmodel/DetectorStream.hpp"
16 : #include "confmodel/GeoId.hpp"
17 : #include "confmodel/NetworkDevice.hpp"
18 : #include "confmodel/Session.hpp"
19 :
20 : #include "HermesModule.hpp"
21 : #include "hermesmodules/opmon/hermescontroller.pb.h"
22 :
23 : #include "logging/Logging.hpp"
24 : #include <arpa/inet.h>
25 : #include <fmt/core.h>
26 : #include <netinet/ether.h>
27 : #include <string>
28 :
29 : namespace dunedaq::hermesmodules {
30 :
31 : //-----------------------------------------------------------------------------
32 : uint64_t
33 0 : ether_atou64(const std::string& addr_str)
34 : {
35 0 : union
36 : {
37 : uint64_t result;
38 : struct ether_addr address;
39 : };
40 0 : result = 0;
41 0 : struct ether_addr* ptr = ether_aton_r(addr_str.c_str(), &address);
42 0 : if (!ptr) {
43 : return (~0);
44 : }
45 : // Big to little endian
46 0 : return (__builtin_bswap64(result) >> 16);
47 : }
48 :
49 : //-----------------------------------------------------------------------------
50 : uint32_t
51 0 : ip_atou32(const std::string& addr_str)
52 : {
53 : // Big to little endian
54 0 : return __builtin_bswap32(inet_addr(addr_str.c_str()));
55 : }
56 :
57 : //-----------------------------------------------------------------------------
58 0 : HermesModule::HermesModule(const std::string& name)
59 0 : : dunedaq::appfwk::DAQModule(name)
60 : {
61 0 : register_command("conf", &HermesModule::do_conf);
62 0 : register_command("start", &HermesModule::do_start);
63 0 : register_command("stop", &HermesModule::do_stop);
64 0 : }
65 :
66 : //-----------------------------------------------------------------------------
67 : void
68 0 : HermesModule::init(std::shared_ptr<appfwk::ConfigurationManager> mcfg)
69 : {
70 0 : uhal::setLogLevelTo(uhal::Error());
71 :
72 : // Save our DAL for later use by do_conf
73 0 : m_dal = mcfg->get_dal<appmodel::HermesModule>(get_name());
74 0 : m_session = mcfg->get_session();
75 0 : }
76 :
77 : //-----------------------------------------------------------------------------
78 : void
79 0 : HermesModule::generate_opmon_data()
80 : {
81 0 : opmon::ControllerInfo ginfo;
82 0 : ginfo.set_total_amount(m_total_amount);
83 0 : ginfo.set_amount_since_last_get_info_call(m_amount_since_last_get_info_call.exchange(0));
84 0 : publish(std::move(ginfo));
85 :
86 0 : if (!m_core_controller)
87 0 : return;
88 :
89 0 : const auto& core_info = m_core_controller->get_info();
90 :
91 0 : for (uint16_t i(0); i < core_info.n_mgt; ++i) {
92 :
93 0 : try {
94 0 : auto geo_info = m_core_controller->read_link_geo_info(i);
95 0 : publish(m_core_controller->read_link_stats(i),
96 0 : { { "detector", std::to_string(geo_info.detid) },
97 0 : { "crate", std::to_string(geo_info.crateid) },
98 0 : { "slot", std::to_string(geo_info.slotid) },
99 0 : { "link", std::to_string(i) } });
100 0 : } catch (const uhal::exception::exception& e) {
101 0 : ers::warning(FailedToRetrieveStats(ERS_HERE, i, e));
102 0 : }
103 :
104 : } // loop over links
105 0 : }
106 :
107 : //-----------------------------------------------------------------------------
108 : void
109 0 : HermesModule::do_conf(const CommandData_t& /*conf_as_json*/)
110 : {
111 : // Create the ipbus
112 0 : auto hw = uhal::ConnectionManager::getDevice(m_dal->UID(), m_dal->get_uri(), m_dal->get_address_table()->get_uri());
113 0 : hw.setTimeoutPeriod(m_dal->get_timeout_ms());
114 :
115 0 : m_core_controller = std::make_unique<HermesCoreController>(hw);
116 :
117 0 : const auto& core_info = m_core_controller->get_info();
118 0 : fmt::print("Hermes\n");
119 0 : fmt::print("n_mgt {}\n", core_info.n_mgt);
120 0 : fmt::print("n_src {}\n", core_info.n_src);
121 0 : fmt::print("ref_freq {}\n", core_info.ref_freq);
122 0 : std::cout << std::flush;
123 :
124 0 : auto links = m_dal->get_links();
125 : // Size check on link conf
126 0 : if (links.size() != core_info.n_mgt) {
127 0 : throw FirmwareConfigLinkMismatch(ERS_HERE, links.size(), core_info.n_mgt);
128 : }
129 :
130 : // Sequence id check
131 0 : std::set<uint32_t> ids;
132 0 : for (const auto l : links) {
133 0 : ids.insert(l->get_link_id());
134 : }
135 :
136 : // Look duplicate link ids
137 0 : if (ids.size() != links.size()) {
138 0 : throw DuplicatedLinkIDs(ERS_HERE, links.size(), ids.size());
139 : }
140 :
141 : // Make sure that the last link id is n_mgt-1
142 0 : if (*ids.rbegin() != (core_info.n_mgt - 1)) {
143 0 : throw LinkIDConfigurationError(ERS_HERE, *ids.rend(), core_info.n_mgt - 1);
144 : }
145 :
146 : // Check ip address consistency
147 : // Redundant check, schema enforces 1:1
148 0 : if (m_dal->get_destination()->get_ip_address().size() != 1) {
149 0 : throw MultipleIPAddressConfigurationError(
150 0 : ERS_HERE, m_dal->get_destination()->UID(), m_dal->get_destination()->get_ip_address().size());
151 : }
152 :
153 : // Redundant check, schema enforces 1:1
154 0 : for (const auto& l : links) {
155 0 : if (l->get_uses()->get_ip_address().size() != 1) {
156 0 : throw MultipleIPAddressConfigurationError(ERS_HERE, l->get_uses()->UID(), l->get_uses()->get_ip_address().size());
157 : }
158 : }
159 : // All good
160 0 : for (uint16_t i(0); i < core_info.n_mgt; ++i) {
161 : // Put the endpoint in a safe state
162 0 : m_core_controller->enable(i, false);
163 : }
164 :
165 0 : m_core_controller->reset();
166 :
167 : // FIXME: What the hell is this again?
168 0 : uint32_t filter_control = 0x07400307;
169 0 : for (const auto& l : links) {
170 0 : if (l->is_excluded(*m_session)) {
171 0 : continue;
172 : }
173 :
174 0 : m_enabled_link_ids.push_back(l->get_link_id());
175 :
176 0 : m_core_controller->config_udp(l->get_link_id(),
177 0 : ether_atou64(l->get_uses()->get_mac_address()),
178 0 : ip_atou32(l->get_uses()->get_ip_address().at(0)),
179 0 : l->get_port(),
180 0 : ether_atou64(m_dal->get_destination()->get_mac_address()),
181 0 : ip_atou32(m_dal->get_destination()->get_ip_address().at(0)),
182 0 : l->get_port(),
183 : filter_control);
184 :
185 : // Get the first DetectorStream
186 : // and use it for the geo id information.
187 0 : const confmodel::DetectorStream* source = l->get_streams()[0];
188 0 : m_core_controller->config_mux(l->get_link_id(),
189 0 : source->get_geo_id()->get_detector_id(),
190 0 : source->get_geo_id()->get_crate_id(),
191 0 : source->get_geo_id()->get_slot_id());
192 : }
193 0 : }
194 :
195 : void
196 0 : HermesModule::do_start(const CommandData_t& /*d*/)
197 : {
198 :
199 0 : for (auto id : m_enabled_link_ids) {
200 : // Put the endpoint in a safe state
201 0 : m_core_controller->enable(id, true);
202 : }
203 :
204 0 : for (auto id : m_enabled_link_ids) {
205 : // Put the endpoint in a safe state
206 0 : m_core_controller->is_link_in_error(id, true);
207 : }
208 :
209 : // for ( uint16_t i(0); i<core_info.n_mgt; ++i){
210 : // // Put the endpoint in a safe state
211 : // m_core_controller->enable(i, true);
212 : // }
213 :
214 : // for ( uint16_t i(0); i<core_info.n_mgt; ++i){
215 : // // Put the endpoint in a safe state
216 : // m_core_controller->is_link_in_error(i);
217 : // }
218 0 : }
219 :
220 : void
221 0 : HermesModule::do_stop(const CommandData_t& /*d*/)
222 : {
223 :
224 0 : for (auto id : m_enabled_link_ids) {
225 : // Put the endpoint in a safe state
226 0 : m_core_controller->enable(id, false);
227 : }
228 0 : }
229 :
230 : } // namespace dunedaq::hermesmodules
231 :
232 0 : DEFINE_DUNE_DAQ_MODULE(dunedaq::hermesmodules::HermesModule)
|