LCOV - code coverage report
Current view: top level - appmodel/src - WIECApplication.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 74 0
Test Date: 2026-10-11 15:05:20 Functions: 0.0 % 5 0

            Line data    Source code
       1              : /**
       2              :  * @file DFO.cpp
       3              :  *
       4              :  * Implementation of WIECApplication'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 "ConfigObjectFactory.hpp"
      12              : #include "conffwk/Configuration.hpp"
      13              : #include "logging/Logging.hpp"
      14              : 
      15              : #include "appmodel/NWDetDataReceiver.hpp"
      16              : #include "confmodel/DetectorStream.hpp"
      17              : #include "confmodel/GeoId.hpp"
      18              : #include "confmodel/NetworkInterface.hpp"
      19              : 
      20              : #include "appmodel/WIECApplication.hpp"
      21              : #include "appmodel/appmodelIssues.hpp"
      22              : 
      23              : #include "appmodel/HermesDataSender.hpp"
      24              : #include "appmodel/HermesModule.hpp"
      25              : #include "appmodel/HermesModuleConf.hpp"
      26              : #include "appmodel/IpbusAddressTable.hpp"
      27              : #include "appmodel/WIBModule.hpp"
      28              : #include "appmodel/WIBModuleConf.hpp"
      29              : #include "appmodel/WIBSettings.hpp"
      30              : #include "confmodel/DetectorToDaqConnection.hpp"
      31              : 
      32              : #include <fmt/core.h>
      33              : #include <iostream>
      34              : #include <string>
      35              : #include <vector>
      36              : 
      37              : namespace dunedaq {
      38              : namespace appmodel {
      39              : 
      40              : //-----------------------------------------------------------------------------
      41              : 
      42              : std::vector<const confmodel::ExcludableEntity*>
      43            0 : WIECApplication::contained_excludable_entities() const
      44              : {
      45            0 :   return to_resources(get_detector_connections());
      46              : }
      47              : 
      48              : void
      49            0 : WIECApplication::generate_modules(std::shared_ptr<appmodel::ConfigurationHelper> helper) const
      50              : {
      51            0 :   ConfigObjectFactory obj_fac(this);
      52            0 :   conffwk::Configuration* config = &this->configuration();
      53            0 :   const std::string& dbfile = this->config_object().contained_in();
      54              : 
      55            0 :   std::vector<const confmodel::DaqModule*> modules;
      56              : 
      57            0 :   std::map<std::string, std::vector<const appmodel::HermesDataSender*>> ctrlhost_sender_map;
      58              : 
      59              :   // uint16_t conn_idx = 0;
      60            0 :   for (auto d2d_conn : get_detector_connections()) {
      61              : 
      62              :     // Are we sure?
      63            0 :     if (helper->is_excluded(d2d_conn)) {
      64            0 :       TLOG_DEBUG(7) << "Ignoring excluded DetectorToDaqConnection " << d2d_conn->UID();
      65            0 :       continue;
      66            0 :     }
      67              : 
      68            0 :     TLOG_DEBUG(6) << "Processing DetectorToDaqConnection " << d2d_conn->UID();
      69              : 
      70              :     // Is this check necessary?
      71            0 :     if (d2d_conn->contained_excludable_entities().empty()) {
      72            0 :       throw(BadConf(ERS_HERE, "DetectorToDaqConnection does not contain senders or receivers"));
      73              :     }
      74              : 
      75            0 :     auto det_senders = d2d_conn->senders();
      76            0 :     auto det_receiver = d2d_conn->receiver();
      77              : 
      78              :     // Ensure that receiver is a nw_receiver
      79            0 :     const auto* nw_receiver = det_receiver->cast<appmodel::NWDetDataReceiver>();
      80              : 
      81            0 :     if (!nw_receiver) {
      82            0 :       throw(BadConf(ERS_HERE,
      83            0 :                     fmt::format("WEICApplication requires NWDetDataReceiver, found {} of class {}",
      84            0 :                                 det_receiver->UID(),
      85            0 :                                 det_receiver->class_name())));
      86              :     }
      87              : 
      88              :     // Note on how to exclude the senders.
      89              :     // The hardware interface requires that all the physical links be configured, even if not used for a run.
      90              :     // Consequently, at the configuration level, we should never remove senders from a detector to daq connection.
      91              :     // At most, we should exclude them at the level of the session.
      92              :     // For the same reason, in this code, we create a map of control hosts to senders, without checking if the senders
      93              :     // are excluded. Once the map is created, if all the senders associated to a control hosts are excluded, then we
      94              :     // skip the creation of all related modules.
      95              : 
      96              :     // Loop over senders to create the map of control hosts to senders.
      97            0 :     for (const auto* sender : det_senders) {
      98              : 
      99              :       // Check the sender type, must be a HermesSender
     100            0 :       const auto* hrms_sender = sender->cast<appmodel::HermesDataSender>();
     101            0 :       if (!hrms_sender) {
     102            0 :         throw(BadConf(ERS_HERE, fmt::format("DataSender {} is not a appmodel::HermesDataSender", sender->UID())));
     103              :       }
     104              : 
     105            0 :       ctrlhost_sender_map[hrms_sender->get_control_host()].push_back(hrms_sender);
     106              :     }
     107              : 
     108            0 :     for (const auto& [ctrlhost, senders] : ctrlhost_sender_map) {
     109              : 
     110              :       // If all senders for this control host are excluded, skip creating related modules.
     111              :       // Of course the opposite logic is faster: check if any sender is included.
     112            0 :       bool any_included = false;
     113            0 :       for (const auto* sender : senders) {
     114            0 :         if (helper->is_included(sender)) {
     115              :           any_included = true;
     116              :           break;
     117              :         }
     118              :       }
     119            0 :       if (!any_included) {
     120            0 :         TLOG_DEBUG(6) << "Skipping control host " << ctrlhost << " whose senders are all excluded.";
     121            0 :         continue;
     122            0 :       }
     123              : 
     124              :       // Create WIBModule
     125            0 :       if (this->get_wib_module_conf()) {
     126              : 
     127            0 :         bool enable_fembs[4] = { false, false, false, false };
     128              : 
     129            0 :         for (const auto* sender : senders) {
     130            0 :           for (const auto* det_stream : sender->get_streams()) {
     131              :             // Loop over streams for this sender
     132              :             // Retrieve stream_id and calculate the femb_id
     133            0 :             uint32_t stream_id = det_stream->get_geo_id()->get_stream_id();
     134            0 :             uint32_t femb_id = (stream_id & 0xf) / 2 + 2 * ((stream_id >> 6) & 0xf);
     135              : 
     136              :             // std::cout << std::format("stream {} -> femb {}", stream_id, femb_id) << std::endl;
     137              : 
     138              :             // Enable the femb if any of the associated streams is enabled
     139            0 :             enable_fembs[femb_id] |= helper->is_included(det_stream);
     140              :           } // loop over streams
     141              :         } // loop over senders for this control host
     142              : 
     143            0 :         std::string wib_uid = fmt::format("wib-ctrl-{}-{}", this->UID(), ctrlhost);
     144            0 :         conffwk::ConfigObject wib_obj = obj_fac.create("WIBModule", wib_uid);
     145            0 :         wib_obj.set_by_val<std::string>("wib_addr",
     146            0 :                                         fmt::format("{}://{}:{}",
     147            0 :                                                     this->get_wib_module_conf()->get_communication_type(),
     148              :                                                     ctrlhost,
     149            0 :                                                     this->get_wib_module_conf()->get_communication_port()));
     150            0 :         for (int i = 0; i < 4; ++i) {
     151            0 :           wib_obj.set_by_val<bool>(fmt::format("enabled_femb{}", i), enable_fembs[i]);
     152              :         }
     153            0 :         wib_obj.set_obj("conf", &this->get_wib_module_conf()->get_settings()->config_object());
     154            0 :         modules.push_back(config->get<appmodel::WIBModule>(wib_obj));
     155            0 :       } // if we have a module configuration for the WIB module
     156              : 
     157              :       // Create Hermes Modules
     158            0 :       if (this->get_hermes_module_conf()) {
     159            0 :         std::string hermes_uid = fmt::format("hermes-ctrl-{}-{}", this->UID(), ctrlhost);
     160            0 :         conffwk::ConfigObject hermes_obj = obj_fac.create("HermesModule", hermes_uid);
     161            0 :         hermes_obj.set_obj("address_table", &this->get_hermes_module_conf()->get_address_table()->config_object());
     162            0 :         hermes_obj.set_by_val<std::string>("uri",
     163            0 :                                            fmt::format("{}://{}:{}",
     164            0 :                                                        this->get_hermes_module_conf()->get_ipbus_type(),
     165              :                                                        ctrlhost,
     166            0 :                                                        this->get_hermes_module_conf()->get_ipbus_port()));
     167            0 :         hermes_obj.set_by_val<uint32_t>("timeout_ms", this->get_hermes_module_conf()->get_ipbus_timeout_ms());
     168            0 :         hermes_obj.set_obj("destination", &nw_receiver->get_uses()->config_object());
     169              : 
     170            0 :         std::vector<const conffwk::ConfigObject*> links_obj;
     171            0 :         for (const auto* sndr : senders) {
     172              :           // Note that it is OK that some of these senders might be excluded
     173              :           // The hardware interface in HermesModule requires that all links be configured, even if not used for a run
     174            0 :           links_obj.push_back(&sndr->config_object());
     175              :         }
     176            0 :         hermes_obj.set_objs("links", links_obj);
     177              : 
     178            0 :         modules.push_back(config->get<appmodel::HermesModule>(hermes_obj));
     179            0 :       } // If we have a module configuration for the Hermes module
     180              : 
     181              :     } // loop over control hosts
     182              : 
     183            0 :   } // loop over detector to daq connections
     184              : 
     185            0 :   obj_fac.update_modules(modules);
     186            0 : }
     187              : 
     188              : } // namespace appmodel
     189              : } // namespace dunedaq
        

Generated by: LCOV version 2.0-1