From 910d95af2f7df9f52bcfed3fc08c5db6b3b39fd0 Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Fri, 6 Mar 2020 14:48:54 -0800 Subject: multi_usrp: Provide valid return value for multi_usrp::get_device() For RFNoC devices, multi_usrp::get_device() no longer returns a device pointer, rather, it returns a nullptr. This is intentional because access to the underlying device is no longer allowed. However, legacy code can segfault (e.g. portions ofr gr-uhd). This patch returns a faux uhd::device class, which almost mimicks the original behaviour perfectly, by redirecting its class methods back to multi_usrp_rfnoc. The only exception is recv_async_msg(), which requires a TX streamer. This function will always return false now. --- host/include/uhd/device.hpp | 11 ++++++-- host/include/uhd/usrp/multi_usrp.hpp | 15 ++++++++-- host/lib/usrp/multi_usrp_rfnoc.cpp | 54 ++++++++++++++++++++++++++++++++++-- 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index f4594504d..a70a396a7 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -88,11 +88,18 @@ public: */ virtual tx_streamer::sptr get_tx_stream(const stream_args_t& args) = 0; - /*! - * Receive and asynchronous message from the device. + /*! Receive asynchronous message from the device + * + * Note that when calling multi_usrp::get_device() on an RFNoC-capable device, + * the returned uhd::device (while still being a valid object) will not be + * able to execute this method. Instead, query the asynchronous messages + * from the appropriate Tx streamer. + * * \param async_metadata the metadata to be filled in * \param timeout the timeout in seconds to wait for a message * \return true when the async_metadata is valid, false for timeout + * \throws uhd::runtime_error if called on a device returned by + * multi_usrp::get_device on an RFNoC device. */ virtual bool recv_async_msg( async_metadata_t& async_metadata, double timeout = 0.1) = 0; diff --git a/host/include/uhd/usrp/multi_usrp.hpp b/host/include/uhd/usrp/multi_usrp.hpp index ac80cc15a..93ef7d090 100644 --- a/host/include/uhd/usrp/multi_usrp.hpp +++ b/host/include/uhd/usrp/multi_usrp.hpp @@ -120,9 +120,18 @@ public: */ static sptr make(const device_addr_t& dev_addr); - /*! - * Get the underlying device object. - * This is needed to get access to the streaming API and properties. + /*! Get the underlying device object + * + * Note that it is not recommended to use this method. The property tree can + * be accessed by calling get_tree() on this object, and the streamers own + * all the streaming-related functionality. get_tx_stream() and + * get_rx_stream() can also be called on this object. + * + * For RFNoC devices, this won't return a true uhd::device anyway, because + * direct device access is locked for those. The returned pointer will + * still point to a valid device object, however, it has reduced + * functionality (in particular, recv_async_msg() won't work). + * * \return the device object within this USRP */ virtual device::sptr get_device(void) = 0; diff --git a/host/lib/usrp/multi_usrp_rfnoc.cpp b/host/lib/usrp/multi_usrp_rfnoc.cpp index b34860989..9a3169e38 100644 --- a/host/lib/usrp/multi_usrp_rfnoc.cpp +++ b/host/lib/usrp/multi_usrp_rfnoc.cpp @@ -37,6 +37,50 @@ constexpr char DEFAULT_OTW_FORMAT[] = "sc16"; constexpr double RX_SIGN = +1.0; constexpr double TX_SIGN = -1.0; +//! A faux container for a UHD device +// +// Note that multi_usrp_rfnoc no longer gives access to the underlying device +// class. Legacy code might use multi_usrp->get_device()->get_tree() or +// similar functionalities; these can be faked with this redirector class. +// +// The only exception is recv_async_msg(), which depends on the streamer. It +// will throw a uhd::runtime_error now. +class redirector_device : public uhd::device +{ +public: + redirector_device(multi_usrp* musrp_ptr) : _musrp(musrp_ptr) {} + + rx_streamer::sptr get_rx_stream(const stream_args_t& args) + { + return _musrp->get_rx_stream(args); + } + + tx_streamer::sptr get_tx_stream(const stream_args_t& args) + { + return _musrp->get_tx_stream(args); + } + + bool recv_async_msg(async_metadata_t&, double) + { + throw uhd::runtime_error( + "uhd::device::recv_async_msg() cannot be called on this device type!"); + return false; + } + + uhd::property_tree::sptr get_tree(void) const + { + return _musrp->get_tree(); + } + + device_filter_t get_device_type() const + { + return USRP; + } + +private: + multi_usrp* _musrp; +}; + /*! Make sure the stream args are valid and can be used by get_tx_stream() * and get_rx_stream(). * @@ -94,7 +138,10 @@ public: * Structors *************************************************************************/ multi_usrp_rfnoc(rfnoc_graph::sptr graph, const device_addr_t& addr) - : _args(addr), _graph(graph), _tree(_graph->get_tree()) + : _args(addr) + , _graph(graph) + , _tree(_graph->get_tree()) + , _device(std::make_shared(this)) { // Discover all of the radios on our devices and create a mapping between // radio chains and channel numbers. The result is sorted. @@ -155,10 +202,9 @@ public: // nop } - // Direct device access makes no sense with RFNoC device::sptr get_device(void) { - return nullptr; + return _device; } uhd::property_tree::sptr get_tree() const @@ -2275,6 +2321,8 @@ private: std::unordered_map _tx_rates; std::recursive_mutex _graph_mutex; + + std::shared_ptr _device; }; /****************************************************************************** -- cgit v1.2.3