LCOV - code coverage report
Current view: top level - src - fromhost_buffer.hpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 26 26 100.0 %
Date: 2025-09-09 12:09:29 Functions: 2 2 100.0 %

          Line data    Source code
       1             : #ifndef FROMHOST_BUFFER_H_
       2             : #define FROMHOST_BUFFER_H_
       3             : 
       4             : #include <cstddef>
       5             : #include <cstdint>
       6             : #include <stdio.h>
       7             : #include <thread>
       8             : #include <mutex>
       9             : #include <atomic>
      10             : #include <shared_mutex>
      11             : #include <condition_variable>
      12             : #include "log.hpp"
      13             : 
      14             : #include "device.hpp"
      15             : #include "encoder.hpp"
      16             : #include "cmem_buffer.hpp"
      17             : #include "disk_io.hpp"
      18             : #include "fromhost_monitor.hpp"
      19             : 
      20             : /**
      21             :  * Abstract class representing a FromHost DMA buffer.
      22             :  * The elinks enabled for the corresponding DMA buffers are read from the
      23             :  * device in the constructors.
      24             :  * */
      25             : class FromHostBuffer
      26             : {
      27             :     public:
      28             : 
      29             :         /**
      30             :          * @brief FromHostBuffer contructor.
      31             :          * @param d Device shared pointer.
      32             :          */
      33           5 :         FromHostBuffer(std::shared_ptr<Device> d) :  
      34          10 :             m_device(d), m_run_flag(true), m_size(0), m_number_of_writers(0),
      35          10 :             m_encoder(), m_mon(), m_mon_prev(), m_trickle_config_size(0)
      36           5 :         {};
      37             : 
      38             :         /**
      39             :          * @return pointer to device in use.
      40             :          */
      41             :         std::shared_ptr<Device> get_device(){return m_device;}
      42             : 
      43             :         /**
      44             :          * @return size of DMA buffer.
      45             :          */
      46       10004 :         [[nodiscard]] size_t get_size() const{return m_size;}
      47             : 
      48             : 
      49             :         /**
      50             :          *  @return size of the trickle configuration message.
      51             :          */
      52           2 :         size_t get_trickle_config_size(){return m_trickle_config_size;}
      53             : 
      54             :         /**
      55             :          * @param size : size of trickle configuration message
      56             :          */
      57           2 :         void set_trickle_config_size(size_t size){m_trickle_config_size = size;}
      58             :         
      59             :         /**
      60             :          * @param format : FromHost data format supported by firmware.
      61             :          */
      62           5 :         void set_encoder_data_format(int format){m_encoder.set_data_format(format);}
      63             : 
      64             :         /**
      65             :          * @return identifier of DMA buffer.
      66             :          */
      67          21 :         [[nodiscard]] int get_dmaid() const{return m_dmaid;}
      68             : 
      69             :         /**
      70             :          * @param dma_id identifier of DMA buffer.
      71             :          * @return null.
      72             :          */
      73           5 :         void set_dmaid(int dma_id) 
      74             :         {
      75           5 :             if(m_dmaid == -1) m_dmaid = dma_id;
      76             :             //else throw std::runtime_error("DMA buffer already initialized with id: " + std::to_string(m_dmaid));
      77             :         }
      78             : 
      79             : 
      80             :         /**
      81             :          * @return stop DMA transfer operations.
      82             :          */
      83           5 :         void stop(){m_run_flag = false;}
      84             : 
      85             :         /**
      86             :          * @param m_dmaid DMA identifier
      87             :          * @return vector of enabled e-links.
      88             :          */
      89           5 :         std::vector<Elink> get_elinks(){return m_device->read_enabled_elinks(m_dmaid);}
      90             : 
      91             :         /**
      92             :          * @param m_dmaid DMA identifier
      93             :          * @return vector of enabled e-links of a given type (DAQ, DCS...)
      94             :          */
      95             :         std::vector<Elink> get_elinks_of_type(elink_type_t t){return m_device->get_enabled_elinks_of_type(m_dmaid, t);};
      96             : 
      97             :         /**
      98             :          * @brief increment the counter of writers concurrently acessing the DMA buffer
      99             :          */
     100             :         void increment_writer_counter (){++m_number_of_writers;}
     101             : 
     102             :         /**
     103             :          * @return whether the FromHost DMA buffer is in use by more than a writer.
     104             :          */
     105       10004 :         [[nodiscard]] bool has_multiple_writers() const{return m_number_of_writers > 1;}
     106             : 
     107             :         /**
     108             :          * @param size of message to be encoded and written.
     109             :          * @return size of the encoded messagesss provided by encoder.
     110             :          */
     111       10004 :         size_t compute_msg_dma_occupancy(size_t size){return m_encoder.compute_max_msg_occupancy(size);};
     112             : 
     113             :         /**
     114             :          * @brief encode and write message in the FromHost buffer.
     115             :          * @param elink of message to be encoded and written.
     116             :          * @param source of message to be encoded and written.
     117             :          * @param size of message to be encoded and written.
     118             :          */ 
     119             :         void encode_and_write(uint64_t elink, const uint8_t *source, size_t size, bool trickle = false);
     120             : 
     121             :         /**
     122             :          * @return free space in the FromHost buffer in MB.
     123             :          */
     124          21 :         uint32_t dma_get_free_MB() {return dma_free_bytes()/1024/1024;}
     125             : 
     126             :         /**
     127             :          * @return monitoring information with rates.
     128             :          */
     129             :         FromHostDmaStats get_monitoring_data();
     130             : 
     131             :         /**
     132             :          * @return free space in the FromHost buffer in bytes.
     133             :          */
     134             :         virtual size_t   dma_free_bytes()                            = 0;
     135             : 
     136             :         /**
     137             :          * @param size of the FromHost DMA buffer.
     138             :          * @param name of the buffer passed to the CMEM driver.
     139             :          * @param vmem allocate the buffer without using the CMEM driver.
     140             :          * @param free_previous_cmem claim an unlocked/orphaned CMEM buffer with the same name.
     141             :          */
     142             :         virtual void allocate_buffer(size_t size,
     143             :                             const std::string& name,
     144             :                             bool vmem, bool free_previous_cmem=true) = 0;
     145             : 
     146             :         std::mutex m_buffer_mutex; //allow FromHostWriters to lock this
     147             : 
     148             :     protected:
     149             :         virtual void set_oneshot_trickle_buffer(size_t config_size) = 0;
     150             :         virtual void     dma_start_continuous()                     = 0;
     151             :         virtual void     dma_start_circular_trickle_buffer()        = 0;
     152             :         virtual bool     dma_is_full()                              = 0;
     153             :         virtual uint64_t dma_get_read_offset()                      = 0;
     154             :         virtual uint64_t dma_get_write_ptr()                        = 0;
     155             :         virtual uint64_t dma_get_write_offset()                     = 0;
     156             :         virtual void     dma_set_write_offset(uint64_t offset)      = 0;
     157             :         virtual void     dma_advance_write_ptr(size_t bytes)        = 0;
     158             : 
     159             :     protected:
     160             :         int m_dmaid = -1; // -1 is just to check if the buffer is not initialized
     161             :         std::shared_ptr<Device> m_device;
     162             :         std::atomic<bool> m_run_flag{true};
     163             :         size_t m_size;
     164             :         int m_number_of_writers;
     165             :         Encoder m_encoder;
     166             :         FromHostDmaStats m_mon;
     167             :         FromHostDmaStats m_mon_prev; //to compute rates
     168             :         size_t m_trickle_config_size;
     169             :         std::unique_ptr<DmaBuffer> m_buffer;
     170             : 
     171             :         size_t dma_compute_free_bytes(uint64_t fw_rd_ptr, uint64_t pc_wr_ptr, bool even);
     172             : };
     173             : 
     174             : 
     175       16798 : inline size_t FromHostBuffer::dma_compute_free_bytes(uint64_t fw_rd_ptr, uint64_t pc_wr_ptr, bool even)
     176             : {
     177       16798 :     size_t value{0};
     178       16798 :     if(pc_wr_ptr < fw_rd_ptr ) {
     179           3 :         value = fw_rd_ptr - pc_wr_ptr;
     180             :     }
     181       16795 :     else if( pc_wr_ptr > fw_rd_ptr ) {
     182       16708 :         value = m_buffer->size - (pc_wr_ptr - fw_rd_ptr);
     183             :     }
     184             :     else { // pc_wr_ptr == fw_rd_ptr
     185          87 :         if( even ) {
     186          87 :             value = m_buffer->size; // Buffer empty
     187             :         } //else value = 0
     188             :     }
     189       16798 :     return value;
     190             : }
     191             : 
     192             : 
     193             : /**
     194             :  * FromHost DMA buffer interfaced with an FLX card
     195             :  * */
     196             : class FlxFromHostBuffer : public FromHostBuffer {
     197             : 
     198             :     public:
     199             :         explicit FlxFromHostBuffer(std::shared_ptr<Device> d);
     200             :         ~FlxFromHostBuffer();
     201             : 
     202             :         void allocate_buffer(size_t size,
     203             :                             const std::string& name,
     204             :                             bool vmem, bool free_previous_cmem=true) override;
     205             : 
     206             :         void     dma_start_continuous()                     override;
     207             :         void     dma_start_circular_trickle_buffer()        override;
     208             :         void set_oneshot_trickle_buffer(size_t config_size) override;
     209             :         size_t   dma_free_bytes()                           override;
     210             :         bool     dma_is_full()                              override;
     211             :         uint64_t dma_get_read_offset()                      override;
     212             :         uint64_t dma_get_write_offset()                     override;
     213             :         uint64_t dma_get_write_ptr()                        override;
     214             :         void     dma_set_write_offset(uint64_t addr)        override;
     215             :         void     dma_advance_write_ptr(size_t bytes)        override;
     216             : };
     217             : 
     218             : 
     219             : /**
     220             :  * FromHost DMA buffer with FLX card emulation.
     221             :  * The card is emulated by a separate thread that can copy the
     222             :  * data to a file or a fifo.
     223             :  * */
     224             : class FileFromHostBuffer : public FromHostBuffer {
     225             : 
     226             :     public:
     227             :         explicit FileFromHostBuffer(std::shared_ptr<Device> d,
     228             :             std::string& filename, bool fifo);
     229             :         ~FileFromHostBuffer();
     230             : 
     231             :         void allocate_buffer(size_t size,
     232             :                             const std::string& name,
     233             :                             bool vmem, bool free_previous_cmem=false) override;
     234             :                         
     235             :         void     dma_start_continuous()                     override;
     236             :         void     dma_start_circular_trickle_buffer()        override;
     237           2 :         void set_oneshot_trickle_buffer(size_t config_size) override {m_fw_reading_trickle.store(false);};
     238             :         bool     dma_is_full()                              override;
     239             :         uint64_t dma_get_read_offset()                      override;
     240             :         size_t   dma_free_bytes()                           override;
     241             :         uint64_t dma_get_write_offset()                     override;
     242             :         uint64_t dma_get_write_ptr()                        override;
     243             :         void     dma_set_write_offset(uint64_t addr)        override;
     244             :         void     dma_advance_write_ptr(size_t bytes)        override;
     245             : 
     246             :     private:
     247             :         bool     dma_is_empty();
     248             :         size_t   dma_bytes_to_consume();
     249             :         void     dma_advance_read_ptr(size_t bytes);
     250             :         void     dma_set_read_offset(uint64_t addr);
     251             :         void     set_write_ptr_paddr(uint64_t p_addr);
     252             :         void     copy_from_dma_buffer_to_file();
     253             : 
     254             :     private:
     255             :         //regulate concurrent access of read and write pointers
     256             :         mutable std::shared_mutex m_driver_mutex;
     257             : 
     258             :         //suspend the card emulator thread when the DMA is empty
     259             :         std::condition_variable m_reader_cond;
     260             :         mutable std::mutex m_wake_reader_mutex;
     261             : 
     262             :         DiskIO m_file;
     263             :         bool m_rd_odd;
     264             :         bool m_wr_odd;
     265             :         std::atomic<bool> m_fw_reading_trickle {false};
     266             :         std::thread m_reader_thread;
     267             : };
     268             : 
     269             : #endif /* FROMHOST_BUFFER_H_ */

Generated by: LCOV version 1.0