diff options
Diffstat (limited to 'host')
-rw-r--r-- | host/lib/usrp/mpmd/CMakeLists.txt | 2 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_find.cpp | 251 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_impl.cpp | 462 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_impl.hpp | 14 | ||||
-rw-r--r-- | host/lib/usrp/mpmd/mpmd_prop_tree.cpp | 235 |
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); + }) + ; +} + |