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