diff options
Diffstat (limited to 'host/lib/utils')
-rw-r--r-- | host/lib/utils/CMakeLists.txt | 87 | ||||
-rw-r--r-- | host/lib/utils/assert.cpp | 24 | ||||
-rw-r--r-- | host/lib/utils/gain_group.cpp | 149 | ||||
-rw-r--r-- | host/lib/utils/load_modules.cpp | 109 | ||||
-rw-r--r-- | host/lib/utils/paths.cpp | 103 | ||||
-rw-r--r-- | host/lib/utils/props.cpp | 43 | ||||
-rw-r--r-- | host/lib/utils/thread_priority.cpp | 98 | ||||
-rw-r--r-- | host/lib/utils/warning.cpp | 36 |
8 files changed, 649 insertions, 0 deletions
diff --git a/host/lib/utils/CMakeLists.txt b/host/lib/utils/CMakeLists.txt new file mode 100644 index 000000000..68945545a --- /dev/null +++ b/host/lib/utils/CMakeLists.txt @@ -0,0 +1,87 @@ +# +# 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! + +######################################################################## +# Setup defines for process scheduling +######################################################################## +MESSAGE(STATUS "Configuring priority scheduling...") + +INCLUDE(CheckCXXSourceCompiles) +CHECK_CXX_SOURCE_COMPILES(" + #include <pthread.h> + int main(){ + struct sched_param sp; + pthread_setschedparam(pthread_self(), SCHED_RR, &sp); + return 0; + } + " HAVE_PTHREAD_SETSCHEDPARAM +) + +CHECK_CXX_SOURCE_COMPILES(" + #include <windows.h> + int main(){ + SetThreadPriority(GetCurrentThread(), 0); + SetPriorityClass(GetCurrentProcess(), 0); + return 0; + } + " HAVE_WIN_SETTHREADPRIORITY +) + +IF(HAVE_PTHREAD_SETSCHEDPARAM) + MESSAGE(STATUS " Priority scheduling supported through pthread_setschedparam.") + ADD_DEFINITIONS(-DHAVE_PTHREAD_SETSCHEDPARAM) +ELSEIF(HAVE_WIN_SETTHREADPRIORITY) + MESSAGE(STATUS " Priority scheduling supported through windows SetThreadPriority.") + ADD_DEFINITIONS(-DHAVE_WIN_SETTHREADPRIORITY) +ELSE(HAVE_PTHREAD_SETSCHEDPARAM) + MESSAGE(STATUS " Priority scheduling not supported.") +ENDIF(HAVE_PTHREAD_SETSCHEDPARAM) + +######################################################################## +# Setup defines for module loading +######################################################################## +MESSAGE(STATUS "Configuring module loading...") + +INCLUDE(CheckIncludeFileCXX) +CHECK_INCLUDE_FILE_CXX(dlfcn.h HAVE_DLFCN_H) +CHECK_INCLUDE_FILE_CXX(windows.h HAVE_WINDOWS_H) + +IF(HAVE_DLFCN_H) + MESSAGE(STATUS " Module loading supported through dlopen.") + ADD_DEFINITIONS(-DHAVE_DLFCN_H) + LIBUHD_APPEND_LIBS(${CMAKE_DL_LIBS}) +ELSEIF(HAVE_WINDOWS_H) + MESSAGE(STATUS " Module loading supported through LoadLibrary.") + ADD_DEFINITIONS(-DHAVE_WINDOWS_H) +ELSE(HAVE_DLFCN_H) + MESSAGE(STATUS " Module loading not supported.") +ENDIF(HAVE_DLFCN_H) + +######################################################################## +# Append sources +######################################################################## +LIBUHD_APPEND_SOURCES( + ${CMAKE_SOURCE_DIR}/lib/utils/assert.cpp + ${CMAKE_SOURCE_DIR}/lib/utils/gain_group.cpp + ${CMAKE_SOURCE_DIR}/lib/utils/load_modules.cpp + ${CMAKE_SOURCE_DIR}/lib/utils/paths.cpp + ${CMAKE_SOURCE_DIR}/lib/utils/props.cpp + ${CMAKE_SOURCE_DIR}/lib/utils/thread_priority.cpp + ${CMAKE_SOURCE_DIR}/lib/utils/warning.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_group.cpp b/host/lib/utils/gain_group.cpp new file mode 100644 index 000000000..c113719c8 --- /dev/null +++ b/host/lib/utils/gain_group.cpp @@ -0,0 +1,149 @@ +// +// 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_group.hpp> +#include <uhd/types/dict.hpp> +#include <uhd/utils/algorithm.hpp> +#include <uhd/utils/assert.hpp> +#include <boost/foreach.hpp> +#include <boost/bind.hpp> +#include <algorithm> +#include <vector> +#include <iostream> + +using namespace uhd; + +static const bool verbose = false; + +static bool compare_by_step_size( + const size_t &rhs, const size_t &lhs, std::vector<gain_fcns_t> &fcns +){ + return fcns.at(rhs).get_range().step > fcns.at(lhs).get_range().step; +} + +/*********************************************************************** + * gain group implementation + **********************************************************************/ +class gain_group_impl : public gain_group{ +public: + gain_group_impl(void){ + /*NOP*/ + } + + gain_range_t get_range(void){ + float overall_min = 0, overall_max = 0, overall_step = 0; + BOOST_FOREACH(const gain_fcns_t &fcns, get_all_fcns()){ + const gain_range_t range = fcns.get_range(); + overall_min += range.min; + overall_max += range.max; + //the overall step is the min (zero is invalid, first run) + if (overall_step == 0) overall_step = range.step; + overall_step = std::min(overall_step, range.step); + } + return gain_range_t(overall_min, overall_max, overall_step); + } + + float get_value(void){ + float overall_gain = 0; + BOOST_FOREACH(const gain_fcns_t &fcns, get_all_fcns()){ + overall_gain += fcns.get_value(); + } + return overall_gain; + } + + void set_value(float gain){ + std::vector<gain_fcns_t> all_fcns = get_all_fcns(); + if (all_fcns.size() == 0) return; //nothing to set! + + //get the max step size among the gains + float max_step = 0; + BOOST_FOREACH(const gain_fcns_t &fcns, all_fcns){ + max_step = std::max(max_step, fcns.get_range().step); + } + + //create gain bucket to distribute power + std::vector<float> gain_bucket; + + //distribute power according to priority (round to max step) + float gain_left_to_distribute = gain; + BOOST_FOREACH(const gain_fcns_t &fcns, all_fcns){ + const gain_range_t range = fcns.get_range(); + gain_bucket.push_back( + max_step*int(std::clip(gain_left_to_distribute, range.min, range.max)/max_step) + ); + gain_left_to_distribute -= gain_bucket.back(); + } + + //get a list of indexes sorted by step size large to small + std::vector<size_t> indexes_step_size_dec; + for (size_t i = 0; i < all_fcns.size(); i++){ + indexes_step_size_dec.push_back(i); + } + std::sort( + indexes_step_size_dec.begin(), indexes_step_size_dec.end(), + boost::bind(&compare_by_step_size, _1, _2, all_fcns) + ); + UHD_ASSERT_THROW( + all_fcns.at(indexes_step_size_dec.front()).get_range().step >= + all_fcns.at(indexes_step_size_dec.back()).get_range().step + ); + + //distribute the remainder (less than max step) + //fill in the largest step sizes first that are less than the remainder + BOOST_FOREACH(size_t i, indexes_step_size_dec){ + const gain_range_t range = all_fcns.at(i).get_range(); + float additional_gain = range.step*int( + std::clip(gain_bucket.at(i) + gain_left_to_distribute, range.min, range.max + )/range.step) - gain_bucket.at(i); + gain_bucket.at(i) += additional_gain; + gain_left_to_distribute -= additional_gain; + } + if (verbose) std::cout << "gain_left_to_distribute " << gain_left_to_distribute << std::endl; + + //now write the bucket out to the individual gain values + for (size_t i = 0; i < gain_bucket.size(); i++){ + if (verbose) std::cout << gain_bucket.at(i) << std::endl; + all_fcns.at(i).set_value(gain_bucket.at(i)); + } + } + + void register_fcns( + const gain_fcns_t &gain_fcns, size_t priority + ){ + _registry[priority].push_back(gain_fcns); + } + +private: + //! get the gain function sets in order (highest priority first) + std::vector<gain_fcns_t> get_all_fcns(void){ + std::vector<gain_fcns_t> all_fcns; + BOOST_FOREACH(size_t key, std::sorted(_registry.keys())){ + const std::vector<gain_fcns_t> &fcns = _registry[key]; + all_fcns.insert(all_fcns.begin(), fcns.begin(), fcns.end()); + } + return all_fcns; + } + + uhd::dict<size_t, std::vector<gain_fcns_t> > _registry; +}; + +/*********************************************************************** + * gain group factory function + **********************************************************************/ +gain_group::sptr gain_group::make(void){ + return sptr(new gain_group_impl()); +} diff --git a/host/lib/utils/load_modules.cpp b/host/lib/utils/load_modules.cpp new file mode 100644 index 000000000..623d31eb6 --- /dev/null +++ b/host/lib/utils/load_modules.cpp @@ -0,0 +1,109 @@ +// +// 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/filesystem.hpp> +#include <iostream> +#include <stdexcept> +#include <string> +#include <vector> + +namespace fs = boost::filesystem; + +/*********************************************************************** + * Module Load Function + **********************************************************************/ +#if defined(HAVE_DLFCN_H) +#include <dlfcn.h> + +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 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 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_module_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_module_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; + } +} + +std::vector<fs::path> get_module_paths(void); //defined in paths.cpp + +/*! + * Load all the modules given in the module paths. + */ +UHD_STATIC_BLOCK(load_modules){ + BOOST_FOREACH(const fs::path &path, get_module_paths()){ + load_module_path(path); + } +} diff --git a/host/lib/utils/paths.cpp b/host/lib/utils/paths.cpp new file mode 100644 index 000000000..0805a44fe --- /dev/null +++ b/host/lib/utils/paths.cpp @@ -0,0 +1,103 @@ +// +// 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 "constants.hpp" +#include <uhd/config.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/program_options.hpp> +#include <boost/filesystem.hpp> +#include <boost/foreach.hpp> +#include <boost/bind.hpp> +#include <stdexcept> +#include <string> +#include <vector> + +namespace po = boost::program_options; +namespace fs = boost::filesystem; + +/*********************************************************************** + * Determine the paths separator + **********************************************************************/ +#ifdef UHD_PLATFORM_WIN32 + static const std::string env_path_sep = ";"; +#else + static const std::string env_path_sep = ":"; +#endif /*UHD_PLATFORM_WIN32*/ + +/*********************************************************************** + * Get a list of paths for an environment variable + **********************************************************************/ +static std::string name_mapper(const std::string &key, const std::string &var_name){ + return (var_name == key)? var_name : ""; +} + +static std::vector<fs::path> get_env_paths(const std::string &var_name){ + //register the options + std::string var_value; + po::options_description desc; + desc.add_options() + (var_name.c_str(), po::value<std::string>(&var_value)->default_value("")) + ; + + //parse environment variables + po::variables_map vm; + po::store(po::parse_environment(desc, boost::bind(&name_mapper, var_name, _1)), vm); + po::notify(vm); + + //split the path at the path separators + std::vector<std::string> path_strings; + boost::split(path_strings, var_value, boost::is_any_of(env_path_sep)); + + //convert to filesystem path, filter blank paths + std::vector<fs::path> paths; + BOOST_FOREACH(std::string &path_string, path_strings){ + if (path_string.size() == 0) continue; + paths.push_back(fs::system_complete(path_string)); + } + return paths; +} + +/*********************************************************************** + * Get a list of special purpose paths + **********************************************************************/ +static const fs::path pkg_data_path = fs::path(UHD_INSTALL_PREFIX) / UHD_PKG_DATA_DIR; + +std::vector<fs::path> get_image_paths(void){ + std::vector<fs::path> paths = get_env_paths("UHD_IMAGE_PATH"); + paths.push_back(pkg_data_path / "images"); + return paths; +} + +std::vector<fs::path> get_module_paths(void){ + std::vector<fs::path> paths = get_env_paths("UHD_MODULE_PATH"); + paths.push_back(pkg_data_path / "modules"); + return paths; +} + +/*********************************************************************** + * Find a image in the image paths + **********************************************************************/ +std::string find_image_path(const std::string &image_name){ + if (fs::exists(image_name)){ + return fs::system_complete(image_name).file_string(); + } + BOOST_FOREACH(const fs::path &path, get_image_paths()){ + fs::path image_path = path / image_name; + if (fs::exists(image_path)) return image_path.file_string(); + } + throw std::runtime_error("Could not find path for image: " + image_name); +} 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 */ diff --git a/host/lib/utils/warning.cpp b/host/lib/utils/warning.cpp new file mode 100644 index 000000000..ae4d4c7aa --- /dev/null +++ b/host/lib/utils/warning.cpp @@ -0,0 +1,36 @@ +// +// 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/warning.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/foreach.hpp> +#include <iostream> +#include <vector> + +using namespace uhd; + +void uhd::print_warning(const std::string &msg){ + //extract the message lines + std::vector<std::string> lines; + boost::split(lines, msg, boost::is_any_of("\n")); + + //print the warning message + std::cerr << std::endl << "Warning:" << std::endl; + BOOST_FOREACH(const std::string &line, lines){ + std::cerr << " " << line << std::endl; + } +} |