LCOV - code coverage report
Current view: top level - hsilibs/plugins - HSIController.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 206 0
Test Date: 2025-12-21 13:07:08 Functions: 0.0 % 41 0

            Line data    Source code
       1              : /**
       2              :  * @file HSIController.cpp HSIController class
       3              :  * implementation
       4              :  *
       5              :  * This is part of the DUNE DAQ Software Suite, copyright 2020.
       6              :  * Licensing/copyright details are in the COPYING file that you should have
       7              :  * received with this code.
       8              :  */
       9              : 
      10              : #include "HSIController.hpp"
      11              : #include "hsilibs/dal/HSIController.hpp"
      12              : 
      13              : #include "timinglibs/TimingIssues.hpp"
      14              : #include "timinglibs/timingcmd/Nljs.hpp"
      15              : #include "timinglibs/timingcmd/Structs.hpp"
      16              : 
      17              : #include "timing/HSIDesignInterface.hpp"
      18              : #include "timinglibs/dal/TimingController.hpp"
      19              : 
      20              : #include "timing/timingfirmwareinfo/Nljs.hpp"
      21              : #include "timing/timingfirmwareinfo/Structs.hpp"
      22              : 
      23              : #include "hsilibs/opmon/hsi_controller_info.pb.cc"
      24              : 
      25              : #include "ers/Issue.hpp"
      26              : #include "logging/Logging.hpp"
      27              : 
      28              : #include <chrono>
      29              : #include <cstdlib>
      30              : #include <string>
      31              : #include <thread>
      32              : #include <vector>
      33              : 
      34              : namespace dunedaq {
      35              : namespace hsilibs {
      36              : 
      37            0 : HSIController::HSIController(const std::string& name)
      38              :   : dunedaq::timinglibs::TimingEndpointControllerBase(name, 9) // 2nd arg: how many hw commands can this module send?
      39            0 :   , m_control_hardware_io(false)
      40            0 :   , m_clock_frequency(62.5e6)
      41            0 :   , m_thread(std::bind(&HSIController::gather_monitor_data, this, std::placeholders::_1))
      42              : {
      43              :   // this controller talks to the hw directly
      44            0 :   m_hw_command_out_connection = "";
      45              : 
      46            0 :   register_command("conf", &HSIController::do_configure);
      47            0 :   register_command("start", &HSIController::do_start);
      48            0 :   register_command("stop_trigger_sources", &HSIController::do_stop);
      49            0 :   register_command("scrap", &HSIController::do_scrap);
      50              :   
      51              :   // hsi hardware commands
      52              :   //register_command("hsi_reset", &HSIController::do_hsi_reset);
      53              :   //register_command("hsi_configure", &HSIController::do_hsi_configure);
      54              :   //register_command("hsi_start", &HSIController::do_hsi_start);
      55              :   //register_command("hsi_stop", &HSIController::do_hsi_stop);
      56              :   //register_command("hsi_print_status", &HSIController::do_hsi_print_status);
      57            0 : }
      58              : 
      59              : void
      60            0 : HSIController::init(std::shared_ptr<appfwk::ConfigurationManager> mcfg)
      61              : {
      62            0 :   TimingController::init(mcfg);
      63            0 :   auto mod_config = mcfg->get_dal<hsilibs::dal::HSIController>(get_name());
      64            0 :   m_hsi_configuration = mod_config->get_configuration()->cast<hsilibs::dal::HSIControllerConf>();
      65            0 : }
      66              : 
      67              : void
      68            0 : HSIController::do_configure(const CommandData_t& data)
      69              : {
      70            0 :   TimingController::do_configure(data);
      71              : 
      72            0 :   m_control_hardware_io = m_hsi_configuration->get_control_hardware_io();
      73              : 
      74            0 :   configure_uhal(m_hsi_configuration); // configure hw ipbus connection
      75              : 
      76            0 :   try
      77              :   {
      78            0 :     m_hsi_device = std::make_unique<uhal::HwInterface>(m_connection_manager->getDevice(m_timing_device));
      79            0 :   } catch (const uhal::exception::ConnectionUIDDoesNotExist& exception) {
      80            0 :     std::stringstream message;
      81            0 :     message << "UHAL device name not " << m_timing_device << " in connections file";
      82            0 :     throw timinglibs::UHALDeviceNameIssue(ERS_HERE, message.str(), exception);
      83            0 :   }
      84              : 
      85            0 :   m_thread.start_working_thread("gather-hsi-info");
      86              : 
      87            0 :   configure_hardware_or_recover_state<timinglibs::TimingEndpointNotReady>(data, "HSI endpoint", m_endpoint_state);
      88              : 
      89            0 :   TLOG() << get_name() << " conf done for hsi endpoint, device: " << m_timing_device;
      90            0 : }
      91              : 
      92              : void
      93            0 : HSIController::do_start(const CommandData_t& data)
      94              : {
      95            0 :   TimingController::do_start(data); // set sent cmd counters to 0
      96            0 :   do_hsi_start(data);
      97            0 : }
      98              : 
      99              : void
     100            0 : HSIController::do_stop(const CommandData_t& data)
     101              : {
     102            0 :   do_hsi_stop(data);
     103            0 : }
     104              : 
     105              : void
     106            0 : HSIController::do_scrap(const CommandData_t& data)
     107              : {
     108            0 :   m_thread.stop_working_thread();
     109            0 :   scrap_uhal();
     110              : 
     111            0 :   m_timing_device="";
     112            0 :   m_control_hardware_io=false;
     113            0 :   m_endpoint_state = 0x0;
     114              : 
     115            0 :   TimingController::do_scrap(data);
     116            0 : }
     117              : 
     118              : void
     119            0 : HSIController::send_configure_hardware_commands(const CommandData_t& data)
     120              : {
     121            0 :   if (m_control_hardware_io)
     122              :   {
     123            0 :     m_thread.stop_working_thread();
     124            0 :     do_io_reset(data);
     125            0 :     m_thread.start_working_thread("gather-hsi-info");
     126              :   }
     127            0 :   do_hsi_reset(data);
     128            0 :   do_endpoint_reset(data);
     129            0 :   do_hsi_configure();
     130            0 : }
     131              : 
     132              : void
     133            0 : HSIController::do_io_reset(const CommandData_t&)
     134              : {
     135            0 :   auto design = dynamic_cast<const timing::HSIDesignInterface*>(&m_hsi_device->getNode(""));
     136              : 
     137            0 :   auto clock_config = m_hsi_configuration->get_clock_config();
     138            0 :   if (m_hsi_configuration->get_soft()) {
     139            0 :     TLOG_DEBUG(0) << get_name() << ": " << m_timing_device << " soft io reset";
     140            0 :     design->soft_reset_io();
     141            0 :   } else if (!clock_config.empty()) {
     142            0 :     TLOG_DEBUG(0) << get_name() << ": " << m_timing_device
     143            0 :                   << " io reset, with supplied clk file: " << clock_config;
     144            0 :     design->reset_io(clock_config);
     145              :   }
     146              :   else
     147              :   {
     148            0 :     TLOG_DEBUG(0) << get_name() << ": " << m_timing_device
     149            0 :                   << " io reset, with supplied clk source: " << m_hsi_configuration->get_clock_source();
     150            0 :     design->reset_io(static_cast<timing::ClockSource>(m_hsi_configuration->get_clock_source()));
     151              :   }
     152              : 
     153            0 :   ++(m_sent_hw_command_counters.at(0).atomic);
     154            0 : }
     155              : 
     156              : void
     157            0 : HSIController::do_endpoint_enable(const CommandData_t& /*data*/)
     158              : {
     159            0 :   auto ept_address = m_hsi_configuration->get_address();
     160            0 :   TLOG_DEBUG(0) << "ept enable hw cmd; a: " << ept_address;
     161              : 
     162            0 :   auto design = dynamic_cast<const timing::HSIDesignInterface*>(&m_hsi_device->getNode(""));
     163            0 :   design->get_endpoint_node_plain(m_managed_endpoint_id)->enable(ept_address, 0);
     164              : 
     165            0 :   ++(m_sent_hw_command_counters.at(1).atomic);
     166            0 : }
     167              : 
     168              : void
     169            0 : HSIController::do_endpoint_disable(const CommandData_t& /*data*/)
     170              : {
     171            0 :   TLOG_DEBUG(0) << "ept disable hw cmd";
     172              : 
     173            0 :   auto design = dynamic_cast<const timing::HSIDesignInterface*>(&m_hsi_device->getNode(""));
     174            0 :   design->get_endpoint_node_plain(m_managed_endpoint_id)->disable();
     175            0 :   ++(m_sent_hw_command_counters.at(2).atomic);
     176            0 : }
     177              : 
     178              : void
     179            0 : HSIController::do_endpoint_reset(const CommandData_t& /*data*/)
     180              : {
     181            0 :   auto ept_address = m_hsi_configuration->get_address();
     182            0 :   TLOG_DEBUG(0) << "ept reset hw cmd; a: " << ept_address;
     183              : 
     184            0 :   auto design = dynamic_cast<const timing::HSIDesignInterface*>(&m_hsi_device->getNode(""));
     185            0 :   design->get_endpoint_node_plain(m_managed_endpoint_id)->reset(ept_address, 0);
     186            0 :   ++(m_sent_hw_command_counters.at(3).atomic);
     187            0 : }
     188              : 
     189              : void
     190            0 : HSIController::do_hsi_reset(const nlohmann::json&)
     191              : {
     192            0 :   TLOG_DEBUG(0) << get_name() << ": " << m_timing_device << " hsi reset";
     193              : 
     194            0 :   auto design = dynamic_cast<const timing::HSIDesignInterface*>(&m_hsi_device->getNode(""));
     195            0 :   design->get_hsi_node().reset_hsi();
     196            0 :   ++(m_sent_hw_command_counters.at(4).atomic);
     197            0 : }
     198              : 
     199              : void
     200            0 : HSIController::do_hsi_configure()
     201              : {
     202            0 :   TLOG_DEBUG(0) << get_name() << ": " << m_timing_device << ", hsi configure";
     203            0 :   auto random_rate = m_hsi_configuration->get_trigger_rate();
     204            0 :   do_hsi_configure(random_rate);
     205            0 : }
     206              : 
     207              : void
     208            0 : HSIController::do_hsi_configure(double random_rate)
     209              : {
     210            0 :   TLOG_DEBUG(0) << get_name() << ": " << m_timing_device << " hsi configure";
     211              : 
     212            0 :   auto data_source = m_hsi_configuration->get_data_source();
     213            0 :   auto rising_edge_mask = m_hsi_configuration->get_rising_edge_mask();
     214            0 :   auto falling_edge_mask = m_hsi_configuration->get_falling_edge_mask();
     215            0 :   auto invert_edge_mask = m_hsi_configuration->get_invert_edge_mask();
     216              : 
     217            0 :   if (random_rate <= 0) {
     218            0 :     throw timinglibs::InvalidTriggerRateValue(ERS_HERE, random_rate);
     219              :   }
     220              : 
     221            0 :   TLOG_DEBUG(0) << get_name() << " Setting emulated event rate [Hz] to: "
     222            0 :          << random_rate;
     223              : 
     224            0 :   auto design = dynamic_cast<const timing::HSIDesignInterface*>(&m_hsi_device->getNode(""));
     225            0 :   design->configure_hsi(
     226              :     data_source, rising_edge_mask, falling_edge_mask, invert_edge_mask, random_rate);
     227            0 :   ++(m_sent_hw_command_counters.at(5).atomic);
     228            0 : }
     229              : 
     230              : void
     231            0 : HSIController::do_hsi_start(const nlohmann::json&)
     232              : {
     233            0 :    TLOG_DEBUG(0) << get_name() << ": " << m_timing_device << " hsi start";
     234              : 
     235            0 :   auto design = dynamic_cast<const timing::HSIDesignInterface*>(&m_hsi_device->getNode(""));
     236            0 :   design->get_hsi_node().start_hsi();
     237            0 :   ++(m_sent_hw_command_counters.at(6).atomic);
     238            0 : }
     239              : 
     240              : void
     241            0 : HSIController::do_hsi_stop(const nlohmann::json&)
     242              : {
     243            0 :   TLOG_DEBUG(0) << get_name() << ": " << m_timing_device << " hsi stop";
     244              : 
     245            0 :   auto design = dynamic_cast<const timing::HSIDesignInterface*>(&m_hsi_device->getNode(""));
     246            0 :   design->get_hsi_node().stop_hsi();
     247            0 :   ++(m_sent_hw_command_counters.at(7).atomic);
     248            0 : }
     249              : 
     250              : void
     251            0 : HSIController::do_hsi_print_status(const nlohmann::json&)
     252              : {
     253            0 :   TLOG_DEBUG(0) << get_name() << ": " << m_timing_device << " hsi print status";
     254              : 
     255            0 :   auto design = dynamic_cast<const timing::HSIDesignInterface*>(&m_hsi_device->getNode(""));
     256            0 :   TLOG_DEBUG(0) << std::endl << design->get_hsi_node().get_status();
     257            0 :   ++(m_sent_hw_command_counters.at(8).atomic);
     258            0 : }
     259              : 
     260              : void
     261            0 : HSIController::generate_opmon_data()
     262              : {
     263              :   // send counters internal to the module
     264            0 :   opmon::HSIControllerInfo info;
     265            0 :   info.set_sent_hsi_io_reset_cmds(m_sent_hw_command_counters.at(0).atomic);
     266            0 :   info.set_sent_hsi_endpoint_enable_cmds(m_sent_hw_command_counters.at(1).atomic);
     267            0 :   info.set_sent_hsi_endpoint_disable_cmds(m_sent_hw_command_counters.at(2).atomic);
     268            0 :   info.set_sent_hsi_endpoint_reset_cmds(m_sent_hw_command_counters.at(3).atomic);
     269            0 :   info.set_sent_hsi_reset_cmds(m_sent_hw_command_counters.at(4).atomic);
     270            0 :   info.set_sent_hsi_configure_cmds(m_sent_hw_command_counters.at(5).atomic);
     271            0 :   info.set_sent_hsi_start_cmds(m_sent_hw_command_counters.at(6).atomic);
     272            0 :   info.set_sent_hsi_stop_cmds(m_sent_hw_command_counters.at(7).atomic);
     273            0 :   info.set_sent_hsi_print_status_cmds(m_sent_hw_command_counters.at(8).atomic);
     274            0 :   info.set_device_infos_received_count(m_device_infos_received_count);
     275              : 
     276            0 :   publish(std::move(info));
     277            0 : }
     278              : 
     279              : void
     280            0 : HSIController::process_device_info(nlohmann::json info)
     281              : {
     282            0 :   ++m_device_infos_received_count;
     283              : 
     284            0 :   timing::timingfirmwareinfo::TimingDeviceInfo device_info;
     285            0 :   from_json(info, device_info);
     286              : 
     287            0 :   auto ept_info = device_info.endpoint_info;
     288            0 :   m_endpoint_state = device_info.endpoint_info.state;
     289            0 :   bool ready = ept_info.ready;
     290              : 
     291            0 :   bool ept_good = (m_endpoint_state == 0x8) && ready;
     292              : 
     293            0 :   auto hsi_info = device_info.hsi_info;
     294            0 :   auto buffer_enabled = hsi_info.buffer_enabled;
     295            0 :   auto buffer_error = hsi_info.buffer_error;
     296            0 :   auto buffer_warning = hsi_info.buffer_warning;
     297            0 :   auto re_mask = hsi_info.re_mask;
     298            0 :   auto fe_mask = hsi_info.fe_mask;
     299            0 :   auto inv_mask = hsi_info.inv_mask;
     300            0 :   auto data_source = hsi_info.source;
     301              : 
     302            0 :   bool hsi_good = buffer_enabled && !buffer_error && !buffer_warning
     303            0 :                   && re_mask == m_hsi_configuration->get_rising_edge_mask()
     304            0 :                   && fe_mask == m_hsi_configuration->get_falling_edge_mask()
     305            0 :                   && inv_mask == m_hsi_configuration->get_invert_edge_mask()
     306            0 :                   && data_source == m_hsi_configuration->get_data_source();
     307              : 
     308            0 :   TLOG_DEBUG(0) << "EPT good: " << ept_good << ", HSI good: " << hsi_good << ", infos received: " << m_device_infos_received_count;
     309              : 
     310            0 :   TLOG_DEBUG(0) << "device data: " << info.dump();
     311              : 
     312            0 :   if (ept_good && hsi_good)
     313              :   {
     314            0 :     if (!m_device_ready)
     315              :     {
     316            0 :       m_device_ready = true;
     317            0 :       TLOG_DEBUG(2) << "HSI device became ready";
     318              :     }
     319              :   }
     320              :   else
     321              :   {
     322            0 :     if (m_device_ready)
     323              :     {
     324            0 :       m_device_ready = false;
     325            0 :       TLOG_DEBUG(2) << "HSI device no longer ready";
     326              :     }
     327              :   }
     328            0 : }
     329              : 
     330              : void
     331            0 : HSIController::gather_monitor_data(std::atomic<bool>& running_flag)
     332              : {
     333            0 :   while (running_flag.load()) {
     334              : 
     335            0 :     timing::timingfirmwareinfo::TimingDeviceInfo device_info;
     336              :     // collect the data from the hardware
     337            0 :     try
     338              :     {
     339            0 :       auto design = cast_timing_device<const timing::HSIDesignInterface*>(&m_hsi_device->getNode(""), m_timing_device);
     340            0 :       design->get_info(device_info);
     341            0 :     } catch (const std::exception& excpt) {
     342            0 :       ers::warning(timinglibs::FailedToCollectOpMonInfo(ERS_HERE, m_timing_device, excpt));
     343            0 :     }
     344              : 
     345            0 :     nlohmann::json info;
     346            0 :     to_json(info, device_info);
     347            0 :     process_device_info(info);
     348              : 
     349            0 :     auto prev_gather_time = std::chrono::steady_clock::now();
     350            0 :     auto next_gather_time = prev_gather_time + std::chrono::milliseconds(500);
     351              : 
     352              :     // check running_flag periodically
     353            0 :     auto slice_period = std::chrono::microseconds(10000);
     354            0 :     auto next_slice_gather_time = prev_gather_time + slice_period;
     355              : 
     356            0 :     bool break_flag = false;
     357            0 :     while (next_gather_time > next_slice_gather_time + slice_period) {
     358            0 :       if (!running_flag.load()) {
     359            0 :         TLOG_DEBUG(0) << "while waiting to gather data, negative run flag detected.";
     360            0 :         break_flag = true;
     361            0 :         break;
     362              :       }
     363            0 :       std::this_thread::sleep_until(next_slice_gather_time);
     364            0 :       next_slice_gather_time = next_slice_gather_time + slice_period;
     365              :     }
     366            0 :     if (break_flag == false) {
     367            0 :       std::this_thread::sleep_until(next_gather_time);
     368              :     }
     369            0 :   }
     370            0 : }
     371              : } // namespace hsilibs
     372              : } // namespace dunedaq
     373              : 
     374            0 : DEFINE_DUNE_DAQ_MODULE(dunedaq::hsilibs::HSIController)
     375              : 
     376              : // Local Variables:
     377              : // c-basic-offset: 2
     378              : // End:
        

Generated by: LCOV version 2.0-1