LCOV - code coverage report
Current view: top level - daphnemodules/plugins - DaphneV3ControllerModule.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 148 0
Test Date: 2026-10-11 15:05:20 Functions: 0.0 % 16 0

            Line data    Source code
       1              : /**
       2              :  * @file DaphneV3ControllerModule.cpp
       3              :  *
       4              :  * Implementation of the DAQModule to control the Daphne mezzanine board
       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 "DaphneV3ControllerModule.hpp"
      12              : #include "daphnemodules/daphne_control_high.pb.h"
      13              : #include "daphnemodules/daphne_control_low.pb.h"
      14              : #include "logging/Logging.hpp"
      15              : 
      16              : #include "appmodel/DaphneConf.hpp"
      17              : #include "appmodel/DaphneV2ADC.hpp"
      18              : #include "appmodel/DaphneV2AFE.hpp"
      19              : #include "appmodel/DaphneV2BoardConf.hpp"
      20              : #include "appmodel/DaphneV2Channel.hpp"
      21              : #include "appmodel/DaphneV2LNA.hpp"
      22              : #include "appmodel/DaphneV2PGA.hpp"
      23              : 
      24              : #include "daphnemodules/opmon/DaphneControllerModule.pb.h"
      25              : 
      26              : #include <fmt/format.h>
      27              : #include <zmq.hpp>
      28              : 
      29              : #include <memory>
      30              : #include <regex>
      31              : #include <string>
      32              : #include <utility>
      33              : 
      34              : namespace dunedaq::daphnemodules {
      35              : 
      36            0 : DaphneV3ControllerModule::DaphneV3ControllerModule(const std::string& name)
      37            0 :   : appfwk::DAQModule(name)
      38              : {
      39            0 :   register_command("conf", &DaphneV3ControllerModule::do_conf);
      40            0 :   register_command("start", &DaphneV3ControllerModule::do_start);
      41            0 :   register_command("scrap", &DaphneV3ControllerModule::do_scrap);
      42            0 : }
      43              : 
      44              : void
      45            0 : DaphneV3ControllerModule::init(std::shared_ptr<appfwk::ConfigurationManager> cfg)
      46              : {
      47            0 :   auto mdal = cfg->get_dal<conf_t>(get_name());
      48            0 :   if (!mdal) {
      49            0 :     throw ConfigurationFailed(ERS_HERE, get_name());
      50              :   }
      51            0 :   m_module_config = mdal;
      52            0 : }
      53              : 
      54              : void
      55            0 : DaphneV3ControllerModule::do_conf(const CommandData_t&)
      56              : {
      57              : 
      58            0 :   const std::lock_guard<std::mutex> lock(m_mutex);
      59              : 
      60            0 :   TLOG() << get_name() << " starting configuring";
      61            0 :   auto start_time = std::chrono::high_resolution_clock::now();
      62              : 
      63            0 :   using namespace daphne;
      64              : 
      65            0 :   auto board_conf = m_module_config->get_board_conf();
      66            0 :   auto general_conf = m_module_config->get_daphne_conf();
      67              : 
      68            0 :   create_interface(board_conf->get_address(), general_conf->get_timeout());
      69              : 
      70              :   // validation to be taken from the previous version
      71              :   // this should include the slot check
      72            0 :   validate_configuration(*board_conf);
      73              : 
      74            0 :   configure_analog_chain(true);
      75              : 
      76            0 :   auto end_time = std::chrono::high_resolution_clock::now();
      77              : 
      78            0 :   auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time);
      79            0 :   TLOG() << get_name() << ": board configured in " << duration.count() << " microseconds";
      80            0 : }
      81              : 
      82              : void
      83            0 : DaphneV3ControllerModule::do_start(const CommandData_t&)
      84              : {
      85            0 :   ;
      86            0 : }
      87              : void
      88            0 : DaphneV3ControllerModule::do_scrap(const CommandData_t&)
      89              : {
      90              : 
      91            0 :   m_scrap_called.store(true);
      92            0 :   const std::lock_guard<std::mutex> lock(m_mutex);
      93              : 
      94            0 :   TLOG() << get_name() << " starting scrap";
      95            0 :   auto start_time = std::chrono::high_resolution_clock::now();
      96              : 
      97            0 :   using namespace daphne;
      98              : 
      99            0 :   configure_analog_chain(false);
     100              : 
     101            0 :   m_iface = nullptr;
     102              : 
     103            0 :   auto end_time = std::chrono::high_resolution_clock::now();
     104            0 :   auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time);
     105            0 :   TLOG() << get_name() << ": scrapped in " << duration.count() << " microseconds";
     106            0 : }
     107              : 
     108              : void
     109            0 : DaphneV3ControllerModule::configure_analog_chain(bool initial_config)
     110              : {
     111              : 
     112            0 :   auto general_conf = m_module_config->get_daphne_conf();
     113            0 :   auto board_conf = initial_config ? m_module_config->get_board_conf() : general_conf->get_default_v3_settings();
     114              : 
     115              :   // Step 1: Build the ConfigureRequest
     116            0 :   daphne::ConfigureRequest req;
     117            0 :   req.set_daphne_address(board_conf->get_address());
     118            0 :   req.set_slot(board_conf->get_slot_id());
     119            0 :   req.set_timeout_ms(general_conf->get_timeout_ms());
     120            0 :   req.set_biasctrl(board_conf->get_bias_ctrl());
     121            0 :   req.set_self_trigger_threshold(board_conf->get_self_trigger_threshold());
     122            0 :   req.set_self_trigger_xcorr(board_conf->get_self_trigger_xcorr());
     123            0 :   req.set_tp_conf(board_conf->get_tp_conf());
     124            0 :   req.set_compensator(board_conf->get_compensator());
     125            0 :   req.set_inverters(board_conf->get_inverter());
     126              : 
     127            0 :   for (ChannelId ch = 0; ch < s_max_channels; ++ch) {
     128              : 
     129            0 :     const auto& channel_conf = board_conf->get_channel(ch);
     130              :     // get_channel returns the running value if the bool argument is true,
     131              :     // and the default values when the bool argument is false
     132              :     // hence, this loop does both the job of enabling and disebling
     133              : 
     134            0 :     auto* channel = req.add_channels();
     135            0 :     channel->set_id(ch);
     136            0 :     channel->set_trim(channel_conf.get_trim());
     137            0 :     channel->set_offset(channel_conf.get_offset());
     138            0 :     channel->set_gain(channel_conf.get_gain());
     139              : 
     140              :   } // loop over channels
     141              : 
     142            0 :   for (AFEId id = 0; id < s_max_afes; ++id) {
     143              : 
     144            0 :     const auto& afe_conf = board_conf->get_afe(id);
     145              : 
     146            0 :     auto* afe = req.add_afes();
     147            0 :     afe->set_id(id);
     148            0 :     afe->set_attenuators(afe_conf.get_attenuator());
     149            0 :     afe->set_v_bias(afe_conf.get_v_bias());
     150              : 
     151            0 :     auto* adc = afe_conf.get_adc();
     152            0 :     afe->mutable_adc()->set_resolution(adc->get_low_resolution());
     153            0 :     afe->mutable_adc()->set_output_format(adc->get_output_offset_binary());
     154            0 :     afe->mutable_adc()->set_sb_first(adc->get_MSB_first());
     155              : 
     156            0 :     auto* pga = afe_conf.get_pga();
     157            0 :     afe->mutable_pga()->set_lpf_cut_frequency(pga->get_lpf_cut_frequency());
     158            0 :     afe->mutable_pga()->set_integrator_disable(pga->get_integrator_disable());
     159            0 :     afe->mutable_pga()->set_gain(pga->get_gain());
     160              : 
     161            0 :     auto* lna = afe_conf.get_lna();
     162            0 :     afe->mutable_lna()->set_clamp(lna->get_clamp());
     163            0 :     afe->mutable_lna()->set_gain(lna->get_gain());
     164            0 :     afe->mutable_lna()->set_integrator_disable(lna->get_integrator_disable());
     165              : 
     166              :   } // loop over AFE
     167              : 
     168            0 :   TLOG() << get_name() << ": Configuration message ready to send";
     169              : 
     170            0 :   auto response = m_iface.load()->send<daphne::ConfigureResponse>(
     171            0 :     req.SerializeAsString(), daphne::MT2_CONFIGURE_FE_REQ, daphne::MT2_CONFIGURE_FE_RESP);
     172              : 
     173            0 :   if (!response.success()) {
     174            0 :     throw UnsuccessfulConfiguration(ERS_HERE, get_name(), response.message());
     175              :   }
     176              : 
     177            0 :   TLOG() << "Success message: " << response.message();
     178            0 : }
     179              : 
     180              : void
     181            0 : DaphneV3ControllerModule::create_interface(const std::string& address, std::chrono::milliseconds timeout)
     182              : {
     183              : 
     184            0 :   m_iface = make_unique<DaphneV3Interface>(address, get_name(), timeout);
     185            0 : }
     186              : 
     187              : void
     188            0 : DaphneV3ControllerModule::validate_configuration(const appmodel::DaphneV2BoardConf& c) const
     189              : {
     190              : 
     191            0 :   const auto& channel_confs = c.get_active_channels();
     192              : 
     193            0 :   for (const auto& ch : channel_confs) {
     194            0 :     auto id = ch->get_channel_id();
     195              : 
     196              :     // CH OFFSET maximum is 2700 if GAIN is 1, 1500 if GAIN is 2
     197            0 :     auto gain = ch->get_gain();
     198            0 :     if (gain != 1 && gain != 2) {
     199            0 :       throw InvalidChannelConfiguration(ERS_HERE, id, ch->get_trim(), ch->get_offset(), gain);
     200              :     }
     201            0 :     auto offset = ch->get_offset();
     202            0 :     if (gain == 1) {
     203            0 :       if (offset > 2700) {
     204            0 :         throw InvalidChannelConfiguration(ERS_HERE, id, ch->get_trim(), offset, gain);
     205              :       }
     206            0 :     } else if (gain == 2) {
     207            0 :       if (offset > 1500) {
     208            0 :         throw InvalidChannelConfiguration(ERS_HERE, id, ch->get_trim(), offset, gain);
     209              :       }
     210              :     }
     211              :   } // loop over channels
     212              : 
     213            0 :   auto size = c.get_full_stream_channels().size();
     214            0 :   if (size > 16) {
     215              :     // we can only stream 16 channels at most
     216            0 :     throw TooManyChannels(ERS_HERE, size);
     217              :   }
     218            0 : }
     219              : 
     220              : void
     221            0 : DaphneV3ControllerModule::generate_opmon_data()
     222              : {
     223              : 
     224            0 :   if (!m_iface.load())
     225            0 :     return;
     226              : 
     227            0 :   if (m_scrap_called.load())
     228              :     return;
     229              : 
     230            0 :   std::unique_lock<std::mutex> lock(m_mutex);
     231              : 
     232            0 :   daphne::ReadTriggerCountersRequest req;
     233            0 :   auto response = m_iface.load()->send<daphne::ReadTriggerCountersResponse>(
     234            0 :     req.SerializeAsString(), daphne::MT2_READ_TRIGGER_COUNTERS_REQ, daphne::MT2_READ_TRIGGER_COUNTERS_RESP);
     235              : 
     236            0 :   if (!response.success()) {
     237            0 :     ers::warning(TriggerMonitoringFailed(ERS_HERE, get_name(), response.message()));
     238            0 :     return;
     239              :   }
     240              : 
     241            0 :   lock.unlock();
     242              : 
     243            0 :   const auto& snapshots = response.snapshots();
     244              : 
     245            0 :   static uint32_t def_threshold = 0x3ff; // NOLINT
     246              : 
     247            0 :   for (const auto& c : snapshots) {
     248              : 
     249              :     // we only publish channels info when threshold is not default or the counters are not zero
     250            0 :     if (c.threshold() == def_threshold && c.record_count() == 0 && c.busy_count() == 0 && c.full_count() == 0)
     251            0 :       continue;
     252              : 
     253            0 :     opmon::TempTriggerSnapshotInfo info;
     254            0 :     info.set_threshold(c.threshold());
     255            0 :     info.set_record_count(c.record_count());
     256            0 :     info.set_busy_count(c.busy_count());
     257            0 :     info.set_full_count(c.full_count());
     258              : 
     259            0 :     publish(std::move(info), { { "channel", fmt::format("{}", c.channel()) } });
     260            0 :   }
     261              : 
     262            0 :   lock.lock();
     263              : 
     264              :   // The request for the general info has no payload, so the first argument is 0
     265            0 :   auto info_response = m_iface.load()->send<daphne::GeneralInfo>(
     266            0 :     "", daphne::MT2_READ_GENERAL_INFO_REQ, daphne::MT2_READ_GENERAL_INFO_RESP);
     267              : 
     268            0 :   lock.unlock();
     269              : 
     270            0 :   opmon::GeneralInfo info;
     271            0 :   info.set_v_bias_0(info_response.v_bias_0());
     272            0 :   info.set_v_bias_1(info_response.v_bias_1());
     273            0 :   info.set_v_bias_2(info_response.v_bias_2());
     274            0 :   info.set_v_bias_3(info_response.v_bias_3());
     275            0 :   info.set_v_bias_4(info_response.v_bias_4());
     276              : 
     277            0 :   info.set_power_minus5v(info_response.power_minus5v());
     278            0 :   info.set_power_plus2p5v(info_response.power_plus2p5v());
     279            0 :   info.set_power_ce(info_response.power_ce());
     280            0 :   info.set_temperature(info_response.temperature());
     281              : 
     282            0 :   publish(std::move(info));
     283            0 : }
     284              : 
     285              : } // namespace dunedaq::daphnemodules
     286              : 
     287            0 : DEFINE_DUNE_DAQ_MODULE(dunedaq::daphnemodules::DaphneV3ControllerModule)
        

Generated by: LCOV version 2.0-1