aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/mpmd/mpmd_mboard_impl.cpp')
-rw-r--r--host/lib/usrp/mpmd/mpmd_mboard_impl.cpp125
1 files changed, 124 insertions, 1 deletions
diff --git a/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp b/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp
index 274e2d370..6df78a9dd 100644
--- a/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp
+++ b/host/lib/usrp/mpmd/mpmd_mboard_impl.cpp
@@ -7,6 +7,7 @@
#include "mpmd_impl.hpp"
#include <uhd/utils/safe_call.hpp>
#include <uhd/utils/log.hpp>
+#include <uhd/transport/udp_simple.hpp>
#include <chrono>
#include <thread>
@@ -19,7 +20,12 @@ namespace {
//! Default timeout value for the init() RPC call (ms)
const size_t MPMD_DEFAULT_INIT_TIMEOUT = 120000;
//! Default timeout value for RPC calls (ms)
- const size_t MPMD_DEFAULT_RPC_TIMEOUT = 2000;
+ constexpr size_t MPMD_DEFAULT_RPC_TIMEOUT = 2000;
+ //! Short timeout value for RPC calls (ms), used for calls that shouldn't
+ // take long. This value can be used to quickly determine a link status.
+ constexpr size_t MPMD_SHORT_RPC_TIMEOUT = 2000;
+ //! Timeout for pings (seconds).
+ constexpr double MPMD_PING_TIMEOUT = 0.1;
//! Default session ID (MPM will recognize a session by this name)
const std::string MPMD_DEFAULT_SESSION_ID = "UHD";
//! Key to initialize a ping/measurement latency test
@@ -33,6 +39,47 @@ namespace {
/*************************************************************************
* Helper functions
************************************************************************/
+ /*! Return true if we can MPM ping a device via discovery service.
+ */
+ bool is_pingable(const std::string& ip_addr, const std::string& udp_port)
+ {
+ auto udp = uhd::transport::udp_simple::make_broadcast(
+ ip_addr,
+ udp_port
+ );
+ const std::string send_buf(
+ uhd::mpmd::mpmd_impl::MPM_ECHO_CMD + " ping"
+ );
+ std::vector<uint8_t> recv_buf;
+ recv_buf.resize(send_buf.size(), ' ');
+ udp->send(boost::asio::buffer(send_buf.c_str(), send_buf.size()));
+ const size_t len =
+ udp->recv(boost::asio::buffer(recv_buf), MPMD_PING_TIMEOUT);
+ if (len == 0) {
+ UHD_LOG_TRACE("MPMD",
+ "Received no MPM ping, assuming device is unreachable.");
+ return false;
+ }
+ if (len != send_buf.size()) {
+ UHD_LOG_DEBUG("MPMD",
+ "Received bad return packet on MPM ping. Assuming endpoint"
+ " is not a valid MPM device.");
+ return false;
+ }
+ if (std::memcmp(
+ (void *) &recv_buf[0],
+ (void *) &send_buf[0],
+ send_buf.size()) != 0) {
+ UHD_LOG_DEBUG("MPMD",
+ "Received invalid return packet on MPM ping. Assuming endpoint"
+ " is not a valid MPM device.");
+ return false;
+ }
+ return true;
+ }
+
+ /*! Call init() on an MPM device.
+ */
void init_device(
uhd::rpc_client::sptr rpc,
const uhd::device_addr_t mb_args
@@ -162,6 +209,82 @@ namespace {
using namespace uhd;
using namespace uhd::mpmd;
+/******************************************************************************
+ * Static Helpers
+ *****************************************************************************/
+boost::optional<device_addr_t> mpmd_mboard_impl::is_device_reachable(
+ const device_addr_t &device_addr
+) {
+ UHD_LOG_TRACE("MPMD",
+ "Checking accessibility of device `" << device_addr.to_string()
+ << "'");
+ UHD_ASSERT_THROW(device_addr.has_key(xport::MGMT_ADDR_KEY));
+ const std::string rpc_addr = device_addr.get(xport::MGMT_ADDR_KEY);
+ const size_t rpc_port = device_addr.cast<size_t>(
+ mpmd_impl::MPM_RPC_PORT_KEY,
+ mpmd_impl::MPM_RPC_PORT
+ );
+ auto rpcc = uhd::rpc_client::make(rpc_addr, rpc_port);
+ rpcc->set_timeout(MPMD_SHORT_RPC_TIMEOUT);
+ // 1) Read back device info
+ dev_info device_info_dict;
+ try {
+ device_info_dict = rpcc->request<dev_info>("get_device_info");
+ } catch (const uhd::runtime_error& e) {
+ UHD_LOG_ERROR("MPMD", e.what());
+ } catch (...) {
+ UHD_LOG_DEBUG("MPMD",
+ "Unexpected exception when trying to query device info. Flagging "
+ "device as unreachable.");
+ return boost::optional<device_addr_t>();
+ }
+ // 2) Check for local device
+ if (device_info_dict.count("connection") and
+ device_info_dict.at("connection") == "local") {
+ UHD_LOG_TRACE("MPMD", "Device is local, flagging as reachable.");
+ return boost::optional<device_addr_t>(device_addr);
+ }
+ // 3) Check for network-reachable device
+ // Note: This makes the assumption that devices will always allow RPC
+ // connections on their CHDR addresses.
+ const std::vector<std::string> addr_keys = {"second_addr", "addr"};
+ for (const auto& addr_key : addr_keys) {
+ if (not device_info_dict.count(addr_key)) {
+ continue;
+ }
+ const std::string chdr_addr = device_info_dict.at(addr_key);
+ UHD_LOG_TRACE("MPMD",
+ "Checking reachability via network addr " << chdr_addr);
+ try {
+ // First do an MPM ping -- there is some issue with rpclib that can
+ // lead to indefinite timeouts
+ const std::string mpm_discovery_port = device_addr.get(
+ mpmd_impl::MPM_DISCOVERY_PORT_KEY,
+ std::to_string(mpmd_impl::MPM_DISCOVERY_PORT)
+ );
+ if (!is_pingable(chdr_addr, mpm_discovery_port)) {
+ UHD_LOG_TRACE("MPMD",
+ "Cannot MPM ping, assuming device is unreachable.");
+ continue;
+ }
+ UHD_LOG_TRACE("MPMD",
+ "Was able to ping device, trying RPC connection.");
+ auto chdr_rpcc = uhd::rpc_client::make(chdr_addr, rpc_port);
+ chdr_rpcc->set_timeout(MPMD_SHORT_RPC_TIMEOUT);
+ chdr_rpcc->request<dev_info>("get_device_info");
+ auto device_addr_copy{device_addr};
+ device_addr_copy["addr"] = chdr_addr;
+ return boost::optional<device_addr_t>(device_addr_copy);
+ } catch (...) {
+ UHD_LOG_DEBUG("MPMD",
+ "Failed to reach device on network addr " << chdr_addr << ".");
+ }
+ }
+ // If everything fails, we probably can't talk to this chap.
+ UHD_LOG_TRACE("MPMD",
+ "All reachability checks failed -- assuming device is not reachable.");
+ return boost::optional<device_addr_t>();
+}
/*****************************************************************************
* Structors