diff options
Diffstat (limited to 'host/lib/device.cpp')
-rw-r--r-- | host/lib/device.cpp | 126 |
1 files changed, 101 insertions, 25 deletions
diff --git a/host/lib/device.cpp b/host/lib/device.cpp index e376a5c50..cd8a01ab4 100644 --- a/host/lib/device.cpp +++ b/host/lib/device.cpp @@ -12,57 +12,133 @@ // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. +// asize_t with this program. If not, see <http://www.gnu.org/licenses/>. // -#include <uhd/usrp/usrp2.hpp> #include <uhd/device.hpp> +#include <uhd/dict.hpp> +#include <uhd/utils.hpp> +#include <boost/foreach.hpp> #include <boost/format.hpp> +#include <boost/weak_ptr.hpp> +#include <boost/functional/hash.hpp> +#include <boost/tuple/tuple.hpp> #include <stdexcept> +#include <algorithm> using namespace uhd; +/*********************************************************************** + * Helper Functions + **********************************************************************/ +/*! + * Make a device hash that maps 1 to 1 with a device address. + * The hash will be used to identify created devices. + * \param dev_addr the device address + * \return the hash number + */ +static size_t hash_device_addr( + const device_addr_t &dev_addr +){ + //sort the keys of the device address + std::vector<std::string> keys = dev_addr.get_keys(); + std::sort(keys.begin(), keys.end()); + + //combine the hashes of sorted keys/value pairs + size_t hash = 0; + BOOST_FOREACH(std::string key, keys){ + boost::hash_combine(hash, key); + boost::hash_combine(hash, dev_addr[key]); + } + return hash; +} + +/*********************************************************************** + * Registration + **********************************************************************/ +typedef boost::tuple<device::discover_t, device::make_t> dev_fcn_reg_t; + +// instantiate the device function registry container +STATIC_INSTANCE(std::vector<dev_fcn_reg_t>, get_dev_fcn_regs) + +void device::register_device( + const discover_t &discover, + const make_t &make +){ + //std::cout << "registering device" << std::endl; + get_dev_fcn_regs().push_back(dev_fcn_reg_t(discover, make)); +} + +/*********************************************************************** + * Discover + **********************************************************************/ device_addrs_t device::discover(const device_addr_t &hint){ device_addrs_t device_addrs; - if (not hint.has_key("type")){ - //TODO call discover for others and append results - } - else if (hint["type"] == "udp"){ - std::vector<device_addr_t> usrp2_addrs = usrp::usrp2::discover(hint); - device_addrs.insert(device_addrs.begin(), usrp2_addrs.begin(), usrp2_addrs.end()); + + BOOST_FOREACH(dev_fcn_reg_t fcn, get_dev_fcn_regs()){ + device_addrs_t discovered_addrs = fcn.get<0>()(hint); + device_addrs.insert( + device_addrs.begin(), + discovered_addrs.begin(), + discovered_addrs.end() + ); } + return device_addrs; } +/*********************************************************************** + * Make + **********************************************************************/ device::sptr device::make(const device_addr_t &hint, size_t which){ - std::vector<device_addr_t> device_addrs = discover(hint); + typedef boost::tuple<device_addr_t, make_t> dev_addr_make_t; + std::vector<dev_addr_make_t> dev_addr_makers; + + BOOST_FOREACH(dev_fcn_reg_t fcn, get_dev_fcn_regs()){ + BOOST_FOREACH(device_addr_t dev_addr, fcn.get<0>()(hint)){ + //copy keys that were in hint but not in dev_addr + //this way, we can pass additional transport arguments + BOOST_FOREACH(std::string key, hint.get_keys()){ + if (not dev_addr.has_key(key)) dev_addr[key] = hint[key]; + } + //append the discovered address and its factory function + dev_addr_makers.push_back(dev_addr_make_t(dev_addr, fcn.get<1>())); + } + } //check that we found any devices - if (device_addrs.size() == 0){ + if (dev_addr_makers.size() == 0){ throw std::runtime_error(str( - boost::format("No devices found for %s") % device_addr_to_string(hint) + boost::format("No devices found for ----->\n%s") % device_addr::to_string(hint) )); } //check that the which index is valid - if (device_addrs.size() <= which){ + if (dev_addr_makers.size() <= which){ throw std::runtime_error(str( - boost::format("No device at index %d for %s") % which % device_addr_to_string(hint) + boost::format("No device at index %d for ----->\n%s") % which % device_addr::to_string(hint) )); } - //create the new device with the discovered address - //TODO only a usrp2 device will be made (until others are supported) - if (hint.has_key("type") and hint["type"] == "udp"){ - return usrp::usrp2::make(device_addrs.at(which)); - } - throw std::runtime_error("cant make a device"); -} + //create a unique hash for the device address + device_addr_t dev_addr; make_t maker; + boost::tie(dev_addr, maker) = dev_addr_makers.at(which); + size_t dev_hash = hash_device_addr(dev_addr); + //std::cout << boost::format("Hash: %u") % dev_hash << std::endl; -device::device(void){ - /* NOP */ -} + //map device address hash to created devices + static uhd::dict<size_t, boost::weak_ptr<device> > hash_to_device; -device::~device(void){ - /* NOP */ + //try to find an existing device + try{ + ASSERT_THROW(hash_to_device.has_key(dev_hash)); + ASSERT_THROW(not hash_to_device[dev_hash].expired()); + return hash_to_device[dev_hash].lock(); + } + //create and register a new device + catch(const std::assert_error &){ + device::sptr dev = maker(dev_addr); + hash_to_device[dev_hash] = dev; + return dev; + } } |