.. _program_listing_file_fromhost_buffer.hpp: Program Listing for File fromhost_buffer.hpp ============================================ |exhale_lsh| :ref:`Return to documentation for file ` (``fromhost_buffer.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #ifndef FROMHOST_BUFFER_H_ #define FROMHOST_BUFFER_H_ #include #include #include #include #include #include #include #include #include "log.hpp" #include "device.hpp" #include "encoder.hpp" #include "cmem_buffer.hpp" #include "disk_io.hpp" #include "fromhost_monitor.hpp" class FromHostBuffer { public: FromHostBuffer(std::shared_ptr d) : m_device(d), m_run_flag(true), m_size(0), m_number_of_writers(0), m_encoder(), m_mon(), m_mon_prev(), m_trickle_config_size(0) {}; std::shared_ptr get_device(){return m_device;} [[nodiscard]] size_t get_size() const{return m_size;} size_t get_trickle_config_size(){return m_trickle_config_size;} void set_trickle_config_size(size_t size){m_trickle_config_size = size;} void set_encoder_data_format(int format){m_encoder.set_data_format(format);} [[nodiscard]] int get_dmaid() const{return m_dmaid;} void set_dmaid(int dma_id) { if(m_dmaid == -1) m_dmaid = dma_id; //else throw std::runtime_error("DMA buffer already initialized with id: " + std::to_string(m_dmaid)); } void stop(){m_run_flag = false;} std::vector get_elinks(){return m_device->read_enabled_elinks(m_dmaid);} std::vector get_elinks_of_type(elink_type_t t){return m_device->get_enabled_elinks_of_type(m_dmaid, t);}; void increment_writer_counter (){++m_number_of_writers;} [[nodiscard]] bool has_multiple_writers() const{return m_number_of_writers > 1;} size_t compute_msg_dma_occupancy(size_t size){return m_encoder.compute_max_msg_occupancy(size);}; void encode_and_write(uint64_t elink, const uint8_t *source, size_t size, bool trickle = false); uint32_t dma_get_free_MB() {return dma_free_bytes()/1024/1024;} FromHostDmaStats get_monitoring_data(); virtual size_t dma_free_bytes() = 0; virtual void allocate_buffer(size_t size, const std::string& name, bool vmem, bool free_previous_cmem=true) = 0; std::mutex m_buffer_mutex; //allow FromHostWriters to lock this protected: virtual void set_oneshot_trickle_buffer(size_t config_size) = 0; virtual void dma_start_continuous() = 0; virtual void dma_start_circular_trickle_buffer() = 0; virtual bool dma_is_full() = 0; virtual uint64_t dma_get_read_offset() = 0; virtual uint64_t dma_get_write_ptr() = 0; virtual uint64_t dma_get_write_offset() = 0; virtual void dma_set_write_offset(uint64_t offset) = 0; virtual void dma_advance_write_ptr(size_t bytes) = 0; protected: int m_dmaid = -1; // -1 is just to check if the buffer is not initialized std::shared_ptr m_device; std::atomic m_run_flag{true}; size_t m_size; int m_number_of_writers; Encoder m_encoder; FromHostDmaStats m_mon; FromHostDmaStats m_mon_prev; //to compute rates size_t m_trickle_config_size; std::unique_ptr m_buffer; size_t dma_compute_free_bytes(uint64_t fw_rd_ptr, uint64_t pc_wr_ptr, bool even); }; inline size_t FromHostBuffer::dma_compute_free_bytes(uint64_t fw_rd_ptr, uint64_t pc_wr_ptr, bool even) { size_t value{0}; if(pc_wr_ptr < fw_rd_ptr ) { value = fw_rd_ptr - pc_wr_ptr; } else if( pc_wr_ptr > fw_rd_ptr ) { value = m_buffer->size - (pc_wr_ptr - fw_rd_ptr); } else { // pc_wr_ptr == fw_rd_ptr if( even ) { value = m_buffer->size; // Buffer empty } //else value = 0 } return value; } class FlxFromHostBuffer : public FromHostBuffer { public: explicit FlxFromHostBuffer(std::shared_ptr d); ~FlxFromHostBuffer(); void allocate_buffer(size_t size, const std::string& name, bool vmem, bool free_previous_cmem=true) override; void dma_start_continuous() override; void dma_start_circular_trickle_buffer() override; void set_oneshot_trickle_buffer(size_t config_size) override; size_t dma_free_bytes() override; bool dma_is_full() override; uint64_t dma_get_read_offset() override; uint64_t dma_get_write_offset() override; uint64_t dma_get_write_ptr() override; void dma_set_write_offset(uint64_t addr) override; void dma_advance_write_ptr(size_t bytes) override; }; class FileFromHostBuffer : public FromHostBuffer { public: explicit FileFromHostBuffer(std::shared_ptr d, std::string& filename, bool fifo); ~FileFromHostBuffer(); void allocate_buffer(size_t size, const std::string& name, bool vmem, bool free_previous_cmem=false) override; void dma_start_continuous() override; void dma_start_circular_trickle_buffer() override; void set_oneshot_trickle_buffer(size_t config_size) override {m_fw_reading_trickle.store(false);}; bool dma_is_full() override; uint64_t dma_get_read_offset() override; size_t dma_free_bytes() override; uint64_t dma_get_write_offset() override; uint64_t dma_get_write_ptr() override; void dma_set_write_offset(uint64_t addr) override; void dma_advance_write_ptr(size_t bytes) override; private: bool dma_is_empty(); size_t dma_bytes_to_consume(); void dma_advance_read_ptr(size_t bytes); void dma_set_read_offset(uint64_t addr); void set_write_ptr_paddr(uint64_t p_addr); void copy_from_dma_buffer_to_file(); private: //regulate concurrent access of read and write pointers mutable std::shared_mutex m_driver_mutex; //suspend the card emulator thread when the DMA is empty std::condition_variable m_reader_cond; mutable std::mutex m_wake_reader_mutex; DiskIO m_file; bool m_rd_odd; bool m_wr_odd; std::atomic m_fw_reading_trickle {false}; std::thread m_reader_thread; }; #endif /* FROMHOST_BUFFER_H_ */