Statistics
| Branch: | Tag: | Revision:

root / host / lib / usrp / misc_utils.cpp @ f5c62a46

History | View | Annotate | Download (8.6 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/usrp/misc_utils.hpp>
19
#include <uhd/utils/assert.hpp>
20
#include <uhd/utils/gain_group.hpp>
21
#include <uhd/usrp/dboard_id.hpp>
22
#include <uhd/usrp/subdev_props.hpp>
23
#include <uhd/usrp/mboard_props.hpp>
24
#include <uhd/usrp/dboard_props.hpp>
25
#include <uhd/usrp/codec_props.hpp>
26
#include <boost/bind.hpp>
27
#include <boost/foreach.hpp>
28
#include <boost/format.hpp>
29

    
30
using namespace uhd;
31
using namespace uhd::usrp;
32

    
33
/***********************************************************************
34
 * codec gain group helper functions:
35
 *    do this so we dont have to bind a templated function
36
 **********************************************************************/
37
static gain_range_t get_codec_gain_range(wax::obj codec, const std::string &name){
38
    return codec[named_prop_t(CODEC_PROP_GAIN_RANGE, name)].as<gain_range_t>();
39
}
40

    
41
static float get_codec_gain_i(wax::obj codec, const std::string &name){
42
    return codec[named_prop_t(CODEC_PROP_GAIN_I, name)].as<float>();
43
}
44

    
45
static float get_codec_gain_q(wax::obj codec, const std::string &name){
46
    return codec[named_prop_t(CODEC_PROP_GAIN_Q, name)].as<float>();
47
}
48

    
49
static void set_codec_gain_both(wax::obj codec, const std::string &name, float gain){
50
    codec[named_prop_t(CODEC_PROP_GAIN_I, name)] = gain;
51
    codec[named_prop_t(CODEC_PROP_GAIN_Q, name)] = gain;
52
}
53

    
54
static void set_codec_gain_i(wax::obj codec, const std::string &name, float gain){
55
    codec[named_prop_t(CODEC_PROP_GAIN_I, name)] = gain;
56
}
57

    
58
static void set_codec_gain_q(wax::obj codec, const std::string &name, float gain){
59
    codec[named_prop_t(CODEC_PROP_GAIN_Q, name)] = gain;
60
}
61

    
62
/***********************************************************************
63
 * subdev gain group helper functions:
64
 *    do this so we dont have to bind a templated function
65
 **********************************************************************/
66
static float get_subdev_gain(wax::obj subdev, const std::string &name){
67
    return subdev[named_prop_t(SUBDEV_PROP_GAIN, name)].as<float>();
68
}
69

    
70
static gain_range_t get_subdev_gain_range(wax::obj subdev, const std::string &name){
71
    return subdev[named_prop_t(SUBDEV_PROP_GAIN_RANGE, name)].as<gain_range_t>();
72
}
73

    
74
static void set_subdev_gain(wax::obj subdev, const std::string &name, float gain){
75
    subdev[named_prop_t(SUBDEV_PROP_GAIN, name)] = gain;
76
}
77

    
78
/***********************************************************************
79
 * gain group factory function for usrp
80
 **********************************************************************/
81
gain_group::sptr usrp::make_gain_group(
82
    wax::obj subdev, wax::obj codec,
83
    gain_group_policy_t gain_group_policy
84
){
85
    const size_t subdev_gain_priority = 1;
86
    const size_t codec_gain_priority = (gain_group_policy == GAIN_GROUP_POLICY_RX)?
87
        (subdev_gain_priority - 1): //RX policy, codec gains fill last (lower priority)
88
        (subdev_gain_priority + 1); //TX policy, codec gains fill first (higher priority)
89

    
90
    gain_group::sptr gg = gain_group::make();
91
    gain_fcns_t fcns;
92
    //add all the subdev gains first (antenna to dsp order)
93
    BOOST_FOREACH(const std::string &name, subdev[SUBDEV_PROP_GAIN_NAMES].as<prop_names_t>()){
94
        fcns.get_range = boost::bind(&get_subdev_gain_range, subdev, name);
95
        fcns.get_value = boost::bind(&get_subdev_gain, subdev, name);
96
        fcns.set_value = boost::bind(&set_subdev_gain, subdev, name, _1);
97
        gg->register_fcns(fcns, subdev_gain_priority);
98
    }
99
    //add all the codec gains last (antenna to dsp order)
100
    BOOST_FOREACH(const std::string &name, codec[CODEC_PROP_GAIN_NAMES].as<prop_names_t>()){
101
        fcns.get_range = boost::bind(&get_codec_gain_range, codec, name);
102

    
103
        //register the value functions depending upon the connection type
104
        switch(subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()){
105
        case SUBDEV_CONN_COMPLEX_IQ:
106
        case SUBDEV_CONN_COMPLEX_QI:
107
            fcns.get_value = boost::bind(&get_codec_gain_i, codec, name); //same as Q
108
            fcns.set_value = boost::bind(&set_codec_gain_both, codec, name, _1); //sets both
109
            break;
110

    
111
        case SUBDEV_CONN_REAL_I:
112
            fcns.get_value = boost::bind(&get_codec_gain_i, codec, name);
113
            fcns.set_value = boost::bind(&set_codec_gain_i, codec, name, _1);
114
            break;
115

    
116
        case SUBDEV_CONN_REAL_Q:
117
            fcns.get_value = boost::bind(&get_codec_gain_q, codec, name);
118
            fcns.set_value = boost::bind(&set_codec_gain_q, codec, name, _1);
119
            break;
120
        }
121
        gg->register_fcns(fcns, codec_gain_priority);
122
    }
123
    return gg;
124
}
125

    
126
/***********************************************************************
127
 * verify subdev specs
128
 **********************************************************************/
129
static void verify_xx_subdev_spec(
130
    mboard_prop_t dboard_names_prop,
131
    mboard_prop_t dboard_prop,
132
    subdev_spec_t &subdev_spec,
133
    wax::obj mboard,
134
    std::string xx_type
135
){
136
    try{
137
        prop_names_t dboard_names = mboard[dboard_names_prop].as<prop_names_t>();
138
        UHD_ASSERT_THROW(dboard_names.size() > 0); //well i hope there is a dboard
139

    
140
        //the subdevice specification is empty: handle automatic
141
        if (subdev_spec.empty()){
142
            BOOST_FOREACH(const std::string &db_name, dboard_names){
143
                wax::obj dboard = mboard[named_prop_t(dboard_prop, db_name)];
144

    
145
                //if the dboard slot is populated, take the first subdevice
146
                if (dboard[DBOARD_PROP_DBOARD_ID].as<dboard_id_t>() != dboard_id_t::none()){
147
                    std::string sd_name = dboard[DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>().front();
148
                    subdev_spec.push_back(subdev_spec_pair_t(db_name, sd_name));
149
                    break;
150
                }
151
            }
152

    
153
            //didnt find any populated dboards: add the first subdevice
154
            if (subdev_spec.empty()){
155
                std::string db_name = dboard_names.front();
156
                wax::obj dboard = mboard[named_prop_t(dboard_prop, db_name)];
157
                std::string sd_name = dboard[DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>().front();
158
                subdev_spec.push_back(subdev_spec_pair_t(db_name, sd_name));
159
            }
160
        }
161

    
162
        //sanity check that the dboard/subdevice names exist for this mboard
163
        BOOST_FOREACH(const subdev_spec_pair_t &pair, subdev_spec){
164
            //empty db name means select dboard automatically
165
            if (pair.db_name.empty()){
166
                if (dboard_names.size() != 1) throw std::runtime_error(
167
                    "A daughterboard name must be provided for multi-slot motherboards: " + subdev_spec.to_string()
168
                );
169
                pair.db_name == dboard_names.front();
170
            }
171
            uhd::assert_has(dboard_names, pair.db_name, xx_type + " dboard name");
172
            wax::obj dboard = mboard[named_prop_t(dboard_prop, pair.db_name)];
173
            prop_names_t subdev_names = dboard[DBOARD_PROP_SUBDEV_NAMES].as<prop_names_t>();
174

    
175
            //empty sd name means select the subdev automatically
176
            if (pair.sd_name.empty()){
177
                if (subdev_names.size() != 1) throw std::runtime_error(
178
                    "A subdevice name must be provided for multi-subdev daughterboards: " + subdev_spec.to_string()
179
                );
180
                pair.sd_name == subdev_names.front();
181
            }
182
            uhd::assert_has(subdev_names, pair.sd_name, xx_type + " subdev name");
183
        }
184
    }catch(const std::exception &e){
185
        throw std::runtime_error(str(boost::format(
186
            "Validate %s subdev spec failed: %s\n    %s"
187
        ) % xx_type % subdev_spec.to_string() % e.what()));
188
    }
189
}
190

    
191
void usrp::verify_rx_subdev_spec(subdev_spec_t &subdev_spec, wax::obj mboard){
192
    return verify_xx_subdev_spec(
193
        MBOARD_PROP_RX_DBOARD_NAMES,
194
        MBOARD_PROP_RX_DBOARD,
195
        subdev_spec, mboard, "rx"
196
    );
197
}
198

    
199
void usrp::verify_tx_subdev_spec(subdev_spec_t &subdev_spec, wax::obj mboard){
200
    return verify_xx_subdev_spec(
201
        MBOARD_PROP_TX_DBOARD_NAMES,
202
        MBOARD_PROP_TX_DBOARD,
203
        subdev_spec, mboard, "tx"
204
    );
205
}