//
// 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
using namespace uhd;
/***********************************************************************
* Helper functions and macros
**********************************************************************/
#define GET_PROP_NAMES() \
wax::cast((*_wax_obj_ptr)[_gain_names_prop])
/*!
* Helper function to simplify getting a named gain (also min, max, step).
*/
static gain_t get_named_gain(wax::obj *wax_obj_ptr, wax::obj prop, std::string name){
return wax::cast((*wax_obj_ptr)[named_prop_t(prop, name)]);
}
/***********************************************************************
* Class methods of gain handler
**********************************************************************/
gain_handler::~gain_handler(void){
/* NOP */
}
void gain_handler::_check_key(const wax::obj &key_){
wax::obj key; std::string name;
boost::tie(key, name) = extract_named_prop(key_);
try{
//only handle non wildcard names
ASSERT_THROW(name != "");
//only handle these gain props
ASSERT_THROW(
_is_equal(key, _gain_prop) or
_is_equal(key, _gain_min_prop) or
_is_equal(key, _gain_max_prop) or
_is_equal(key, _gain_step_prop)
);
//check that the name is allowed
prop_names_t prop_names = GET_PROP_NAMES();
ASSERT_THROW(not std::has(prop_names.begin(), prop_names.end(), name));
//if we get here, throw an exception
throw std::invalid_argument(str(
boost::format("Unknown gain name %s") % name
));
}
catch(const std::assert_error &){}
}
bool gain_handler::intercept_get(const wax::obj &key, wax::obj &val){
_check_key(key); //verify the key
// use a vector of tuples to map properties to a reducer function
// we cant use a map because the wax::obj cant be sorted
typedef boost::function reducer_t;
typedef boost::tuple tuple_t;
reducer_t reducer_sum = boost::bind(std::sum, _1, _2);
reducer_t reducer_max = boost::bind(std::max, _1, _2);
std::vector prop_to_reducer = boost::assign::tuple_list_of
(_gain_prop, reducer_sum)(_gain_min_prop, reducer_sum)
(_gain_max_prop, reducer_sum)(_gain_step_prop, reducer_max);
/*!
* Handle getting overall gains when a name is not specified.
* For the gain props below, set the overall value and return true.
*/
BOOST_FOREACH(tuple_t p2r, prop_to_reducer){
if (_is_equal(key, p2r.get<0>())){
//form the gains vector from the props vector
prop_names_t prop_names = GET_PROP_NAMES();
std::vector gains(prop_names.size());
std::transform(
prop_names.begin(), prop_names.end(), gains.begin(),
boost::bind(get_named_gain, _wax_obj_ptr, p2r.get<0>(), _1)
);
//reduce across the gain vector
val = std::reduce(gains.begin(), gains.end(), p2r.get<1>());
return true;
}
}
return false;
}
bool gain_handler::intercept_set(const wax::obj &key_, const wax::obj &val){
_check_key(key_); //verify the key
wax::obj key; std::string name;
boost::tie(key, name) = extract_named_prop(key_);
/*!
* Verify that a named gain component is in range.
*/
try{
//only handle the gain props
ASSERT_THROW(_is_equal(key, _gain_prop));
//check that the gain is in range
gain_t gain = wax::cast(val);
gain_t gain_min = get_named_gain(_wax_obj_ptr, _gain_min_prop, name);
gain_t gain_max = get_named_gain(_wax_obj_ptr, _gain_max_prop, name);
ASSERT_THROW(gain > gain_max or gain < gain_min);
//if we get here, throw an exception
throw std::range_error(str(
boost::format("gain %s is out of range of (%f, %f)") % name % gain_min % gain_max
));
}
catch(const std::assert_error &){}
/*!
* Handle setting the overall gain.
*/
if (_is_equal(key, _gain_prop) and name == ""){
gain_t gain = wax::cast(val);
prop_names_t prop_names = GET_PROP_NAMES();
BOOST_FOREACH(std::string name, prop_names){
//get the min, max, step for this gain name
gain_t gain_min = get_named_gain(_wax_obj_ptr, _gain_min_prop, name);
gain_t gain_max = get_named_gain(_wax_obj_ptr, _gain_max_prop, name);
gain_t gain_step = get_named_gain(_wax_obj_ptr, _gain_step_prop, name);
//clip g to be within the allowed range
gain_t g = std::min(std::max(gain, 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
(*_wax_obj_ptr)[named_prop_t(_gain_prop, name)] = g;
//subtract g out of the total gain left to apply
gain -= g;
}
return true;
}
return false;
}