aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/gain_handler.cpp
blob: 36e2e8ed3ea61fd6ef0593df9cc79763b7561528 (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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//
// 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
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#include <uhd/utils/gain_handler.hpp>
#include <uhd/utils/assert.hpp>
#include <uhd/types/ranges.hpp>
#include <uhd/utils/props.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <cmath>
#include <vector>

using namespace uhd;

/***********************************************************************
 * gain handler implementation interface
 **********************************************************************/
class gain_handler_impl : public gain_handler{
public:
    gain_handler_impl(
        const wax::obj &link,
        const props_t &props,
        is_equal_t is_equal
    );
    ~gain_handler_impl(void);
    bool intercept_get(const wax::obj &key, wax::obj &val);
    bool intercept_set(const wax::obj &key, const wax::obj &val);

private:
    wax::obj     _link;
    props_t _props;
    is_equal_t   _is_equal;

    prop_names_t get_gain_names(void);
    float get_overall_gain_val(void);
    gain_range_t get_overall_gain_range(void);
    template <class T> T get_named_prop(const wax::obj &prop, const std::string &name){
        return _link[named_prop_t(prop, name)].as<T>();
    }
};

/***********************************************************************
 * the make function
 **********************************************************************/
gain_handler::sptr gain_handler::make(
    const wax::obj &link,
    const props_t &props,
    is_equal_t is_equal
){
    return sptr(new gain_handler_impl(link, props, is_equal));
}

/***********************************************************************
 * gain handler implementation methods
 **********************************************************************/
gain_handler::props_t::props_t(void){
    /* NOP */
}

gain_handler_impl::gain_handler_impl(
    const wax::obj &link,
    const props_t &props,
    is_equal_t is_equal
){
    _link = link;
    _props = props;
    _is_equal = is_equal;
}

gain_handler_impl::~gain_handler_impl(void){
    /* NOP */
}

prop_names_t gain_handler_impl::get_gain_names(void){
    return _link[_props.names].as<prop_names_t>();
}

float gain_handler_impl::get_overall_gain_val(void){
    float gain_val = 0;
    BOOST_FOREACH(std::string name, get_gain_names()){
        gain_val += get_named_prop<float>(_props.value, name);
    }
    return gain_val;
}

gain_range_t gain_handler_impl::get_overall_gain_range(void){
    float gain_min = 0, gain_max = 0, gain_step = 0;
    BOOST_FOREACH(std::string name, get_gain_names()){
        gain_range_t floatmp = get_named_prop<gain_range_t>(_props.range, name);
        gain_min += floatmp.min;
        gain_max += floatmp.max;
        gain_step = std::max(gain_step, floatmp.step);
    }
    return gain_range_t(gain_min, gain_max, gain_step);
}

/***********************************************************************
 * gain handler implementation get method
 **********************************************************************/
bool gain_handler_impl::intercept_get(const wax::obj &key_, wax::obj &val){
    wax::obj key; std::string name;
    boost::tie(key, name) = extract_named_prop(key_);

    //not a wildcard... dont handle (but check name)
    if (name != ""){
        assert_has(get_gain_names(), name, "gain name");
        return false;
    }

    if (_is_equal(key, _props.value)){
        val = get_overall_gain_val();
        return true;
    }

    if (_is_equal(key, _props.range)){
        val = get_overall_gain_range();
        return true;
    }

    return false; //not handled
}

/***********************************************************************
 * gain handler implementation set method
 **********************************************************************/
bool gain_handler_impl::intercept_set(const wax::obj &key_, const wax::obj &val){
    wax::obj key; std::string name;
    boost::tie(key, name) = extract_named_prop(key_);

    //not a gain value key... dont handle
    if (not _is_equal(key, _props.value)) return false;

    float gain_val = val.as<float>();

    //not a wildcard... dont handle (but check name and range)
    if (name != ""){
        assert_has(get_gain_names(), name, "gain name");
        gain_range_t gain = get_named_prop<gain_range_t>(_props.range, name);
        if (gain_val > gain.max or gain_val < gain.min) throw std::range_error(str(
            boost::format("A value of %f for gain %s is out of range of (%f, %f)")
            % gain_val % name % gain.min % gain.max
        ));
        return false;
    }

    //set the overall gain
    BOOST_FOREACH(std::string name, get_gain_names()){
        //get the min, max, step for this gain name
        gain_range_t gain = get_named_prop<gain_range_t>(_props.range, name);

        //clip g to be within the allowed range
        float g = std::min(std::max(gain_val, gain.min), gain.max);
        //set g to be a multiple of the step size
        g -= std::fmod(g, gain.step);
        //set g to be the new gain
        _link[named_prop_t(_props.value, name)] = g;
        //subtract g out of the total gain left to apply
        gain_val -= g;
    }

    return true;
}