Line data Source code
1 : /**
2 : * @file MLTApplication.cpp
3 : *
4 : * Implementation of MLTApplication'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 :
12 : #include "ConfigObjectFactory.hpp"
13 :
14 : #include "conffwk/Configuration.hpp"
15 :
16 : #include "confmodel/Connection.hpp"
17 : #include "confmodel/NetworkConnection.hpp"
18 : // #include "confmodel/ReadoutGroup.hpp"
19 : // #include "confmodel/ReadoutInterface.hpp"
20 : // #include "confmodel/DetectorStream.hpp"
21 : #include "confmodel/DetectorStream.hpp"
22 : #include "confmodel/DetectorToDaqConnection.hpp"
23 : #include "confmodel/ResourceSet.hpp"
24 : #include "confmodel/Service.hpp"
25 : #include "confmodel/Session.hpp"
26 :
27 : #include "appmodel/DTSHSIApplication.hpp"
28 : #include "appmodel/DFApplication.hpp"
29 : #include "appmodel/DataHandlerConf.hpp"
30 : #include "appmodel/DataHandlerModule.hpp"
31 : #include "appmodel/DataReaderConf.hpp"
32 : #include "appmodel/DataRecorderConf.hpp"
33 : #include "appmodel/DataSubscriberModule.hpp"
34 : #include "appmodel/CTBApplication.hpp"
35 : #include "appmodel/CIBApplication.hpp"
36 : #include "appmodel/FakeDataApplication.hpp"
37 : #include "appmodel/FakeDataProdConf.hpp"
38 : #include "appmodel/FakeHSIApplication.hpp"
39 : #include "appmodel/MLTApplication.hpp"
40 : #include "appmodel/MLTConf.hpp"
41 : #include "appmodel/MLTModule.hpp"
42 : #include "appmodel/NetworkConnectionDescriptor.hpp"
43 : #include "appmodel/NetworkConnectionRule.hpp"
44 : #include "appmodel/QueueConnectionRule.hpp"
45 : #include "appmodel/QueueDescriptor.hpp"
46 : #include "appmodel/ReadoutApplication.hpp"
47 : #include "appmodel/SourceIDConf.hpp"
48 : #include "appmodel/StandaloneTCMakerConf.hpp"
49 : #include "appmodel/StandaloneTCMakerModule.hpp"
50 : #include "appmodel/TCDataProcessor.hpp"
51 : #include "appmodel/TPStreamConf.hpp"
52 : #include "appmodel/TriggerApplication.hpp"
53 : #include "appmodel/TPReplayModuleConf.hpp"
54 : #include "appmodel/TPReplayApplication.hpp"
55 : #include "appmodel/appmodelIssues.hpp"
56 :
57 : #include "logging/Logging.hpp"
58 :
59 : #include <string>
60 : #include <vector>
61 :
62 : namespace dunedaq {
63 : namespace appmodel {
64 :
65 :
66 : void
67 0 : MLTApplication::generate_modules(const confmodel::Session* session) const
68 : {
69 :
70 0 : std::vector<const confmodel::DaqModule*> modules;
71 :
72 0 : ConfigObjectFactory obj_fac(this);
73 :
74 : // auto mlt_conf = get_mlt_conf();
75 : // auto mlt_class = mlt_conf->get_template_for();
76 :
77 0 : auto tch_conf = get_trigger_inputs_handler();
78 0 : auto tch_class = tch_conf->get_template_for();
79 :
80 0 : auto mlt_conf = get_mlt_conf();
81 0 : auto mlt_class = mlt_conf->get_template_for();
82 0 : std::string handler_name(tch_conf->UID());
83 :
84 0 : if (!mlt_conf) {
85 : throw(BadConf(ERS_HERE, "No MLT configuration in MLTApplication given"));
86 : }
87 :
88 : // Queue descriptors
89 : // Process the queue rules looking for inputs to our trigger handler modules
90 0 : const QueueDescriptor* tc_inputq_desc = nullptr;
91 0 : const QueueDescriptor* td_outputq_desc = nullptr;
92 :
93 0 : for (auto rule : get_queue_rules()) {
94 0 : auto destination_class = rule->get_destination_class();
95 0 : auto data_type = rule->get_descriptor()->get_data_type();
96 0 : if (destination_class == tch_class) {
97 0 : tc_inputq_desc = rule->get_descriptor();
98 0 : } else if (destination_class == mlt_class) {
99 0 : td_outputq_desc = rule->get_descriptor();
100 : }
101 0 : }
102 :
103 0 : if (tc_inputq_desc == nullptr) {
104 0 : throw(BadConf(ERS_HERE, "No TC input queue descriptor given"));
105 : }
106 0 : if (td_outputq_desc == nullptr) {
107 0 : throw(BadConf(ERS_HERE, "No TD output-input queue descriptor given"));
108 : }
109 :
110 : // Create queues
111 0 : auto input_queue_obj = obj_fac.create_queue_obj(tc_inputq_desc);
112 0 : auto output_queue_obj = obj_fac.create_queue_obj(td_outputq_desc);
113 :
114 : // Net descriptors
115 0 : const NetworkConnectionDescriptor* req_net_desc = nullptr;
116 0 : const NetworkConnectionDescriptor* tc_net_desc = nullptr;
117 0 : const NetworkConnectionDescriptor* ti_net_desc = nullptr;
118 0 : const NetworkConnectionDescriptor* td_net_desc = nullptr;
119 0 : const NetworkConnectionDescriptor* timesync_net_desc = nullptr;
120 :
121 0 : for (auto rule : get_network_rules()) {
122 0 : std::string data_type = rule->get_descriptor()->get_data_type();
123 :
124 : // Network connections for the MLT
125 0 : if (data_type == "TriggerInhibit") {
126 0 : ti_net_desc = rule->get_descriptor();
127 : }
128 0 : if (data_type == "TriggerDecision") {
129 0 : td_net_desc = rule->get_descriptor();
130 : }
131 0 : if (data_type == "TriggerCandidate") {
132 0 : tc_net_desc = rule->get_descriptor();
133 : }
134 0 : if (data_type == "TimeSync") {
135 0 : timesync_net_desc = rule->get_descriptor();
136 : }
137 0 : if (data_type == "DataRequest") {
138 0 : req_net_desc = rule->get_descriptor();
139 : }
140 :
141 0 : TLOG_DEBUG(3) << "Endpoint class (currently not used in for networkconnections): data_type: " << data_type;
142 0 : }
143 :
144 0 : if (!td_net_desc) {
145 0 : throw(BadConf(ERS_HERE, "No MLT network connection for the output TriggerDecision given"));
146 : }
147 0 : if (!ti_net_desc) {
148 0 : throw(BadConf(ERS_HERE, "No MLT network connection for the output TriggerInhibit given"));
149 : }
150 0 : if (!tc_net_desc) {
151 0 : throw(BadConf(ERS_HERE, "No MLT network connection for the Input of TriggerCandidates given"));
152 : }
153 0 : if (!req_net_desc) {
154 0 : throw(BadConf(ERS_HERE, "No MLT network connection for the Input of DataRequests given"));
155 : }
156 : // Network connection for input TriggerInhibit, input TCs
157 :
158 0 : conffwk::ConfigObject ti_net_obj =
159 0 : obj_fac.create_net_obj(ti_net_desc, "");
160 :
161 0 : conffwk::ConfigObject tc_net_obj =
162 0 : obj_fac.create_net_obj(tc_net_desc, ".*");
163 :
164 : // Network connection for output TriggerDecision
165 0 : conffwk::ConfigObject td_net_obj =
166 0 : obj_fac.create_net_obj(td_net_desc, "");
167 :
168 : // Network conection for the input Data Requests
169 0 : conffwk::ConfigObject dr_net_obj =
170 0 : obj_fac.create_net_obj(req_net_desc, UID());
171 :
172 0 : conffwk::ConfigObject timesync_net_obj;
173 0 : if (timesync_net_desc != nullptr) {
174 0 : timesync_net_obj =
175 0 : obj_fac.create_net_obj(timesync_net_desc, ".*");
176 : }
177 :
178 : /**************************************************************
179 : * Instantiate standalone TC generator modules (e.g. random TC generator)
180 : **************************************************************/
181 :
182 0 : auto standalone_TC_maker_confs = get_standalone_candidate_maker_confs();
183 0 : std::vector<conffwk::ConfigObject> generated_tc_conns;
184 0 : generated_tc_conns.reserve(standalone_TC_maker_confs.size());
185 0 : for (auto gen_conf : standalone_TC_maker_confs) {
186 0 : conffwk::ConfigObject gen_obj = obj_fac.create(gen_conf->get_template_for(),
187 0 : gen_conf->UID());
188 0 : gen_obj.set_obj("configuration", &(gen_conf->config_object()));
189 0 : if (gen_conf->get_timestamp_method() == "kTimeSync" && !timesync_net_obj.is_null()) {
190 0 : gen_obj.set_objs("inputs", { ×ync_net_obj });
191 : }
192 :
193 0 : auto tc_net_gen = obj_fac.create_net_obj(tc_net_desc, gen_conf->UID());
194 0 : generated_tc_conns.push_back(tc_net_gen);
195 :
196 0 : gen_obj.set_objs("outputs", { &generated_tc_conns.back() });
197 0 : modules.push_back(obj_fac.get_dal<StandaloneTCMakerModule>(gen_conf->UID()));
198 0 : }
199 :
200 : /**************************************************************
201 : * Create the Data Reader
202 : **************************************************************/
203 0 : auto rdr_conf = get_data_subscriber();
204 0 : if (rdr_conf == nullptr) {
205 : throw(BadConf(ERS_HERE, "No DataReaderModule configuration given"));
206 : }
207 :
208 0 : std::string reader_uid("data-reader-" + UID());
209 0 : std::string reader_class = rdr_conf->get_template_for();
210 0 : TLOG_DEBUG(7) << "creating OKS configuration object for Data subscriber class " << reader_class;
211 0 : conffwk::ConfigObject reader_obj = obj_fac.create(reader_class, reader_uid);
212 0 : reader_obj.set_objs("inputs", { &tc_net_obj });
213 0 : reader_obj.set_objs("outputs", { &input_queue_obj });
214 0 : reader_obj.set_obj("configuration", &rdr_conf->config_object());
215 :
216 0 : modules.push_back(obj_fac.get_dal<DataSubscriberModule>(reader_uid));
217 :
218 : /**************************************************************
219 : * Create the readout map
220 : **************************************************************/
221 :
222 0 : std::vector<const dunedaq::confmodel::Application*> apps = session->enabled_applications();
223 :
224 0 : std::vector<const conffwk::ConfigObject*> sourceIds;
225 :
226 0 : for (auto app : apps) {
227 0 : auto ro_app = app->cast<appmodel::ReadoutApplication>();
228 0 : if (ro_app != nullptr) {
229 0 : auto connections = ro_app->get_detector_connections();
230 : // Interate over all the readout groups
231 0 : for (auto d2d_conn : connections) {
232 0 : if (d2d_conn->is_disabled(*session)) {
233 0 : TLOG_DEBUG(7) << "Ignoring disabled Detector2DaqConnection " << d2d_conn->UID();
234 0 : continue;
235 0 : }
236 :
237 0 : if (d2d_conn->contained_resources().empty()) {
238 0 : throw(BadConf(ERS_HERE, "DetectorToDaqConnection does not contain interfaces"));
239 : }
240 :
241 : // Interate over all the streams
242 0 : for (auto stream : d2d_conn->streams()) {
243 0 : if (stream == nullptr) {
244 0 : throw(BadConf(ERS_HERE, "ReadoutInterface contains something other than DetectorStream"));
245 : }
246 0 : if (stream->is_disabled(*session)) {
247 0 : TLOG_DEBUG(7) << "Ignoring disabled DetectorStream " << stream->UID();
248 0 : continue;
249 0 : }
250 :
251 : // Create SourceIDConf object for the MLT
252 0 : auto id = stream->get_source_id();
253 0 : std::string sourceIdConfUID = "dro-mlt-stream-config-" + std::to_string(id);
254 0 : conffwk::ConfigObject* sourceIdConf = new conffwk::ConfigObject(
255 0 : obj_fac.create("SourceIDConf", sourceIdConfUID));
256 0 : sourceIdConf->set_by_val<uint32_t>("sid", id);
257 : // https://github.com/DUNE-DAQ/daqdataformats/blob/5b99506675a586c8a09123900e224f2371d96df9/include/daqdataformats/detail/SourceID.hxx#L108
258 0 : sourceIdConf->set_by_val<std::string>("subsystem", "Detector_Readout");
259 0 : sourceIds.push_back(sourceIdConf);
260 0 : }
261 : }
262 0 : if (ro_app->get_tp_generation_enabled()) {
263 0 : for (auto sid : ro_app->get_tp_source_ids()) {
264 0 : sourceIds.push_back(&(sid->config_object()));
265 : }
266 : // conffwk::ConfigObject* tpSourceIdConf = new conffwk::ConfigObject();
267 : // confdb->create(dbfile, "SourceIDConf", ro_app->UID()+"-"+ std::to_string(ro_app->get_tp_source_id()),
268 : // *tpSourceIdConf); tpSourceIdConf->set_by_val<uint32_t>("sid", ro_app->get_tp_source_id());
269 : // tpSourceIdConf->set_by_val<std::string>("subsystem", "Trigger");
270 : // sourceIds.push_back(tpSourceIdConf);
271 : }
272 0 : }
273 :
274 0 : auto tpreplay_app = app->cast<appmodel::TPReplayApplication>();
275 0 : if (tpreplay_app != nullptr) {
276 0 : for (auto sid : tpreplay_app->get_tp_source_ids()) {
277 0 : sourceIds.push_back(&(sid->config_object()));
278 : }
279 : }
280 :
281 0 : auto fd_app = app->cast<appmodel::FakeDataApplication>();
282 0 : if (fd_app != nullptr) {
283 :
284 0 : auto producers = fd_app->get_producers();
285 : // Interate over all the FakeDataProd modules
286 0 : for (auto stream : producers) {
287 :
288 0 : if (stream->is_disabled(*session)) {
289 0 : TLOG_DEBUG(7) << "Ignoring disabled FakeDataProdConf " << stream->UID();
290 0 : continue;
291 0 : }
292 :
293 : // Create SourceIDConf object for the MLT
294 0 : auto id = stream->get_source_id();
295 0 : std::string sourceIdConfUID = "dro-mlt-stream-config-" + std::to_string(id);
296 0 : conffwk::ConfigObject* sourceIdConf = new conffwk::ConfigObject(
297 0 : obj_fac.create("SourceIDConf", sourceIdConfUID));
298 0 : sourceIdConf->set_by_val<uint32_t>("sid", id);
299 : // https://github.com/DUNE-DAQ/daqdataformats/blob/5b99506675a586c8a09123900e224f2371d96df9/include/daqdataformats/detail/SourceID.hxx#L108
300 0 : sourceIdConf->set_by_val<std::string>("subsystem", "Detector_Readout");
301 0 : sourceIds.push_back(sourceIdConf);
302 0 : }
303 0 : }
304 :
305 : // SmartDaqApplication now has source_id member, might want to use that but make sure that it's actually a data
306 : // source somehow...
307 0 : auto trg_app = app->cast<appmodel::TriggerApplication>();
308 0 : if (trg_app != nullptr && trg_app->get_source_id() != nullptr) {
309 0 : conffwk::ConfigObject* tcSourceIdConf = new conffwk::ConfigObject(
310 0 : obj_fac.create(
311 : "SourceIDConf",
312 0 : trg_app->UID() + "-" + std::to_string(trg_app->get_source_id()->get_sid())
313 0 : ));
314 0 : tcSourceIdConf->set_by_val<uint32_t>("sid", trg_app->get_source_id()->get_sid());
315 0 : tcSourceIdConf->set_by_val<std::string>("subsystem", trg_app->get_source_id()->get_subsystem());
316 0 : sourceIds.push_back(tcSourceIdConf);
317 : }
318 :
319 : // FIXME: add here same logics for HSI application(s)
320 : //
321 0 : auto hsi_app = app->cast<appmodel::FakeHSIApplication>();
322 0 : if (hsi_app != nullptr && hsi_app->get_source_id() != nullptr) {
323 0 : conffwk::ConfigObject* hsEventSourceIdConf = new conffwk::ConfigObject(
324 0 : obj_fac.create(
325 : "SourceIDConf",
326 0 : hsi_app->UID() + "-" + std::to_string(hsi_app->get_source_id()->get_sid())));
327 0 : hsEventSourceIdConf->set_by_val<uint32_t>("sid", hsi_app->get_source_id()->get_sid());
328 0 : hsEventSourceIdConf->set_by_val<std::string>("subsystem", hsi_app->get_source_id()->get_subsystem());
329 0 : sourceIds.push_back(hsEventSourceIdConf);
330 : }
331 :
332 0 : auto dts_hsi_app = app->cast<appmodel::DTSHSIApplication>();
333 0 : if (dts_hsi_app != nullptr && dts_hsi_app->get_source_id() != nullptr) {
334 0 : conffwk::ConfigObject* hsEventSourceIdConf = new conffwk::ConfigObject(
335 0 : obj_fac.create(
336 : "SourceIDConf",
337 0 : dts_hsi_app->UID() + "-" + std::to_string(dts_hsi_app->get_source_id()->get_sid())
338 : )
339 0 : );
340 0 : hsEventSourceIdConf->set_by_val<uint32_t>("sid", dts_hsi_app->get_source_id()->get_sid());
341 0 : hsEventSourceIdConf->set_by_val<std::string>("subsystem", dts_hsi_app->get_source_id()->get_subsystem());
342 0 : sourceIds.push_back(hsEventSourceIdConf);
343 : }
344 :
345 0 : auto ctb_app = app->cast<appmodel::CTBApplication>();
346 0 : if (ctb_app) {
347 0 : auto sources = ctb_app->get_sources();
348 0 : for ( const auto & s : sources ) {
349 0 : auto src_id_conf_ptr = new conffwk::ConfigObject( obj_fac.create("SourceIDConf",
350 0 : ctb_app->UID() + "-" + s.first ) );
351 0 : src_id_conf_ptr->set_by_val<uint32_t>("sid", s.second->get_sid());
352 0 : src_id_conf_ptr->set_by_val<std::string>("subsystem", s.second->get_subsystem());
353 0 : sourceIds.push_back(src_id_conf_ptr);
354 : } // loop over CTB sources
355 0 : } // CTB app
356 :
357 0 : auto cib_app = app->cast<appmodel::CIBApplication>();
358 0 : if (cib_app) {
359 0 : conffwk::ConfigObject* hsEventSourceIdConf = new conffwk::ConfigObject(
360 0 : obj_fac.create(
361 : "SourceIDConf",
362 0 : cib_app->UID() + "-" + std::to_string(cib_app->get_source_id()->get_sid())
363 : )
364 0 : );
365 0 : hsEventSourceIdConf->set_by_val<uint32_t>("sid", cib_app->get_source_id()->get_sid());
366 0 : hsEventSourceIdConf->set_by_val<std::string>("subsystem", cib_app->get_source_id()->get_subsystem());
367 0 : sourceIds.push_back(hsEventSourceIdConf);
368 : } // CIB app
369 :
370 : } // loop over applications
371 :
372 : // Get mandatory links
373 0 : std::vector<const conffwk::ConfigObject*> mandatory_sids;
374 0 : const TCDataProcessor* tc_dp = tch_conf->get_data_processor()->cast<TCDataProcessor>();
375 0 : if (tc_dp != nullptr) {
376 0 : for (auto m : tc_dp->get_mandatory_links()) {
377 0 : mandatory_sids.push_back(&m->config_object());
378 : }
379 : }
380 :
381 : /**************************************************************
382 : * Create the TC handler
383 : **************************************************************/
384 :
385 : // Process special Network rules!
386 : // Looking for Fragment rules from DFAppplications in current Session
387 0 : auto sessionApps = session->enabled_applications();
388 0 : std::vector<conffwk::ConfigObject> fragOutObjs;
389 0 : for (auto app : sessionApps) {
390 0 : auto dfapp = app->cast<appmodel::DFApplication>();
391 0 : if (dfapp == nullptr)
392 0 : continue;
393 :
394 0 : auto dfNRules = dfapp->get_network_rules();
395 0 : for (auto rule : dfNRules) {
396 0 : auto descriptor = rule->get_descriptor();
397 0 : auto data_type = descriptor->get_data_type();
398 0 : if (data_type == "Fragment") {
399 0 : fragOutObjs.emplace_back(obj_fac.create_net_obj(descriptor, dfapp->UID()));
400 : } // If network rule has TriggerDecision type of data
401 0 : } // Loop over Apps network rules
402 0 : } // loop over Session specific Apps
403 :
404 : // build up the full list of outputs
405 0 : std::vector<const conffwk::ConfigObject*> ti_output_objs;
406 0 : for (auto& fNet : fragOutObjs) {
407 0 : ti_output_objs.push_back(&fNet);
408 : }
409 0 : ti_output_objs.push_back(&output_queue_obj);
410 :
411 0 : auto tch_conf_obj = tch_conf->config_object();
412 0 : if (get_source_id() == nullptr) {
413 0 : throw(BadConf(ERS_HERE, "No source_id associated with this TriggerApplication!"));
414 : }
415 0 : uint32_t source_id = get_source_id()->get_sid();
416 0 : std::string ti_uid(handler_name + "-" + std::to_string(source_id));
417 0 : conffwk::ConfigObject ti_obj = obj_fac.create(tch_class, ti_uid);
418 0 : ti_obj.set_by_val<uint32_t>("source_id", source_id);
419 0 : ti_obj.set_by_val<uint32_t>("detector_id", 1); // 1 == kDAQ
420 0 : ti_obj.set_obj("module_configuration", &tch_conf_obj);
421 0 : ti_obj.set_objs("enabled_source_ids", sourceIds);
422 0 : ti_obj.set_objs("mandatory_source_ids", mandatory_sids);
423 0 : ti_obj.set_objs("inputs", { &input_queue_obj, &dr_net_obj });
424 0 : ti_obj.set_objs("outputs", ti_output_objs);
425 :
426 : // Add to our list of modules to return
427 0 : modules.push_back(obj_fac.get_dal<DataHandlerModule>(ti_uid));
428 :
429 : /**************************************************************
430 : * Instantiate the MLTModule module
431 : **************************************************************/
432 :
433 0 : conffwk::ConfigObject mlt_obj = obj_fac.create(mlt_conf->get_template_for(),
434 0 : mlt_conf->UID());
435 0 : mlt_obj.set_obj("configuration", &(mlt_conf->config_object()));
436 0 : mlt_obj.set_objs("inputs", { &output_queue_obj, &ti_net_obj });
437 0 : mlt_obj.set_objs("outputs", { &td_net_obj });
438 0 : modules.push_back(obj_fac.get_dal<MLTModule>(mlt_conf->UID()));
439 :
440 0 : obj_fac.update_modules(modules);
441 0 : }
442 :
443 : } // namespace appmodel
444 : } // namespace dunedaq
|