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_ */