host: refactor find and centralize device filtering

- centralize device filtering:
  instead of filtering the discovered devices in each device specific
  finds, move this filtering logic to device::find. Also merge all the
  filtering conditions here.

- remove type=mpm filtering ability
  this feature of finding device using hint type=mpm is not used as
  much and is not documented. Removing this helps to keep filtering
  logic cleaner and centralized.

- refactor find to return [device,make] pairs
  moving device specific find filtering into device::find method breaks
  device::make which was calling its own device finds and was relying
  on the device specific find filtering.
  To solve this, we create a device addr and make fcn pairs in the
  device::find which is now called into device::make. Based on filtered
  discovered devices, the rest of the make method is executed.
  2 more internal functions are created supporting device::find that
  helps to make the code readable.
This commit is contained in:
Abhishek Verma 2025-09-11 13:41:03 +02:00 committed by Jörg Hofrichter
parent a2ee0402f4
commit 8f6c7e5f0e
5 changed files with 104 additions and 69 deletions

View File

@ -12,6 +12,7 @@
#include <uhd/utils/log.hpp>
#include <uhd/utils/static.hpp>
#include <uhdlib/utils/prefs.hpp>
#include <uhdlib/utils/serial_number.hpp>
#include <boost/functional/hash.hpp>
#include <future>
#include <memory>
@ -80,40 +81,99 @@ device::~device(void)
/***********************************************************************
* Discover
**********************************************************************/
device_addrs_t device::find(const device_addr_t& hint, device_filter_t filter)
{
std::lock_guard<std::mutex> lock(_device_mutex);
device_addrs_t device_addrs;
std::vector<std::future<device_addrs_t>> find_tasks;
// Internal function that discovers devices and returns them with their make functions
static std::vector<std::tuple<device_addr_t, device::make_t>>
discover_devices_with_makers(const device_addr_t& hint, device::device_filter_t filter)
{
std::vector<std::tuple<device_addr_t, device::make_t>> device_maker_pairs;
// Launch async find tasks with their corresponding make functions
std::vector<std::pair<std::future<device_addrs_t>, device::make_t>> tasks;
for (const auto& fcn : get_dev_fcn_regs()) {
if (filter == ANY or std::get<2>(fcn) == filter) {
find_tasks.emplace_back(std::async(
std::launch::async, [fcn, hint]() { return std::get<0>(fcn)(hint); }));
if (filter == device::ANY or std::get<2>(fcn) == filter) {
tasks.emplace_back(std::async(std::launch::async,
[fcn, hint]() { return std::get<0>(fcn)(hint); }),
std::get<1>(fcn));
}
}
for (auto& find_task : find_tasks) {
// Collect results from async tasks
for (auto& [task, maker] : tasks) {
try {
device_addrs_t discovered_addrs = find_task.get();
device_addrs.insert(
device_addrs.begin(), discovered_addrs.begin(), discovered_addrs.end());
device_addrs_t discovered_addrs = task.get();
for (const auto& addr : discovered_addrs) {
device_maker_pairs.emplace_back(addr, maker);
}
} catch (const std::exception& e) {
UHD_LOGGER_ERROR("UHD") << "Device discovery error: " << e.what();
}
}
return device_maker_pairs;
}
// Internal function that returns filtered device-maker pairs
static std::vector<std::tuple<device_addr_t, device::make_t>>
find_filtered_devices_with_makers(
const device_addr_t& hint, device::device_filter_t filter)
{
// Get devices with their makers
auto device_maker_pairs = discover_devices_with_makers(hint, filter);
std::vector<std::tuple<device_addr_t, device::make_t>> filtered_pairs;
// Filter the discovered devices
for (const auto& pair : device_maker_pairs) {
const device_addr_t& discovered_addr = std::get<0>(pair);
// Filter with the optional keys name/serial/type/product
if ((not hint.has_key("name") or hint["name"] == discovered_addr["name"])
and (not hint.has_key("serial")
or utils::serial_numbers_match(
hint["serial"], discovered_addr["serial"]))
and (not hint.has_key("type") or hint["type"] == discovered_addr["type"])
and (not hint.has_key("product") or not discovered_addr.has_key("product")
or hint["product"] == discovered_addr["product"])) {
UHD_LOG_DEBUG("Device FIND",
"Found device that matches hints: " << discovered_addr.to_string());
filtered_pairs.push_back(pair);
} else {
UHD_LOG_DEBUG("Device FIND",
"Found device, but does not match hint: " << discovered_addr.to_string());
}
}
// find might return duplicate entries if a device received a broadcast multiple
// times. These entries needs to be removed from the result.
std::set<size_t> device_hashes;
device_addrs.erase(std::remove_if(device_addrs.begin(),
device_addrs.end(),
[&device_hashes](const device_addr_t& other) {
size_t hash = hash_device_addr(other);
const bool result = device_hashes.count(hash);
device_hashes.insert(hash);
return result;
}),
device_addrs.end());
filtered_pairs.erase(
std::remove_if(filtered_pairs.begin(),
filtered_pairs.end(),
[&device_hashes](const std::tuple<device_addr_t, device::make_t>& pair) {
size_t hash = hash_device_addr(std::get<0>(pair));
const bool result = device_hashes.count(hash);
device_hashes.insert(hash);
return result;
}),
filtered_pairs.end());
return filtered_pairs;
}
device_addrs_t device::find(const device_addr_t& hint, device_filter_t filter)
{
std::lock_guard<std::mutex> lock(_device_mutex);
// Get filtered device-maker pairs
auto filtered_pairs = find_filtered_devices_with_makers(hint, filter);
// Extract just the device addresses
device_addrs_t device_addrs;
std::transform(filtered_pairs.begin(),
filtered_pairs.end(),
std::back_inserter(device_addrs),
[](const auto& pair) { return std::get<0>(pair); });
return device_addrs;
}
@ -125,21 +185,15 @@ device::sptr device::make(const device_addr_t& hint, device_filter_t filter, siz
{
std::lock_guard<std::mutex> lock(_device_mutex);
// Use the internal function that returns filtered device-maker pairs
auto filtered_pairs = find_filtered_devices_with_makers(hint, filter);
typedef std::tuple<device_addr_t, make_t> dev_addr_make_t;
std::vector<dev_addr_make_t> dev_addr_makers;
for (const dev_fcn_reg_t& fcn : get_dev_fcn_regs()) {
try {
if (filter == ANY or std::get<2>(fcn) == filter) {
for (device_addr_t dev_addr : std::get<0>(fcn)(hint)) {
// append the discovered address and its factory function
dev_addr_makers.push_back(
dev_addr_make_t(dev_addr, std::get<1>(fcn)));
}
}
} catch (const std::exception& e) {
UHD_LOGGER_ERROR("UHD") << "Device discovery error: " << e.what();
}
// Convert to the expected format (no additional filtering needed)
for (const auto& pair : filtered_pairs) {
dev_addr_makers.push_back(dev_addr_make_t(std::get<0>(pair), std::get<1>(pair)));
}
// check that we found any devices

View File

@ -14,6 +14,7 @@
#include <uhd/transport/usb_control.hpp>
#include <uhd/types/metadata.hpp>
#include <uhd/usrp/dboard_eeprom.hpp>
#include <uhd/utils/algorithm.hpp>
#include <uhd/utils/cast.hpp>
#include <uhd/utils/log.hpp>
#include <uhd/utils/paths.hpp>
@ -184,6 +185,13 @@ static device_addrs_t b200_find(const device_addr_t& hint)
if (hint.has_key("type") and hint["type"] != "b200")
return b200_addrs;
// return an empty list of addresses when product is set to non-B2XX
if (hint.has_key("product")) {
if (!uhd::has(B2XX_STR_NAMES.vals(), hint["product"])) {
return b200_addrs;
}
}
// Return an empty list of addresses when an address or resource is specified,
// since an address and resource is intended for a different, non-USB, device.
for (device_addr_t hint_i : separate_device_addr(hint)) {
@ -252,13 +260,7 @@ static device_addrs_t b200_find(const device_addr_t& hint)
// No problem if this fails -- this is just device discovery, after all.
new_addr["product"] = "B2??";
}
// this is a found b200 when the hint serial and name match or blank
if ((not hint.has_key("name") or hint["name"] == new_addr["name"])
and (not hint.has_key("serial")
or hint["serial"] == new_addr["serial"])) {
b200_addrs.push_back(new_addr);
}
b200_addrs.push_back(new_addr);
}
}

View File

@ -112,21 +112,7 @@ device_addrs_t mpmd_find_with_addr(
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 utils::serial_numbers_match(hint_["serial"], new_addr["serial"]))
and (not hint_.has_key("type") or hint_["type"] == new_addr["type"]
or hint_["type"] == MPM_CATCHALL_DEVICE_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);
}
addrs.push_back(new_addr);
}
return addrs;
};

View File

@ -70,6 +70,11 @@ device_addrs_t usrp2_find(const device_addr_t& hint_)
if (hint.has_key("resource"))
return usrp2_addrs;
// Return an empty list of addresses when a product is specified,
// since a product is intended for a different, non-usrp2, device.
if (hint.has_key("product"))
return usrp2_addrs;
// if no address was specified, send a broadcast on each interface
if (not hint.has_key("addr")) {
for (const if_addrs_t& if_addrs : get_if_addrs()) {
@ -161,14 +166,7 @@ device_addrs_t usrp2_find(const device_addr_t& hint_)
new_addr["name"] = "";
new_addr["serial"] = "";
}
// 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"])) {
usrp2_addrs.push_back(new_addr);
}
usrp2_addrs.push_back(new_addr);
// dont break here, it will exit the while loop
// just continue on to the next loop iteration
}

View File

@ -168,12 +168,7 @@ device_addrs_t eth_manager::find(const device_addr_t& hint)
new_addr["name"] = "";
new_addr["serial"] = "";
}
// 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("product") or hint["product"] == new_addr["product"])) {
addrs.push_back(new_addr);
}
addrs.push_back(new_addr);
}
return addrs;