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

            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
        

Generated by: LCOV version 2.0-1