diff options
Diffstat (limited to 'host')
-rw-r--r-- | host/include/uhd/transport/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/include/uhd/transport/frame_buff.hpp | 69 | ||||
-rw-r--r-- | host/lib/include/uhdlib/transport/link_base.hpp | 233 | ||||
-rw-r--r-- | host/lib/include/uhdlib/transport/link_if.hpp | 101 |
4 files changed, 404 insertions, 0 deletions
diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index d0810e502..400b3db0b 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -10,6 +10,7 @@ UHD_INSTALL(FILES bounded_buffer.ipp buffer_pool.hpp chdr.hpp + frame_buff.hpp if_addrs.hpp udp_constants.hpp udp_simple.hpp diff --git a/host/include/uhd/transport/frame_buff.hpp b/host/include/uhd/transport/frame_buff.hpp new file mode 100644 index 000000000..c335f0c4b --- /dev/null +++ b/host/include/uhd/transport/frame_buff.hpp @@ -0,0 +1,69 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef INCLUDED_UHD_TRANSPORT_FRAME_BUFF_HPP +#define INCLUDED_UHD_TRANSPORT_FRAME_BUFF_HPP + +#include <memory> + +namespace uhd { namespace transport { + +/*! + * Contains a reference to a frame buffer managed by a link. + */ +class frame_buff +{ +public: + /*! + * No-op deleter to prevent unique_ptr from deleting the buffer if the + * pointer goes out of scope. The lifetime of the buffers is controlled + * by the links. + */ + struct deleter + { + void operator()(frame_buff*) {} + }; + + using uptr = std::unique_ptr<frame_buff, deleter>; + + /*! + * Get the raw data buffer contained within the frame buffer + * \return a pointer to the buffer memory. + */ + void* data() const + { + return _data; + } + + /*! + * Returns the size of the packet + * \return the size of the packet contained in the frame buffer, in bytes. + */ + size_t packet_size() const + { + return _packet_size; + } + + /*! + * Sets the size of the packet contained in the frame buffer, in bytes. + * \param size Number of bytes occupied in the buffer + */ + void set_packet_size(size_t size) + { + _packet_size = size; + } + +protected: + /*! Pointer to data of current frame */ + void* _data = nullptr; + + /*! Size of packet in current frame */ + size_t _packet_size = 0; +}; + +}} // namespace uhd::transport + +#endif /* INCLUDED_UHD_TRANSPORT_FRAME_BUFF_HPP */ diff --git a/host/lib/include/uhdlib/transport/link_base.hpp b/host/lib/include/uhdlib/transport/link_base.hpp new file mode 100644 index 000000000..e4d329e2a --- /dev/null +++ b/host/lib/include/uhdlib/transport/link_base.hpp @@ -0,0 +1,233 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef INCLUDED_UHDLIB_TRANSPORT_LINK_BASE_HPP +#define INCLUDED_UHDLIB_TRANSPORT_LINK_BASE_HPP + +#include <uhdlib/transport/link_if.hpp> +#include <cassert> +#include <vector> + +namespace uhd { namespace transport { +namespace detail { + +/*! + * Container for free buffers used by link base classes. + */ +class free_buff_pool +{ +public: + free_buff_pool(const size_t capacity) + { + _buffs.reserve(capacity); + } + + frame_buff* pop() + { + // Free buffer pool should not be empty unless user has requested more + // buffers than the number of frames in the link. + assert(!_buffs.empty()); + + frame_buff* buff = _buffs.back(); + _buffs.pop_back(); + return buff; + } + + void push(frame_buff* buff) + { + _buffs.push_back(buff); + } + +private: + std::vector<frame_buff*> _buffs; +}; + +} // namespace detail + +/*! + * Reusable base class implementation of send_link_iface. Link implementations + * should derive from this template and pass their own type as the derived_t + * template parameter. + * + * The base class template manages a pool of frame_buff pointers and implements + * the link interface methods. + * + * This template requires the following methods in the derived class: + * bool get_send_buf_derived(frame_buff& buf, int32_t timeout_ms); + * void release_send_buf_derived(frame_buff& buf); + * + * Additionally, the subclass must call preload_free_buf for each frame_buff + * object it owns during initialization to add it to the free buffer pool. + * + * \param derived_t type of the derived class + */ +template <typename derived_t> +class send_link_base : public virtual send_link_if +{ +public: + send_link_base(const size_t num_frames, const size_t frame_size) + : _send_frame_size(frame_size) + , _num_send_frames(num_frames) + , _free_send_buffs(num_frames) + { + } + + virtual size_t get_num_send_frames() const + { + return _num_send_frames; + } + + virtual size_t get_send_frame_size() const + { + return _send_frame_size; + } + + virtual frame_buff::uptr get_send_buff(int32_t timeout_ms) + { + frame_buff* buff = _free_send_buffs.pop(); + + // Call the derived class for link-specific implementation + auto* derived = static_cast<derived_t*>(this); + + if (!derived->get_send_buff_derived(*buff, timeout_ms)) { + _free_send_buffs.push(buff); + return frame_buff::uptr(); + } + + return frame_buff::uptr(buff); + } + + virtual void release_send_buff(frame_buff::uptr buff) + { + frame_buff* buff_ptr = buff.release(); + assert(buff_ptr); + + if (buff_ptr->packet_size() != 0) { + // Call the derived class for link-specific implementation + auto* derived = static_cast<derived_t*>(this); + derived->release_send_buff_derived(*buff_ptr); + } + + // Reset buff and re-add to free pool + buff_ptr->set_packet_size(0); + _free_send_buffs.push(buff_ptr); + } + +protected: + /*! + * Add buffer pointer to free buffer pool. + * + * Derived classes should call this method during initialization for each + * frame buffer it owns. + * + * \param buffer pointer to the buffer to add to the free buffer pool. + */ + void preload_free_buff(frame_buff* buff) + { + _free_send_buffs.push(buff); + } + +private: + size_t _send_frame_size; + size_t _num_send_frames; + detail::free_buff_pool _free_send_buffs; +}; + +/*! + * Reusable base class implementation of recv_link_if. Link implementations + * should derive from this template and pass their own type as the derived_t + * template parameter. + * + * The base class template manages a pool of free_buff pointers and implements + * the link interface methods. + * + * This template requires the following methods in the derived class: + * bool get_recv_buff_derived(frame_buff& buff, int32_t timeout_ms); + * void release_recv_buff_derived(frame_buff& buff); + * + * Additionally, the subclass must call preload_free_buff for each + * frame_buff object it owns during initialization to add it to the free + * buff pool. + * + * \param derived_t type of the derived class + */ +template <typename derived_t> +class recv_link_base : public virtual recv_link_if +{ +public: + recv_link_base(const size_t num_frames, const size_t frame_size) + : _recv_frame_size(frame_size) + , _num_recv_frames(num_frames) + , _free_recv_buffs(num_frames) + { + } + + virtual size_t get_num_recv_frames() const + { + return _num_recv_frames; + } + + virtual size_t get_recv_frame_size() const + { + return _recv_frame_size; + } + + virtual frame_buff::uptr get_recv_buff(int32_t timeout_ms) + { + frame_buff* buff = _free_recv_buffs.pop(); + + // Call the derived class for link specific implementation + auto* derived = static_cast<derived_t*>(this); + + size_t len = derived->get_recv_buff_derived(*buff, timeout_ms); + + if (len == 0) { + _free_recv_buffs.push(buff); + return frame_buff::uptr(); + } else { + buff->set_packet_size(len); + return frame_buff::uptr(buff); + } + } + + virtual void release_recv_buff(frame_buff::uptr buff) + { + frame_buff* buff_ptr = buff.release(); + assert(buff_ptr); + + // Call the derived class for link specific implementation + auto* derived = static_cast<derived_t*>(this); + + derived->release_recv_buff_derived(*buff_ptr); + + // Reset buffer and re-add to free pool + buff_ptr->set_packet_size(0); + _free_recv_buffs.push(buff_ptr); + } + +protected: + /*! + * Add buffer pointer to free buffer pool. + * + * Derived classes should call this method during initialization for each + * frame buffer it owns. + * + * \param buffer pointer to the buffer to add to the free buffer pool. + */ + void preload_free_buff(frame_buff* buff) + { + _free_recv_buffs.push(buff); + } + +private: + size_t _recv_frame_size; + size_t _num_recv_frames; + detail::free_buff_pool _free_recv_buffs; +}; + +}} // namespace uhd::transport + +#endif /* INCLUDED_UHDLIB_TRANSPORT_LINK_BASE_HPP */ diff --git a/host/lib/include/uhdlib/transport/link_if.hpp b/host/lib/include/uhdlib/transport/link_if.hpp new file mode 100644 index 000000000..60376e571 --- /dev/null +++ b/host/lib/include/uhdlib/transport/link_if.hpp @@ -0,0 +1,101 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include <uhd/transport/frame_buff.hpp> +#include <memory> + +#ifndef INCLUDED_UHDLIB_TRANSPORT_LINK_IF_HPP +# define INCLUDED_UHDLIB_TRANSPORT_LINK_IF_HPP + +namespace uhd { namespace transport { + +/*! + * Link interface for transmitting packets. + */ +class send_link_if +{ +public: + using sptr = std::shared_ptr<send_link_if>; + + /*! + * Get the number of frame buffers that can be queued by this link. + */ + virtual size_t get_num_send_frames() const = 0; + + /*! + * Get the maximum capacity of a frame buffer. + */ + virtual size_t get_send_frame_size() const = 0; + + /*! + * Get an empty frame buffer in which to write packet contents. + * + * \param timeout_ms a positive timeout value specifies the maximum number + of ms to wait, a negative value specifies to block + until successful, and a value of 0 specifies no wait. + * \return a frame buffer, or null uptr if timeout occurs + */ + virtual frame_buff::uptr get_send_buff(int32_t timeout_ms) = 0; + + /*! + * Send a packet with the contents of the frame buffer and release the + * buffer, allowing the link driver to reuse it. If the size of the frame + * buffer is 0, the buffer is released with no packet being sent. + * + * \param buffer frame buffer containing packet data + * + * Throws an exception if an I/O error occurs while sending + */ + virtual void release_send_buff(frame_buff::uptr buff) = 0; + + send_link_if() = default; + send_link_if(const send_link_if&) = delete; + send_link_if& operator=(const send_link_if&) = delete; +}; + +/*! + * Link interface for receiving packets. + */ +class recv_link_if +{ +public: + using sptr = std::shared_ptr<recv_link_if>; + + /*! + * Get the number of frame buffers that can be queued by this link. + */ + virtual size_t get_num_recv_frames() const = 0; + + /*! + * Get the maximum capacity of a frame buffer. + */ + virtual size_t get_recv_frame_size() const = 0; + + /*! + * Receive a packet and return a frame buffer containing the packet data. + * + * \param timeout_ms a positive timeout value specifies the maximum number + of ms to wait, a negative value specifies to block + until successful, and a value of 0 specifies no wait. + * \return a frame buffer, or null uptr if timeout occurs + */ + virtual frame_buff::uptr get_recv_buff(int32_t timeout_ms) = 0; + + /*! + * Release a frame buffer, allowing the link driver to reuse it. + * + * \param buffer frame buffer to release for reuse by the link + */ + virtual void release_recv_buff(frame_buff::uptr buff) = 0; + + recv_link_if() = default; + recv_link_if(const recv_link_if&) = delete; + recv_link_if& operator=(const recv_link_if&) = delete; +}; + +}} // namespace uhd::transport + +#endif /* INCLUDED_UHDLIB_TRANSPORT_LINK_IF_HPP */ |