// // Copyright 2014-2015 Ettus Research LLC // Copyright 2018 Ettus Research, a National Instruments Company // // SPDX-License-Identifier: GPL-3.0-or-later // // Declares the device3_impl class which is a layer between device3 and // the different 3-rd gen device impls (e.g. x300_impl) #ifndef INCLUDED_DEVICE3_IMPL_HPP #define INCLUDED_DEVICE3_IMPL_HPP #include "../../transport/super_recv_packet_handler.hpp" #include "../../transport/super_send_packet_handler.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace uhd { namespace usrp { /*********************************************************************** * Default settings (any device3 may override these) **********************************************************************/ static const size_t DEVICE3_RX_FC_REQUEST_FREQ = 32; // per flow-control window static const size_t DEVICE3_TX_FC_RESPONSE_FREQ = 8; static const size_t DEVICE3_FC_PACKET_LEN_IN_WORDS32 = 2; static const size_t DEVICE3_FC_PACKET_COUNT_OFFSET = 0; static const size_t DEVICE3_FC_BYTE_COUNT_OFFSET = 1; static const size_t DEVICE3_LINE_SIZE = 8; static const size_t DEVICE3_TX_MAX_HDR_LEN = uhd::transport::vrt::chdr::max_if_hdr_words64 * sizeof(uint64_t); // Bytes static const size_t DEVICE3_RX_MAX_HDR_LEN = uhd::transport::vrt::chdr::max_if_hdr_words64 * sizeof(uint64_t); // Bytes // This class manages the lifetime of the TX async message handler task, transports, and // terminator class device3_send_packet_streamer : public uhd::transport::sph::send_packet_streamer { public: device3_send_packet_streamer(const size_t max_num_samps, const uhd::rfnoc::tx_stream_terminator::sptr terminator, const both_xports_t data_xport, const both_xports_t async_msg_xport) : uhd::transport::sph::send_packet_streamer(max_num_samps) , _terminator(terminator) , _data_xport(data_xport) , _async_msg_xport(async_msg_xport) { } ~device3_send_packet_streamer() { // Make sure the async task is destroyed before the transports _tx_async_msg_tasks.clear(); } uhd::rfnoc::tx_stream_terminator::sptr get_terminator() { return _terminator; } void add_async_msg_task(task::sptr task) { _tx_async_msg_tasks.push_back(task); } private: uhd::rfnoc::tx_stream_terminator::sptr _terminator; both_xports_t _data_xport; both_xports_t _async_msg_xport; std::vector _tx_async_msg_tasks; }; // This class manages the lifetime of the RX transports and terminator and provides access // to both class device3_recv_packet_streamer : public uhd::transport::sph::recv_packet_streamer { public: device3_recv_packet_streamer(const size_t max_num_samps, const uhd::rfnoc::rx_stream_terminator::sptr terminator, const both_xports_t xport) : uhd::transport::sph::recv_packet_streamer(max_num_samps) , _terminator(terminator) , _xport(xport) { } ~device3_recv_packet_streamer() {} both_xports_t get_xport() { return _xport; } uhd::rfnoc::rx_stream_terminator::sptr get_terminator() { return _terminator; } private: uhd::rfnoc::rx_stream_terminator::sptr _terminator; both_xports_t _xport; }; class device3_impl : public uhd::device3, public boost::enable_shared_from_this { public: /*********************************************************************** * device3-specific Types **********************************************************************/ typedef uhd::transport::bounded_buffer async_md_type; //! The purpose of a transport enum xport_type_t { CTRL = 0, ASYNC_MSG, TX_DATA, RX_DATA }; enum xport_t { AXI, ETH, PCIE }; //! Stores all streaming-related options struct stream_options_t { //! Max size of the header in bytes for TX size_t tx_max_len_hdr; //! Max size of the header in bytes for RX size_t rx_max_len_hdr; //! How often we send ACKs to the upstream block per one full FC window size_t rx_fc_request_freq; //! How often the downstream block should send ACKs per one full FC window size_t tx_fc_response_freq; stream_options_t(void) : tx_max_len_hdr(DEVICE3_TX_MAX_HDR_LEN) , rx_max_len_hdr(DEVICE3_RX_MAX_HDR_LEN) , rx_fc_request_freq(DEVICE3_RX_FC_REQUEST_FREQ) , tx_fc_response_freq(DEVICE3_TX_FC_RESPONSE_FREQ) { } }; /*********************************************************************** * I/O Interface **********************************************************************/ uhd::tx_streamer::sptr get_tx_stream(const uhd::stream_args_t&); uhd::rx_streamer::sptr get_rx_stream(const uhd::stream_args_t&); bool recv_async_msg(uhd::async_metadata_t& async_metadata, double timeout); /*********************************************************************** * Other public APIs **********************************************************************/ rfnoc::graph::sptr create_graph(const std::string& name = ""); protected: /*********************************************************************** * Structors **********************************************************************/ device3_impl(); virtual ~device3_impl() {} /*********************************************************************** * Streaming-related **********************************************************************/ // The 'rate' argument is so we can use these as subscribers to rate changes public: // TODO make these protected again void update_rx_streamers(double rate = -1.0); void update_tx_streamers(double rate = -1.0); protected: /*********************************************************************** * Transport-related **********************************************************************/ stream_options_t stream_options; /*! \brief Create a transport to a given endpoint. * * \param address The endpoint address of the block we're creating a transport to. * The source address in this value is not considered, only the * destination address. * \param xport_type Specify which kind of transport this is. * \param args Additional arguments for the transport generation. See \ref * page_transport for valid arguments. */ virtual uhd::both_xports_t make_transport(const uhd::sid_t& address, const xport_type_t xport_type, const uhd::device_addr_t& args) = 0; virtual uhd::device_addr_t get_tx_hints(size_t) { return uhd::device_addr_t(); } virtual uhd::device_addr_t get_rx_hints(size_t) { return uhd::device_addr_t(); } //! Is called after a streamer is generated virtual void post_streamer_hooks(uhd::direction_t) {} //! get mtu virtual size_t get_mtu(const size_t, const uhd::direction_t) = 0; /*********************************************************************** * Channel-related **********************************************************************/ /*! Merge a list of channels into the existing channel definition. * * Intelligently merge the channels described in \p chan_ids * into the current channel definition. If none of the channels in * \p chan_ids is in the current definition, they simply get appended. * Otherwise, they get overwritten in the order of \p chan_ids. * * \param chan_ids List of block IDs for the channels. * \param chan_args New channel args. Must have same length as chan_ids. * */ void merge_channel_defs(const std::vector& chan_ids, const std::vector& chan_args, const uhd::direction_t dir); /*********************************************************************** * RFNoC-Specific **********************************************************************/ void enumerate_rfnoc_blocks(size_t device_index, size_t n_blocks, size_t base_port, const uhd::sid_t& base_sid, uhd::device_addr_t transport_args); /*********************************************************************** * Members **********************************************************************/ // TODO: Maybe move these to private uhd::dict> _rx_streamers; uhd::dict> _tx_streamers; private: /*********************************************************************** * Private Members **********************************************************************/ //! Buffer for async metadata boost::shared_ptr _async_md; //! This mutex locks the get_xx_stream() functions. boost::mutex _transport_setup_mutex; }; }} /* namespace uhd::usrp */ #endif /* INCLUDED_DEVICE3_IMPL_HPP */