LCOV - code coverage report
Current view: top level - timinglibs/src - TimingHardwareManagerBase.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 362 0
Test Date: 2025-12-21 13:07:08 Functions: 0.0 % 71 0

            Line data    Source code
       1              : /**
       2              :  * @file TimingHardwareManagerBase.cpp
       3              :  *
       4              :  * This is part of the DUNE DAQ Software Suite, copyright 2020.
       5              :  * Licensing/copyright details are in the COPYING file that you should have
       6              :  * received with this code.
       7              :  */
       8              : 
       9              : #include "TimingHardwareManagerBase.hpp"
      10              : 
      11              : #include "timinglibs/dal/TimingHardwareManagerBase.hpp"
      12              : #include "timinglibs/dal/TimingFanoutDevice.hpp"
      13              : 
      14              : #include "iomanager/IOManager.hpp"
      15              : #include "logging/Logging.hpp"
      16              : #include "timing/definitions.hpp"
      17              : 
      18              : #include "timing/FanoutDesign.hpp"
      19              : #include "timing/MuxDesignInterface.hpp"
      20              : 
      21              : #include "timing/timingfirmware/Nljs.hpp"
      22              : #include "timing/timingfirmware/Structs.hpp"
      23              : #include "appfwk/ConfigurationManager.hpp"
      24              : 
      25              : #include <memory>
      26              : #include <string>
      27              : #include <utility>
      28              : #include <vector>
      29              : 
      30              : #define TRACE_NAME "TimingHardwareManagerBase" // NOLINT
      31              : 
      32              : namespace dunedaq {
      33              : 
      34            0 : DUNE_DAQ_SERIALIZABLE(timinglibs::timingcmd::TimingHwCmd, "TimingHwCmd");
      35            0 : DUNE_DAQ_SERIALIZABLE(nlohmann::json, "JSON");
      36              : 
      37              : namespace timinglibs {
      38              : 
      39            0 : TimingHardwareManagerBase::TimingHardwareManagerBase(const std::string& name)
      40              :   : dunedaq::appfwk::DAQModule(name)
      41            0 :   , m_hw_cmd_connection("timing_cmds")
      42            0 :   , m_hw_command_receiver(nullptr)
      43            0 :   , m_gather_interval(1e6)
      44            0 :   , m_gather_interval_debug(10e6)
      45            0 :   , m_monitored_device_name_master("")
      46            0 :   , m_monitored_device_name_endpoint("")
      47            0 :   , m_monitored_device_name_hsi("")
      48            0 :   , m_received_hw_commands_counter{ 0 }
      49            0 :   , m_accepted_hw_commands_counter{ 0 }
      50            0 :   , m_rejected_hw_commands_counter{ 0 }
      51            0 :   , m_failed_hw_commands_counter{ 0 }
      52            0 :   , m_endpoint_scan_threads_clean_up_thread(nullptr)
      53              : {
      54              :   //  register_command("start", &TimingHardwareManagerBase::do_start);
      55              :   //  register_command("stop", &TimingHardwareManagerBase::do_stop);
      56            0 :    register_command("scrap", &TimingHardwareManagerBase::do_scrap);
      57            0 : }
      58              : 
      59              : void
      60            0 : TimingHardwareManagerBase::init(std::shared_ptr<appfwk::ConfigurationManager> mcfg)
      61              : {
      62            0 :   auto mod_config = mcfg->get_dal<timinglibs::dal::TimingHardwareManagerBase>(get_name());
      63            0 :   m_params = mod_config->get_configuration();
      64              : 
      65              :   // set up queues
      66            0 :   for (auto con : mod_config->get_inputs())
      67              :   {
      68            0 :     if (con->get_data_type() == datatype_to_string<timingcmd::TimingHwCmd>()) {
      69            0 :       m_hw_cmd_connection = con->UID();
      70            0 :       TLOG() << "m_hw_cmd_connection: " << m_hw_cmd_connection;
      71              :     }
      72              :   }
      73              : 
      74            0 :   try
      75              :   {
      76            0 :     m_hw_command_receiver = iomanager::IOManager::get()->get_receiver<timingcmd::TimingHwCmd>(m_hw_cmd_connection);
      77            0 :   } catch (const ers::Issue& excpt) {
      78            0 :     throw InvalidQueueFatalError(ERS_HERE, get_name(), "input", excpt);
      79            0 :   }
      80              : 
      81            0 :   m_endpoint_scan_threads_clean_up_thread = std::make_unique<dunedaq::utilities::ReusableThread>(0);
      82            0 : }
      83              : 
      84              : void
      85            0 : TimingHardwareManagerBase::conf(const CommandData_t& /*data*/)
      86              : {
      87            0 :   m_received_hw_commands_counter = 0;
      88            0 :   m_accepted_hw_commands_counter = 0;
      89            0 :   m_rejected_hw_commands_counter = 0;
      90            0 :   m_failed_hw_commands_counter = 0;
      91              : 
      92            0 :   m_gather_interval = m_params->get_gather_interval();
      93            0 :   m_gather_interval_debug = m_params->get_gather_interval_debug();
      94              : 
      95            0 :   m_monitored_device_name_master = m_params->get_monitored_device_name_master();
      96            0 :   for (auto fanout : m_params->get_monitored_device_names_fanout())
      97              :   {
      98            0 :     TLOG_DEBUG(3) << fanout->get_device() << ": device, slot: " << fanout->get_fanout_slot() << std::endl;
      99            0 :     m_monitored_device_names_fanout.emplace(fanout->get_fanout_slot(), fanout->get_device());
     100              :   }
     101              : 
     102            0 :   m_monitored_device_name_endpoint = m_params->get_monitored_device_name_endpoint();
     103            0 :   m_monitored_device_name_hsi = m_params->get_monitored_device_name_hsi();
     104              : 
     105            0 :   configure_uhal(m_params); // configure hw ipbus connection
     106              : 
     107            0 :   m_hw_command_receiver->add_callback(std::bind(&TimingHardwareManagerBase::process_hardware_command, this, std::placeholders::_1));
     108              : 
     109            0 :   m_run_endpoint_scan_cleanup_thread.store(true);
     110            0 :   m_endpoint_scan_threads_clean_up_thread->set_work(&TimingHardwareManagerBase::clean_endpoint_scan_threads, this);
     111            0 : }
     112              : 
     113              : void
     114            0 : TimingHardwareManagerBase::do_scrap(const CommandData_t& /*data*/)
     115              : {
     116            0 :   m_hw_command_receiver->remove_callback();
     117              : 
     118            0 :   auto time_of_scrap = std::chrono::high_resolution_clock::now();
     119            0 :   while(m_command_threads.size())
     120              :   {
     121            0 :     auto now = std::chrono::high_resolution_clock::now();
     122            0 :     auto ms_since_scrap = std::chrono::duration_cast<std::chrono::milliseconds>(now - time_of_scrap);
     123            0 :     TLOG_DEBUG(0) << "Have been waiting for " << ms_since_scrap.count() << " ms for " << m_command_threads.size() << " command threads to finish...";
     124            0 :     std::this_thread::sleep_for(std::chrono::microseconds(250000));
     125              :   }
     126            0 :   m_run_endpoint_scan_cleanup_thread.store(false);
     127              :   
     128            0 :   stop_hw_mon_gathering();
     129              :   
     130            0 :   scrap_uhal();
     131              : 
     132            0 :   m_command_threads.clear(); 
     133            0 :   m_info_gatherers.clear();
     134            0 :   m_timing_hw_cmd_map_.clear();
     135            0 :   m_hw_device_map.clear();
     136            0 :   m_connection_manager.reset();
     137            0 : }
     138              : 
     139              : const timing::TimingNode*
     140            0 : TimingHardwareManagerBase::get_timing_device_plain(const std::string& device_name)
     141              : {
     142              : 
     143            0 :   if (!device_name.compare("")) {
     144            0 :     std::stringstream message;
     145            0 :     message << "UHAL device name is an empty string";
     146            0 :     throw UHALDeviceNameIssue(ERS_HERE, message.str());
     147            0 :   }
     148              : 
     149            0 :   if (auto hw_device_entry = m_hw_device_map.find(device_name); hw_device_entry != m_hw_device_map.end()) {
     150            0 :     return dynamic_cast<const timing::TimingNode*>(&hw_device_entry->second->getNode(""));
     151              :   } else {
     152            0 :     TLOG_DEBUG(0) << get_name() << ": hw device interface for: " << device_name
     153            0 :                   << " does not exist. I will try to create it.";
     154              : 
     155            0 :     try {
     156            0 :       std::lock_guard<std::mutex> hw_device_map_guard(m_hw_device_map_mutex);
     157            0 :       m_hw_device_map.emplace(device_name,
     158            0 :                               std::make_unique<uhal::HwInterface>(m_connection_manager->getDevice(device_name)));
     159            0 :     } catch (const uhal::exception::ConnectionUIDDoesNotExist& exception) {
     160            0 :       std::stringstream message;
     161            0 :       message << "UHAL device name not " << device_name << " in connections file";
     162            0 :       throw UHALDeviceNameIssue(ERS_HERE, message.str(), exception);
     163            0 :     }
     164              : 
     165            0 :     TLOG_DEBUG(0) << get_name() << ": hw device interface for: " << device_name << " successfully created.";
     166              : 
     167            0 :     return dynamic_cast<const timing::TimingNode*>(&m_hw_device_map.find(device_name)->second->getNode(""));
     168              :   }
     169              : }
     170              : 
     171              : void
     172            0 : TimingHardwareManagerBase::gather_monitor_data(InfoGatherer& gatherer)
     173              : {
     174            0 :   auto device_name = gatherer.get_device_name();
     175              : 
     176            0 :   while (gatherer.run_gathering()) {
     177              : 
     178              :     // collect the data from the hardware
     179            0 :     try {
     180            0 :       auto design = get_timing_device<const timing::TopDesignInterface*>(device_name);
     181              : 
     182            0 :       gatherer.collect_info_from_device(*design);
     183            0 :     } catch (const std::exception& excpt) {
     184            0 :       ers::warning(FailedToCollectOpMonInfo(ERS_HERE, device_name, excpt));
     185            0 :     }
     186              : 
     187            0 :     auto prev_gather_time = std::chrono::steady_clock::now();
     188            0 :     auto next_gather_time = prev_gather_time + std::chrono::microseconds(gatherer.get_gather_interval());
     189              : 
     190              :     // check running_flag periodically
     191            0 :     auto slice_period = std::chrono::microseconds(10000);
     192            0 :     auto next_slice_gather_time = prev_gather_time + slice_period;
     193              : 
     194            0 :     bool break_flag = false;
     195            0 :     while (next_gather_time > next_slice_gather_time + slice_period) {
     196            0 :       if (!gatherer.run_gathering()) {
     197            0 :         TLOG_DEBUG(0) << "while waiting to gather data, negative run gatherer flag detected.";
     198            0 :         break_flag = true;
     199            0 :         break;
     200              :       }
     201            0 :       std::this_thread::sleep_until(next_slice_gather_time);
     202            0 :       next_slice_gather_time = next_slice_gather_time + slice_period;
     203              :     }
     204            0 :     if (break_flag == false) {
     205            0 :       std::this_thread::sleep_until(next_gather_time);
     206              :     }
     207              :   }
     208            0 : }
     209              : 
     210              : void
     211            0 : TimingHardwareManagerBase::register_info_gatherer(uint gather_interval, const std::string& device_name, int op_mon_level)
     212              : {
     213            0 :   std::string gatherer_name = device_name + "_level_" + std::to_string(op_mon_level);
     214            0 :   if (m_info_gatherers.find(gatherer_name) == m_info_gatherers.end()) {
     215            0 :     std::unique_ptr<InfoGatherer> gatherer = std::make_unique<InfoGatherer>(
     216            0 :       std::bind(&TimingHardwareManagerBase::gather_monitor_data, this, std::placeholders::_1),
     217              :       gather_interval,
     218              :       device_name,
     219            0 :       op_mon_level);
     220              : 
     221            0 :     TLOG_DEBUG(0) << "Registering info gatherer: " << gatherer_name;
     222            0 :     m_info_gatherers.emplace(std::make_pair(gatherer_name, std::move(gatherer)));
     223            0 :   } else {
     224            0 :     TLOG() << "Skipping registration of " << gatherer_name << ". Already exists.";
     225              :   }
     226            0 : }
     227              : 
     228              : void
     229            0 : TimingHardwareManagerBase::start_hw_mon_gathering(const std::string& device_name)
     230              : {
     231              :   // start all gatherers if no device name is given
     232            0 :   if (!device_name.compare("")) {
     233            0 :     TLOG_DEBUG(0) << get_name() << " Starting all info gatherers";
     234            0 :     for (auto it = m_info_gatherers.begin(); it != m_info_gatherers.end(); ++it)
     235            0 :       it->second.get()->start_gathering_thread();
     236              :   } else {
     237              :     // find gatherer for suppled device name and start it
     238            0 :     bool gatherer_found=false;
     239            0 :     for (auto it = m_info_gatherers.lower_bound(device_name); it != m_info_gatherers.end(); ++it) {
     240            0 :       TLOG_DEBUG(0) << get_name() << " Starting info gatherer: " << it->first;
     241            0 :       it->second.get()->start_gathering_thread();
     242            0 :       gatherer_found=true;
     243              :     } 
     244            0 :     if (!gatherer_found) ers::warning(AttemptedToControlNonExantInfoGatherer(ERS_HERE, "start", device_name));
     245              :   }
     246            0 : }
     247              : 
     248              : void
     249            0 : TimingHardwareManagerBase::stop_hw_mon_gathering(const std::string& device_name)
     250              : {
     251              :   // stop all gatherers if no device name is given
     252            0 :   if (!device_name.compare("")) {
     253            0 :     TLOG_DEBUG(0) << get_name() << " Stopping all info gatherers";
     254            0 :     for (auto it = m_info_gatherers.begin(); it != m_info_gatherers.end(); ++it)
     255            0 :       it->second.get()->stop_gathering_thread();
     256              :   } else {
     257              :     // find gatherer for suppled device name and stop it
     258            0 :     bool gatherer_found=false;
     259            0 :     for (auto it = m_info_gatherers.lower_bound(device_name); it != m_info_gatherers.end(); ++it) {
     260            0 :       TLOG_DEBUG(0) << get_name() << " Stopping info gatherer: " << it->first;
     261            0 :       it->second.get()->stop_gathering_thread();
     262            0 :       gatherer_found=true;
     263              :     } 
     264            0 :     if (!gatherer_found) ers::warning(AttemptedToControlNonExantInfoGatherer(ERS_HERE, "stop", device_name));
     265              :   }
     266            0 : }
     267              : 
     268              : std::vector<std::string>
     269            0 : TimingHardwareManagerBase::check_hw_mon_gatherer_is_running(const std::string& device_name)
     270              : {
     271            0 :   std::vector<std::string> running_gatherers;
     272            0 :   for (auto it = m_info_gatherers.lower_bound(device_name); it != m_info_gatherers.end(); ++it)
     273              :   {
     274            0 :     TLOG_DEBUG(0) << get_name() << " Checking run state of info gatherer: " << it->first << ", and the state is " << it->second.get()->run_gathering();
     275            0 :     if (it->second.get()->run_gathering())
     276              :     {
     277            0 :       running_gatherers.push_back(it->first);
     278              :     }
     279              :   }
     280            0 :   return running_gatherers;  
     281            0 : }
     282              : 
     283              : // cmd stuff
     284              : 
     285              : void
     286            0 : TimingHardwareManagerBase::process_hardware_command(timingcmd::TimingHwCmd& timing_hw_cmd)
     287              : {
     288            0 :   std::ostringstream starting_stream;
     289            0 :   starting_stream << ": Executing process_hardware_command() callback.";
     290            0 :   TLOG_DEBUG(0) << get_name() << starting_stream.str();
     291              : 
     292            0 :   ++m_received_hw_commands_counter;
     293              : 
     294            0 :   TLOG_DEBUG(0) << get_name() << ": Received hardware command #" << m_received_hw_commands_counter.load()
     295            0 :                   << ", it is of type: " << timing_hw_cmd.id << ", targeting device: " << timing_hw_cmd.device << ", with payload: " << timing_hw_cmd.payload.dump();
     296              : 
     297            0 :   std::string hw_cmd_name = timing_hw_cmd.id;
     298            0 :   if (auto cmd = m_timing_hw_cmd_map_.find(hw_cmd_name); cmd != m_timing_hw_cmd_map_.end()) {
     299              : 
     300            0 :     ++m_accepted_hw_commands_counter;
     301              : 
     302            0 :     TLOG_DEBUG(0) << "Found hw cmd: " << hw_cmd_name;
     303            0 :     try {
     304            0 :       std::invoke(cmd->second, timing_hw_cmd);
     305            0 :     } catch (const std::exception& exception) {
     306            0 :       ers::error(FailedToExecuteHardwareCommand(ERS_HERE, hw_cmd_name, timing_hw_cmd.device, exception));
     307            0 :       ++m_failed_hw_commands_counter;
     308            0 :     }
     309              :   } else {
     310            0 :     ers::error(InvalidHardwareCommandID(ERS_HERE, hw_cmd_name));
     311            0 :     ++m_rejected_hw_commands_counter;
     312              :   }
     313              : 
     314            0 :   std::ostringstream exiting_stream;
     315            0 :   exiting_stream << ": Finished executing process_hardware_command() callback. Received " << m_received_hw_commands_counter.load()
     316            0 :                  << " commands";
     317            0 :   TLOG_DEBUG(0) << get_name() << exiting_stream.str();
     318            0 : }
     319              : 
     320              : // common commands
     321              : void
     322            0 : TimingHardwareManagerBase::io_reset(const timingcmd::TimingHwCmd& hw_cmd)
     323              : {
     324            0 :   timingcmd::IOResetCmdPayload cmd_payload;
     325            0 :   timingcmd::from_json(hw_cmd.payload, cmd_payload);
     326              :   
     327            0 :   TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " io reset";
     328              : 
     329              :   // io reset disrupts hw mon gathering, so stop if running
     330            0 :   auto running_hw_gatherers = check_hw_mon_gatherer_is_running(hw_cmd.device);
     331            0 :   for (auto& gatherer: running_hw_gatherers)
     332              :   {
     333            0 :     stop_hw_mon_gathering(gatherer);
     334              :   }
     335              : 
     336            0 :   auto design = get_timing_device<const timing::TopDesignInterface*>(hw_cmd.device);
     337              : 
     338            0 :   if (cmd_payload.soft) {
     339            0 :     TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " soft io reset";
     340            0 :     design->soft_reset_io();
     341            0 :   } else if (!cmd_payload.clock_config.empty()) {
     342            0 :     TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device
     343            0 :                   << " io reset, with supplied clk file: " << cmd_payload.clock_config;
     344            0 :     design->reset_io(cmd_payload.clock_config);
     345              :   }
     346              :   else
     347              :   {
     348            0 :     TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device
     349            0 :                   << " io reset, with supplied clk source: " << cmd_payload.clock_source;
     350            0 :     design->reset_io(static_cast<timing::ClockSource>(cmd_payload.clock_source));
     351              :   }
     352              : 
     353              :   // if hw mon gathering was running previously, start it again
     354            0 :   for (auto& gatherer: running_hw_gatherers)
     355              :   {
     356            0 :     start_hw_mon_gathering(gatherer);
     357              :   }
     358            0 : }
     359              : 
     360              : void
     361            0 : TimingHardwareManagerBase::print_status(const timingcmd::TimingHwCmd& hw_cmd)
     362              : {
     363            0 :   TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " print status";
     364              : 
     365            0 :   auto design = get_timing_device<const timing::TopDesignInterface*>(hw_cmd.device);
     366            0 :   TLOG() << std::endl << design->get_status();
     367            0 : }
     368              : 
     369              : // master commands
     370              : void
     371            0 : TimingHardwareManagerBase::set_timestamp(const timingcmd::TimingHwCmd& hw_cmd)
     372              : {
     373            0 :   timingcmd::SyncTimestampPayload cmd_payload;
     374            0 :   timingcmd::from_json(hw_cmd.payload, cmd_payload);
     375              : 
     376            0 :   TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device
     377            0 :                               << " set timestamp, with supplied ts source: " << cmd_payload.timestamp_source;
     378              : 
     379            0 :   auto design = get_timing_device<const timing::MasterDesignInterface*>(hw_cmd.device);
     380            0 :   design->sync_timestamp(static_cast<timing::TimestampSource>(cmd_payload.timestamp_source));
     381            0 : }
     382              : 
     383              : void
     384            0 : TimingHardwareManagerBase::master_endpoint_scan(const timingcmd::TimingHwCmd& hw_cmd)
     385              : {
     386            0 :   TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " master_endpoint_scan";
     387              : 
     388            0 :   std::stringstream command_thread_uid;
     389            0 :   auto t = std::time(nullptr);
     390            0 :   auto tm = *std::localtime(&t);
     391            0 :   command_thread_uid << "enpoint_scan_cmd_at_" << std::put_time(&tm, "%d-%m-%Y %H-%M-%S") << "_cmd_num_" << m_accepted_hw_commands_counter.load();
     392              :   
     393            0 :   if (m_command_threads.size() > 5)
     394              :   {
     395            0 :     ers::warning(TooManyEndpointScanThreadsQueued(ERS_HERE, m_command_threads.size()));
     396              :   }
     397              :   else
     398              :   {
     399            0 :     TLOG_DEBUG(1) << "Queuing: " << command_thread_uid.str();
     400              : 
     401            0 :     auto thread_key = command_thread_uid.str();
     402            0 :     std::unique_lock map_lock(m_command_threads_map_mutex);
     403              : 
     404            0 :     m_command_threads.emplace(thread_key, std::make_unique<std::thread>(std::bind(&TimingHardwareManagerBase::perform_endpoint_scan, this, hw_cmd)));
     405            0 :   }
     406            0 : }
     407              : 
     408            0 : void TimingHardwareManagerBase::perform_endpoint_scan(const timingcmd::TimingHwCmd& hw_cmd)
     409              : {
     410            0 :   timingcmd::TimingMasterEndpointScanPayload cmd_payload;
     411            0 :   timingcmd::from_json(hw_cmd.payload, cmd_payload);
     412              : 
     413            0 :   for (auto& endpoint_location : cmd_payload.endpoints)
     414              :   {
     415            0 :     auto endpoint_address = endpoint_location.address;
     416            0 :     auto fanout_slot = endpoint_location.fanout_slot;
     417            0 :     auto sfp_slot = endpoint_location.sfp_slot;
     418              : 
     419            0 :     std::unique_lock<std::mutex> master_sfp_lock(master_sfp_mutex);
     420              : 
     421            0 :     TLOG_DEBUG(1) << get_name() << ": " << hw_cmd.device << " master_endpoint_scan starting: ept adr: " << endpoint_address << ", ept sfp: " << sfp_slot << ", fanout slot: " << fanout_slot;
     422              : 
     423            0 :     auto master_design = get_timing_device<const timing::MasterDesignInterface*>(hw_cmd.device);
     424            0 :     try
     425              :     {
     426              :       //master_design->get_master_node_plain()->switch_endpoint_sfp(endpoint_address, true);
     427              : 
     428            0 :       if (sfp_slot >= 0)
     429              :       {
     430            0 :         if (fanout_slot >= 0)
     431              :         {
     432              :           // configure fanout/FIB
     433            0 :           try
     434              :           {
     435            0 :             get_timing_device<const timing::MuxDesignInterface*>(m_monitored_device_names_fanout.at(fanout_slot))->switch_mux(sfp_slot);
     436              :           }
     437            0 :           catch(const UHALDeviceClassIssue& e)
     438              :           {
     439            0 :             ers::error(e);
     440            0 :             continue;
     441            0 :           }
     442              : 
     443              :           // slot 0 for board without multiple data tx paths, e.g. FMC, TLU
     444            0 :           if (fanout_slot != 0)
     445              :           {
     446              :             // configure GIB/MIB
     447            0 :             try
     448              :             {
     449            0 :               get_timing_device<const timing::MuxDesignInterface*>(hw_cmd.device)->switch_mux(fanout_slot-1);
     450              :             }
     451            0 :             catch(const UHALDeviceClassIssue& e)
     452              :             {
     453            0 :               ers::error(e);
     454            0 :               continue;
     455            0 :             }
     456              :           }
     457              :         }
     458              :         else
     459              :         {
     460            0 :           dynamic_cast<const timing::MuxDesignInterface*>(master_design)->switch_mux(sfp_slot);
     461              :         }
     462              :       }
     463              : 
     464            0 :       auto scan_result = master_design->get_master_node_plain()->scan_endpoint(endpoint_address, true);
     465            0 :       if (scan_result.alive)
     466              :       {
     467            0 :         auto current_rtt = scan_result.round_trip_time;
     468            0 :         ers::info(EndpointRTTMeasurement(ERS_HERE,fanout_slot,sfp_slot,endpoint_address,current_rtt));
     469            0 :         if (m_monitored_endpoints_round_trip_times.count(endpoint_address))
     470              :         {
     471            0 :           auto previous_rtt = m_monitored_endpoints_round_trip_times[endpoint_address];
     472            0 :           if (previous_rtt != current_rtt)
     473              :           {
     474              :             //TLOG() << "New round trip time for endpoint " << endpoint_address << " measured. Previous: "
     475              :             //  << m_monitored_endpoints_round_trip_times[endpoint_address] << ", current: " << current_rtt;
     476            0 :             ers::warning(ChangedEndpointRTTMeasurement(ERS_HERE,fanout_slot,sfp_slot,endpoint_address,current_rtt,previous_rtt));
     477              :           }
     478              :         }
     479              :         else
     480              :         {
     481              :            //TLOG() << "First measured round trip time for endpoint " << endpoint_address << " is: " << current_rtt;
     482              :         }
     483            0 :         m_monitored_endpoints_round_trip_times[endpoint_address]=current_rtt;
     484              :       }
     485              :       else
     486              :       {
     487            0 :         ers::error(EndpointUnresponsive(ERS_HERE,fanout_slot,sfp_slot,endpoint_address));
     488              :         //TLOG() << endpoint_address << " endpoint was not alive...";
     489              :       }
     490              :       //master_design->get_master_node_plain()->switch_endpoint_sfp(endpoint_address, false);
     491              :     }
     492            0 :     catch(std::exception& e)
     493              :     {
     494            0 :       ers::error(EndpointScanFailure(ERS_HERE,e));
     495            0 :       master_design->get_master_node_plain()->switch_endpoint_sfp(endpoint_address, false);
     496            0 :     }
     497            0 :   }
     498            0 : }
     499              : 
     500            0 : void TimingHardwareManagerBase::clean_endpoint_scan_threads()
     501              : {
     502            0 :   TLOG_DEBUG(0) << "Entering clean_endpoint_scan_threads()";
     503            0 :   bool break_flag = false;
     504            0 :   while (!break_flag)
     505              :   {
     506            0 :     for (auto& thread : m_command_threads)
     507              :     {
     508            0 :       if (thread.second->joinable())
     509              :       {
     510            0 :         std::unique_lock map_lock(m_command_threads_map_mutex);
     511            0 :         TLOG_DEBUG(2) << thread.first << " thread ready. Cleaning up.";
     512            0 :         thread.second->join();
     513            0 :         m_command_threads.erase(thread.first);
     514            0 :       }
     515              :     }
     516              :     
     517            0 :     auto prev_clean_time = std::chrono::steady_clock::now();
     518            0 :     auto next_clean_time = prev_clean_time + std::chrono::milliseconds(30);
     519              : 
     520              :     // check running_flag periodically
     521            0 :     auto flag_check_period = std::chrono::milliseconds(1);
     522            0 :     auto next_flag_check_time = prev_clean_time + flag_check_period;
     523              : 
     524            0 :     while (next_clean_time > next_flag_check_time + flag_check_period) {
     525            0 :       if (!m_run_endpoint_scan_cleanup_thread.load()) {
     526            0 :         TLOG_DEBUG(2) << "while waiting to clean up endpoint scan threads, negative run gatherer flag detected.";
     527            0 :         break_flag = true;
     528            0 :         break;
     529              :       }
     530            0 :       std::this_thread::sleep_until(next_flag_check_time);
     531            0 :       next_flag_check_time = next_flag_check_time + flag_check_period;
     532              :     }
     533            0 :     if (break_flag == false) {
     534            0 :       std::this_thread::sleep_until(next_clean_time);
     535              :     }
     536              :   }
     537            0 :   TLOG_DEBUG(0) << "Exiting clean_endpoint_scan_threads()";
     538            0 : }
     539              : 
     540              : // master commands
     541              : void
     542            0 : TimingHardwareManagerBase::set_endpoint_delay(const timingcmd::TimingHwCmd& hw_cmd)
     543              : {
     544            0 :   TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " set endpoint delay";
     545              :   
     546            0 :   timingcmd::TimingMasterSetEndpointDelayCmdPayload cmd_payload;
     547            0 :   timingcmd::from_json(hw_cmd.payload, cmd_payload);
     548              : 
     549            0 :   auto design = get_timing_device<const timing::MasterDesignInterface*>(hw_cmd.device);
     550            0 :   design->apply_endpoint_delay(cmd_payload.address, cmd_payload.coarse_delay, cmd_payload.fine_delay, cmd_payload.phase_delay, cmd_payload.measure_rtt, cmd_payload.control_sfp, cmd_payload.sfp_mux);
     551            0 : }
     552              : 
     553              : void
     554            0 : TimingHardwareManagerBase::send_fl_cmd(const timingcmd::TimingHwCmd& hw_cmd)
     555              : {
     556            0 :   timingcmd::TimingMasterSendFLCmdCmdPayload cmd_payload;
     557            0 :   timingcmd::from_json(hw_cmd.payload, cmd_payload);
     558              : 
     559            0 :   TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " send fl cmd. Payload: " << hw_cmd.payload.dump()
     560            0 :          << ", parsed data: " << cmd_payload.fl_cmd_id
     561            0 :          << ", " << cmd_payload.channel
     562            0 :          << ", " << cmd_payload.number_of_commands_to_send;
     563              : 
     564            0 :   auto design = get_timing_device<const timing::MasterDesignInterface*>(hw_cmd.device);
     565            0 :   design->get_master_node_plain()->send_fl_cmd(cmd_payload.fl_cmd_id, cmd_payload.channel, cmd_payload.number_of_commands_to_send);
     566            0 : }
     567              : 
     568              : // endpoint commands
     569              : void
     570            0 : TimingHardwareManagerBase::endpoint_enable(const timingcmd::TimingHwCmd& hw_cmd)
     571              : {
     572            0 :   timingcmd::TimingEndpointConfigureCmdPayload cmd_payload;
     573            0 :   timingcmd::from_json(hw_cmd.payload, cmd_payload);
     574              : 
     575            0 :   TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " ept enable, adr: " << cmd_payload.address
     576            0 :                 << ", part: " << cmd_payload.partition;
     577              : 
     578            0 :   auto design = get_timing_device<const timing::EndpointDesignInterface*>(hw_cmd.device);
     579            0 :   design->get_endpoint_node_plain(cmd_payload.endpoint_id)->enable(cmd_payload.address, cmd_payload.partition);
     580            0 : }
     581              : 
     582              : void
     583            0 : TimingHardwareManagerBase::endpoint_disable(const timingcmd::TimingHwCmd& hw_cmd)
     584              : {
     585            0 :   timingcmd::TimingEndpointCmdPayload cmd_payload;
     586            0 :   timingcmd::from_json(hw_cmd.payload, cmd_payload);
     587              : 
     588            0 :   TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " ept disable";
     589              : 
     590            0 :   auto design = get_timing_device<const timing::EndpointDesignInterface*>(hw_cmd.device);
     591            0 :   design->get_endpoint_node_plain(cmd_payload.endpoint_id)->disable();
     592            0 : }
     593              : 
     594              : void
     595            0 : TimingHardwareManagerBase::endpoint_reset(const timingcmd::TimingHwCmd& hw_cmd)
     596              : {
     597            0 :   timingcmd::TimingEndpointConfigureCmdPayload cmd_payload;
     598            0 :   timingcmd::from_json(hw_cmd.payload, cmd_payload);
     599              : 
     600            0 :   TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " ept reset, adr: " << cmd_payload.address
     601            0 :                 << ", part: " << cmd_payload.partition;
     602              : 
     603            0 :   auto design = get_timing_device<const timing::EndpointDesignInterface*>(hw_cmd.device);
     604            0 :   design->get_endpoint_node_plain(cmd_payload.endpoint_id)->reset(cmd_payload.address, cmd_payload.partition);
     605            0 : }
     606              : 
     607              : // hsi commands
     608              : void
     609            0 : TimingHardwareManagerBase::hsi_reset(const timingcmd::TimingHwCmd& hw_cmd)
     610              : {
     611            0 :   TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " hsi reset";
     612              : 
     613            0 :   auto design = get_timing_device<const timing::HSIDesignInterface*>(hw_cmd.device);
     614            0 :   design->get_hsi_node().reset_hsi();
     615            0 : }
     616              : 
     617              : void
     618            0 : TimingHardwareManagerBase::hsi_configure(const timingcmd::TimingHwCmd& hw_cmd)
     619              : {
     620            0 :   timingcmd::HSIConfigureCmdPayload cmd_payload;
     621            0 :   timingcmd::from_json(hw_cmd.payload, cmd_payload);
     622              : 
     623            0 :   TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " hsi configure";
     624              : 
     625            0 :   auto design = get_timing_device<const timing::HSIDesignInterface*>(hw_cmd.device);
     626            0 :   design->configure_hsi(
     627              :     cmd_payload.data_source, cmd_payload.rising_edge_mask, cmd_payload.falling_edge_mask, cmd_payload.invert_edge_mask, cmd_payload.random_rate);
     628            0 : }
     629              : 
     630              : void
     631            0 : TimingHardwareManagerBase::hsi_start(const timingcmd::TimingHwCmd& hw_cmd)
     632              : {
     633            0 :   TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " hsi start";
     634              : 
     635            0 :   auto design = get_timing_device<const timing::HSIDesignInterface*>(hw_cmd.device);
     636            0 :   design->get_hsi_node().start_hsi();
     637            0 : }
     638              : 
     639              : void
     640            0 : TimingHardwareManagerBase::hsi_stop(const timingcmd::TimingHwCmd& hw_cmd)
     641              : {
     642            0 :   TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " hsi stop";
     643              : 
     644            0 :   auto design = get_timing_device<const timing::HSIDesignInterface*>(hw_cmd.device);
     645            0 :   design->get_hsi_node().stop_hsi();
     646            0 : }
     647              : 
     648              : void
     649            0 : TimingHardwareManagerBase::hsi_print_status(const timingcmd::TimingHwCmd& hw_cmd)
     650              : {
     651            0 :   TLOG_DEBUG(0) << get_name() << ": " << hw_cmd.device << " hsi print status";
     652              : 
     653            0 :   auto design = get_timing_device<const timing::HSIDesignInterface*>(hw_cmd.device);
     654            0 :   TLOG() << std::endl << design->get_hsi_node().get_status();
     655            0 : }
     656              : 
     657              : } // namespace timinglibs
     658              : } // namespace dunedaq
        

Generated by: LCOV version 2.0-1