//
// 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 .
//
#include
#include
#include
#include
#include
#include
#include
using namespace uhd;
/***********************************************************************
* helper functions
**********************************************************************/
static gain_t gain_max(gain_t a, gain_t b){
return std::max(a, b);
}
static gain_t gain_sum(gain_t a, gain_t b){
return std::sum(a, b);
}
/***********************************************************************
* gain handler implementation interface
**********************************************************************/
class gain_handler_impl : public gain_handler{
public:
gain_handler_impl(
const wax::obj &link,
const gain_props_t &gain_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;
gain_props_t _gain_props;
is_equal_t _is_equal;
prop_names_t get_gain_names(void);
std::vector get_gains(const wax::obj &prop_key);
gain_t get_overall_gain_val(void);
gain_t get_overall_gain_min(void);
gain_t get_overall_gain_max(void);
gain_t get_overall_gain_step(void);
};
/***********************************************************************
* the make function
**********************************************************************/
gain_handler::sptr gain_handler::make(
const wax::obj &link,
const gain_props_t &gain_props,
is_equal_t is_equal
){
return sptr(new gain_handler_impl(link, gain_props, is_equal));
}
/***********************************************************************
* gain handler implementation methods
**********************************************************************/
gain_handler::gain_props_t::gain_props_t(void){
/* NOP */
}
gain_handler_impl::gain_handler_impl(
const wax::obj &link,
const gain_props_t &gain_props,
is_equal_t is_equal
){
_link = link;
_gain_props = gain_props;
_is_equal = is_equal;
}
gain_handler_impl::~gain_handler_impl(void){
/* NOP */
}
prop_names_t gain_handler_impl::get_gain_names(void){
return wax::cast(_link[_gain_props.gain_names_prop]);
}
std::vector gain_handler_impl::get_gains(const wax::obj &prop_key){
std::vector gains;
BOOST_FOREACH(std::string name, get_gain_names()){
gains.push_back(wax::cast(_link[named_prop_t(prop_key, name)]));
}
return gains;
}
gain_t gain_handler_impl::get_overall_gain_val(void){
return std::reduce(get_gains(_gain_props.gain_val_prop), gain_sum);
}
gain_t gain_handler_impl::get_overall_gain_min(void){
return std::reduce(get_gains(_gain_props.gain_min_prop), gain_sum);
}
gain_t gain_handler_impl::get_overall_gain_max(void){
return std::reduce(get_gains(_gain_props.gain_max_prop), gain_sum);
}
gain_t gain_handler_impl::get_overall_gain_step(void){
return std::reduce(get_gains(_gain_props.gain_step_prop), gain_max);
}
/***********************************************************************
* 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, _gain_props.gain_val_prop)){
val = get_overall_gain_val();
return true;
}
if (_is_equal(key, _gain_props.gain_min_prop)){
val = get_overall_gain_min();
return true;
}
if (_is_equal(key, _gain_props.gain_max_prop)){
val = get_overall_gain_max();
return true;
}
if (_is_equal(key, _gain_props.gain_step_prop)){
val = get_overall_gain_step();
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, _gain_props.gain_val_prop)) return false;
gain_t gain_val = wax::cast(val);
//not a wildcard... dont handle (but check name and range)
if (name != ""){
assert_has(get_gain_names(), name, "gain name");
gain_t gain_min = wax::cast(_link[named_prop_t(_gain_props.gain_min_prop, name)]);
gain_t gain_max = wax::cast(_link[named_prop_t(_gain_props.gain_max_prop, 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_t gain_min = wax::cast(_link[named_prop_t(_gain_props.gain_min_prop, name)]);
gain_t gain_max = wax::cast(_link[named_prop_t(_gain_props.gain_max_prop, name)]);
gain_t gain_step = wax::cast(_link[named_prop_t(_gain_props.gain_step_prop, name)]);
//clip g to be within the allowed range
gain_t g = std::min(std::max(gain_val, gain_min), gain_max);
//set g to be a multiple of the step size
g -= fmod(g, gain_step);
//set g to be the new gain
_link[named_prop_t(_gain_props.gain_val_prop, name)] = g;
//subtract g out of the total gain left to apply
gain_val -= g;
}
return true;
}