diff options
Diffstat (limited to 'gr-uhd/lib/rfnoc_graph_impl.cc')
-rw-r--r-- | gr-uhd/lib/rfnoc_graph_impl.cc | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/gr-uhd/lib/rfnoc_graph_impl.cc b/gr-uhd/lib/rfnoc_graph_impl.cc new file mode 100644 index 0000000000..436faeedea --- /dev/null +++ b/gr-uhd/lib/rfnoc_graph_impl.cc @@ -0,0 +1,214 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 Ettus Research, a National Instruments Brand. + * Copyright 2020 Free Software Foundation, Inc. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gr_uhd_common.h" +#include <gnuradio/uhd/rfnoc_block.h> +#include <gnuradio/uhd/rfnoc_graph.h> +#include <uhd/rfnoc/mb_controller.hpp> +#include <uhd/rfnoc_graph.hpp> +#include <unordered_map> +#include <boost/make_shared.hpp> +#include <atomic> +#include <stdexcept> + +using ::uhd::rfnoc::block_id_t; +using namespace gr::uhd; +using namespace ::uhd; + + +class rfnoc_graph_impl : public rfnoc_graph +{ +public: + rfnoc_graph_impl(const device_addr_t& dev_addr) + : _graph(::uhd::rfnoc::rfnoc_graph::make(dev_addr)) + { + // nop + } + + void connect(const std::string& src_block_id, + const size_t src_block_port, + const std::string& dst_block_id, + const size_t dst_block_port, + const bool skip_property_propagation) + { + if (_tx_streamers.count(src_block_id)) { + if (_rx_streamers.count(dst_block_id)) { + throw std::runtime_error("Cannot connect RFNoC streamers directly!"); + } + _graph->connect(_tx_streamers.at(src_block_id), + src_block_port, + block_id_t(dst_block_id), + dst_block_port); + return; + } + if (_rx_streamers.count(dst_block_id)) { + _graph->connect(src_block_id, + src_block_port, + _rx_streamers.at(dst_block_id), + dst_block_port); + return; + } + + _graph->connect(block_id_t(src_block_id), + src_block_port, + block_id_t(dst_block_id), + dst_block_port); + } + + void connect(const std::string& block1, + const std::string& block2, + bool skip_property_propagation) + { + connect(block1, 0, block2, 0, skip_property_propagation); + } + + void connect(rfnoc_block::sptr src_block, + const size_t src_block_port, + rfnoc_block::sptr dst_block, + const size_t dst_block_port, + const bool skip_property_propagation) + { + connect(src_block->get_unique_id(), + src_block_port, + dst_block->get_unique_id(), + dst_block_port, + skip_property_propagation); + } + + + ::uhd::rx_streamer::sptr create_rx_streamer(const size_t num_ports, + const stream_args_t& args) + { + auto streamer = _graph->create_rx_streamer(num_ports, args); + const std::string streamer_id = + std::dynamic_pointer_cast<::uhd::rfnoc::node_t>(streamer)->get_unique_id(); + _rx_streamers.insert({ streamer_id, streamer }); + return streamer; + } + + ::uhd::tx_streamer::sptr create_tx_streamer(const size_t num_ports, + const stream_args_t& args) + { + auto streamer = _graph->create_tx_streamer(num_ports, args); + const std::string streamer_id = + std::dynamic_pointer_cast<::uhd::rfnoc::node_t>(streamer)->get_unique_id(); + _tx_streamers.insert({ streamer_id, streamer }); + return streamer; + } + + void commit() + { + if (!_commit_called.exchange(true)) { + _graph->commit(); + } + } + + std::string get_block_id(const std::string& block_name, + const int device_select, + const int block_select) + { + std::string block_hint = block_name; + if (device_select >= 0) { + block_hint = str(boost::format("%d/%s") % device_select % block_hint); + } + if (block_select >= 0) { + block_hint = str(boost::format("%s#%d") % block_hint % block_select); + } + + auto block_ids = _graph->find_blocks(block_hint); + if (block_ids.empty()) { + return ""; + } + + // If the hint produced a unique hit, then we return that + if (block_ids.size() == 1) { + return block_ids.front().to_string(); + } + + // If the hint produced multiple hits, then we default to one that was + // not yet acquired. If that fails, return any one. + std::lock_guard<std::mutex> l(_block_ref_mutex); + for (const auto& block_id : block_ids) { + const std::string block_id_str = block_id.to_string(); + if (!_acqd_block_refs.count(block_id_str)) { + return block_id_str; + } + } + return block_ids.front().to_string(); + } + + void set_time_source(const std::string& source, const size_t mb_index) + { + _graph->get_mb_controller(mb_index)->set_time_source(source); + } + + void set_clock_source(const std::string& source, const size_t mb_index) + { + _graph->get_mb_controller(mb_index)->set_clock_source(source); + } + + ::uhd::rfnoc::noc_block_base::sptr get_block_ref(const std::string& block_id, + const size_t max_ref_count) + { + std::lock_guard<std::mutex> l(_block_ref_mutex); + if (max_ref_count == 0) { + throw std::runtime_error("Invalid max_ref_count 0!"); + } + + auto block_ref = _graph->get_block(block_id_t(block_id)); + const std::string real_block_id = block_ref->get_unique_id(); + + // If this is the first time we encounter this block ID, create a ref + // counter for it + if (!_acqd_block_refs.count(real_block_id)) { + _acqd_block_refs.insert({ real_block_id, 0 }); + } + // Make sure the max ref count limit is set. If it already exists, + // decrease it if max_ref_count is smaller than what we already have. + if (!_max_ref_count.count(real_block_id)) { + _max_ref_count.insert({ real_block_id, max_ref_count }); + } else { + _max_ref_count[real_block_id] = + std::min(max_ref_count, _max_ref_count[real_block_id]); + } + // Now check we haven't exceeded the ref count limit + if (_acqd_block_refs.at(real_block_id) >= _max_ref_count.at(real_block_id)) { + throw std::runtime_error( + std::string("Attempting to get another reference to block ") + + real_block_id); + } + // Increase ref counter for this block ID + _acqd_block_refs[real_block_id]++; + + // And Bob's your uncle + return block_ref; + } + + +private: + std::atomic<bool> _commit_called{ false }; + ::uhd::rfnoc::rfnoc_graph::sptr _graph; + + std::unordered_map<std::string, ::uhd::rx_streamer::sptr> _rx_streamers; + std::unordered_map<std::string, ::uhd::tx_streamer::sptr> _tx_streamers; + + std::mutex _block_ref_mutex; + std::unordered_map<std::string, size_t> _acqd_block_refs; + std::unordered_map<std::string, size_t> _max_ref_count; +}; + + +rfnoc_graph::sptr rfnoc_graph::make(const device_addr_t& dev_addr) +{ + check_abi(); + return boost::make_shared<rfnoc_graph_impl>(dev_addr); +} |