LCOV - code coverage report
Current view: top level - crtmodules/plugins - CRTGrenobleFrameBuilderModule.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 111 0
Test Date: 2026-07-12 15:23:06 Functions: 0.0 % 21 0

            Line data    Source code
       1              : /**
       2              :  * @file CRTGrenobleFrameBuilderModule.cpp
       3              :  *
       4              :  * Reads data from the HW then puts it in a queue
       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 "CRTGrenobleFrameBuilderModule.hpp"
      12              : 
      13              : #include "crtmodules/opmon/CRTGrenobleFrameBuilderModule.pb.h"
      14              : 
      15              : #include "datahandlinglibs/utils/RateLimiter.hpp"
      16              : 
      17              : #include "appmodel/DetectorFrameBuilderModule.hpp"
      18              : #include "appmodel/SocketDetectorToDaqConnection.hpp"
      19              : #include "appmodel/NWDetDataSender.hpp"
      20              : 
      21              : #include "confmodel/QueueWithSourceId.hpp"
      22              : #include "confmodel/DetectorStream.hpp"
      23              : #include "confmodel/GeoId.hpp"
      24              : 
      25              : #include "datahandlinglibs/DataHandlingIssues.hpp"
      26              : 
      27              : #include "detdataformats/DetID.hpp"
      28              : 
      29              : #include <utility>
      30              : #include <memory>
      31              : #include <string>
      32              : 
      33            0 : DUNE_DAQ_TYPESTRING(dunedaq::fddetdataformats::CRTGrenobleFrame, "CRTGrenobleFrame")
      34              : 
      35              : namespace dunedaq::crtmodules {
      36              : 
      37              : /**
      38              :  * @brief Maximum packet sequence ID before reset
      39              :  */
      40              : constexpr uint64_t max_seq_id = 4095; // NOLINT(build/unsigned)
      41              : 
      42              : /**
      43              :  * @brief Fake packet detector ID
      44              :  */
      45              : constexpr uint8_t fake_det_id = static_cast<uint8_t>(detdataformats::DetID::Subdetector::kVD_GrenobleCRT); // NOLINT(build/unsigned)
      46              : 
      47              : /**
      48              :  * @brief Fake packet block length
      49              :  */
      50              : constexpr uint64_t fake_block_length = 0x382; // NOLINT(build/unsigned)
      51              : 
      52              : /**
      53              :  * @brief Calculate the next fake sequence ID for a packet
      54              :  * @param seq_id Fake packet sequence ID
      55              :  */
      56              : void
      57            0 : fake_sequence_id(uint64_t& seq_id) // NOLINT(build/unsigned)
      58              : {
      59            0 :   seq_id = (seq_id == max_seq_id ? 0 : seq_id+1);
      60            0 : }
      61              : 
      62              : /**
      63              :  * @brief Calculate the next fake timestamp for a packet
      64              :  * @param timestamp Fake packet timestamp
      65              :  */
      66              : void
      67            0 : fake_timestamp(uint64_t& timestamp) // NOLINT(build/unsigned)
      68              : {
      69            0 :     auto time_now = std::chrono::steady_clock::now().time_since_epoch();
      70            0 :     uint64_t current_time = // NOLINT (build/unsigned)
      71            0 :     std::chrono::duration_cast<std::chrono::nanoseconds>(time_now).count();
      72            0 :     timestamp = current_time / 16; // 625/10000 (same as 625*us/10)
      73            0 : }
      74              : 
      75              : /**
      76              :  * @brief Fake ADC of the given packet
      77              :  * @param frame Fake packet
      78              :  */
      79              : void
      80            0 : fake_adc(fddetdataformats::CRTGrenobleFrame& frame)
      81              : {
      82            0 :   for (int channel = 0; channel < fddetdataformats::CRTGrenobleFrame::s_num_channels; ++channel) {
      83            0 :     frame.set_adc(channel, 0);
      84              :   }
      85            0 : }
      86              : 
      87              : /**
      88              :  * @brief Create a fake packet
      89              :  * @param frame Fake packet
      90              :  * @param seq_id Fake packet sequence ID
      91              :  * @param timestamp Fake packet timestamp
      92              :  * @param stream_id Fake packet stream ID
      93              :  */
      94              : void
      95            0 : fake_data(fddetdataformats::CRTGrenobleFrame& frame, uint64_t& seq_id, uint64_t& timestamp, uint32_t stream_id) // NOLINT(build/unsigned)
      96              : {
      97            0 :   frame.daq_header.det_id = fake_det_id & 0x3f; //6 bits for det id
      98            0 :   frame.daq_header.crate_id = 1;
      99            0 :   frame.daq_header.slot_id = 1;
     100            0 :   frame.daq_header.stream_id = stream_id;
     101            0 :   fake_sequence_id(seq_id);
     102            0 :   frame.daq_header.seq_id = seq_id;
     103            0 :   frame.daq_header.block_length = fake_block_length;
     104            0 :   fake_timestamp(timestamp);
     105            0 :   frame.daq_header.timestamp = timestamp;
     106            0 :   fake_adc(frame);
     107            0 : }
     108              : 
     109            0 : CRTGrenobleFrameBuilderModule::CRTGrenobleFrameBuilderModule(const std::string& name)
     110            0 :   : DAQModule(name)
     111              : {
     112            0 :   register_command("conf", &CRTGrenobleFrameBuilderModule::do_conf);
     113            0 :   register_command("start", &CRTGrenobleFrameBuilderModule::do_start);
     114            0 :   register_command("stop_trigger_sources", &CRTGrenobleFrameBuilderModule::do_stop);
     115            0 :   register_command("scrap", &CRTGrenobleFrameBuilderModule::do_scrap);
     116            0 : }
     117              : 
     118              : void
     119            0 : CRTGrenobleFrameBuilderModule::init(const std::shared_ptr<appfwk::ConfigurationManager> mcfg)
     120              : {
     121            0 :   auto* mdal = mcfg->get_dal<appmodel::DetectorFrameBuilderModule>(get_name());
     122              : 
     123            0 :   auto* d2d_conn = mdal->get_connection();
     124            0 :   auto* socket_d2d_conn = d2d_conn->cast<appmodel::SocketDetectorToDaqConnection>();
     125            0 :   if (socket_d2d_conn == nullptr) {
     126            0 :     auto err = datahandlinglibs::InitializationError(ERS_HERE, "Connection is not of type SocketDetectorToDaqConnection.");
     127            0 :     ers::fatal(err);
     128            0 :     throw err;
     129            0 :   } 
     130              : 
     131            0 :   auto* nw_sender = socket_d2d_conn->get_net_senders()[0]; // there's only 1 sender
     132              : 
     133            0 :   for (auto det_stream : nw_sender->get_streams()) {
     134            0 :     if (det_stream->is_disabled(*(mcfg->get_session()))) {
     135            0 :       continue;
     136              :     }
     137              : 
     138            0 :     m_fake_stream_ids.push_back(det_stream->get_geo_id()->get_stream_id());
     139              : 
     140            0 :     m_producer_threads.emplace_back(std::make_unique<utilities::ReusableThread>());
     141              :   }
     142              : 
     143            0 :   auto* con = mdal->get_outputs()[0]; // there's only 1 output  
     144            0 :   auto* queue = con->cast<confmodel::Queue>();
     145            0 :   if (queue == nullptr) {
     146            0 :     auto err = datahandlinglibs::InitializationError(ERS_HERE, "Output is not of type Queue.");
     147            0 :     ers::fatal(err);
     148            0 :     throw err;
     149            0 :   }
     150              :   
     151            0 :   auto connection_name = queue->UID();
     152            0 :   m_sender = get_iom_sender<fddetdataformats::CRTGrenobleFrame>(connection_name);
     153            0 : }
     154              : 
     155              : void
     156            0 : CRTGrenobleFrameBuilderModule::do_conf(const CommandData_t& /*obj*/)
     157              : {
     158              :   // Configure HW interface?
     159            0 :   if (!m_run_marker.load()) {
     160            0 :     set_running(true);
     161              :   } else {
     162            0 :     TLOG_DEBUG(5) << "Already running!";
     163              :   }
     164            0 : }
     165              : 
     166              : void
     167            0 : CRTGrenobleFrameBuilderModule::do_scrap(const CommandData_t& /*obj*/)
     168              : {
     169            0 :   if (m_run_marker.load()) {
     170            0 :     TLOG() << "Raising stop through variables!";
     171            0 :     set_running(false);
     172            0 :     for (const auto& producer : m_producer_threads) {
     173            0 :       while (!producer->get_readiness()) {
     174            0 :         std::this_thread::sleep_for(std::chrono::milliseconds(10));
     175              :       }
     176              :     }
     177              :   } else {
     178            0 :     TLOG_DEBUG(5) << "Already stopped!";
     179              :   }
     180            0 : }
     181              : 
     182              : void
     183            0 : CRTGrenobleFrameBuilderModule::do_start(const CommandData_t& /*startobj*/)
     184              : {
     185            0 :   m_packet_count = 0;
     186              : 
     187            0 :   m_t0 = std::chrono::steady_clock::now();
     188              : 
     189            0 :   enable_flow();
     190              : 
     191            0 :   uint32_t i = 0; // NOLINT(build/unsigned)
     192            0 :   for (auto& producer : m_producer_threads) {
     193            0 :     producer->set_work(&CRTGrenobleFrameBuilderModule::run_produce, this, m_fake_stream_ids[i++]);
     194              :   }
     195            0 : }
     196              : 
     197              : void
     198            0 : CRTGrenobleFrameBuilderModule::do_stop(const CommandData_t& /*stopobj*/)
     199              : {
     200            0 :   disable_flow();
     201            0 : }
     202              : 
     203              : void
     204            0 : CRTGrenobleFrameBuilderModule::generate_opmon_data()
     205              : {
     206            0 :   opmon::CRTGrenobleFrameBuilderInfo i;
     207              : 
     208            0 :   auto now = std::chrono::steady_clock::now();
     209            0 :   int new_packets = m_packet_count.exchange(0);
     210            0 :   double seconds = std::chrono::duration_cast<std::chrono::microseconds>(now - m_t0).count() / 1000000.;
     211            0 :   m_t0 = now;
     212              : 
     213            0 :   i.set_packet_rate_khz(new_packets / seconds / 1000.);
     214              : 
     215            0 :   publish(std::move(i));
     216            0 : }
     217              : 
     218              : void
     219            0 : CRTGrenobleFrameBuilderModule::run_produce(uint32_t fake_stream_id) // NOLINT(build/unsigned)
     220              : {
     221            0 :   TLOG() << "Producer thread started..."; // TODO (DTE): Debug log instead
     222              : 
     223            0 :   fddetdataformats::CRTGrenobleFrame frame;
     224            0 :   uint64_t seq_id = 0; // NOLINT(build/unsigned)
     225            0 :   uint64_t timestamp = 0; // NOLINT(build/unsigned)
     226              : 
     227            0 :   datahandlinglibs::RateLimiter rate_limiter(m_configured_packet_rate_khz);
     228              : 
     229            0 :   while (m_run_marker.load()) {
     230              :     // Create a fake packet for stream
     231            0 :     fake_data(frame, seq_id, timestamp, fake_stream_id); // TODO: To be filled by the CRT experts
     232              : 
     233            0 :     if (m_enable_flow.load()) [[likely]] {   
     234            0 :       m_sender->try_send(std::move(frame), iomanager::Sender::s_no_block);        
     235            0 :       ++m_packet_count;
     236              :     }
     237              : 
     238            0 :     rate_limiter.limit();    
     239              :   }
     240              : 
     241            0 :   TLOG() << "Producer thread joins... "; // TODO (DTE): Debug log instead
     242            0 : }
     243              : 
     244              : void 
     245            0 : CRTGrenobleFrameBuilderModule::set_running(bool should_run)
     246              : {
     247            0 :   bool was_running = m_run_marker.exchange(should_run);
     248            0 :   TLOG_DEBUG(5) << "Active state was toggled from " << was_running << " to " << should_run;
     249            0 : }
     250              : 
     251              : } // namespace dunedaq::crtmodules
     252              : 
     253            0 : DEFINE_DUNE_DAQ_MODULE(dunedaq::crtmodules::CRTGrenobleFrameBuilderModule)
        

Generated by: LCOV version 2.0-1