summaryrefslogtreecommitdiff
path: root/gr-uhd/lib/rfnoc_graph_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gr-uhd/lib/rfnoc_graph_impl.cc')
-rw-r--r--gr-uhd/lib/rfnoc_graph_impl.cc214
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);
+}