aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp
diff options
context:
space:
mode:
authormichael-west <michael.west@ettus.com>2020-06-12 10:15:45 -0700
committerAaron Rossetto <aaron.rossetto@ni.com>2020-08-04 15:41:07 -0500
commit57c39779f1c7f8fe78e5c1d326a59d7a172e3de3 (patch)
tree7d360b2254d5d69daa49560ae7550057289d72b7 /host/lib/usrp
parentf659c1af8f5a0e2e629ec67c9a3a4d54f8c7d529 (diff)
downloaduhd-57c39779f1c7f8fe78e5c1d326a59d7a172e3de3.tar.gz
uhd-57c39779f1c7f8fe78e5c1d326a59d7a172e3de3.tar.bz2
uhd-57c39779f1c7f8fe78e5c1d326a59d7a172e3de3.zip
multi_usrp: Fix connect/disconnect of RFNoC chains
- Added helper methods to connect and disconnect TX and RX chains. - Directly create streamer objects and register local disconnect methods to make sure chains are disconnected and the streamer is removed from the graph when streamers are destroyed. Signed-off-by: michael-west <michael.west@ettus.com>
Diffstat (limited to 'host/lib/usrp')
-rw-r--r--host/lib/usrp/multi_usrp_rfnoc.cpp282
1 files changed, 202 insertions, 80 deletions
diff --git a/host/lib/usrp/multi_usrp_rfnoc.cpp b/host/lib/usrp/multi_usrp_rfnoc.cpp
index 4554f4e57..c937cb892 100644
--- a/host/lib/usrp/multi_usrp_rfnoc.cpp
+++ b/host/lib/usrp/multi_usrp_rfnoc.cpp
@@ -15,6 +15,8 @@
#include <uhd/usrp/multi_usrp.hpp>
#include <uhd/utils/graph_utils.hpp>
#include <uhdlib/rfnoc/rfnoc_device.hpp>
+#include <uhdlib/rfnoc/rfnoc_rx_streamer.hpp>
+#include <uhdlib/rfnoc/rfnoc_tx_streamer.hpp>
#include <uhdlib/usrp/gpio_defs.hpp>
#include <uhdlib/utils/narrow.hpp>
#include <unordered_set>
@@ -32,13 +34,13 @@ using namespace uhd::usrp;
using namespace uhd::rfnoc;
//! Fan out (mux) an API call that is for all channels or all motherboards
-#define MUX_API_CALL(max_index, api_call, mux_var, mux_cond, ...) \
- if (mux_var == mux_cond) { \
- for (size_t __index = 0; __index < max_index; ++__index) { \
- api_call(__VA_ARGS__, __index); \
- } \
- return; \
- }
+#define MUX_API_CALL(max_index, api_call, mux_var, mux_cond, ...) \
+ if (mux_var == mux_cond) { \
+ for (size_t __index = 0; __index < max_index; ++__index) { \
+ api_call(__VA_ARGS__, __index); \
+ } \
+ return; \
+ }
//! Fan out (mux) an RX-specific API call that is for all channels
#define MUX_RX_API_CALL(api_call, ...) \
@@ -81,7 +83,7 @@ public:
tx_streamer::sptr get_tx_stream(const stream_args_t& args)
{
- auto streamer = _musrp->get_tx_stream(args);
+ auto streamer = _musrp->get_tx_stream(args);
_last_tx_streamer = streamer;
return streamer;
}
@@ -239,13 +241,15 @@ public:
for (size_t rx_chan = 0; rx_chan < get_rx_num_channels(); ++rx_chan) {
auto& rx_chain = _get_rx_chan(rx_chan);
if (rx_chain.ddc) {
- rx_chain.ddc->set_input_rate(rx_chain.radio->get_rate(), rx_chain.block_chan);
+ rx_chain.ddc->set_input_rate(
+ rx_chain.radio->get_rate(), rx_chain.block_chan);
}
}
for (size_t tx_chan = 0; tx_chan < get_tx_num_channels(); ++tx_chan) {
auto& tx_chain = _get_tx_chan(tx_chan);
if (tx_chain.duc) {
- tx_chain.duc->set_output_rate(tx_chain.radio->get_rate(), tx_chain.block_chan);
+ tx_chain.duc->set_output_rate(
+ tx_chain.radio->get_rate(), tx_chain.block_chan);
}
}
_graph->commit();
@@ -270,33 +274,34 @@ public:
{
std::lock_guard<std::recursive_mutex> l(_graph_mutex);
stream_args_t args = sanitize_stream_args(args_);
+ double rate = 1.0;
+
// Note that we don't release the graph, which means that property
// propagation is possible. This is necessary so we don't disrupt
// existing streamers. We use the _graph_mutex to try and avoid any
// property propagation where possible.
- double rate = 1.0;
- // This will create an unconnected streamer
- auto rx_streamer = _graph->create_rx_streamer(args.channels.size(), args);
+
+ // Connect the chains
+ _connect_rx_chains(args.channels);
+
+ // Create the streamer
+ // The disconnect callback must disconnect the entire chain because the radio
+ // relies on the connections to determine what is enabled.
+ auto rx_streamer = std::make_shared<rfnoc_rx_streamer>(args.channels.size(),
+ args,
+ [this, channels = args.channels](const std::string& id) {
+ this->_graph->disconnect(id);
+ this->_disconnect_rx_chains(channels);
+ });
+
+ // Connect the streamer
for (size_t strm_port = 0; strm_port < args.channels.size(); ++strm_port) {
auto rx_channel = args.channels.at(strm_port);
auto rx_chain = _get_rx_chan(rx_channel);
- UHD_ASSERT_THROW(!rx_chain.edge_list.empty())
- // Make all of the connections in our chain
- for (auto edge : rx_chain.edge_list) {
- if (block_id_t(edge.dst_blockid).match(NODE_ID_SEP)) {
- break;
- }
- UHD_LOG_TRACE("MULTI_USRP",
- boost::format("Connecting RX edge: %s:%d -> %s:%d") % edge.src_blockid
- % edge.src_port % edge.dst_blockid % edge.dst_port);
- _graph->connect(
- edge.src_blockid, edge.src_port, edge.dst_blockid, edge.dst_port);
- }
- // Including the connection to the streamer
UHD_LOG_TRACE("MULTI_USRP",
- boost::format("Connecting %s:%d -> RxStreamer:%d")
- % rx_chain.edge_list.back().src_blockid
- % rx_chain.edge_list.back().src_port % strm_port);
+ "Connecting " << rx_chain.edge_list.back().src_blockid << ":"
+ << rx_chain.edge_list.back().src_port
+ << " -> RxStreamer:" << strm_port);
_graph->connect(rx_chain.edge_list.back().src_blockid,
rx_chain.edge_list.back().src_port,
rx_streamer,
@@ -307,11 +312,13 @@ public:
if (rate > 1.0) {
UHD_LOG_DEBUG("MULTI_USRP",
"Inconsistent RX rates when creating streamer! "
- "Harmonizing to " << chan_rate);
+ "Harmonizing to "
+ << chan_rate);
}
rate = chan_rate;
}
}
+
// Now everything is connected, commit() again so we can have stream
// commands go through the graph
_graph->commit();
@@ -333,6 +340,7 @@ public:
}
}
}
+
return rx_streamer;
}
@@ -340,33 +348,34 @@ public:
{
std::lock_guard<std::recursive_mutex> l(_graph_mutex);
stream_args_t args = sanitize_stream_args(args_);
+ double rate = 1.0;
+
// Note that we don't release the graph, which means that property
// propagation is possible. This is necessary so we don't disrupt
// existing streamers. We use the _graph_mutex to try and avoid any
// property propagation where possible.
- double rate = 1.0;
- // This will create an unconnected streamer
- auto tx_streamer = _graph->create_tx_streamer(args.channels.size(), args);
+
+ // Connect the chains
+ _connect_tx_chains(args.channels);
+
+ // Create a streamer
+ // The disconnect callback must disconnect the entire chain because the radio
+ // relies on the connections to determine what is enabled.
+ auto tx_streamer = std::make_shared<rfnoc_tx_streamer>(args.channels.size(),
+ args,
+ [this, channels = args.channels](const std::string& id) {
+ this->_graph->disconnect(id);
+ this->_disconnect_tx_chains(channels);
+ });
+
+ // Connect the streamer
for (size_t strm_port = 0; strm_port < args.channels.size(); ++strm_port) {
auto tx_channel = args.channels.at(strm_port);
auto tx_chain = _get_tx_chan(tx_channel);
- UHD_ASSERT_THROW(!tx_chain.edge_list.empty())
- // Make all of the connections in our chain
- for (auto edge : tx_chain.edge_list) {
- if (block_id_t(edge.src_blockid).match(NODE_ID_SEP)) {
- break;
- }
- UHD_LOG_TRACE("MULTI_USRP",
- boost::format("Connecting TX edge %s:%d -> %s:%d") % edge.src_blockid
- % edge.src_port % edge.dst_blockid % edge.dst_port);
- _graph->connect(
- edge.src_blockid, edge.src_port, edge.dst_blockid, edge.dst_port);
- }
- // Including the connection to the streamer
UHD_LOG_TRACE("MULTI_USRP",
- boost::format("Connecting TxStreamer:%d -> %s:%d") % strm_port
- % tx_chain.edge_list.back().dst_blockid
- % tx_chain.edge_list.back().dst_port);
+ "Connecting TxStreamer:" << strm_port << " -> "
+ << tx_chain.edge_list.back().dst_blockid << ":"
+ << tx_chain.edge_list.back().dst_port);
_graph->connect(tx_streamer,
strm_port,
tx_chain.edge_list.back().dst_blockid,
@@ -403,10 +412,12 @@ public:
}
}
}
+
// For legacy purposes: This enables recv_async_msg(), which is considered
// deprecated, but as long as it's there, we need this to approximate
// previous behaviour.
_device->set_tx_stream(tx_streamer);
+
return tx_streamer;
}
@@ -451,15 +462,17 @@ public:
const auto db_eeprom = rx_chain.radio->get_db_eeprom();
usrp_info["rx_serial"] =
- db_eeprom.count("rx_serial") ? bytes_to_str(db_eeprom.at("rx_serial")) :
- db_eeprom.count("serial") ? bytes_to_str(db_eeprom.at("serial")) :"";
+ db_eeprom.count("rx_serial")
+ ? bytes_to_str(db_eeprom.at("rx_serial"))
+ : db_eeprom.count("serial") ? bytes_to_str(db_eeprom.at("serial")) : "";
usrp_info["rx_id"] =
- db_eeprom.count("rx_id") ? bytes_to_str(db_eeprom.at("rx_id")) :
- db_eeprom.count("pid") ? bytes_to_str(db_eeprom.at("pid")) : "";
+ db_eeprom.count("rx_id")
+ ? bytes_to_str(db_eeprom.at("rx_id"))
+ : db_eeprom.count("pid") ? bytes_to_str(db_eeprom.at("pid")) : "";
const auto rx_power_ref_keys = rx_chain.radio->get_rx_power_ref_keys();
if (!rx_power_ref_keys.empty() && rx_power_ref_keys.size() == 2) {
- usrp_info["rx_ref_power_key"] = rx_power_ref_keys.at(0);
+ usrp_info["rx_ref_power_key"] = rx_power_ref_keys.at(0);
usrp_info["rx_ref_power_serial"] = rx_power_ref_keys.at(1);
}
@@ -483,15 +496,17 @@ public:
const auto db_eeprom = tx_chain.radio->get_db_eeprom();
usrp_info["tx_serial"] =
- db_eeprom.count("tx_serial") ? bytes_to_str(db_eeprom.at("tx_serial")) :
- db_eeprom.count("serial") ? bytes_to_str(db_eeprom.at("serial")) : "";
+ db_eeprom.count("tx_serial")
+ ? bytes_to_str(db_eeprom.at("tx_serial"))
+ : db_eeprom.count("serial") ? bytes_to_str(db_eeprom.at("serial")) : "";
usrp_info["tx_id"] =
- db_eeprom.count("tx_id") ? bytes_to_str(db_eeprom.at("tx_id")) :
- db_eeprom.count("pid") ? bytes_to_str(db_eeprom.at("pid")) : "";
+ db_eeprom.count("tx_id")
+ ? bytes_to_str(db_eeprom.at("tx_id"))
+ : db_eeprom.count("pid") ? bytes_to_str(db_eeprom.at("pid")) : "";
const auto tx_power_ref_keys = tx_chain.radio->get_tx_power_ref_keys();
if (!tx_power_ref_keys.empty() && tx_power_ref_keys.size() == 2) {
- usrp_info["tx_ref_power_key"] = tx_power_ref_keys.at(0);
+ usrp_info["tx_ref_power_key"] = tx_power_ref_keys.at(0);
usrp_info["tx_ref_power_serial"] = tx_power_ref_keys.at(1);
}
@@ -877,7 +892,8 @@ public:
get_mbc(mboard)->set_sync_source(clock_source, time_source);
}
- void set_sync_source(const device_addr_t& sync_source, const size_t mboard = ALL_MBOARDS)
+ void set_sync_source(
+ const device_addr_t& sync_source, const size_t mboard = ALL_MBOARDS)
{
MUX_MB_API_CALL(set_sync_source, sync_source);
get_mbc(mboard)->set_sync_source(sync_source);
@@ -1069,10 +1085,16 @@ public:
return new_rx_chans;
}();
- // Now register them
+ // Disconnect and clear the existing chains
+ for (size_t i = 0; i < _rx_chans.size(); i++) {
+ _disconnect_rx_chain(i);
+ }
_rx_chans.clear();
- for (size_t rx_chan = 0; rx_chan < new_rx_chans.size(); ++rx_chan) {
- _rx_chans.emplace(rx_chan, new_rx_chans.at(rx_chan));
+
+ // Register the new chains
+ size_t musrp_rx_channel = 0;
+ for (auto rx_chan : new_rx_chans) {
+ _rx_chans.emplace(musrp_rx_channel++, rx_chan);
}
}
@@ -1244,7 +1266,8 @@ public:
return rx_chain.radio->get_rx_lo_names(rx_chain.block_chan);
}
- void set_rx_lo_source(const std::string& src, const std::string& name = ALL_LOS, size_t chan = 0)
+ void set_rx_lo_source(
+ const std::string& src, const std::string& name = ALL_LOS, size_t chan = 0)
{
MUX_RX_API_CALL(set_rx_lo_source, src, name);
auto rx_chain = _get_rx_chan(chan);
@@ -1257,18 +1280,19 @@ public:
return rx_chain.radio->get_rx_lo_source(name, rx_chain.block_chan);
}
- std::vector<std::string> get_rx_lo_sources(const std::string& name = ALL_LOS, size_t chan = 0)
+ std::vector<std::string> get_rx_lo_sources(
+ const std::string& name = ALL_LOS, size_t chan = 0)
{
auto rx_chain = _get_rx_chan(chan);
return rx_chain.radio->get_rx_lo_sources(name, rx_chain.block_chan);
}
- void set_rx_lo_export_enabled(bool enabled, const std::string& name = ALL_LOS, size_t chan = 0)
+ void set_rx_lo_export_enabled(
+ bool enabled, const std::string& name = ALL_LOS, size_t chan = 0)
{
MUX_RX_API_CALL(set_rx_lo_export_enabled, enabled, name);
auto rx_chain = _get_rx_chan(chan);
- rx_chain.radio->set_rx_lo_export_enabled(
- enabled, name, rx_chain.block_chan);
+ rx_chain.radio->set_rx_lo_export_enabled(enabled, name, rx_chain.block_chan);
}
bool get_rx_lo_export_enabled(const std::string& name = ALL_LOS, size_t chan = 0)
@@ -1310,13 +1334,15 @@ public:
tx_chain.radio->set_tx_lo_source(src, name, tx_chain.block_chan);
}
- const std::string get_tx_lo_source(const std::string& name = ALL_LOS, const size_t chan = 0)
+ const std::string get_tx_lo_source(
+ const std::string& name = ALL_LOS, const size_t chan = 0)
{
auto tx_chain = _get_tx_chan(chan);
return tx_chain.radio->get_tx_lo_source(name, tx_chain.block_chan);
}
- std::vector<std::string> get_tx_lo_sources(const std::string& name = ALL_LOS, const size_t chan = 0)
+ std::vector<std::string> get_tx_lo_sources(
+ const std::string& name = ALL_LOS, const size_t chan = 0)
{
auto tx_chain = _get_tx_chan(chan);
return tx_chain.radio->get_tx_lo_sources(name, tx_chain.block_chan);
@@ -1330,13 +1356,15 @@ public:
tx_chain.radio->set_tx_lo_export_enabled(enabled, name, tx_chain.block_chan);
}
- bool get_tx_lo_export_enabled(const std::string& name = ALL_LOS, const size_t chan = 0)
+ bool get_tx_lo_export_enabled(
+ const std::string& name = ALL_LOS, const size_t chan = 0)
{
auto tx_chain = _get_tx_chan(chan);
return tx_chain.radio->get_tx_lo_export_enabled(name, tx_chain.block_chan);
}
- double set_tx_lo_freq(const double freq, const std::string& name, const size_t chan = 0)
+ double set_tx_lo_freq(
+ const double freq, const std::string& name, const size_t chan = 0)
{
auto tx_chain = _get_tx_chan(chan);
return tx_chain.radio->set_tx_lo_freq(freq, name, tx_chain.block_chan);
@@ -1679,10 +1707,16 @@ public:
return new_tx_chans;
}();
- // Now register them
+ // Disconnect and clear existing chains
+ for (size_t i = 0; i < _tx_chans.size(); i++) {
+ _disconnect_tx_chain(i);
+ }
_tx_chans.clear();
- for (size_t tx_chan = 0; tx_chan < new_tx_chans.size(); ++tx_chan) {
- _tx_chans.emplace(tx_chan, new_tx_chans.at(tx_chan));
+
+ // Register new chains
+ size_t musrp_tx_channel = 0;
+ for (auto tx_chan : new_tx_chans) {
+ _tx_chans.emplace(musrp_tx_channel++, tx_chan);
}
}
@@ -1987,7 +2021,8 @@ public:
return tx_chain.radio->get_tx_dc_offset_range(tx_chain.block_chan);
}
- void set_tx_iq_balance(const std::complex<double>& correction, size_t chan = ALL_CHANS)
+ void set_tx_iq_balance(
+ const std::complex<double>& correction, size_t chan = ALL_CHANS)
{
MUX_TX_API_CALL(set_tx_iq_balance, correction);
const auto tx_chain = _get_tx_chan(chan);
@@ -2091,18 +2126,21 @@ public:
return get_mbc(mboard)->get_gpio_banks();
}
- std::vector<std::string> get_gpio_srcs(const std::string& bank, const size_t mboard = 0)
+ std::vector<std::string> get_gpio_srcs(
+ const std::string& bank, const size_t mboard = 0)
{
return get_mbc(mboard)->get_gpio_srcs(bank);
}
- std::vector<std::string> get_gpio_src(const std::string& bank, const size_t mboard = 0)
+ std::vector<std::string> get_gpio_src(
+ const std::string& bank, const size_t mboard = 0)
{
return get_mbc(mboard)->get_gpio_src(bank);
}
- void set_gpio_src(
- const std::string& bank, const std::vector<std::string>& src, const size_t mboard = 0)
+ void set_gpio_src(const std::string& bank,
+ const std::vector<std::string>& src,
+ const size_t mboard = 0)
{
get_mbc(mboard)->set_gpio_src(bank, src);
}
@@ -2383,6 +2421,90 @@ private:
return _tx_chans.at(chan);
}
+ void _connect_rx_chain(size_t chan)
+ {
+ auto rx_chan = _rx_chans.at(chan);
+ for (auto edge : rx_chan.edge_list) {
+ if (block_id_t(edge.dst_blockid).match(NODE_ID_SEP)) {
+ break;
+ }
+ UHD_LOG_TRACE(
+ "MULTI_USRP", std::string("Connecting RX edge: ") + edge.to_string());
+ _graph->connect(
+ edge.src_blockid, edge.src_port, edge.dst_blockid, edge.dst_port);
+ }
+ }
+
+ void _connect_rx_chains(std::vector<size_t> chans)
+ {
+ for (auto chan : chans) {
+ _connect_rx_chain(chan);
+ }
+ }
+
+ void _connect_tx_chain(size_t chan)
+ {
+ auto tx_chan = _tx_chans.at(chan);
+ for (auto edge : tx_chan.edge_list) {
+ if (block_id_t(edge.src_blockid).match(NODE_ID_SEP)) {
+ break;
+ }
+ UHD_LOG_TRACE(
+ "MULTI_USRP", std::string("Connecting TX edge: ") + edge.to_string());
+ _graph->connect(
+ edge.src_blockid, edge.src_port, edge.dst_blockid, edge.dst_port);
+ }
+ }
+
+ void _connect_tx_chains(std::vector<size_t> chans)
+ {
+ for (auto chan : chans) {
+ _connect_tx_chain(chan);
+ }
+ }
+
+ void _disconnect_rx_chain(size_t chan)
+ {
+ auto rx_chan = _rx_chans.at(chan);
+ for (auto edge : rx_chan.edge_list) {
+ if (block_id_t(edge.dst_blockid).match(NODE_ID_SEP)) {
+ break;
+ }
+ UHD_LOG_TRACE(
+ "MULTI_USRP", std::string("Disconnecting RX edge: ") + edge.to_string());
+ _graph->disconnect(
+ edge.src_blockid, edge.src_port, edge.dst_blockid, edge.dst_port);
+ }
+ }
+
+ void _disconnect_rx_chains(std::vector<size_t> chans)
+ {
+ for (auto chan : chans) {
+ _disconnect_rx_chain(chan);
+ }
+ }
+
+ void _disconnect_tx_chain(size_t chan)
+ {
+ auto tx_chan = _tx_chans.at(chan);
+ for (auto edge : tx_chan.edge_list) {
+ if (block_id_t(edge.src_blockid).match(NODE_ID_SEP)) {
+ break;
+ }
+ UHD_LOG_TRACE(
+ "MULTI_USRP", std::string("Disconnecting TX edge: ") + edge.to_string());
+ _graph->disconnect(
+ edge.src_blockid, edge.src_port, edge.dst_blockid, edge.dst_port);
+ }
+ }
+
+ void _disconnect_tx_chains(std::vector<size_t> chans)
+ {
+ for (auto chan : chans) {
+ _disconnect_tx_chain(chan);
+ }
+ }
+
/**************************************************************************
* Private Attributes
*************************************************************************/