summaryrefslogtreecommitdiffstats
path: root/host/lib/device.cpp
blob: 4b64e4a15b22ed1df6527973191573c210700397 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//
// Copyright 2010 Ettus Research LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// asize_t with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#include <uhd/usrp/usrp1e.hpp>
#include <uhd/usrp/usrp2.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 <stdexcept>
#include <algorithm>

using namespace uhd;

/*!
 * Create a new device from a device address.
 * Based on the address, call the appropriate make functions.
 * \param dev_addr the device address
 * \param hint the device address that was used to find the device
 * \return a smart pointer to a device
 */
static device::sptr make_device(const device_addr_t &dev_addr_, const device_addr_t &hint){
    //copy keys that were in hint but not in dev_addr
    //this way, we can pass additional transport arguments
    device_addr_t dev_addr = dev_addr_;
    BOOST_FOREACH(std::string key, hint.get_keys()){
        if (not dev_addr.has_key(key)) dev_addr[key] = hint[key];
    }

    //create a usrp1e
    if (dev_addr["type"] == "usrp1e"){
        return usrp::usrp1e::make(dev_addr);
    }

    //create a usrp2
    if (dev_addr["type"] == "usrp2"){
        return usrp::usrp2::make(dev_addr);
    }

    throw std::runtime_error(str(
        boost::format("Cant make a device for %s") % device_addr::to_string(dev_addr)
    ));
}

/*!
 * 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;
}

/***********************************************************************
 * Discover
 **********************************************************************/
device_addrs_t device::discover(const device_addr_t &hint){
    device_addrs_t device_addrs;

    //discover the usrp1es
    std::vector<device_addr_t> usrp2_addrs = usrp::usrp1e::discover(hint);
    device_addrs.insert(device_addrs.begin(), usrp2_addrs.begin(), usrp2_addrs.end());

    //discover the usrp2s
    if (hint.has_key("addr")){
        std::vector<device_addr_t> usrp2_addrs = usrp::usrp2::discover(hint);
        device_addrs.insert(device_addrs.begin(), usrp2_addrs.begin(), usrp2_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);

    //check that we found any devices
    if (device_addrs.size() == 0){
        throw std::runtime_error(str(
            boost::format("No devices found for %s") % device_addr::to_string(hint)
        ));
    }

    //check that the which index is valid
    if (device_addrs.size() <= which){
        throw std::runtime_error(str(
            boost::format("No device at index %d for %s") % which % device_addr::to_string(hint)
        ));
    }

    //create a unique hash for the device address
    device_addr_t dev_addr = device_addrs.at(which);
    size_t dev_hash = hash_device_addr(dev_addr);
    //std::cout << boost::format("Hash: %u") % dev_hash << std::endl;

    //map device address hash to created devices
    static uhd::dict<size_t, boost::weak_ptr<device> > hash_to_device;

    //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 &e){
        device::sptr dev = make_device(dev_addr, hint);
        hash_to_device[dev_hash] = dev;
        return dev;
    }
}