Statistics
| Branch: | Tag: | Revision:

root / host / lib / usrp / multi_usrp.cpp @ 81b4689c

History | View | Annotate | Download (32 KB)

1 c861f98c Josh Blum
//
2 261bb80d Josh Blum
// Copyright 2010-2011 Ettus Research LLC
3 c861f98c Josh Blum
//
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 ebd2ecc6 Josh Blum
#include <uhd/property_tree.hpp>
19 c861f98c Josh Blum
#include <uhd/usrp/multi_usrp.hpp>
20 09be0518 Josh Blum
#include <uhd/utils/msg.hpp>
21 16f08844 Josh Blum
#include <uhd/exception.hpp>
22 7f01386f Josh Blum
#include <uhd/utils/msg.hpp>
23 c861f98c Josh Blum
#include <uhd/utils/gain_group.hpp>
24
#include <boost/thread.hpp>
25
#include <boost/foreach.hpp>
26
#include <boost/format.hpp>
27 aa619a76 Josh Blum
#include <cmath>
28 c861f98c Josh Blum
29
using namespace uhd;
30
using namespace uhd::usrp;
31
32 8e341caa Josh Blum
const std::string multi_usrp::ALL_GAINS = "";
33
34 c861f98c Josh Blum
/***********************************************************************
35 aa619a76 Josh Blum
 * Helper methods
36
 **********************************************************************/
37 ebd2ecc6 Josh Blum
static void do_samp_rate_warning_message(
38 aa619a76 Josh Blum
    double target_rate,
39
    double actual_rate,
40
    const std::string &xx
41
){
42
    static const double max_allowed_error = 1.0; //Sps
43
    if (std::abs(target_rate - actual_rate) > max_allowed_error){
44 7f01386f Josh Blum
        UHD_MSG(warning) << boost::format(
45 aa619a76 Josh Blum
            "The hardware does not support the requested %s sample rate:\n"
46
            "Target sample rate: %f MSps\n"
47
            "Actual sample rate: %f MSps\n"
48 7f01386f Josh Blum
        ) % xx % (target_rate/1e6) % (actual_rate/1e6);
49 aa619a76 Josh Blum
    }
50
}
51
52 ebd2ecc6 Josh Blum
static void do_tune_freq_warning_message(
53 3cb60c97 Josh Blum
    const tune_request_t &tune_req,
54 aa619a76 Josh Blum
    double actual_freq,
55
    const std::string &xx
56
){
57 3cb60c97 Josh Blum
    //forget the warning when manual policy
58
    if (tune_req.dsp_freq_policy == tune_request_t::POLICY_MANUAL) return;
59
    if (tune_req.rf_freq_policy == tune_request_t::POLICY_MANUAL) return;
60
61
    const double target_freq = tune_req.target_freq;
62 aa619a76 Josh Blum
    static const double max_allowed_error = 1.0; //Hz
63
    if (std::abs(target_freq - actual_freq) > max_allowed_error){
64 7f01386f Josh Blum
        UHD_MSG(warning) << boost::format(
65 aa619a76 Josh Blum
            "The hardware does not support the requested %s frequency:\n"
66
            "Target frequency: %f MHz\n"
67
            "Actual frequency: %f MHz\n"
68 7f01386f Josh Blum
        ) % xx % (target_freq/1e6) % (actual_freq/1e6);
69 aa619a76 Josh Blum
    }
70
}
71
72 e033fc3d Josh Blum
static meta_range_t make_overall_tune_range(
73
    const meta_range_t &fe_range,
74
    const meta_range_t &dsp_range,
75
    const double bw
76
){
77 78e95562 Josh Blum
    meta_range_t range;
78
    BOOST_FOREACH(const range_t &sub_range, fe_range){
79
        range.push_back(range_t(
80
            sub_range.start() + std::max(dsp_range.start(), -bw),
81
            sub_range.stop() + std::min(dsp_range.stop(), bw),
82
            dsp_range.step()
83
        ));
84
    }
85
    return range;
86 e033fc3d Josh Blum
}
87
88 adbe1a0e Josh Blum
/***********************************************************************
89
 * Gain helper functions
90
 **********************************************************************/
91 aa6b340f Josh Blum
static double get_gain_value(property_tree::sptr subtree){
92
    return subtree->access<double>("value").get();
93 ebd2ecc6 Josh Blum
}
94
95 aa6b340f Josh Blum
static void set_gain_value(property_tree::sptr subtree, const double gain){
96
    subtree->access<double>("value").set(gain);
97 ebd2ecc6 Josh Blum
}
98
99 aa6b340f Josh Blum
static meta_range_t get_gain_range(property_tree::sptr subtree){
100
    return subtree->access<meta_range_t>("range").get();
101 ebd2ecc6 Josh Blum
}
102
103 aa6b340f Josh Blum
static gain_fcns_t make_gain_fcns_from_subtree(property_tree::sptr subtree){
104 ebd2ecc6 Josh Blum
    gain_fcns_t gain_fcns;
105 aa6b340f Josh Blum
    gain_fcns.get_range = boost::bind(&get_gain_range, subtree);
106
    gain_fcns.get_value = boost::bind(&get_gain_value, subtree);
107
    gain_fcns.set_value = boost::bind(&set_gain_value, subtree, _1);
108 ebd2ecc6 Josh Blum
    return gain_fcns;
109
}
110
111 aa619a76 Josh Blum
/***********************************************************************
112 adbe1a0e Josh Blum
 * Tune Helper Functions
113
 **********************************************************************/
114
static const double RX_SIGN = +1.0;
115
static const double TX_SIGN = -1.0;
116
117
static tune_result_t tune_xx_subdev_and_dsp(
118
    const double xx_sign,
119 aa6b340f Josh Blum
    property_tree::sptr dsp_subtree,
120
    property_tree::sptr rf_fe_subtree,
121 adbe1a0e Josh Blum
    const tune_request_t &tune_request
122
){
123
    //------------------------------------------------------------------
124
    //-- calculate the LO offset, only used with automatic policy
125
    //------------------------------------------------------------------
126
    double lo_offset = 0.0;
127 aa6b340f Josh Blum
    if (rf_fe_subtree->access<bool>("use_lo_offset").get()){
128 adbe1a0e Josh Blum
        //If the local oscillator will be in the passband, use an offset.
129
        //But constrain the LO offset by the width of the filter bandwidth.
130 aa6b340f Josh Blum
        const double rate = dsp_subtree->access<double>("rate/value").get();
131
        const double bw = rf_fe_subtree->access<double>("bandwidth/value").get();
132 adbe1a0e Josh Blum
        if (bw > rate) lo_offset = std::min((bw - rate)/2, rate/2);
133
    }
134
135
    //------------------------------------------------------------------
136
    //-- set the RF frequency depending upon the policy
137
    //------------------------------------------------------------------
138
    double target_rf_freq = 0.0;
139
    switch (tune_request.rf_freq_policy){
140
    case tune_request_t::POLICY_AUTO:
141
        target_rf_freq = tune_request.target_freq + lo_offset;
142 aa6b340f Josh Blum
        rf_fe_subtree->access<double>("freq/value").set(target_rf_freq);
143 adbe1a0e Josh Blum
        break;
144
145
    case tune_request_t::POLICY_MANUAL:
146
        target_rf_freq = tune_request.rf_freq;
147 aa6b340f Josh Blum
        rf_fe_subtree->access<double>("freq/value").set(target_rf_freq);
148 adbe1a0e Josh Blum
        break;
149
150
    case tune_request_t::POLICY_NONE: break; //does not set
151
    }
152 aa6b340f Josh Blum
    const double actual_rf_freq = rf_fe_subtree->access<double>("freq/value").get();
153 adbe1a0e Josh Blum
154
    //------------------------------------------------------------------
155
    //-- calculate the dsp freq, only used with automatic policy
156
    //------------------------------------------------------------------
157
    double target_dsp_freq = actual_rf_freq - tune_request.target_freq;
158
159
    //invert the sign on the dsp freq for transmit
160
    target_dsp_freq *= xx_sign;
161
162
    //------------------------------------------------------------------
163
    //-- set the dsp frequency depending upon the dsp frequency policy
164
    //------------------------------------------------------------------
165
    switch (tune_request.dsp_freq_policy){
166
    case tune_request_t::POLICY_AUTO:
167 aa6b340f Josh Blum
        dsp_subtree->access<double>("freq/value").set(target_dsp_freq);
168 adbe1a0e Josh Blum
        break;
169
170
    case tune_request_t::POLICY_MANUAL:
171
        target_dsp_freq = tune_request.dsp_freq;
172 aa6b340f Josh Blum
        dsp_subtree->access<double>("freq/value").set(target_dsp_freq);
173 adbe1a0e Josh Blum
        break;
174
175
    case tune_request_t::POLICY_NONE: break; //does not set
176
    }
177 aa6b340f Josh Blum
    const double actual_dsp_freq = dsp_subtree->access<double>("freq/value").get();
178 adbe1a0e Josh Blum
179
    //------------------------------------------------------------------
180
    //-- load and return the tune result
181
    //------------------------------------------------------------------
182
    tune_result_t tune_result;
183
    tune_result.target_rf_freq = target_rf_freq;
184
    tune_result.actual_rf_freq = actual_rf_freq;
185
    tune_result.target_dsp_freq = target_dsp_freq;
186
    tune_result.actual_dsp_freq = actual_dsp_freq;
187
    return tune_result;
188
}
189
190
static double derive_freq_from_xx_subdev_and_dsp(
191
    const double xx_sign,
192 aa6b340f Josh Blum
    property_tree::sptr dsp_subtree,
193
    property_tree::sptr rf_fe_subtree
194 adbe1a0e Josh Blum
){
195
    //extract actual dsp and IF frequencies
196 aa6b340f Josh Blum
    const double actual_rf_freq = rf_fe_subtree->access<double>("freq/value").get();
197
    const double actual_dsp_freq = dsp_subtree->access<double>("freq/value").get();
198 adbe1a0e Josh Blum
199
    //invert the sign on the dsp freq for transmit
200
    return actual_rf_freq - actual_dsp_freq * xx_sign;
201
}
202
203
/***********************************************************************
204 aa619a76 Josh Blum
 * Multi USRP Implementation
205 c861f98c Josh Blum
 **********************************************************************/
206
class multi_usrp_impl : public multi_usrp{
207
public:
208
    multi_usrp_impl(const device_addr_t &addr){
209
        _dev = device::make(addr);
210 748e4baf Josh Blum
        _tree = _dev->get_tree();
211 c861f98c Josh Blum
    }
212
213
    device::sptr get_device(void){
214
        return _dev;
215
    }
216
217
    /*******************************************************************
218
     * Mboard methods
219
     ******************************************************************/
220 625d5605 Josh Blum
    void set_master_clock_rate(double rate, size_t mboard){
221
        if (mboard != ALL_MBOARDS){
222 ebd2ecc6 Josh Blum
            _tree->access<double>(mb_root(mboard) / "tick_rate").set(rate);
223 625d5605 Josh Blum
            return;
224
        }
225
        for (size_t m = 0; m < get_num_mboards(); m++){
226
            set_master_clock_rate(rate, m);
227
        }
228
    }
229
230
    double get_master_clock_rate(size_t mboard){
231 ebd2ecc6 Josh Blum
        return _tree->access<double>(mb_root(mboard) / "tick_rate").get();
232 625d5605 Josh Blum
    }
233
234 c861f98c Josh Blum
    std::string get_pp_string(void){
235 bcd2c4e2 Josh Blum
        std::string buff = str(boost::format(
236
            "%s USRP:\n"
237
            "  Device: %s\n"
238
        )
239
            % ((get_num_mboards() > 1)? "Multi" : "Single")
240
            % (_tree->access<std::string>("/name").get())
241
        );
242
        for (size_t m = 0; m < get_num_mboards(); m++){
243
            buff += str(boost::format(
244
                "  Mboard %d: %s\n"
245
            ) % m
246
                % (_tree->access<std::string>(mb_root(m) / "name").get())
247
            );
248
        }
249
250
        //----------- rx side of life ----------------------------------
251
        for (size_t m = 0, chan = 0; m < get_num_mboards(); m++){
252
            for (; chan < (m + 1)*get_rx_subdev_spec(m).size(); chan++){
253
                buff += str(boost::format(
254
                    "  RX Channel: %u\n"
255
                    "    RX DSP: %s\n"
256
                    "    RX Dboard: %s\n"
257
                    "    RX Subdev: %s\n"
258
                ) % chan
259
                    % rx_dsp_root(chan).leaf()
260
                    % rx_rf_fe_root(chan).branch_path().branch_path().leaf()
261
                    % (_tree->access<std::string>(rx_rf_fe_root(chan) / "name").get())
262
                );
263
            }
264
        }
265
266
        //----------- tx side of life ----------------------------------
267
        for (size_t m = 0, chan = 0; m < get_num_mboards(); m++){
268
            for (; chan < (m + 1)*get_tx_subdev_spec(m).size(); chan++){
269
                buff += str(boost::format(
270
                    "  TX Channel: %u\n"
271
                    "    TX DSP: %s\n"
272
                    "    TX Dboard: %s\n"
273
                    "    TX Subdev: %s\n"
274
                ) % chan
275
                    % tx_dsp_root(chan).leaf()
276
                    % tx_rf_fe_root(chan).branch_path().branch_path().leaf()
277
                    % (_tree->access<std::string>(tx_rf_fe_root(chan) / "name").get())
278
                );
279
            }
280
        }
281
282
        return buff;
283 c861f98c Josh Blum
    }
284
285
    std::string get_mboard_name(size_t mboard){
286 ebd2ecc6 Josh Blum
        return _tree->access<std::string>(mb_root(mboard) / "name").get();
287 c861f98c Josh Blum
    }
288
289 24c626a1 Josh Blum
    time_spec_t get_time_now(size_t mboard = 0){
290 ebd2ecc6 Josh Blum
        return _tree->access<time_spec_t>(mb_root(mboard) / "time/now").get();
291 c861f98c Josh Blum
    }
292
293 24c626a1 Josh Blum
    time_spec_t get_time_last_pps(size_t mboard = 0){
294 ebd2ecc6 Josh Blum
        return _tree->access<time_spec_t>(mb_root(mboard) / "time/pps").get();
295 76c8b7fa Josh Blum
    }
296
297 e1644548 Josh Blum
    void set_time_now(const time_spec_t &time_spec, size_t mboard){
298
        if (mboard != ALL_MBOARDS){
299 ebd2ecc6 Josh Blum
            _tree->access<time_spec_t>(mb_root(mboard) / "time/now").set(time_spec);
300 e1644548 Josh Blum
            return;
301
        }
302
        for (size_t m = 0; m < get_num_mboards(); m++){
303
            set_time_now(time_spec, m);
304
        }
305
    }
306
307 84ebf02b Josh Blum
    void set_time_next_pps(const time_spec_t &time_spec, size_t mboard){
308
        if (mboard != ALL_MBOARDS){
309
            _tree->access<time_spec_t>(mb_root(mboard) / "time/pps").set(time_spec);
310
            return;
311
        }
312 c861f98c Josh Blum
        for (size_t m = 0; m < get_num_mboards(); m++){
313 84ebf02b Josh Blum
            set_time_next_pps(time_spec, m);
314 c861f98c Josh Blum
        }
315
    }
316
317
    void set_time_unknown_pps(const time_spec_t &time_spec){
318 09be0518 Josh Blum
        UHD_MSG(status) << "    1) catch time transition at pps edge" << std::endl;
319 76c8b7fa Josh Blum
        time_spec_t time_start = get_time_now();
320
        time_spec_t time_start_last_pps = get_time_last_pps();
321
        while(true){
322
            if (get_time_last_pps() != time_start_last_pps) break;
323
            if ((get_time_now() - time_start) > time_spec_t(1.1)){
324 4357f5d3 Josh Blum
                throw uhd::runtime_error(
325 64263e44 Josh Blum
                    "Board 0 may not be getting a PPS signal!\n"
326
                    "No PPS detected within the time interval.\n"
327
                    "See the application notes for your device.\n"
328 76c8b7fa Josh Blum
                );
329
            }
330 c861f98c Josh Blum
        }
331
332 09be0518 Josh Blum
        UHD_MSG(status) << "    2) set times next pps (synchronously)" << std::endl;
333 84ebf02b Josh Blum
        set_time_next_pps(time_spec, ALL_MBOARDS);
334 c861f98c Josh Blum
        boost::this_thread::sleep(boost::posix_time::seconds(1));
335
336
        //verify that the time registers are read to be within a few RTT
337
        for (size_t m = 1; m < get_num_mboards(); m++){
338 ebd2ecc6 Josh Blum
            time_spec_t time_0 = this->get_time_now(0);
339
            time_spec_t time_i = this->get_time_now(m);
340 c861f98c Josh Blum
            if (time_i < time_0 or (time_i - time_0) > time_spec_t(0.01)){ //10 ms: greater than RTT but not too big
341 7f01386f Josh Blum
                UHD_MSG(warning) << boost::format(
342 c861f98c Josh Blum
                    "Detected time deviation between board %d and board 0.\n"
343
                    "Board 0 time is %f seconds.\n"
344
                    "Board %d time is %f seconds.\n"
345 7f01386f Josh Blum
                ) % m % time_0.get_real_secs() % m % time_i.get_real_secs();
346 c861f98c Josh Blum
            }
347
        }
348
    }
349
350 211e1906 Josh Blum
    bool get_time_synchronized(void){
351
        for (size_t m = 1; m < get_num_mboards(); m++){
352 ebd2ecc6 Josh Blum
            time_spec_t time_0 = this->get_time_now(0);
353
            time_spec_t time_i = this->get_time_now(m);
354 211e1906 Josh Blum
            if (time_i < time_0 or (time_i - time_0) > time_spec_t(0.01)) return false;
355
        }
356
        return true;
357
    }
358
359 5cdbf5b3 Josh Blum
    void set_command_time(const time_spec_t &, size_t){
360
        throw uhd::not_implemented_error("Not implemented yet, but we have a very good idea of how to do it.");
361
    }
362
363
    void clear_command_time(size_t){
364 7f815e12 Josh Blum
        throw uhd::not_implemented_error("Not implemented yet, but we have a very good idea of how to do it.");
365
    }
366
367 1628434a Josh Blum
    void issue_stream_cmd(const stream_cmd_t &stream_cmd, size_t chan){
368
        if (chan != ALL_CHANS){
369 ebd2ecc6 Josh Blum
            _tree->access<stream_cmd_t>(rx_dsp_root(chan) / "stream_cmd").set(stream_cmd);
370 1628434a Josh Blum
            return;
371
        }
372 e128948a Josh Blum
        for (size_t c = 0; c < get_rx_num_channels(); c++){
373 1628434a Josh Blum
            issue_stream_cmd(stream_cmd, c);
374 c861f98c Josh Blum
        }
375
    }
376
377
    void set_clock_config(const clock_config_t &clock_config, size_t mboard){
378 93692591 Josh Blum
        //set the reference source...
379
        std::string clock_source;
380
        switch(clock_config.ref_source){
381
        case clock_config_t::REF_INT: clock_source = "internal"; break;
382
        case clock_config_t::PPS_SMA: clock_source = "external"; break;
383
        case clock_config_t::PPS_MIMO: clock_source = "mimo"; break;
384
        default: clock_source = "unknown";
385
        }
386
        this->set_clock_source(clock_source, mboard);
387
388
        //set the time source
389
        std::string time_source;
390
        switch(clock_config.pps_source){
391
        case clock_config_t::PPS_INT: time_source = "internal"; break;
392
        case clock_config_t::PPS_SMA: time_source = "external"; break;
393
        case clock_config_t::PPS_MIMO: time_source = "mimo"; break;
394
        default: time_source = "unknown";
395
        }
396
        if (time_source == "external" and clock_config.pps_polarity == clock_config_t::PPS_NEG) time_source = "_external_";
397
        this->set_time_source(time_source, mboard);
398
    }
399
400
    void set_time_source(const std::string &source, const size_t mboard){
401 c861f98c Josh Blum
        if (mboard != ALL_MBOARDS){
402 93692591 Josh Blum
            _tree->access<std::string>(mb_root(mboard) / "time_source" / "value").set(source);
403 c861f98c Josh Blum
            return;
404
        }
405
        for (size_t m = 0; m < get_num_mboards(); m++){
406 93692591 Josh Blum
            return this->set_time_source(source, m);
407 c861f98c Josh Blum
        }
408
    }
409
410 93692591 Josh Blum
    std::string get_time_source(const size_t mboard){
411
        return _tree->access<std::string>(mb_root(mboard) / "time_source" / "value").get();
412
    }
413
414
    std::vector<std::string> get_time_sources(const size_t mboard){
415
        return _tree->access<std::vector<std::string> >(mb_root(mboard) / "time_source" / "options").get();
416
    }
417
418
    void set_clock_source(const std::string &source, const size_t mboard){
419
        if (mboard != ALL_MBOARDS){
420
            _tree->access<std::string>(mb_root(mboard) / "clock_source" / "value").set(source);
421
            return;
422
        }
423
        for (size_t m = 0; m < get_num_mboards(); m++){
424
            return this->set_clock_source(source, m);
425
        }
426
    }
427
428
    std::string get_clock_source(const size_t mboard){
429
        return _tree->access<std::string>(mb_root(mboard) / "clock_source" / "value").get();
430
    }
431
432
    std::vector<std::string> get_clock_sources(const size_t mboard){
433
        return _tree->access<std::vector<std::string> >(mb_root(mboard) / "clock_source" / "options").get();
434
    }
435
436 c861f98c Josh Blum
    size_t get_num_mboards(void){
437 ebd2ecc6 Josh Blum
        return _tree->list("/mboards").size();
438 c861f98c Josh Blum
    }
439
440 e4b45cca Josh Blum
    sensor_value_t get_mboard_sensor(const std::string &name, size_t mboard){
441 ebd2ecc6 Josh Blum
        return _tree->access<sensor_value_t>(mb_root(mboard) / "sensors" / name).get();
442 e4b45cca Josh Blum
    }
443
444
    std::vector<std::string> get_mboard_sensor_names(size_t mboard){
445 ebd2ecc6 Josh Blum
        return _tree->list(mb_root(mboard) / "sensors");
446 e4b45cca Josh Blum
    }
447 ebd2ecc6 Josh Blum
448 781cafa8 Josh Blum
    void set_user_register(const boost::uint8_t addr, const boost::uint32_t data, size_t mboard){
449
        if (mboard != ALL_MBOARDS){
450
            typedef std::pair<boost::uint8_t, boost::uint32_t> user_reg_t;
451
            _tree->access<user_reg_t>(mb_root(mboard) / "user/reg").set(user_reg_t(addr, data));
452
            return;
453
        }
454
        for (size_t m = 0; m < get_num_mboards(); m++){
455
            set_user_register(addr, data, m);
456
        }
457
    }
458
459 c861f98c Josh Blum
    /*******************************************************************
460
     * RX methods
461
     ******************************************************************/
462
    void set_rx_subdev_spec(const subdev_spec_t &spec, size_t mboard){
463
        if (mboard != ALL_MBOARDS){
464 ebd2ecc6 Josh Blum
            _tree->access<subdev_spec_t>(mb_root(mboard) / "rx_subdev_spec").set(spec);
465 c861f98c Josh Blum
            return;
466
        }
467
        for (size_t m = 0; m < get_num_mboards(); m++){
468
            set_rx_subdev_spec(spec, m);
469
        }
470
    }
471
472
    subdev_spec_t get_rx_subdev_spec(size_t mboard){
473 ebd2ecc6 Josh Blum
        return _tree->access<subdev_spec_t>(mb_root(mboard) / "rx_subdev_spec").get();
474 c861f98c Josh Blum
    }
475
476
    size_t get_rx_num_channels(void){
477 ede85c10 Josh Blum
        size_t sum = 0;
478
        for (size_t m = 0; m < get_num_mboards(); m++){
479
            sum += get_rx_subdev_spec(m).size();
480
        }
481
        return sum;
482 c861f98c Josh Blum
    }
483
484
    std::string get_rx_subdev_name(size_t chan){
485 ebd2ecc6 Josh Blum
        return _tree->access<std::string>(rx_rf_fe_root(chan) / "name").get();
486 c861f98c Josh Blum
    }
487
488 e128948a Josh Blum
    void set_rx_rate(double rate, size_t chan){
489 1628434a Josh Blum
        if (chan != ALL_CHANS){
490 ebd2ecc6 Josh Blum
            _tree->access<double>(rx_dsp_root(chan) / "rate" / "value").set(rate);
491 1628434a Josh Blum
            do_samp_rate_warning_message(rate, get_rx_rate(chan), "RX");
492
            return;
493
        }
494 e128948a Josh Blum
        for (size_t c = 0; c < get_rx_num_channels(); c++){
495 1628434a Josh Blum
            set_rx_rate(rate, c);
496 c861f98c Josh Blum
        }
497
    }
498
499 1628434a Josh Blum
    double get_rx_rate(size_t chan){
500 ebd2ecc6 Josh Blum
        return _tree->access<double>(rx_dsp_root(chan) / "rate" / "value").get();
501 c861f98c Josh Blum
    }
502
503 ae9e89d7 Josh Blum
    meta_range_t get_rx_rates(size_t chan){
504
        return _tree->access<meta_range_t>(rx_dsp_root(chan) / "rate" / "range").get();
505
    }
506
507 359c4e16 Josh Blum
    tune_result_t set_rx_freq(const tune_request_t &tune_request, size_t chan){
508 aa6b340f Josh Blum
        tune_result_t r = tune_xx_subdev_and_dsp(RX_SIGN, _tree->subtree(rx_dsp_root(chan)), _tree->subtree(rx_rf_fe_root(chan)), tune_request);
509 3cb60c97 Josh Blum
        do_tune_freq_warning_message(tune_request, get_rx_freq(chan), "RX");
510 adbe1a0e Josh Blum
        return r;
511 c861f98c Josh Blum
    }
512
513
    double get_rx_freq(size_t chan){
514 aa6b340f Josh Blum
        return derive_freq_from_xx_subdev_and_dsp(RX_SIGN, _tree->subtree(rx_dsp_root(chan)), _tree->subtree(rx_rf_fe_root(chan)));
515 c861f98c Josh Blum
    }
516
517
    freq_range_t get_rx_freq_range(size_t chan){
518 e033fc3d Josh Blum
        return make_overall_tune_range(
519
            _tree->access<meta_range_t>(rx_rf_fe_root(chan) / "freq" / "range").get(),
520
            _tree->access<meta_range_t>(rx_dsp_root(chan) / "freq" / "range").get(),
521
            this->get_rx_bandwidth(chan)
522
        );
523 c861f98c Josh Blum
    }
524
525 395bbbbc Josh Blum
    void set_rx_gain(double gain, const std::string &name, size_t chan){
526 ebd2ecc6 Josh Blum
        return rx_gain_group(chan)->set_value(gain, name);
527 8e341caa Josh Blum
    }
528
529 395bbbbc Josh Blum
    double get_rx_gain(const std::string &name, size_t chan){
530 ebd2ecc6 Josh Blum
        return rx_gain_group(chan)->get_value(name);
531 c861f98c Josh Blum
    }
532
533 8e341caa Josh Blum
    gain_range_t get_rx_gain_range(const std::string &name, size_t chan){
534 ebd2ecc6 Josh Blum
        return rx_gain_group(chan)->get_range(name);
535 c861f98c Josh Blum
    }
536
537 8e341caa Josh Blum
    std::vector<std::string> get_rx_gain_names(size_t chan){
538 ebd2ecc6 Josh Blum
        return rx_gain_group(chan)->get_names();
539 c861f98c Josh Blum
    }
540
541
    void set_rx_antenna(const std::string &ant, size_t chan){
542 ebd2ecc6 Josh Blum
        _tree->access<std::string>(rx_rf_fe_root(chan) / "antenna" / "value").set(ant);
543 c861f98c Josh Blum
    }
544
545
    std::string get_rx_antenna(size_t chan){
546 ebd2ecc6 Josh Blum
        return _tree->access<std::string>(rx_rf_fe_root(chan) / "antenna" / "value").get();
547 c861f98c Josh Blum
    }
548
549
    std::vector<std::string> get_rx_antennas(size_t chan){
550 ebd2ecc6 Josh Blum
        return _tree->access<std::vector<std::string> >(rx_rf_fe_root(chan) / "antenna" / "options").get();
551 c861f98c Josh Blum
    }
552
553 799d5059 Josh Blum
    void set_rx_bandwidth(double bandwidth, size_t chan){
554 ebd2ecc6 Josh Blum
        _tree->access<double>(rx_rf_fe_root(chan) / "bandwidth" / "value").set(bandwidth);
555 799d5059 Josh Blum
    }
556
557
    double get_rx_bandwidth(size_t chan){
558 ebd2ecc6 Josh Blum
        return _tree->access<double>(rx_rf_fe_root(chan) / "bandwidth" / "value").get();
559 799d5059 Josh Blum
    }
560
561 3a9edd27 Josh Blum
    meta_range_t get_rx_bandwidth_range(size_t chan){
562
        return _tree->access<meta_range_t>(rx_rf_fe_root(chan) / "bandwidth" / "range").get();
563
    }
564
565 c861f98c Josh Blum
    dboard_iface::sptr get_rx_dboard_iface(size_t chan){
566 ebd2ecc6 Josh Blum
        return _tree->access<dboard_iface::sptr>(rx_rf_fe_root(chan).branch_path().branch_path() / "iface").get();
567 c861f98c Josh Blum
    }
568
569 e4b45cca Josh Blum
    sensor_value_t get_rx_sensor(const std::string &name, size_t chan){
570 ebd2ecc6 Josh Blum
        return _tree->access<sensor_value_t>(rx_rf_fe_root(chan) / "sensors" / name).get();
571 e4b45cca Josh Blum
    }
572
573
    std::vector<std::string> get_rx_sensor_names(size_t chan){
574 ebd2ecc6 Josh Blum
        return _tree->list(rx_rf_fe_root(chan) / "sensors");
575 e4b45cca Josh Blum
    }
576
577 07ba9464 Josh Blum
    void set_rx_dc_offset(const bool enb, size_t chan){
578
        if (chan != ALL_CHANS){
579 dedfa652 Josh Blum
            _tree->access<bool>(rx_fe_root(chan) / "dc_offset" / "enable").set(enb);
580 07ba9464 Josh Blum
            return;
581
        }
582
        for (size_t c = 0; c < get_rx_num_channels(); c++){
583
            this->set_rx_dc_offset(enb, c);
584
        }
585
    }
586
587
    void set_rx_dc_offset(const std::complex<double> &offset, size_t chan){
588
        if (chan != ALL_CHANS){
589 dedfa652 Josh Blum
            _tree->access<std::complex<double> >(rx_fe_root(chan) / "dc_offset" / "value").set(offset);
590 07ba9464 Josh Blum
            return;
591
        }
592
        for (size_t c = 0; c < get_rx_num_channels(); c++){
593
            this->set_rx_dc_offset(offset, c);
594
        }
595
    }
596
597 a6264508 Josh Blum
    void set_rx_iq_balance(const std::complex<double> &offset, size_t chan){
598 c63a38e1 Josh Blum
        if (chan != ALL_CHANS){
599 dedfa652 Josh Blum
            _tree->access<std::complex<double> >(rx_fe_root(chan) / "iq_balance" / "value").set(offset);
600 c63a38e1 Josh Blum
            return;
601
        }
602
        for (size_t c = 0; c < get_rx_num_channels(); c++){
603 a6264508 Josh Blum
            this->set_rx_iq_balance(offset, c);
604 c63a38e1 Josh Blum
        }
605
    }
606
607 c861f98c Josh Blum
    /*******************************************************************
608
     * TX methods
609
     ******************************************************************/
610
    void set_tx_subdev_spec(const subdev_spec_t &spec, size_t mboard){
611
        if (mboard != ALL_MBOARDS){
612 ebd2ecc6 Josh Blum
            _tree->access<subdev_spec_t>(mb_root(mboard) / "tx_subdev_spec").set(spec);
613 c861f98c Josh Blum
            return;
614
        }
615
        for (size_t m = 0; m < get_num_mboards(); m++){
616
            set_tx_subdev_spec(spec, m);
617
        }
618
    }
619
620
    subdev_spec_t get_tx_subdev_spec(size_t mboard){
621 ebd2ecc6 Josh Blum
        return _tree->access<subdev_spec_t>(mb_root(mboard) / "tx_subdev_spec").get();
622 c861f98c Josh Blum
    }
623
624
    std::string get_tx_subdev_name(size_t chan){
625 ebd2ecc6 Josh Blum
        return _tree->access<std::string>(tx_rf_fe_root(chan) / "name").get();
626 c861f98c Josh Blum
    }
627
628
    size_t get_tx_num_channels(void){
629 ede85c10 Josh Blum
        size_t sum = 0;
630
        for (size_t m = 0; m < get_num_mboards(); m++){
631
            sum += get_tx_subdev_spec(m).size();
632
        }
633
        return sum;
634 c861f98c Josh Blum
    }
635
636 e128948a Josh Blum
    void set_tx_rate(double rate, size_t chan){
637 1628434a Josh Blum
        if (chan != ALL_CHANS){
638 ebd2ecc6 Josh Blum
            _tree->access<double>(tx_dsp_root(chan) / "rate" / "value").set(rate);
639 1628434a Josh Blum
            do_samp_rate_warning_message(rate, get_tx_rate(chan), "TX");
640
            return;
641
        }
642 e128948a Josh Blum
        for (size_t c = 0; c < get_tx_num_channels(); c++){
643 1628434a Josh Blum
            set_tx_rate(rate, c);
644 c861f98c Josh Blum
        }
645
    }
646
647 1628434a Josh Blum
    double get_tx_rate(size_t chan){
648 ebd2ecc6 Josh Blum
        return _tree->access<double>(tx_dsp_root(chan) / "rate" / "value").get();
649 c861f98c Josh Blum
    }
650
651 ae9e89d7 Josh Blum
    meta_range_t get_tx_rates(size_t chan){
652
        return _tree->access<meta_range_t>(tx_dsp_root(chan) / "rate" / "range").get();
653
    }
654
655 359c4e16 Josh Blum
    tune_result_t set_tx_freq(const tune_request_t &tune_request, size_t chan){
656 aa6b340f Josh Blum
        tune_result_t r = tune_xx_subdev_and_dsp(TX_SIGN, _tree->subtree(tx_dsp_root(chan)), _tree->subtree(tx_rf_fe_root(chan)), tune_request);
657 3cb60c97 Josh Blum
        do_tune_freq_warning_message(tune_request, get_tx_freq(chan), "TX");
658 adbe1a0e Josh Blum
        return r;
659 c861f98c Josh Blum
    }
660
661
    double get_tx_freq(size_t chan){
662 aa6b340f Josh Blum
        return derive_freq_from_xx_subdev_and_dsp(TX_SIGN, _tree->subtree(tx_dsp_root(chan)), _tree->subtree(tx_rf_fe_root(chan)));
663 c861f98c Josh Blum
    }
664
665
    freq_range_t get_tx_freq_range(size_t chan){
666 e033fc3d Josh Blum
        return make_overall_tune_range(
667
            _tree->access<meta_range_t>(tx_rf_fe_root(chan) / "freq" / "range").get(),
668
            _tree->access<meta_range_t>(tx_dsp_root(chan) / "freq" / "range").get(),
669
            this->get_tx_bandwidth(chan)
670
        );
671 c861f98c Josh Blum
    }
672
673 395bbbbc Josh Blum
    void set_tx_gain(double gain, const std::string &name, size_t chan){
674 ebd2ecc6 Josh Blum
        return tx_gain_group(chan)->set_value(gain, name);
675 8e341caa Josh Blum
    }
676
677 395bbbbc Josh Blum
    double get_tx_gain(const std::string &name, size_t chan){
678 ebd2ecc6 Josh Blum
        return tx_gain_group(chan)->get_value(name);
679 c861f98c Josh Blum
    }
680
681 8e341caa Josh Blum
    gain_range_t get_tx_gain_range(const std::string &name, size_t chan){
682 ebd2ecc6 Josh Blum
        return tx_gain_group(chan)->get_range(name);
683 c861f98c Josh Blum
    }
684
685 8e341caa Josh Blum
    std::vector<std::string> get_tx_gain_names(size_t chan){
686 ebd2ecc6 Josh Blum
        return tx_gain_group(chan)->get_names();
687 c861f98c Josh Blum
    }
688
689
    void set_tx_antenna(const std::string &ant, size_t chan){
690 ebd2ecc6 Josh Blum
        _tree->access<std::string>(tx_rf_fe_root(chan) / "antenna" / "value").set(ant);
691 c861f98c Josh Blum
    }
692
693
    std::string get_tx_antenna(size_t chan){
694 ebd2ecc6 Josh Blum
        return _tree->access<std::string>(tx_rf_fe_root(chan) / "antenna" / "value").get();
695 c861f98c Josh Blum
    }
696
697
    std::vector<std::string> get_tx_antennas(size_t chan){
698 ebd2ecc6 Josh Blum
        return _tree->access<std::vector<std::string> >(tx_rf_fe_root(chan) / "antenna" / "options").get();
699 c861f98c Josh Blum
    }
700
701 799d5059 Josh Blum
    void set_tx_bandwidth(double bandwidth, size_t chan){
702 ebd2ecc6 Josh Blum
        _tree->access<double>(tx_rf_fe_root(chan) / "bandwidth" / "value").set(bandwidth);
703 799d5059 Josh Blum
    }
704
705
    double get_tx_bandwidth(size_t chan){
706 ebd2ecc6 Josh Blum
        return _tree->access<double>(tx_rf_fe_root(chan) / "bandwidth" / "value").get();
707 799d5059 Josh Blum
    }
708
709 3a9edd27 Josh Blum
    meta_range_t get_tx_bandwidth_range(size_t chan){
710
        return _tree->access<meta_range_t>(tx_rf_fe_root(chan) / "bandwidth" / "range").get();
711
    }
712
713 c861f98c Josh Blum
    dboard_iface::sptr get_tx_dboard_iface(size_t chan){
714 ebd2ecc6 Josh Blum
        return _tree->access<dboard_iface::sptr>(tx_rf_fe_root(chan).branch_path().branch_path() / "iface").get();
715 c861f98c Josh Blum
    }
716
717 e4b45cca Josh Blum
    sensor_value_t get_tx_sensor(const std::string &name, size_t chan){
718 ebd2ecc6 Josh Blum
        return _tree->access<sensor_value_t>(tx_rf_fe_root(chan) / "sensors" / name).get();
719 e4b45cca Josh Blum
    }
720
721
    std::vector<std::string> get_tx_sensor_names(size_t chan){
722 ebd2ecc6 Josh Blum
        return _tree->list(tx_rf_fe_root(chan) / "sensors");
723 e4b45cca Josh Blum
    }
724
725 07ba9464 Josh Blum
    void set_tx_dc_offset(const std::complex<double> &offset, size_t chan){
726
        if (chan != ALL_CHANS){
727 dedfa652 Josh Blum
            _tree->access<std::complex<double> >(tx_fe_root(chan) / "dc_offset" / "value").set(offset);
728 07ba9464 Josh Blum
            return;
729
        }
730
        for (size_t c = 0; c < get_tx_num_channels(); c++){
731
            this->set_tx_dc_offset(offset, c);
732
        }
733
    }
734
735 a6264508 Josh Blum
    void set_tx_iq_balance(const std::complex<double> &offset, size_t chan){
736 c63a38e1 Josh Blum
        if (chan != ALL_CHANS){
737 dedfa652 Josh Blum
            _tree->access<std::complex<double> >(tx_fe_root(chan) / "iq_balance" / "value").set(offset);
738 c63a38e1 Josh Blum
            return;
739
        }
740
        for (size_t c = 0; c < get_tx_num_channels(); c++){
741 a6264508 Josh Blum
            this->set_tx_iq_balance(offset, c);
742 c63a38e1 Josh Blum
        }
743
    }
744
745 c861f98c Josh Blum
private:
746
    device::sptr _dev;
747 ebd2ecc6 Josh Blum
    property_tree::sptr _tree;
748 982ac435 Josh Blum
749 ede85c10 Josh Blum
    struct mboard_chan_pair{
750
        size_t mboard, chan;
751
        mboard_chan_pair(void): mboard(0), chan(0){}
752
    };
753
754
    mboard_chan_pair rx_chan_to_mcp(size_t chan){
755
        mboard_chan_pair mcp;
756
        mcp.chan = chan;
757
        for (mcp.mboard = 0; mcp.mboard < get_num_mboards(); mcp.mboard++){
758
            size_t sss = get_rx_subdev_spec(mcp.mboard).size();
759
            if (mcp.chan < sss) break;
760
            mcp.chan -= sss;
761 083413de Josh Blum
        }
762 ede85c10 Josh Blum
        return mcp;
763 982ac435 Josh Blum
    }
764
765 ede85c10 Josh Blum
    mboard_chan_pair tx_chan_to_mcp(size_t chan){
766
        mboard_chan_pair mcp;
767
        mcp.chan = chan;
768
        for (mcp.mboard = 0; mcp.mboard < get_num_mboards(); mcp.mboard++){
769
            size_t sss = get_tx_subdev_spec(mcp.mboard).size();
770
            if (mcp.chan < sss) break;
771
            mcp.chan -= sss;
772 083413de Josh Blum
        }
773 ede85c10 Josh Blum
        return mcp;
774 982ac435 Josh Blum
    }
775
776 da40a1ae Josh Blum
    fs_path mb_root(const size_t mboard){
777 ebd2ecc6 Josh Blum
        const std::string name = _tree->list("/mboards").at(mboard);
778
        return "/mboards/" + name;
779 c861f98c Josh Blum
    }
780 ebd2ecc6 Josh Blum
781 da40a1ae Josh Blum
    fs_path rx_dsp_root(const size_t chan){
782 ede85c10 Josh Blum
        mboard_chan_pair mcp = rx_chan_to_mcp(chan);
783 ebd2ecc6 Josh Blum
        const std::string name = _tree->list(mb_root(mcp.mboard) / "rx_dsps").at(mcp.chan);
784
        return mb_root(mcp.mboard) / "rx_dsps" / name;
785 c861f98c Josh Blum
    }
786 ebd2ecc6 Josh Blum
787 da40a1ae Josh Blum
    fs_path tx_dsp_root(const size_t chan){
788 ede85c10 Josh Blum
        mboard_chan_pair mcp = tx_chan_to_mcp(chan);
789 ebd2ecc6 Josh Blum
        const std::string name = _tree->list(mb_root(mcp.mboard) / "tx_dsps").at(mcp.chan);
790
        return mb_root(mcp.mboard) / "tx_dsps" / name;
791 c861f98c Josh Blum
    }
792 ebd2ecc6 Josh Blum
793 dedfa652 Josh Blum
    fs_path rx_fe_root(const size_t chan){
794
        mboard_chan_pair mcp = rx_chan_to_mcp(chan);
795
        const subdev_spec_pair_t spec = get_rx_subdev_spec(mcp.mboard).at(mcp.chan);
796
        return mb_root(mcp.mboard) / "rx_frontends" / spec.db_name;
797
    }
798
799
    fs_path tx_fe_root(const size_t chan){
800
        mboard_chan_pair mcp = tx_chan_to_mcp(chan);
801
        const subdev_spec_pair_t spec = get_tx_subdev_spec(mcp.mboard).at(mcp.chan);
802
        return mb_root(mcp.mboard) / "tx_frontends" / spec.db_name;
803
    }
804
805 da40a1ae Josh Blum
    fs_path rx_rf_fe_root(const size_t chan){
806 ede85c10 Josh Blum
        mboard_chan_pair mcp = rx_chan_to_mcp(chan);
807 ebd2ecc6 Josh Blum
        const subdev_spec_pair_t spec = get_rx_subdev_spec(mcp.mboard).at(mcp.chan);
808
        return mb_root(mcp.mboard) / "dboards" / spec.db_name / "rx_frontends" / spec.sd_name;
809 c861f98c Josh Blum
    }
810 ebd2ecc6 Josh Blum
811 da40a1ae Josh Blum
    fs_path tx_rf_fe_root(const size_t chan){
812 ede85c10 Josh Blum
        mboard_chan_pair mcp = tx_chan_to_mcp(chan);
813 ebd2ecc6 Josh Blum
        const subdev_spec_pair_t spec = get_tx_subdev_spec(mcp.mboard).at(mcp.chan);
814
        return mb_root(mcp.mboard) / "dboards" / spec.db_name / "tx_frontends" / spec.sd_name;
815 c861f98c Josh Blum
    }
816 ebd2ecc6 Josh Blum
817
    gain_group::sptr rx_gain_group(size_t chan){
818 ede85c10 Josh Blum
        mboard_chan_pair mcp = rx_chan_to_mcp(chan);
819 ebd2ecc6 Josh Blum
        const subdev_spec_pair_t spec = get_rx_subdev_spec(mcp.mboard).at(mcp.chan);
820
        gain_group::sptr gg = gain_group::make();
821
        BOOST_FOREACH(const std::string &name, _tree->list(mb_root(mcp.mboard) / "rx_codecs" / spec.db_name / "gains")){
822 aa6b340f Josh Blum
            gg->register_fcns("ADC-"+name, make_gain_fcns_from_subtree(_tree->subtree(mb_root(mcp.mboard) / "rx_codecs" / spec.db_name / "gains" / name)), 0 /* low prio */);
823 ebd2ecc6 Josh Blum
        }
824
        BOOST_FOREACH(const std::string &name, _tree->list(rx_rf_fe_root(chan) / "gains")){
825 aa6b340f Josh Blum
            gg->register_fcns(name, make_gain_fcns_from_subtree(_tree->subtree(rx_rf_fe_root(chan) / "gains" / name)), 1 /* high prio */);
826 ebd2ecc6 Josh Blum
        }
827
        return gg;
828 c861f98c Josh Blum
    }
829 ebd2ecc6 Josh Blum
830
    gain_group::sptr tx_gain_group(size_t chan){
831 ede85c10 Josh Blum
        mboard_chan_pair mcp = tx_chan_to_mcp(chan);
832 ebd2ecc6 Josh Blum
        const subdev_spec_pair_t spec = get_tx_subdev_spec(mcp.mboard).at(mcp.chan);
833
        gain_group::sptr gg = gain_group::make();
834
        BOOST_FOREACH(const std::string &name, _tree->list(mb_root(mcp.mboard) / "tx_codecs" / spec.db_name / "gains")){
835 aa6b340f Josh Blum
            gg->register_fcns("ADC-"+name, make_gain_fcns_from_subtree(_tree->subtree(mb_root(mcp.mboard) / "tx_codecs" / spec.db_name / "gains" / name)), 1 /* high prio */);
836 ebd2ecc6 Josh Blum
        }
837
        BOOST_FOREACH(const std::string &name, _tree->list(tx_rf_fe_root(chan) / "gains")){
838 aa6b340f Josh Blum
            gg->register_fcns(name, make_gain_fcns_from_subtree(_tree->subtree(tx_rf_fe_root(chan) / "gains" / name)), 0 /* low prio */);
839 ebd2ecc6 Josh Blum
        }
840
        return gg;
841 c861f98c Josh Blum
    }
842
};
843
844
/***********************************************************************
845
 * The Make Function
846
 **********************************************************************/
847
multi_usrp::sptr multi_usrp::make(const device_addr_t &dev_addr){
848
    return sptr(new multi_usrp_impl(dev_addr));
849
}