// // Copyright 2019 Ettus Research, a National Instruments Brand // // SPDX-License-Identifier: GPL-3.0-or-later // #include #include #include #include using namespace uhd; using namespace uhd::rfnoc; using namespace uhd::rfnoc::chdr; chdr_packet::~chdr_packet() = default; //------------------------------------------------------------ // chdr_packet //------------------------------------------------------------ // endianness is the link endianness, not the host endianness template class chdr_packet_impl : public chdr_packet { public: chdr_packet_impl() = delete; chdr_packet_impl(size_t mtu_bytes) : _mtu_bytes(mtu_bytes) {} ~chdr_packet_impl() = default; virtual void refresh(const void* pkt_buff) const { assert(pkt_buff); _pkt_buff = const_cast(reinterpret_cast(pkt_buff)); _mdata_offset = _compute_mdata_offset(get_chdr_header()); } virtual void refresh(void* pkt_buff, chdr_header& header, uint64_t timestamp = 0) { assert(pkt_buff); _pkt_buff = reinterpret_cast(pkt_buff); _pkt_buff[0] = u64_from_host(header); if (_has_timestamp(header)) { _pkt_buff[1] = u64_from_host(timestamp); } _mdata_offset = _compute_mdata_offset(get_chdr_header()); } virtual void update_payload_size(size_t payload_size_bytes) { chdr_header header = get_chdr_header(); header.set_length(((_mdata_offset + header.get_num_mdata()) * chdr_w_bytes) + payload_size_bytes); _pkt_buff[0] = u64_from_host(header); } virtual endianness_t get_byte_order() const { return endianness; } virtual size_t get_mtu_bytes() const { return _mtu_bytes; } virtual chdr_header get_chdr_header() const { assert(_pkt_buff); return std::move(chdr_header(u64_to_host(_pkt_buff[0]))); } virtual boost::optional get_timestamp() const { if (_has_timestamp(get_chdr_header())) { // In a unit64_t buffer, the timestamp is always immediately after the header // regardless of chdr_w. return u64_to_host(_pkt_buff[1]); } else { return boost::none; } } virtual size_t get_mdata_size() const { return get_chdr_header().get_num_mdata() * chdr_w_bytes; } virtual const void* get_mdata_const_ptr() const { return const_cast( const_cast*>(this)->get_mdata_ptr()); } virtual void* get_mdata_ptr() { return reinterpret_cast(_pkt_buff + (chdr_w_stride * _mdata_offset)); } virtual size_t get_payload_size() const { return get_chdr_header().get_length() - get_mdata_size() - (chdr_w_bytes * _mdata_offset); } virtual const void* get_payload_const_ptr() const { return const_cast( const_cast*>(this)->get_payload_ptr()); } virtual void* get_payload_ptr() { return reinterpret_cast( _pkt_buff + (chdr_w_stride * (_mdata_offset + get_chdr_header().get_num_mdata()))); } virtual size_t calculate_payload_offset(const packet_type_t pkt_type, const uint8_t num_mdata = 0) const { chdr_header header; header.set_pkt_type(pkt_type); return (_compute_mdata_offset(header) + num_mdata) * chdr_w_bytes; } private: inline bool _has_timestamp(const chdr_header& header) const { return (header.get_pkt_type() == PKT_TYPE_DATA_WITH_TS); } inline size_t _compute_mdata_offset(const chdr_header& header) const { // The metadata offset depends on the chdr_w and whether we have a timestamp if (chdr_w == 64) { return _has_timestamp(header) ? 2 : 1; } else { return 1; } } inline static uint64_t u64_to_host(uint64_t word) { return (endianness == ENDIANNESS_BIG) ? uhd::ntohx(word) : uhd::wtohx(word); } inline static uint64_t u64_from_host(uint64_t word) { return (endianness == ENDIANNESS_BIG) ? uhd::htonx(word) : uhd::htowx(word); } static const size_t chdr_w_bytes = (chdr_w / 8); static const size_t chdr_w_stride = (chdr_w / 64); // Packet state const size_t _mtu_bytes = 0; mutable uint64_t* _pkt_buff = nullptr; mutable size_t _mdata_offset = 0; }; chdr_packet_factory::chdr_packet_factory(chdr_w_t chdr_w, endianness_t endianness) : _chdr_w(chdr_w), _endianness(endianness) { } chdr_packet::uptr chdr_packet_factory::make_generic(size_t mtu_bytes) const { if (_endianness == ENDIANNESS_BIG) { switch (_chdr_w) { case CHDR_W_512: return std::make_unique>(mtu_bytes); case CHDR_W_256: return std::make_unique>(mtu_bytes); case CHDR_W_128: return std::make_unique>(mtu_bytes); case CHDR_W_64: return std::make_unique>(mtu_bytes); default: assert(0); } } else { switch (_chdr_w) { case CHDR_W_512: return std::make_unique>( mtu_bytes); case CHDR_W_256: return std::make_unique>( mtu_bytes); case CHDR_W_128: return std::make_unique>( mtu_bytes); case CHDR_W_64: return std::make_unique>( mtu_bytes); default: assert(0); } } return chdr_packet::uptr(); } chdr_ctrl_packet::uptr chdr_packet_factory::make_ctrl(size_t mtu_bytes) const { return std::make_unique(make_generic(mtu_bytes)); } chdr_strs_packet::uptr chdr_packet_factory::make_strs(size_t mtu_bytes) const { return std::make_unique(make_generic(mtu_bytes)); } chdr_strc_packet::uptr chdr_packet_factory::make_strc(size_t mtu_bytes) const { return std::make_unique(make_generic(mtu_bytes)); } chdr_mgmt_packet::uptr chdr_packet_factory::make_mgmt(size_t mtu_bytes) const { return std::make_unique(make_generic(mtu_bytes)); }