Statistics
| Branch: | Tag: | Revision:

root / host / lib / usrp / usrp2 / usrp2_impl.cpp @ 91ef1802

History | View | Annotate | Download (8.67 KB)

1
//
2
// Copyright 2010 Ettus Research LLC
3
//
4
// This program is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
//
17

    
18
#include <uhd/transport/if_addrs.hpp>
19
#include <uhd/usrp/device_props.hpp>
20
#include <uhd/utils/assert.hpp>
21
#include <uhd/utils/static.hpp>
22
#include <boost/format.hpp>
23
#include <boost/foreach.hpp>
24
#include <boost/bind.hpp>
25
#include <iostream>
26
#include "usrp2_impl.hpp"
27

    
28
using namespace uhd;
29
using namespace uhd::usrp;
30
using namespace uhd::transport;
31
namespace asio = boost::asio;
32

    
33
UHD_STATIC_BLOCK(register_usrp2_device){
34
    device::register_device(&usrp2::find, &usrp2::make);
35
}
36

    
37
/***********************************************************************
38
 * Discovery over the udp transport
39
 **********************************************************************/
40
uhd::device_addrs_t usrp2::find(const device_addr_t &hint){
41
    device_addrs_t usrp2_addrs;
42

    
43
    //if no address was specified, send a broadcast on each interface
44
    if (not hint.has_key("addr")){
45
        BOOST_FOREACH(const if_addrs_t &if_addrs, get_if_addrs()){
46
            //avoid the loopback device
47
            if (if_addrs.inet == asio::ip::address_v4::loopback().to_string()) continue;
48

    
49
            //create a new hint with this broadcast address
50
            device_addr_t new_hint = hint;
51
            new_hint["addr"] = if_addrs.bcast;
52

    
53
            //call discover with the new hint and append results
54
            device_addrs_t new_usrp2_addrs = usrp2::find(new_hint);
55
            usrp2_addrs.insert(usrp2_addrs.begin(),
56
                new_usrp2_addrs.begin(), new_usrp2_addrs.end()
57
            );
58
        }
59
        return usrp2_addrs;
60
    }
61

    
62
    //create a udp transport to communicate
63
    //TODO if an addr is not provided, search all interfaces?
64
    std::string ctrl_port = boost::lexical_cast<std::string>(USRP2_UDP_CTRL_PORT);
65
    udp_simple::sptr udp_transport = udp_simple::make_broadcast(
66
        hint["addr"], ctrl_port
67
    );
68

    
69
    //send a hello control packet
70
    usrp2_ctrl_data_t ctrl_data_out;
71
    ctrl_data_out.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO);
72
    udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out)));
73

    
74
    //loop and recieve until the timeout
75
    while(true){
76
        usrp2_ctrl_data_t ctrl_data_in;
77
        size_t len = udp_transport->recv(asio::buffer(&ctrl_data_in, sizeof(ctrl_data_in)));
78
        //std::cout << len << "\n";
79
        if (len >= sizeof(usrp2_ctrl_data_t)){
80
            //handle the received data
81
            switch(ntohl(ctrl_data_in.id)){
82
            case USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE:
83
                //make a boost asio ipv4 with the raw addr in host byte order
84
                boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in.data.ip_addr));
85
                device_addr_t new_addr;
86
                new_addr["name"] = "USRP2";
87
                new_addr["addr"] = ip_addr.to_string();
88
                usrp2_addrs.push_back(new_addr);
89
                //dont break here, it will exit the while loop
90
                //just continue on to the next loop iteration
91
            }
92
        }
93
        if (len == 0) break; //timeout
94
    }
95

    
96
    return usrp2_addrs;
97
}
98

    
99
/***********************************************************************
100
 * Make
101
 **********************************************************************/
102
template <class T> std::string num2str(T num){
103
    return boost::lexical_cast<std::string>(num);
104
}
105

    
106
device::sptr usrp2::make(const device_addr_t &device_addr){
107
    //create a control transport
108
    udp_simple::sptr ctrl_transport = udp_simple::make_connected(
109
        device_addr["addr"], num2str(USRP2_UDP_CTRL_PORT)
110
    );
111

    
112
    //create a data transport
113
    udp_zero_copy::sptr data_transport = udp_zero_copy::make(
114
        device_addr["addr"], num2str(USRP2_UDP_DATA_PORT)
115
    );
116

    
117
    //create the usrp2 implementation guts
118
    return device::sptr(
119
        new usrp2_impl(ctrl_transport, data_transport)
120
    );
121
}
122

    
123
/***********************************************************************
124
 * Structors
125
 **********************************************************************/
126
usrp2_impl::usrp2_impl(
127
    udp_simple::sptr ctrl_transport,
128
    udp_zero_copy::sptr data_transport
129
){
130
    _ctrl_transport = ctrl_transport;
131
    _data_transport = data_transport;
132

    
133
    //load the allowed decim/interp rates
134
    //_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4)
135
    _allowed_decim_and_interp_rates.clear();
136
    for (size_t i = 4; i <= 128; i+=1){
137
        _allowed_decim_and_interp_rates.push_back(i);
138
    }
139
    for (size_t i = 130; i <= 256; i+=2){
140
        _allowed_decim_and_interp_rates.push_back(i);
141
    }
142
    for (size_t i = 260; i <= 512; i+=4){
143
        _allowed_decim_and_interp_rates.push_back(i);
144
    }
145

    
146
    //init the mboard
147
    mboard_init();
148

    
149
    //init the ddc
150
    init_ddc_config();
151

    
152
    //init the duc
153
    init_duc_config();
154

    
155
    //initialize the clock configuration
156
    init_clock_config();
157

    
158
    //init the tx and rx dboards (do last)
159
    dboard_init();
160

    
161
    //init the send and recv io
162
    io_init();
163

    
164
}
165

    
166
usrp2_impl::~usrp2_impl(void){
167
    /* NOP */
168
}
169

    
170
/***********************************************************************
171
 * Misc Access Methods
172
 **********************************************************************/
173
double usrp2_impl::get_master_clock_freq(void){
174
    return 100e6;
175
}
176

    
177
void usrp2_impl::poke(boost::uint32_t addr, boost::uint32_t data){
178
    //setup the out data
179
    usrp2_ctrl_data_t out_data;
180
    out_data.id = htonl(USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO);
181
    out_data.data.poke_args.addr = htonl(addr);
182
    out_data.data.poke_args.data = htonl(data);
183

    
184
    //send and recv
185
    usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data);
186
    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE);
187
}
188

    
189
boost::uint32_t usrp2_impl::peek(boost::uint32_t addr){
190
    //setup the out data
191
    usrp2_ctrl_data_t out_data;
192
    out_data.id = htonl(USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO);
193
    out_data.data.poke_args.addr = htonl(addr);
194

    
195
    //send and recv
196
    usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data);
197
    ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE);
198
    return ntohl(out_data.data.poke_args.data);
199
}
200

    
201
/***********************************************************************
202
 * Control Send/Recv
203
 **********************************************************************/
204
usrp2_ctrl_data_t usrp2_impl::ctrl_send_and_recv(const usrp2_ctrl_data_t &out_data){
205
    boost::mutex::scoped_lock lock(_ctrl_mutex);
206

    
207
    //fill in the seq number and send
208
    usrp2_ctrl_data_t out_copy = out_data;
209
    out_copy.seq = htonl(++_ctrl_seq_num);
210
    _ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t)));
211

    
212
    //loop until we get the packet or timeout
213
    while(true){
214
        usrp2_ctrl_data_t in_data;
215
        size_t len = _ctrl_transport->recv(asio::buffer(&in_data, sizeof(in_data)));
216
        if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(in_data.seq) == _ctrl_seq_num){
217
            return in_data;
218
        }
219
        if (len == 0) break; //timeout
220
        //didnt get seq or bad packet, continue looking...
221
    }
222
    throw std::runtime_error("usrp2 no control response");
223
}
224

    
225
/***********************************************************************
226
 * Device Properties
227
 **********************************************************************/
228
void usrp2_impl::get(const wax::obj &key_, wax::obj &val){
229
    wax::obj key; std::string name;
230
    boost::tie(key, name) = extract_named_prop(key_);
231

    
232
    //handle the get request conditioned on the key
233
    switch(key.as<device_prop_t>()){
234
    case DEVICE_PROP_NAME:
235
        val = std::string("usrp2 device");
236
        return;
237

    
238
    case DEVICE_PROP_MBOARD:
239
        ASSERT_THROW(_mboards.has_key(name));
240
        val = _mboards[name]->get_link();
241
        return;
242

    
243
    case DEVICE_PROP_MBOARD_NAMES:
244
        val = prop_names_t(_mboards.get_keys());
245
        return;
246

    
247
    case DEVICE_PROP_MAX_RX_SAMPLES:
248
        val = size_t(_max_rx_samples_per_packet);
249
        return;
250

    
251
    case DEVICE_PROP_MAX_TX_SAMPLES:
252
        val = size_t(_max_tx_samples_per_packet);
253
        return;
254

    
255
    }
256
}
257

    
258
void usrp2_impl::set(const wax::obj &, const wax::obj &){
259
    throw std::runtime_error("Cannot set in usrp2 device");
260
}