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

Generated by: LCOV version 2.0-1