diff options
Diffstat (limited to 'host/lib/include/uhdlib')
| -rw-r--r-- | host/lib/include/uhdlib/transport/link_base.hpp | 233 | ||||
| -rw-r--r-- | host/lib/include/uhdlib/transport/link_if.hpp | 101 | 
2 files changed, 334 insertions, 0 deletions
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 */  | 
