diff options
Diffstat (limited to 'host/lib/utils')
-rw-r--r-- | host/lib/utils/CMakeLists.txt | 26 | ||||
-rw-r--r-- | host/lib/utils/assert.cpp | 24 | ||||
-rw-r--r-- | host/lib/utils/gain_handler.cpp | 177 | ||||
-rw-r--r-- | host/lib/utils/load_modules.cpp | 146 | ||||
-rw-r--r-- | host/lib/utils/props.cpp | 43 | ||||
-rw-r--r-- | host/lib/utils/thread_priority.cpp | 98 |
6 files changed, 514 insertions, 0 deletions
diff --git a/host/lib/utils/CMakeLists.txt b/host/lib/utils/CMakeLists.txt new file mode 100644 index 000000000..450112462 --- /dev/null +++ b/host/lib/utils/CMakeLists.txt @@ -0,0 +1,26 @@ +# +# 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/>. +# + +#This file will be included by cmake, use absolute paths! + +LIBUHD_APPEND_SOURCES( + ${CMAKE_SOURCE_DIR}/lib/utils/assert.cpp + ${CMAKE_SOURCE_DIR}/lib/utils/gain_handler.cpp + ${CMAKE_SOURCE_DIR}/lib/utils/load_modules.cpp + ${CMAKE_SOURCE_DIR}/lib/utils/props.cpp + ${CMAKE_SOURCE_DIR}/lib/utils/thread_priority.cpp +) diff --git a/host/lib/utils/assert.cpp b/host/lib/utils/assert.cpp new file mode 100644 index 000000000..7ace9024c --- /dev/null +++ b/host/lib/utils/assert.cpp @@ -0,0 +1,24 @@ +// +// 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/assert.hpp> + +using namespace uhd; + +assert_error::assert_error(const std::string &what) : std::runtime_error(what){ + /* NOP */ +} diff --git a/host/lib/utils/gain_handler.cpp b/host/lib/utils/gain_handler.cpp new file mode 100644 index 000000000..36e2e8ed3 --- /dev/null +++ b/host/lib/utils/gain_handler.cpp @@ -0,0 +1,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; +} diff --git a/host/lib/utils/load_modules.cpp b/host/lib/utils/load_modules.cpp new file mode 100644 index 000000000..dbb8d0695 --- /dev/null +++ b/host/lib/utils/load_modules.cpp @@ -0,0 +1,146 @@ +// +// 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/static.hpp> +#include <boost/format.hpp> +#include <boost/foreach.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/filesystem.hpp> +#include <boost/program_options.hpp> +#include <iostream> +#include <stdexcept> + +namespace po = boost::program_options; +namespace fs = boost::filesystem; + +/*********************************************************************** + * Module Load Function + **********************************************************************/ +#if defined(HAVE_DLFCN_H) +#include <dlfcn.h> +static const std::string env_path_sep = ":"; + +static void load_module(const std::string &file_name){ + if (dlopen(file_name.c_str(), RTLD_LAZY) == NULL){ + throw std::runtime_error(str( + boost::format("dlopen failed to load \"%s\"") % file_name + )); + } +} + +#elif defined(HAVE_WINDOWS_H) +#include <windows.h> +static const std::string env_path_sep = ";"; + +static void load_module(const std::string &file_name){ + if (LoadLibrary(file_name.c_str()) == NULL){ + throw std::runtime_error(str( + boost::format("LoadLibrary failed to load \"%s\"") % file_name + )); + } +} + +#else +static const std::string env_path_sep = ":"; + +static void load_module(const std::string &file_name){ + throw std::runtime_error(str( + boost::format("Module loading not supported: Cannot load \"%s\"") % file_name + )); +} + +#endif + +/*********************************************************************** + * Load Modules + **********************************************************************/ +/*! + * Load all modules in a given path. + * This will recurse into sub-directories. + * Does not throw, prints to std error. + * \param path the filesystem path + */ +static void load_path(const fs::path &path){ + if (not fs::exists(path)){ + std::cerr << boost::format("Module path \"%s\" not found.") % path.file_string() << std::endl; + return; + } + + //try to load the files in this path + if (fs::is_directory(path)){ + for( + fs::directory_iterator dir_itr(path); + dir_itr != fs::directory_iterator(); + ++dir_itr + ){ + load_path(dir_itr->path()); + } + return; + } + + //its not a directory, try to load it + try{ + load_module(path.file_string()); + } + catch(const std::exception &err){ + std::cerr << boost::format("Error: %s") % err.what() << std::endl; + } +} + +//! The string constant for the module path environment variable +static const std::string MODULE_PATH_KEY = "UHD_MODULE_PATH"; + +/*! + * Name mapper function for the environment variable parser. + * Map environment variable names (that we use) to option names. + * \param the variable name + * \return the option name or blank string + */ +static std::string name_mapper(const std::string &var_name){ + if (var_name == MODULE_PATH_KEY) return var_name; + return ""; +} + +/*! + * Load all the modules given by the module path enviroment variable. + * The path variable may be several paths split by path separators. + */ +UHD_STATIC_BLOCK(load_modules){ + //register the options + std::string env_module_path; + po::options_description desc("UHD Module Options"); + desc.add_options() + (MODULE_PATH_KEY.c_str(), po::value<std::string>(&env_module_path)->default_value("")) + ; + + //parse environment variables + po::variables_map vm; + po::store(po::parse_environment(desc, &name_mapper), vm); + po::notify(vm); + + if (env_module_path == "") return; + //std::cout << "env_module_path: " << env_module_path << std::endl; + + //split the path at the path separators + std::vector<std::string> module_paths; + boost::split(module_paths, env_module_path, boost::is_any_of(env_path_sep)); + + //load modules in each path + BOOST_FOREACH(const std::string &module_path, module_paths){ + load_path(fs::system_complete(fs::path(module_path))); + } +} diff --git a/host/lib/utils/props.cpp b/host/lib/utils/props.cpp new file mode 100644 index 000000000..fac5fe24f --- /dev/null +++ b/host/lib/utils/props.cpp @@ -0,0 +1,43 @@ +// +// 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/props.hpp> + +using namespace uhd; + +named_prop_t::named_prop_t( + const wax::obj &key, + const std::string &name +): + key(key), + name(name) +{ + /* NOP */ +} + +typedef boost::tuple<wax::obj, std::string> named_prop_tuple; + +named_prop_tuple uhd::extract_named_prop( + const wax::obj &key, + const std::string &name +){ + if (key.type() == typeid(named_prop_t)){ + named_prop_t np = key.as<named_prop_t>(); + return named_prop_tuple(np.key, np.name); + } + return named_prop_tuple(key, name); +} diff --git a/host/lib/utils/thread_priority.cpp b/host/lib/utils/thread_priority.cpp new file mode 100644 index 000000000..c35e5fcb1 --- /dev/null +++ b/host/lib/utils/thread_priority.cpp @@ -0,0 +1,98 @@ +// +// 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/thread_priority.hpp> +#include <stdexcept> +#include <iostream> + +bool uhd::set_thread_priority_safe(float priority, bool realtime){ + try{ + set_thread_priority(priority, realtime); + return true; + }catch(const std::exception &e){ + std::cerr << "set_thread_priority: " << e.what() << std::endl; + return false; + } +} + +static void check_priority_range(float priority){ + if (priority > +1.0 or priority < -1.0) + throw std::range_error("priority out of range [-1.0, +1.0]"); +} + +/*********************************************************************** + * Pthread API to set priority + **********************************************************************/ +#if defined(HAVE_PTHREAD_SETSCHEDPARAM) + #include <pthread.h> + + void uhd::set_thread_priority(float priority, bool realtime){ + check_priority_range(priority); + + //when realtime is not enabled, use sched other + int policy = (realtime)? SCHED_RR : SCHED_OTHER; + + //we cannot have below normal priority, set to zero + if (priority < 0) priority = 0; + + //get the priority bounds for the selected policy + int min_pri = sched_get_priority_min(policy); + int max_pri = sched_get_priority_max(policy); + if (min_pri == -1 or max_pri == -1) throw std::runtime_error("error in sched_get_priority_min/max"); + + //set the new priority and policy + sched_param sp; + sp.sched_priority = int(priority*(max_pri - min_pri)) + min_pri; + int ret = pthread_setschedparam(pthread_self(), policy, &sp); + if (ret != 0) throw std::runtime_error("error in pthread_setschedparam"); + } + +/*********************************************************************** + * Windows API to set priority + **********************************************************************/ +#elif defined(HAVE_WIN_SETTHREADPRIORITY) + #include <windows.h> + + void uhd::set_thread_priority(float priority, bool realtime){ + check_priority_range(priority); + + //set the priority class on the process + int pri_class = (realtime)? REALTIME_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS; + if (SetPriorityClass(GetCurrentProcess(), pri_class) == 0) + throw std::runtime_error("error in SetPriorityClass"); + + //scale the priority value to the constants + int priorities[] = { + THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL, THREAD_PRIORITY_NORMAL, + THREAD_PRIORITY_ABOVE_NORMAL, THREAD_PRIORITY_HIGHEST, THREAD_PRIORITY_TIME_CRITICAL + }; + size_t pri_index = size_t((priority+1.0)*6/2.0); // -1 -> 0, +1 -> 6 + + //set the thread priority on the thread + if (SetThreadPriority(GetCurrentThread(), priorities[pri_index]) == 0) + throw std::runtime_error("error in SetThreadPriority"); + } + +/*********************************************************************** + * Unimplemented API to set priority + **********************************************************************/ +#else + void uhd::set_thread_priority(float, bool){ + throw std::runtime_error("set thread priority not implemented"); + } + +#endif /* HAVE_PTHREAD_SETSCHEDPARAM */ |