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

Generated by: LCOV version 2.0-1