Line data Source code
1 : #ifndef FELIX_DECODER_H_ 2 : #define FELIX_DECODER_H_ 3 : 4 : #include <string> 5 : #include <memory> 6 : #include "device.hpp" 7 : #include "elink.hpp" 8 : #include "tohost_monitor.hpp" 9 : #include "block.hpp" 10 : #include "publisher.hpp" 11 : #include "l0id_decoder.hpp" 12 : 13 : 14 : /** 15 : * Data structure used to store a chunk as a vector of subchunks. 16 : * Each subchunk is described by an iovec. 17 : * */ 18 0 : struct chunk_buffer 19 : { 20 : std::uint8_t m_status_byte{}; 21 : size_t chunk_size{}; 22 : std::vector<iovec> iov; 23 : 24 40 : chunk_buffer() : m_status_byte(0), chunk_size(0){ 25 40 : iov.emplace_back(&m_status_byte, 1); 26 40 : }; 27 : 28 998775047 : void push_back(iovec&& x) { 29 998775047 : iov.push_back(x); 30 998955470 : chunk_size += x.iov_len; 31 : } 32 : 33 775711068 : void clear() noexcept { 34 775711068 : iov.resize(1); 35 775705090 : chunk_size = 0; 36 0 : m_status_byte = 0; 37 0 : } 38 : 39 1030477035 : bool empty() const noexcept { 40 : // Status byte 41 1030477035 : return iov.size() == 1; 42 : } 43 : 44 6596785 : void remove_last_entry() { 45 6596785 : chunk_size -= iov.back().iov_len; 46 6596785 : iov.resize(iov.size()-1); 47 6596651 : } 48 : 49 809468744 : void update_status_byte(uint8_t status) { 50 809468737 : m_status_byte |= status; 51 7 : } 52 : 53 1556768206 : uint8_t get_status_byte() const { 54 1556768206 : return m_status_byte; 55 : } 56 : 57 880528330 : size_t byte_size() { 58 775714178 : return chunk_size; 59 : } 60 : 61 814247556 : size_t iov_len() { 62 814247556 : return iov.size(); 63 : } 64 : 65 : iovec* iov_addr() { 66 814247556 : return iov.data(); 67 : } 68 : 69 : }; 70 : 71 : 72 : /** 73 : * Block decoder associated to a one e-link. 74 : * The Decoder translates blocks into chunks and published them over the 75 : * network. Multiple Decoders share one Publisher. 76 : * */ 77 : class Decoder 78 : { 79 : public: 80 : Decoder(const Decoder&) = delete; 81 : Decoder& operator=(const Decoder&) = delete; 82 : 83 0 : Decoder(Decoder&&) = default; 84 : Decoder& operator=(Decoder&&) = default; 85 : 86 : /** 87 : * @brief Decoder class constructor 88 : * @param elink whose blocks are to be processed by this decoder. 89 : * @param l0id_decoder_fmt data format for L0ID sequence check (debug feature for detector integration). 90 : * @param block_size size of the blocks read from the DMA buffer. 91 : * @param buf_vaddr virtual address of beginning of DMA buffer (used for computation of key needed in zero-copy mode). 92 : * 93 : * @return Publisher return code 94 : */ 95 : Decoder(const Elink &elink, Publisher &publisher, flx_tohost_format fmt, 96 : int l0id_decoder_fmt, unsigned int block_size, uint64_t buf_vaddr); 97 : 98 : /** 99 : * @return address of the last processed block. Used in zero-copy mode. 100 : */ 101 : uint32_t get_last_block(){return m_last_block;} 102 : 103 : /** 104 : * @return fid of the e-link associated to this decoder 105 : */ 106 : uint64_t get_fid(){return m_elink.fid;} 107 : 108 : /** 109 : * @brief set the block size used by firmware 110 : */ 111 4 : void set_block_size(unsigned int block_size){m_block_size = block_size;} 112 : 113 : /** 114 : * @brief decode the block. This function will redirect to decode_subchunk_headers or decode_subchunk_trailers 115 : * @param block address of the block to decode 116 : * @return Publisher return code 117 : */ 118 : Publisher::Result decode(Block & block); 119 : 120 : /** 121 : * @return copy of the current monitoring data 122 : */ 123 4 : ToHostElinkStats get_decoder_stats(){return m_stats;} 124 : 125 : /** 126 : * @brief wrapper of ToHostElinkStats::get_increment 127 : * @return a new instance of ToHostElinkStats containing the difference between the current values 128 : * and the previous ones. It also updates the the "previous" value to the current one. 129 : */ 130 : ToHostElinkStats get_decoder_stats_increment(ToHostElinkStats & previous); 131 : 132 : private: 133 : enum SubchunkType { 134 : NIL = 0, FIRST, LAST, WHOLE, MIDDLE, TIMEOUT, OOB 135 : }; 136 : 137 : /** 138 : * @details subchunks are accumulated. If the chunk is completed it is posted to the Publisher. 139 : */ 140 : Publisher::Result post_subchunk(uint8_t *data, uint32_t length, SubchunkType type, uint8_t err); 141 : 142 : /** 143 : * @details Check header integrity, sequence number. 144 : */ 145 : [[nodiscard]] Publisher::Result check_block_integrity(Block & block); 146 : 147 : 148 : /** 149 : * @brief decode the block chunk header format 150 : * @param block address of the block to decode 151 : * @return Publisher return code 152 : */ 153 : Publisher::Result decode_subchunk_headers(Block & block); 154 : 155 : /** 156 : * @brief decode the block with chunk trailer format 157 : * @param block address of the block to decode 158 : * @return Publisher return code 159 : */ 160 : Publisher::Result decode_subchunk_trailers(Block & block); 161 : 162 : void on_successful_send(); 163 : 164 : private: 165 : ToHostElinkStats m_stats; 166 : Elink m_elink; 167 : Publisher &m_publisher; 168 : uint64_t m_buffer_vaddr; 169 : unsigned int m_block_size; 170 : 171 : uint8_t m_seqnr_err = 0; 172 : uint8_t m_last_seqnr = 0; 173 : uint32_t m_last_block = 0; 174 : uint16_t m_chunk_position = 0; 175 : std::function< Publisher::Result(Block & block)> m_decode; 176 : 177 : 178 : std::unique_ptr<L0Decoder> m_l0id_checker; 179 : std::vector<std::pair<uint16_t, uint32_t>> m_subchunks; 180 : chunk_buffer m_scratch; 181 : }; 182 : 183 : #endif /* FELIX_DECODER_H_ */