Line data Source code
1 : /**
2 : * @file DaphneApplication.cpp
3 : *
4 : * Implementation of DaphneApplication's generate_modules dal method
5 : *
6 : * This is part of the DUNE DAQ Software Suite, copyright 2023.
7 : * Licensing/copyright details are in the COPYING file that you should have
8 : * received with this code.
9 : */
10 :
11 : #include "conffwk/Configuration.hpp"
12 : #include "logging/Logging.hpp"
13 : #include "oks/kernel.hpp"
14 :
15 : #include "confmodel/DetectorStream.hpp"
16 : #include "confmodel/GeoId.hpp"
17 : #include "confmodel/NetworkInterface.hpp"
18 :
19 : #include "ConfigObjectFactory.hpp"
20 : #include "appmodel/DaphneApplication.hpp"
21 : #include "appmodel/DaphneConf.hpp"
22 : #include "appmodel/DaphneMapEntry.hpp"
23 : #include "appmodel/DaphneV2ADC.hpp"
24 : #include "appmodel/DaphneV2AFE.hpp"
25 : #include "appmodel/DaphneV2BoardConf.hpp"
26 : #include "appmodel/DaphneV2Channel.hpp"
27 : #include "appmodel/DaphneV2ControllerModule.hpp"
28 : #include "appmodel/DaphneV2LNA.hpp"
29 : #include "appmodel/DaphneV2PGA.hpp"
30 : #include "appmodel/DaphneV3ControllerModule.hpp"
31 : #include "appmodel/FelixDataSender.hpp"
32 : #include "appmodel/FelixDetectorToDaqConnection.hpp"
33 : #include "appmodel/HermesDataSender.hpp"
34 : #include "appmodel/HermesModule.hpp"
35 : #include "appmodel/HermesModuleConf.hpp"
36 : #include "appmodel/IpbusAddressTable.hpp"
37 : #include "appmodel/NWDetDataReceiver.hpp"
38 : #include "appmodel/NWDetDataSender.hpp"
39 : #include "appmodel/NetworkDetectorToDaqConnection.hpp"
40 : #include "appmodel/appmodelIssues.hpp"
41 :
42 : #include <bitset>
43 : #include <fmt/core.h>
44 : #include <iostream>
45 : #include <map>
46 : #include <set>
47 : #include <string>
48 : #include <vector>
49 :
50 : namespace dunedaq::appmodel {
51 :
52 : std::vector<const confmodel::ExcludableEntity*>
53 0 : DaphneApplication::contained_excludable_entities() const
54 : {
55 0 : return to_resources(get_detector_connections());
56 : }
57 :
58 : void
59 0 : DaphneApplication::generate_modules(std::shared_ptr<appmodel::ConfigurationHelper> helper) const
60 : {
61 0 : ConfigObjectFactory obj_fac(this);
62 :
63 0 : std::vector<const confmodel::DaqModule*> modules;
64 :
65 0 : auto daphne_conf = get_configuration();
66 :
67 0 : std::map<std::string, const DaphneV2BoardConf*> conf_map;
68 0 : auto confs = daphne_conf->get_boards();
69 0 : for (const auto& c : confs) {
70 0 : conf_map[c->get_key()] = c->get_conf();
71 : }
72 :
73 : // these maps are all indexed on the board id {detector].{crate}.{slot}
74 0 : std::map<std::string, bool> v3_map;
75 0 : std::map<std::string, const confmodel::NetworkInterface*> interfaces;
76 0 : std::map<std::string, std::string> ctrl_hosts;
77 :
78 : // map from ctrl_host to senders
79 0 : std::map<std::string, std::vector<const appmodel::HermesDataSender*>> hermes_senders;
80 :
81 0 : for (auto d2d_conn : get_detector_connections()) {
82 :
83 : // A ExcludableEntity can be disabled and still its application can be enabled because the application can have
84 : // multile resources, so we need to check which resources are enabled
85 0 : if (helper->is_excluded(d2d_conn)) {
86 0 : TLOG_DEBUG(7) << "Ignoring disabled DetectorToDaqConnection " << d2d_conn->UID();
87 0 : continue;
88 0 : }
89 :
90 0 : TLOG_DEBUG(6) << "Processing DetectorToDaqConnection " << d2d_conn->UID();
91 : // get the readout groups and the interfaces and streams therein; 1 reaout group corresponds to 1 data reader module
92 :
93 : // Redundant? Schema forbids 0 connections
94 0 : if (d2d_conn->contained_excludable_entities().empty()) {
95 0 : throw(BadConf(ERS_HERE, "DetectorToDaqConnection does not contain senders or receivers"));
96 : }
97 :
98 0 : auto flx_conn = dynamic_cast<const appmodel::FelixDetectorToDaqConnection*>(d2d_conn); // NOLINT(runtime/rtti)
99 0 : auto net_conn = dynamic_cast<const appmodel::NetworkDetectorToDaqConnection*>(d2d_conn); // NOLINT(runtime/rtti)
100 :
101 0 : if (!net_conn && !flx_conn) {
102 0 : throw BadConf(ERS_HERE, d2d_conn->UID() + " is neither felix or eth connection");
103 : }
104 :
105 0 : if (flx_conn) {
106 0 : auto det_senders = flx_conn->get_felix_senders();
107 :
108 : // Loop over senders
109 0 : for (const auto* felix_sender : det_senders) {
110 :
111 0 : if (helper->is_excluded(felix_sender)) {
112 0 : TLOG() << "Skipping disabled sender: " << felix_sender->UID();
113 0 : continue;
114 0 : }
115 :
116 0 : auto ip = felix_sender->get_control_host();
117 :
118 : // from the felix sender we get the DetStream and then the GeoID
119 :
120 0 : auto streams = felix_sender->get_streams();
121 :
122 0 : for (const auto* det_s : streams) {
123 :
124 0 : if (helper->is_excluded(det_s)) {
125 0 : TLOG() << "Skipping disabled DetStream: " << det_s->UID();
126 0 : continue;
127 0 : }
128 :
129 0 : auto geo_id = det_s->get_geo_id();
130 0 : auto id = fmt::format("{}.{}.{}", geo_id->get_detector_id(), geo_id->get_crate_id(), geo_id->get_slot_id());
131 0 : if (!v3_map.contains(id)) {
132 0 : v3_map[id] = false;
133 : }
134 :
135 0 : } // loop over DetStreams
136 :
137 0 : } // loop over det_senders
138 0 : } // if flx connection
139 :
140 0 : if (net_conn) {
141 0 : auto det_senders = net_conn->get_net_senders();
142 :
143 0 : for (const auto* nw_sender : det_senders) {
144 0 : if (helper->is_excluded(nw_sender)) {
145 0 : TLOG() << "Skipping disabled sender: " << nw_sender->UID();
146 0 : continue;
147 0 : }
148 :
149 : // Check the sender type, must me a HermesSender
150 0 : const auto* hrms_sender = nw_sender->cast<appmodel::HermesDataSender>();
151 0 : if (!hrms_sender) {
152 0 : throw(BadConf(ERS_HERE, fmt::format("DataSender {} is not a appmodel::HermesDataSender", nw_sender->UID())));
153 : }
154 :
155 0 : hermes_senders[hrms_sender->get_control_host()].push_back(hrms_sender);
156 :
157 0 : auto streams = nw_sender->get_streams();
158 0 : for (const auto* det_s : streams) {
159 :
160 0 : if (helper->is_excluded(det_s)) {
161 0 : TLOG() << "Skipping disabled DetStream: " << det_s->UID();
162 0 : continue;
163 0 : }
164 :
165 0 : auto geo_id = det_s->get_geo_id();
166 0 : auto id = fmt::format("{}.{}.{}", geo_id->get_detector_id(), geo_id->get_crate_id(), geo_id->get_slot_id());
167 0 : if (!v3_map.contains(id)) {
168 0 : v3_map[id] = true;
169 0 : interfaces[id] = net_conn->get_net_receiver()->get_uses();
170 0 : ctrl_hosts[id] = hrms_sender->get_control_host();
171 : }
172 :
173 0 : } // loop over streams
174 :
175 0 : } // loop over NW senders
176 :
177 0 : } // if net_connection
178 :
179 : } // loop over det2DAQ Connections
180 :
181 0 : for (const auto& [id, v3] : v3_map) {
182 :
183 0 : auto conf_it = conf_map.find(id);
184 0 : if (conf_it == conf_map.end()) {
185 0 : throw MissingDaphne(ERS_HERE, id);
186 : }
187 0 : auto conf = conf_it->second;
188 :
189 0 : conffwk::ConfigObject module_obj =
190 0 : obj_fac.create((v3 ? "DaphneV3ControllerModule" : "DaphneV2ControllerModule"), fmt::format("controller-{}", id));
191 0 : module_obj.set_obj("daphne_conf", &daphne_conf->config_object());
192 0 : module_obj.set_obj("board_conf", &conf->config_object());
193 :
194 0 : auto module = obj_fac.get_dal<confmodel::DaqModule>(module_obj);
195 0 : modules.push_back(module);
196 :
197 : // Create Hermes Modules
198 0 : if (v3) {
199 0 : std::string hermes_uid = fmt::format("daphne-hermes-ctrl-{}", id);
200 0 : conffwk::ConfigObject hermes_obj = obj_fac.create("HermesModule", hermes_uid);
201 0 : hermes_obj.set_obj("address_table", &this->get_hermes_module_conf()->get_address_table()->config_object());
202 0 : hermes_obj.set_by_val<std::string>("uri",
203 0 : fmt::format("{}://{}:{}",
204 0 : this->get_hermes_module_conf()->get_ipbus_type(),
205 0 : ctrl_hosts[id],
206 0 : this->get_hermes_module_conf()->get_ipbus_port()));
207 0 : hermes_obj.set_by_val<uint32_t>("timeout_ms", this->get_hermes_module_conf()->get_ipbus_timeout_ms()); // NOLINT
208 0 : hermes_obj.set_obj("destination", &interfaces[id]->config_object());
209 :
210 0 : std::vector<const conffwk::ConfigObject*> links_obj;
211 0 : const auto& senders = hermes_senders[ctrl_hosts[id]];
212 0 : for (const auto* sndr : senders) {
213 0 : links_obj.push_back(&sndr->config_object());
214 : }
215 0 : hermes_obj.set_objs("links", links_obj);
216 :
217 0 : modules.push_back(obj_fac.get_dal<appmodel::HermesModule>(hermes_obj));
218 0 : }
219 :
220 0 : } // ips
221 :
222 0 : obj_fac.update_modules(modules);
223 0 : } // NOLINT
224 :
225 : bool
226 0 : DaphneV2BoardConf::is_channel_used(size_t ch) const
227 : {
228 :
229 0 : for (auto ch_p : get_active_channels()) {
230 0 : if (ch_p->get_channel_id() == ch) {
231 0 : return true;
232 : }
233 : }
234 :
235 0 : return false;
236 : }
237 :
238 : const DaphneV2Channel&
239 0 : DaphneV2BoardConf::get_channel(size_t ch) const
240 : {
241 :
242 0 : for (auto ch_p : get_active_channels()) {
243 0 : if (ch_p->get_channel_id() == ch) {
244 0 : return *ch_p;
245 : }
246 : }
247 :
248 0 : return *get_default_channel();
249 : }
250 :
251 : bool
252 0 : DaphneV2BoardConf::is_afe_used(size_t afe) const
253 : {
254 :
255 0 : auto begin = afe * 8;
256 0 : auto end = (afe + 1) * 8;
257 0 : for (size_t i = begin; i < end; ++i) {
258 0 : if (is_channel_used(i))
259 : return true;
260 : }
261 :
262 : return false;
263 : }
264 :
265 : const DaphneV2AFE&
266 0 : DaphneV2BoardConf::get_afe(size_t ch) const
267 : {
268 :
269 0 : if (!is_afe_used(ch))
270 0 : return *get_default_afe();
271 :
272 0 : for (auto afe_p : get_active_afes()) {
273 0 : if (afe_p->get_afe_id() == ch) {
274 0 : return *afe_p;
275 : }
276 : }
277 :
278 0 : throw appmodel::MissingAFE(ERS_HERE, UID(), ch);
279 : }
280 :
281 : uint16_t
282 0 : DaphneV2ADC::get_reg4() const
283 : {
284 :
285 : // ADC, reg 4 has no parsing as it's all made of booleans
286 0 : std::bitset<5> reg4;
287 : // bits 0 and 2 are reserved
288 0 : reg4[1] = get_low_resolution();
289 0 : reg4[3] = get_output_offset_binary();
290 0 : reg4[4] = get_MSB_first();
291 0 : return reg4.to_ulong();
292 : }
293 :
294 : uint16_t
295 0 : DaphneV2PGA::get_reg51() const
296 : {
297 :
298 0 : std::bitset<14> reg51(get_lpf_cut_frequency());
299 0 : reg51 <<= 1;
300 0 : reg51[4] = get_integrator_disable();
301 0 : reg51[7] = true; // clamp is always disabled and we are in low noise mode
302 0 : reg51[13] = get_gain();
303 :
304 0 : return reg51.to_ulong();
305 : }
306 :
307 : uint16_t
308 0 : DaphneV2LNA::get_reg52() const
309 : {
310 :
311 0 : std::bitset<16> reg52;
312 :
313 0 : decltype(reg52) clamp(get_clamp());
314 0 : clamp <<= 6;
315 :
316 0 : reg52[12] = get_integrator_disable();
317 :
318 0 : decltype(reg52) gain(get_gain());
319 0 : clamp <<= 13;
320 :
321 0 : reg52 |= clamp;
322 0 : reg52 |= gain;
323 :
324 0 : return reg52.to_ulong();
325 : }
326 :
327 : } // namespace dunedaq::appmodel
|