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

Generated by: LCOV version 2.0-1