aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2018-01-23 18:27:11 -0800
committerMartin Braun <martin.braun@ettus.com>2018-02-07 17:01:06 -0800
commit3df3b6cc62911f1a87d2c7ff0775e7c2644900d5 (patch)
tree5d9d6b890be85f99c7686ad94dd4ba4278d20210 /host/lib
parent342971d2683b7b1a53f38b9e88749add37c9fa36 (diff)
downloaduhd-3df3b6cc62911f1a87d2c7ff0775e7c2644900d5.tar.gz
uhd-3df3b6cc62911f1a87d2c7ff0775e7c2644900d5.tar.bz2
uhd-3df3b6cc62911f1a87d2c7ff0775e7c2644900d5.zip
mpmd: Factor find and prop tree init code out of mpmd_impl.cpp
No functional changes.
Diffstat (limited to 'host/lib')
-rw-r--r--host/lib/usrp/mpmd/CMakeLists.txt2
-rw-r--r--host/lib/usrp/mpmd/mpmd_find.cpp251
-rw-r--r--host/lib/usrp/mpmd/mpmd_impl.cpp462
-rw-r--r--host/lib/usrp/mpmd/mpmd_impl.hpp14
-rw-r--r--host/lib/usrp/mpmd/mpmd_prop_tree.cpp235
5 files changed, 503 insertions, 461 deletions
diff --git a/host/lib/usrp/mpmd/CMakeLists.txt b/host/lib/usrp/mpmd/CMakeLists.txt
index b873f7a72..4447f2dc4 100644
--- a/host/lib/usrp/mpmd/CMakeLists.txt
+++ b/host/lib/usrp/mpmd/CMakeLists.txt
@@ -11,9 +11,11 @@ IF(ENABLE_MPMD)
ENDIF(ENABLE_LIBERIO)
LIBUHD_APPEND_SOURCES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_find.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mpmd_image_loader.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mpmd_impl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mpmd_mboard_impl.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/mpmd_prop_tree.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mpmd_xport.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mpmd_xport_mgr.cpp
${CMAKE_CURRENT_SOURCE_DIR}/mpmd_xport_ctrl_udp.cpp
diff --git a/host/lib/usrp/mpmd/mpmd_find.cpp b/host/lib/usrp/mpmd/mpmd_find.cpp
new file mode 100644
index 000000000..2f70ec280
--- /dev/null
+++ b/host/lib/usrp/mpmd/mpmd_find.cpp
@@ -0,0 +1,251 @@
+//
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+
+// find-related code for MPM devices
+
+#include "mpmd_impl.hpp"
+#include <uhd/types/device_addr.hpp>
+#include <uhd/transport/udp_simple.hpp>
+#include <uhd/transport/if_addrs.hpp>
+#include <boost/algorithm/string.hpp>
+#include <boost/asio.hpp>
+
+using namespace uhd;
+using namespace uhd::mpmd;
+
+constexpr char mpmd_impl::MPM_DISC_RESPONSE_PREAMBLE[];
+
+namespace {
+ //! How long we wait for discovery responses (in seconds)
+ constexpr double MPMD_FIND_TIMEOUT = 0.5;
+ constexpr char MPMD_CHDR_REACHABILITY_KEY[] = "reachable";
+ constexpr char MPMD_CHDR_REACHABILITY_NEGATIVE[] = "No";
+
+ device_addr_t flag_dev_as_unreachable(const device_addr_t& device_args)
+ {
+ device_addr_t flagged_device_args(device_args);
+ flagged_device_args[MPMD_CHDR_REACHABILITY_KEY] =
+ MPMD_CHDR_REACHABILITY_NEGATIVE;
+ return flagged_device_args;
+ }
+}
+
+device_addrs_t mpmd_find_with_addr(
+ const std::string& mgmt_addr,
+ const device_addr_t& hint_
+) {
+ UHD_ASSERT_THROW(not mgmt_addr.empty());
+ const std::string mpm_discovery_port = hint_.get(
+ mpmd_impl::MPM_DISCOVERY_PORT_KEY,
+ std::to_string(mpmd_impl::MPM_DISCOVERY_PORT)
+ );
+ UHD_LOG_DEBUG("MPMD",
+ "Discovering MPM devices on port " << mpm_discovery_port);
+
+ device_addrs_t addrs;
+ transport::udp_simple::sptr comm = transport::udp_simple::make_broadcast(
+ mgmt_addr, mpm_discovery_port);
+ comm->send(
+ boost::asio::buffer(
+ mpmd_impl::MPM_DISCOVERY_CMD.c_str(),
+ mpmd_impl::MPM_DISCOVERY_CMD.size()
+ )
+ );
+ while (true) {
+ const size_t MAX_MTU = 8000;
+ char buff[MAX_MTU] = {};
+ const size_t nbytes = comm->recv(
+ boost::asio::buffer(buff, MAX_MTU),
+ MPMD_FIND_TIMEOUT
+ );
+ if (nbytes == 0) {
+ break;
+ }
+ const char* reply = (const char*)buff;
+ std::string reply_string = std::string(reply);
+ std::vector<std::string> result;
+ boost::algorithm::split(result, reply_string,
+ [](const char& in) { return in == ';'; },
+ boost::token_compress_on);
+ if (result.empty()) {
+ continue;
+ }
+ // Verify we didn't receive something other than an MPM discovery
+ // response
+ if (result[0] != mpmd_impl::MPM_DISC_RESPONSE_PREAMBLE) {
+ continue;
+ }
+ const std::string recv_addr = comm->get_recv_addr();
+
+ // remove external iface addrs if executed directly on device
+ bool external_iface = false;
+ for (const auto& addr : transport::get_if_addrs()) {
+ if ((addr.inet == comm->get_recv_addr()) &&
+ recv_addr !=
+ boost::asio::ip::address_v4::loopback().to_string()) {
+ external_iface = true;
+ break;
+ }
+ }
+ if (external_iface) {
+ continue;
+ }
+
+ // Create result to return
+ device_addr_t new_addr;
+ new_addr[xport::MGMT_ADDR_KEY] = recv_addr;
+ new_addr["type"] = "mpmd"; // hwd will overwrite this
+ // remove ident string and put other informations into device_args dict
+ result.erase(result.begin());
+ // parse key-value pairs in the discovery string and add them to the
+ // device_args
+ for (const auto& el : result) {
+ std::vector<std::string> value;
+ boost::algorithm::split(value, el,
+ [](const char& in) { return in == '='; },
+ boost::token_compress_on);
+ if (value[0] != xport::MGMT_ADDR_KEY) {
+ new_addr[value[0]] = value[1];
+ }
+ }
+ // filter the discovered device below by matching optional keys
+ if (
+ (not hint_.has_key("name") or hint_["name"] == new_addr["name"])
+ and (not hint_.has_key("serial") or hint_["serial"] == new_addr["serial"])
+ and (not hint_.has_key("type") or hint_["type"] == new_addr["type"])
+ and (not hint_.has_key("product") or hint_["product"] == new_addr["product"])
+ ){
+ UHD_LOG_TRACE("MPMD FIND",
+ "Found device that matches hints: " << new_addr.to_string());
+ addrs.push_back(new_addr);
+ } else {
+ UHD_LOG_DEBUG("MPMD FIND",
+ "Found device, but does not match hint: " << recv_addr
+ );
+ }
+ }
+ return addrs;
+};
+
+
+
+// Implements scenario 1) (see below)
+device_addrs_t mpmd_find_with_addrs(const device_addrs_t& hints)
+{
+ UHD_LOG_TRACE("MPMD FIND", "Finding with addrs.");
+ device_addrs_t found_devices;
+ found_devices.reserve(hints.size());
+ for (const auto& hint : hints) {
+ if (not (hint.has_key(xport::FIRST_ADDR_KEY) or
+ hint.has_key(xport::MGMT_ADDR_KEY))) {
+ UHD_LOG_DEBUG("MPMD FIND",
+ "No address given in hint " << hint.to_string());
+ continue;
+ }
+ const std::string mgmt_addr =
+ hint.get(xport::MGMT_ADDR_KEY, hint.get(xport::FIRST_ADDR_KEY, ""));
+ device_addrs_t reply_addrs = mpmd_find_with_addr(mgmt_addr, hint);
+ if (reply_addrs.size() > 1) {
+ UHD_LOG_ERROR("MPMD",
+ "Could not resolve device hint \"" << hint.to_string()
+ << "\" to a unique device.");
+ continue;
+ } else if (reply_addrs.empty()) {
+ continue;
+ }
+ UHD_LOG_TRACE("MPMD FIND",
+ "Device responded: " << reply_addrs[0].to_string());
+ found_devices.push_back(reply_addrs[0]);
+ }
+ if (found_devices.size() == 0) {
+ return device_addrs_t();
+ } else if (found_devices.size() == 1) {
+ return found_devices;
+ } else {
+ return device_addrs_t(1, combine_device_addrs(found_devices));
+ }
+}
+
+device_addrs_t mpmd_find_with_bcast(const device_addr_t& hint)
+{
+ device_addrs_t addrs;
+ UHD_LOG_TRACE("MPMD FIND",
+ "Broadcasting on all available interfaces to find MPM devices.");
+ for (const transport::if_addrs_t& if_addr : transport::get_if_addrs()) {
+ device_addrs_t reply_addrs = mpmd_find_with_addr(if_addr.bcast, hint);
+ addrs.insert(addrs.begin(), reply_addrs.begin(), reply_addrs.end());
+ }
+ return addrs;
+}
+
+/*! Find MPM devices based on a hint
+ *
+ * There are two scenarios:
+ *
+ * 1) an addr or mgmt_addr was defined
+ *
+ * In this case, we will go through all the addrs. If they point to a device,
+ * we will then compare the other attributes (serial, etc.). If they match,
+ * the device goes into a list.
+ *
+ * 2) No addrs were defined
+ *
+ * In this case, we do a broadcast ping to see if any devices respond. After
+ * that, we do the same matching.
+ *
+ */
+device_addrs_t mpmd_find(const device_addr_t& hint_)
+{
+ device_addrs_t hints = separate_device_addr(hint_);
+ UHD_LOG_TRACE("MPMD FIND",
+ "Finding with " << hints.size() << " different hint(s).");
+
+ // Scenario 1): User gave us at least one address
+ if (not hints.empty() and
+ (hints[0].has_key(xport::FIRST_ADDR_KEY) or
+ hints[0].has_key(xport::MGMT_ADDR_KEY))) {
+ // Note: We don't try and connect to the devices in this mode, because
+ // we only get here if the user specified addresses, and we assume she
+ // knows what she's doing.
+ return mpmd_find_with_addrs(hints);
+ }
+
+ // Scenario 2): User gave us no address, and we need to broadcast
+ if (hints.empty()) {
+ hints.resize(1);
+ }
+ const auto bcast_mpm_devs = mpmd_find_with_bcast(hints[0]);
+ UHD_LOG_TRACE("MPMD FIND",
+ "Found " << bcast_mpm_devs.size() << " device via broadcast.");
+ const bool find_all = hint_.has_key(mpmd_impl::MPM_FINDALL_KEY);
+ if (find_all) {
+ UHD_LOG_TRACE("MPMD FIND",
+ "User provided " << mpmd_impl::MPM_FINDALL_KEY << ", will not "
+ "check devices for CHDR accessibility.");
+ }
+ // Filter found devices for those that we can actually talk to via CHDR
+ device_addrs_t filtered_mpm_devs;
+ for (const auto &mpm_dev : bcast_mpm_devs) {
+ const auto reachable_device_addr =
+ mpmd_mboard_impl::is_device_reachable(mpm_dev);
+ if (bool(reachable_device_addr)) {
+ filtered_mpm_devs.push_back(reachable_device_addr.get());
+ } else if (find_all) {
+ filtered_mpm_devs.emplace_back(
+ flag_dev_as_unreachable(mpm_dev)
+ );
+ }
+ }
+
+ if (filtered_mpm_devs.empty() and not bcast_mpm_devs.empty()) {
+ UHD_LOG_INFO("MPMD FIND",
+ "Found MPM devices, but none are reachable for a UHD session. "
+ "Specify " << mpmd_impl::MPM_FINDALL_KEY << " to find all devices."
+ );
+ }
+
+ return filtered_mpm_devs;
+}
diff --git a/host/lib/usrp/mpmd/mpmd_impl.cpp b/host/lib/usrp/mpmd/mpmd_impl.cpp
index 241c834cd..662676203 100644
--- a/host/lib/usrp/mpmd/mpmd_impl.cpp
+++ b/host/lib/usrp/mpmd/mpmd_impl.cpp
@@ -8,17 +8,8 @@
#include "rpc_block_ctrl.hpp"
#include <../device3/device3_impl.hpp>
#include <uhd/exception.hpp>
-#include <uhd/property_tree.hpp>
-#include <uhd/transport/if_addrs.hpp>
-#include <uhd/transport/udp_simple.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/tasks.hpp>
-#include <uhd/types/sensors.hpp>
-#include <uhd/types/eeprom.hpp>
-#include <uhd/types/component_file.hpp>
-#include <uhd/usrp/mboard_eeprom.hpp>
-#include <boost/algorithm/string.hpp>
-#include <boost/asio.hpp>
#include <boost/make_shared.hpp>
#include <boost/thread.hpp>
#include <memory>
@@ -32,247 +23,21 @@
using namespace uhd;
using namespace uhd::mpmd;
-constexpr char mpmd_impl::MPM_DISC_RESPONSE_PREAMBLE[];
-
namespace {
/*************************************************************************
* Local constants
************************************************************************/
const size_t MPMD_CROSSBAR_MAX_LADDR = 255;
- //! How long we wait for discovery responses (in seconds)
- const double MPMD_FIND_TIMEOUT = 0.5;
//! Most pessimistic time for a CHDR query to go to device and back
const double MPMD_CHDR_MAX_RTT = 0.02;
//! MPM Compatibility number
const std::vector<size_t> MPM_COMPAT_NUM = {1, 1};
//! Timeout value for the update_component RPC call (ms)
const size_t MPMD_UPDATE_COMPONENT_TIMEOUT = 20000;
- constexpr char MPMD_CHDR_REACHABILITY_KEY[] = "reachable";
- constexpr char MPMD_CHDR_REACHABILITY_NEGATIVE[] = "No";
-
/*************************************************************************
* Helper functions
************************************************************************/
- uhd::usrp::component_files_t _update_component(
- const uhd::usrp::component_files_t& comps,
- mpmd_mboard_impl *mb
- ) {
- // Construct the arguments to update component
- std::vector<std::vector<uint8_t>> all_data;
- std::vector<std::map<std::string, std::string>> all_metadata;
- // Also construct a copy of just the metadata to store in the property tree
- uhd::usrp::component_files_t all_comps_copy;
-
- for (const auto& comp : comps) {
- // Make a map for update components args
- std::map<std::string, std::string> metadata;
- // Make a component copy to add to the property tree
- uhd::usrp::component_file_t comp_copy;
- // Copy the metadata
- for (const auto& key : comp.metadata.keys()) {
- metadata[key] = comp.metadata[key];
- comp_copy.metadata[key] = comp.metadata[key];
- }
- // Copy to the update component args
- all_data.push_back(comp.data);
- all_metadata.push_back(metadata);
- // Copy to the property tree
- all_comps_copy.push_back(comp_copy);
- }
-
- // Now call update component
- const size_t update_component_timeout = MPMD_UPDATE_COMPONENT_TIMEOUT * comps.size();
- mb->rpc->set_timeout(update_component_timeout);
- mb->rpc->notify_with_token("update_component", all_metadata, all_data);
- mb->set_timeout_default();
-
- return all_comps_copy;
- }
-
-
- /*! Initialize property tree for a single device.
- *
- * \param tree Property tree reference (to the whole tree)
- * \param mb_path Subtree path for this device
- * \param mb Reference to the actual device
- */
- void init_property_tree(
- uhd::property_tree::sptr tree,
- fs_path mb_path,
- mpmd_mboard_impl *mb
- ) {
- /*** Device info ****************************************************/
- if (not tree->exists("/name")) {
- tree->create<std::string>("/name")
- .set(mb->device_info.get("name", "Unknown MPM device"))
- ;
- }
- tree->create<std::string>(mb_path / "name")
- .set(mb->device_info.get("type", "UNKNOWN"));
- tree->create<std::string>(mb_path / "serial")
- .set(mb->device_info.get("serial", "n/a"));
- tree->create<std::string>(mb_path / "connection")
- .set(mb->device_info.get("connection", "UNKNOWN"));
- tree->create<size_t>(mb_path / "link_max_rate").set(1e9 / 8);
-
- /*** Clocking *******************************************************/
- tree->create<std::string>(mb_path / "clock_source/value")
- .add_coerced_subscriber([mb](const std::string &clock_source){
- // FIXME: Undo these changes
- //mb->rpc->notify_with_token("set_clock_source", clock_source);
- auto current_src = mb->rpc->request_with_token<std::string>(
- "get_clock_source"
- );
- if (current_src != clock_source) {
- UHD_LOG_WARNING("MPMD",
- "Setting clock source at runtime is currently not "
- "supported. Use clock_source=XXX as a device arg to "
- "select a clock source. The current source is: "
- << current_src);
- }
- })
- .set_publisher([mb](){
- return mb->rpc->request_with_token<std::string>(
- "get_clock_source"
- );
- })
- ;
- tree->create<std::vector<std::string>>(
- mb_path / "clock_source/options")
- .set_publisher([mb](){
- return mb->rpc->request_with_token<std::vector<std::string>>(
- "get_clock_sources"
- );
- })
- ;
- tree->create<std::string>(mb_path / "time_source/value")
- .add_coerced_subscriber([mb](const std::string &time_source){
- //mb->rpc->notify_with_token("set_time_source", time_source);
- // FIXME: Undo these changes
- auto current_src = mb->rpc->request_with_token<std::string>(
- "get_time_source"
- );
- if (current_src != time_source) {
- UHD_LOG_WARNING("MPMD",
- "Setting time source at runtime is currently not "
- "supported. Use time_source=XXX as a device arg to "
- "select a time source. The current source is: "
- << current_src);
- }
- })
- .set_publisher([mb](){
- return mb->rpc->request_with_token<std::string>(
- "get_time_source"
- );
- })
- ;
- tree->create<std::vector<std::string>>(
- mb_path / "time_source/options")
- .set_publisher([mb](){
- return mb->rpc->request_with_token<std::vector<std::string>>(
- "get_time_sources"
- );
- })
- ;
-
- /*** Sensors ********************************************************/
- auto sensor_list =
- mb->rpc->request_with_token<std::vector<std::string>>(
- "get_mb_sensors"
- );
- UHD_LOG_DEBUG("MPMD",
- "Found " << sensor_list.size() << " motherboard sensors."
- );
- for (const auto& sensor_name : sensor_list) {
- UHD_LOG_TRACE("MPMD",
- "Adding motherboard sensor `" << sensor_name << "'"
- );
- tree->create<sensor_value_t>(
- mb_path / "sensors" / sensor_name)
- .set_publisher([mb, sensor_name](){
- return sensor_value_t(
- mb->rpc->request_with_token<sensor_value_t::sensor_map_t>(
- "get_mb_sensor", sensor_name
- )
- );
- })
- .set_coercer([](const sensor_value_t &){
- throw uhd::runtime_error(
- "Trying to write read-only sensor value!"
- );
- return sensor_value_t("", "", "");
- })
- ;
- }
-
- /*** EEPROM *********************************************************/
- tree->create<uhd::usrp::mboard_eeprom_t>(mb_path / "eeprom")
- .add_coerced_subscriber([mb](const uhd::usrp::mboard_eeprom_t& mb_eeprom){
- eeprom_map_t eeprom_map;
- for (const auto& key : mb_eeprom.keys()) {
- eeprom_map[key] = std::vector<uint8_t>(
- mb_eeprom[key].cbegin(),
- mb_eeprom[key].cend()
- );
- }
- mb->rpc->notify_with_token("set_mb_eeprom", eeprom_map);
- })
- .set_publisher([mb](){
- auto mb_eeprom =
- mb->rpc->request_with_token<std::map<std::string, std::string>>(
- "get_mb_eeprom"
- );
- uhd::usrp::mboard_eeprom_t mb_eeprom_dict(
- mb_eeprom.cbegin(), mb_eeprom.cend()
- );
- return mb_eeprom_dict;
- })
- ;
-
- /*** Updateable Components ******************************************/
- std::vector<std::string> updateable_components =
- mb->rpc->request<std::vector<std::string>>(
- "list_updateable_components"
- );
- // TODO: Check the 'id' against the registered property
- UHD_LOG_DEBUG("MPMD",
- "Found " << updateable_components.size() << " updateable motherboard components."
- );
- for (const auto& comp_name : updateable_components) {
- UHD_LOG_TRACE("MPMD",
- "Adding motherboard component: " << comp_name);
- tree->create<uhd::usrp::component_files_t>(mb_path / "components" / comp_name)
- .set_coercer([mb](const uhd::usrp::component_files_t& comp_files) {
- return _update_component(
- comp_files,
- mb
- );
- })
- ;
- }
-
- /*** MTUs ***********************************************************/
- tree->create<size_t>(mb_path / "mtu/recv")
- .add_coerced_subscriber([](const size_t){
- throw uhd::runtime_error(
- "Attempting to write read-only value (MTU)!");
- })
- .set_publisher([mb](){
- return mb->get_mtu(uhd::RX_DIRECTION);
- })
- ;
- tree->create<size_t>(mb_path / "mtu/send")
- .add_coerced_subscriber([](const size_t){
- throw uhd::runtime_error(
- "Attempting to write read-only value (MTU)!");
- })
- .set_publisher([mb](){
- return mb->get_mtu(uhd::TX_DIRECTION);
- })
- ;
- }
-
void reset_time_synchronized(uhd::property_tree::sptr tree)
{
const size_t n_mboards = tree->list("/mboards").size();
@@ -381,17 +146,8 @@ namespace {
UHD_LOG_WARNING("MPMD", err_msg);
}
}
-
- device_addr_t flag_dev_as_unreachable(const device_addr_t& device_args)
- {
- device_addr_t flagged_device_args(device_args);
- flagged_device_args[MPMD_CHDR_REACHABILITY_KEY] =
- MPMD_CHDR_REACHABILITY_NEGATIVE;
- return flagged_device_args;
- }
}
-
/*****************************************************************************
* Static class attributes
****************************************************************************/
@@ -605,224 +361,8 @@ void mpmd_impl::setup_rpc_blocks(
}
/*****************************************************************************
- * Find, Factory & Registry
+ * Factory & Registry
****************************************************************************/
-device_addrs_t mpmd_find_with_addr(
- const std::string& mgmt_addr,
- const device_addr_t& hint_
-) {
- UHD_ASSERT_THROW(not mgmt_addr.empty());
- const std::string mpm_discovery_port = hint_.get(
- mpmd_impl::MPM_DISCOVERY_PORT_KEY,
- std::to_string(mpmd_impl::MPM_DISCOVERY_PORT)
- );
- UHD_LOG_DEBUG("MPMD",
- "Discovering MPM devices on port " << mpm_discovery_port);
-
- device_addrs_t addrs;
- transport::udp_simple::sptr comm = transport::udp_simple::make_broadcast(
- mgmt_addr, mpm_discovery_port);
- comm->send(
- boost::asio::buffer(
- mpmd_impl::MPM_DISCOVERY_CMD.c_str(),
- mpmd_impl::MPM_DISCOVERY_CMD.size()
- )
- );
- while (true) {
- const size_t MAX_MTU = 8000;
- char buff[MAX_MTU] = {};
- const size_t nbytes = comm->recv(
- boost::asio::buffer(buff, MAX_MTU),
- MPMD_FIND_TIMEOUT
- );
- if (nbytes == 0) {
- break;
- }
- const char* reply = (const char*)buff;
- std::string reply_string = std::string(reply);
- std::vector<std::string> result;
- boost::algorithm::split(result, reply_string,
- [](const char& in) { return in == ';'; },
- boost::token_compress_on);
- if (result.empty()) {
- continue;
- }
- // Verify we didn't receive something other than an MPM discovery
- // response
- if (result[0] != mpmd_impl::MPM_DISC_RESPONSE_PREAMBLE) {
- continue;
- }
- const std::string recv_addr = comm->get_recv_addr();
-
- // remove external iface addrs if executed directly on device
- bool external_iface = false;
- for (const auto& addr : transport::get_if_addrs()) {
- if ((addr.inet == comm->get_recv_addr()) &&
- recv_addr !=
- boost::asio::ip::address_v4::loopback().to_string()) {
- external_iface = true;
- }
- }
- if (external_iface) {
- continue;
- }
-
- // Create result to return
- device_addr_t new_addr;
- new_addr[xport::MGMT_ADDR_KEY] = recv_addr;
- new_addr["type"] = "mpmd"; // hwd will overwrite this
- // remove ident string and put other informations into device_args dict
- result.erase(result.begin());
- // parse key-value pairs in the discovery string and add them to the
- // device_args
- for (const auto& el : result) {
- std::vector<std::string> value;
- boost::algorithm::split(value, el,
- [](const char& in) { return in == '='; },
- boost::token_compress_on);
- if (value[0] != xport::MGMT_ADDR_KEY) {
- new_addr[value[0]] = value[1];
- }
- }
- // filter the discovered device below by matching optional keys
- if (
- (not hint_.has_key("name") or hint_["name"] == new_addr["name"])
- and (not hint_.has_key("serial") or hint_["serial"] == new_addr["serial"])
- and (not hint_.has_key("type") or hint_["type"] == new_addr["type"])
- and (not hint_.has_key("product") or hint_["product"] == new_addr["product"])
- ){
- UHD_LOG_TRACE("MPMD FIND",
- "Found device that matches hints: " << new_addr.to_string());
- addrs.push_back(new_addr);
- } else {
- UHD_LOG_DEBUG("MPMD FIND",
- "Found device, but does not match hint: " << recv_addr
- );
- }
- }
- return addrs;
-};
-
-
-
-// Implements scenario 1) (see below)
-device_addrs_t mpmd_find_with_addrs(const device_addrs_t& hints)
-{
- UHD_LOG_TRACE("MPMD FIND", "Finding with addrs.");
- device_addrs_t found_devices;
- found_devices.reserve(hints.size());
- for (const auto& hint : hints) {
- if (not (hint.has_key(xport::FIRST_ADDR_KEY) or
- hint.has_key(xport::MGMT_ADDR_KEY))) {
- UHD_LOG_DEBUG("MPMD FIND",
- "No address given in hint " << hint.to_string());
- continue;
- }
- const std::string mgmt_addr =
- hint.get(xport::MGMT_ADDR_KEY, hint.get(xport::FIRST_ADDR_KEY, ""));
- device_addrs_t reply_addrs = mpmd_find_with_addr(mgmt_addr, hint);
- if (reply_addrs.size() > 1) {
- UHD_LOG_ERROR("MPMD",
- "Could not resolve device hint \"" << hint.to_string()
- << "\" to a unique device.");
- continue;
- } else if (reply_addrs.empty()) {
- continue;
- }
- UHD_LOG_TRACE("MPMD FIND",
- "Device responded: " << reply_addrs[0].to_string());
- found_devices.push_back(reply_addrs[0]);
- }
- if (found_devices.size() == 0) {
- return device_addrs_t();
- } else if (found_devices.size() == 1) {
- return found_devices;
- } else {
- return device_addrs_t(1, combine_device_addrs(found_devices));
- }
-}
-
-device_addrs_t mpmd_find_with_bcast(const device_addr_t& hint)
-{
- device_addrs_t addrs;
- UHD_LOG_TRACE("MPMD FIND",
- "Broadcasting on all available interfaces to find MPM devices.");
- for (const transport::if_addrs_t& if_addr : transport::get_if_addrs()) {
- device_addrs_t reply_addrs = mpmd_find_with_addr(if_addr.bcast, hint);
- addrs.insert(addrs.begin(), reply_addrs.begin(), reply_addrs.end());
- }
- return addrs;
-}
-
-/*! Find MPM devices based on a hint
- *
- * There are two scenarios:
- *
- * 1) an addr or mgmt_addr was defined
- *
- * In this case, we will go through all the addrs. If they point to a device,
- * we will then compare the other attributes (serial, etc.). If they match,
- * the device goes into a list.
- *
- * 2) No addrs were defined
- *
- * In this case, we do a broadcast ping to see if any devices respond. After
- * that, we do the same matching.
- *
- */
-device_addrs_t mpmd_find(const device_addr_t& hint_)
-{
- device_addrs_t hints = separate_device_addr(hint_);
- UHD_LOG_TRACE("MPMD FIND",
- "Finding with " << hints.size() << " different hint(s).");
-
- // Scenario 1): User gave us at least one address
- if (not hints.empty() and
- (hints[0].has_key(xport::FIRST_ADDR_KEY) or
- hints[0].has_key(xport::MGMT_ADDR_KEY))) {
- // Note: We don't try and connect to the devices in this mode, because
- // we only get here if the user specified addresses, and we assume she
- // knows what she's doing.
- return mpmd_find_with_addrs(hints);
- }
-
- // Scenario 2): User gave us no address, and we need to broadcast
- if (hints.empty()) {
- hints.resize(1);
- }
- const auto bcast_mpm_devs = mpmd_find_with_bcast(hints[0]);
- UHD_LOG_TRACE("MPMD FIND",
- "Found " << bcast_mpm_devs.size() << " device via broadcast.");
- const bool find_all = hint_.has_key(mpmd_impl::MPM_FINDALL_KEY);
- if (find_all) {
- UHD_LOG_TRACE("MPMD FIND",
- "User provided " << mpmd_impl::MPM_FINDALL_KEY << ", will not "
- "filter devices based on CHDR accessibility.");
- }
- // Filter found devices for those that we can actually talk to via CHDR
- device_addrs_t filtered_mpm_devs;
- for (const auto &mpm_dev : bcast_mpm_devs) {
- const auto reachable_device_addr =
- mpmd_mboard_impl::is_device_reachable(mpm_dev);
- if (bool(reachable_device_addr)) {
- filtered_mpm_devs.push_back(reachable_device_addr.get());
- } else if (find_all) {
- filtered_mpm_devs.emplace_back(
- flag_dev_as_unreachable(mpm_dev)
- );
- }
- }
-
- if (filtered_mpm_devs.empty() and not bcast_mpm_devs.empty()) {
- UHD_LOG_INFO("MPMD FIND",
- "Found MPM devices, but none are reachable for a UHD session. "
- "Specify " << mpmd_impl::MPM_FINDALL_KEY << " to find all devices."
- );
- }
-
- return filtered_mpm_devs;
-}
-
static device::sptr mpmd_make(const device_addr_t& device_args)
{
return device::sptr(boost::make_shared<mpmd_impl>(device_args));
diff --git a/host/lib/usrp/mpmd/mpmd_impl.hpp b/host/lib/usrp/mpmd/mpmd_impl.hpp
index c935a8b8e..291ee7fdd 100644
--- a/host/lib/usrp/mpmd/mpmd_impl.hpp
+++ b/host/lib/usrp/mpmd/mpmd_impl.hpp
@@ -15,6 +15,7 @@
#include <uhd/types/dict.hpp>
#include <uhd/utils/tasks.hpp>
#include <uhd/transport/muxed_zero_copy_if.hpp>
+#include <uhd/property_tree.hpp>
#include <boost/optional.hpp>
#include <map>
#include <memory>
@@ -257,6 +258,19 @@ public:
*/
size_t identify_mboard_by_xbar_addr(const size_t xbar_addr) const;
+ /*! Initialize property tree for a single device.
+ *
+ * \param tree Property tree reference (to the whole tree)
+ * \param mb_path Subtree path for this device
+ * \param mb Reference to the actual device
+ */
+ static void init_property_tree(
+ uhd::property_tree::sptr tree,
+ fs_path mb_path,
+ mpmd_mboard_impl *mb
+ );
+
+
/*************************************************************************
* Private attributes
************************************************************************/
diff --git a/host/lib/usrp/mpmd/mpmd_prop_tree.cpp b/host/lib/usrp/mpmd/mpmd_prop_tree.cpp
new file mode 100644
index 000000000..01e78e2cd
--- /dev/null
+++ b/host/lib/usrp/mpmd/mpmd_prop_tree.cpp
@@ -0,0 +1,235 @@
+//
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0
+//
+
+// property tree initialization code
+
+#include "mpmd_impl.hpp"
+#include <uhd/property_tree.hpp>
+#include <uhd/types/component_file.hpp>
+#include <uhd/types/sensors.hpp>
+#include <uhd/types/eeprom.hpp>
+#include <uhd/usrp/mboard_eeprom.hpp>
+
+using namespace uhd;
+using namespace uhd::mpmd;
+
+namespace {
+ //! Timeout value for the update_component RPC call (ms)
+ constexpr size_t MPMD_UPDATE_COMPONENT_TIMEOUT = 10000;
+
+ uhd::usrp::component_files_t _update_component(
+ const uhd::usrp::component_files_t& comps,
+ mpmd_mboard_impl *mb
+ ) {
+ // Construct the arguments to update component
+ std::vector<std::vector<uint8_t>> all_data;
+ std::vector<std::map<std::string, std::string>> all_metadata;
+ // Also construct a copy of just the metadata to store in the property tree
+ uhd::usrp::component_files_t all_comps_copy;
+
+ for (const auto& comp : comps) {
+ // Make a map for update components args
+ std::map<std::string, std::string> metadata;
+ // Make a component copy to add to the property tree
+ uhd::usrp::component_file_t comp_copy;
+ // Copy the metadata
+ for (const auto& key : comp.metadata.keys()) {
+ metadata[key] = comp.metadata[key];
+ comp_copy.metadata[key] = comp.metadata[key];
+ }
+ // Copy to the update component args
+ all_data.push_back(comp.data);
+ all_metadata.push_back(metadata);
+ // Copy to the property tree
+ all_comps_copy.push_back(comp_copy);
+ }
+
+ // Now call update component
+ mb->rpc->set_timeout(MPMD_UPDATE_COMPONENT_TIMEOUT);
+ mb->rpc->notify_with_token("update_component", all_metadata, all_data);
+ mb->set_timeout_default();
+
+ return all_comps_copy;
+ }
+
+}
+
+void mpmd_impl::init_property_tree(
+ uhd::property_tree::sptr tree,
+ fs_path mb_path,
+ mpmd_mboard_impl *mb
+) {
+ /*** Device info ****************************************************/
+ if (not tree->exists("/name")) {
+ tree->create<std::string>("/name")
+ .set(mb->device_info.get("name", "Unknown MPM device"))
+ ;
+ }
+ tree->create<std::string>(mb_path / "name")
+ .set(mb->device_info.get("type", "UNKNOWN"));
+ tree->create<std::string>(mb_path / "serial")
+ .set(mb->device_info.get("serial", "n/a"));
+ tree->create<std::string>(mb_path / "connection")
+ .set(mb->device_info.get("connection", "UNKNOWN"));
+ tree->create<size_t>(mb_path / "link_max_rate").set(1e9 / 8);
+
+ /*** Clocking *******************************************************/
+ tree->create<std::string>(mb_path / "clock_source/value")
+ .add_coerced_subscriber([mb](const std::string &clock_source){
+ // FIXME: Undo these changes
+ //mb->rpc->notify_with_token("set_clock_source", clock_source);
+ auto current_src = mb->rpc->request_with_token<std::string>(
+ "get_clock_source"
+ );
+ if (current_src != clock_source) {
+ UHD_LOG_WARNING("MPMD",
+ "Setting clock source at runtime is currently not "
+ "supported. Use clock_source=XXX as a device arg to "
+ "select a clock source. The current source is: "
+ << current_src);
+ }
+ })
+ .set_publisher([mb](){
+ return mb->rpc->request_with_token<std::string>(
+ "get_clock_source"
+ );
+ })
+ ;
+ tree->create<std::vector<std::string>>(
+ mb_path / "clock_source/options")
+ .set_publisher([mb](){
+ return mb->rpc->request_with_token<std::vector<std::string>>(
+ "get_clock_sources"
+ );
+ })
+ ;
+ tree->create<std::string>(mb_path / "time_source/value")
+ .add_coerced_subscriber([mb](const std::string &time_source){
+ //mb->rpc->notify_with_token("set_time_source", time_source);
+ // FIXME: Undo these changes
+ auto current_src = mb->rpc->request_with_token<std::string>(
+ "get_time_source"
+ );
+ if (current_src != time_source) {
+ UHD_LOG_WARNING("MPMD",
+ "Setting time source at runtime is currently not "
+ "supported. Use time_source=XXX as a device arg to "
+ "select a time source. The current source is: "
+ << current_src);
+ }
+ })
+ .set_publisher([mb](){
+ return mb->rpc->request_with_token<std::string>(
+ "get_time_source"
+ );
+ })
+ ;
+ tree->create<std::vector<std::string>>(
+ mb_path / "time_source/options")
+ .set_publisher([mb](){
+ return mb->rpc->request_with_token<std::vector<std::string>>(
+ "get_time_sources"
+ );
+ })
+ ;
+
+ /*** Sensors ********************************************************/
+ auto sensor_list =
+ mb->rpc->request_with_token<std::vector<std::string>>(
+ "get_mb_sensors"
+ );
+ UHD_LOG_DEBUG("MPMD",
+ "Found " << sensor_list.size() << " motherboard sensors."
+ );
+ for (const auto& sensor_name : sensor_list) {
+ UHD_LOG_TRACE("MPMD",
+ "Adding motherboard sensor `" << sensor_name << "'"
+ );
+ tree->create<sensor_value_t>(
+ mb_path / "sensors" / sensor_name)
+ .set_publisher([mb, sensor_name](){
+ return sensor_value_t(
+ mb->rpc->request_with_token<sensor_value_t::sensor_map_t>(
+ "get_mb_sensor", sensor_name
+ )
+ );
+ })
+ .set_coercer([](const sensor_value_t &){
+ throw uhd::runtime_error(
+ "Trying to write read-only sensor value!"
+ );
+ return sensor_value_t("", "", "");
+ })
+ ;
+ }
+
+ /*** EEPROM *********************************************************/
+ tree->create<uhd::usrp::mboard_eeprom_t>(mb_path / "eeprom")
+ .add_coerced_subscriber([mb](const uhd::usrp::mboard_eeprom_t& mb_eeprom){
+ eeprom_map_t eeprom_map;
+ for (const auto& key : mb_eeprom.keys()) {
+ eeprom_map[key] = std::vector<uint8_t>(
+ mb_eeprom[key].cbegin(),
+ mb_eeprom[key].cend()
+ );
+ }
+ mb->rpc->notify_with_token("set_mb_eeprom", eeprom_map);
+ })
+ .set_publisher([mb](){
+ auto mb_eeprom =
+ mb->rpc->request_with_token<std::map<std::string, std::string>>(
+ "get_mb_eeprom"
+ );
+ uhd::usrp::mboard_eeprom_t mb_eeprom_dict(
+ mb_eeprom.cbegin(), mb_eeprom.cend()
+ );
+ return mb_eeprom_dict;
+ })
+ ;
+
+ /*** Updateable Components ******************************************/
+ std::vector<std::string> updateable_components =
+ mb->rpc->request<std::vector<std::string>>(
+ "list_updateable_components"
+ );
+ // TODO: Check the 'id' against the registered property
+ UHD_LOG_DEBUG("MPMD",
+ "Found " << updateable_components.size() << " updateable motherboard components."
+ );
+ for (const auto& comp_name : updateable_components) {
+ UHD_LOG_TRACE("MPMD",
+ "Adding motherboard component: " << comp_name);
+ tree->create<uhd::usrp::component_files_t>(mb_path / "components" / comp_name)
+ .set_coercer([mb](const uhd::usrp::component_files_t& comp_files) {
+ return _update_component(
+ comp_files,
+ mb
+ );
+ })
+ ;
+ }
+
+ /*** MTUs ***********************************************************/
+ tree->create<size_t>(mb_path / "mtu/recv")
+ .add_coerced_subscriber([](const size_t){
+ throw uhd::runtime_error(
+ "Attempting to write read-only value (MTU)!");
+ })
+ .set_publisher([mb](){
+ return mb->get_mtu(uhd::RX_DIRECTION);
+ })
+ ;
+ tree->create<size_t>(mb_path / "mtu/send")
+ .add_coerced_subscriber([](const size_t){
+ throw uhd::runtime_error(
+ "Attempting to write read-only value (MTU)!");
+ })
+ .set_publisher([mb](){
+ return mb->get_mtu(uhd::TX_DIRECTION);
+ })
+ ;
+}
+