diff options
-rw-r--r-- | host/CMakeLists.txt | 22 | ||||
-rw-r--r-- | host/docs/images.dox | 6 | ||||
-rw-r--r-- | host/docs/usrp_e3x0.dox | 16 | ||||
-rw-r--r-- | host/include/uhd/config.hpp | 12 | ||||
-rw-r--r-- | host/include/uhd/transport/nirio/nifpga_lvbitx.h | 2 | ||||
-rw-r--r-- | host/include/uhd/utils/paths.hpp | 49 | ||||
-rw-r--r-- | host/lib/transport/nirio/lvbitx/CMakeLists.txt | 7 | ||||
-rw-r--r-- | host/lib/transport/nirio/lvbitx/template_lvbitx.cpp | 6 | ||||
-rw-r--r-- | host/lib/transport/nirio/nifpga_lvbitx.cpp | 103 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_impl.cpp | 11 | ||||
-rw-r--r-- | host/lib/utils/load_modules.cpp | 5 | ||||
-rw-r--r-- | host/lib/utils/paths.cpp | 283 |
12 files changed, 346 insertions, 176 deletions
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 0f756ef2d..960e321ff 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -60,6 +60,26 @@ SET(PKG_DOC_DIR share/doc/uhd) SET(PKG_MAN_DIR share/man/man1) ######################################################################## +# UHD Image Directories +######################################################################## +IF(NOT DEFINED UHD_IMAGES_DIR) + IF(DEFINED FPGA_IMAGES_DIR) + SET(UHD_IMAGES_DIR ${FPGA_IMAGES_DIR}) + ELSE(DEFINED FPGA_IMAGES_DIR) + FILE(TO_NATIVE_PATH ${CMAKE_INSTALL_PREFIX}/share/uhd/images using_images_dir) + SET(UHD_IMAGES_DIR ${using_images_dir}) + ENDIF(DEFINED FPGA_IMAGES_DIR) +ENDIF(NOT DEFINED UHD_IMAGES_DIR) + +OPTION(UHD_IMAGES_DIR "Path to installed UHD image binaries.") +MESSAGE( STATUS "Using UHD Images Directory: ${UHD_IMAGES_DIR}" ) +ADD_DEFINITIONS(-DUHD_IMAGES_DIR=${UHD_IMAGES_DIR}) + +IF(DEFINED USE_NIUSRP_WINREG_KEY) + ADD_DEFINITIONS(-DUSE_NIUSRP_WINREG_KEY) +ENDIF(DEFINED USE_NIUSRP_WINREG_KEY) + +######################################################################## # Local Include Dir ######################################################################## INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/include) @@ -378,7 +398,7 @@ UHD_INSTALL( ) ######################################################################## -# Handle pre-built images +# Handle pre-built UHD Images meant for installation ######################################################################## IF(DEFINED UHD_IMAGES_DIR AND EXISTS "${UHD_IMAGES_DIR}") FILE(GLOB_RECURSE _image_files "${UHD_IMAGES_DIR}/*") diff --git a/host/docs/images.dox b/host/docs/images.dox index e00f599b5..bd2ffacf6 100644 --- a/host/docs/images.dox +++ b/host/docs/images.dox @@ -65,9 +65,9 @@ configure-time. <b>Option 2:</b> -Unpack the archive anywhere and set the `UHD_IMAGES_PATH` -environment variable. `UHD_IMAGES_PATH` may contain a list of -directories to search for image files. +Unpack the archive anywhere and set the `UHD_IMAGES_DIR` environment variable. +The `UHD_IMAGES_DIR` environment variable may contain a list of paths. They +should be ordered by preference. \section images_building Building Images diff --git a/host/docs/usrp_e3x0.dox b/host/docs/usrp_e3x0.dox index 01b0fd929..68ffc0122 100644 --- a/host/docs/usrp_e3x0.dox +++ b/host/docs/usrp_e3x0.dox @@ -132,7 +132,7 @@ which should return 'arm-oe-linux-gnueabi'. -# Setup your environment as described in \ref e3x0_sdk_usage -# Type the following in the build directory (assuming a build in host/build): - $ cmake -DCMAKE_TOOLCHAIN_FILE=<youruhdsrc>/host/cmake/Toolchains/oe-sdk_cross.cmake -DENABLE_E300=On .. + $ cmake -DCMAKE_TOOLCHAIN_FILE=<youruhdsrc>/host/cmake/Toolchains/oe-sdk_cross.cmake -DCMAKE_INSTALL_PREFIX=/usr -DENABLE_E300=ON .. $ make \subsubsection e3x0_sdk_usage_gnuradio Building GNU Radio @@ -143,7 +143,7 @@ which should return 'arm-oe-linux-gnueabi'. \code{.sh} $ mkdir build-arm -$ cmake -Wno-dev -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchains/oe-sdk_cross.cmake \-DCMAKE_INSTALL_PREFIX=/usr -DENABLE_GR_VOCODER=OFF -DGR_ENABLE_ATSC=OFF \ +$ cmake -Wno-dev -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchains/oe-sdk_cross.cmake \-DCMAKE_INSTALL_PREFIX=/usr -DENABLE_GR_VOCODER=OFF -DENABLE_GR_ATSC=OFF \ -DENABLE_GR_DTV=OFF -DENABLE_DOXYGEN=OFF ../ \endcode @@ -274,8 +274,18 @@ You may need to change the USRP's IP address for several reasons: - **USB**: USB 2.0 Port - **SERIAL**: Micro USB connection for serial uart console +\subsection e3x0_hw_sync Clock and Time Synchronization +Unlike most USRP devices, the E310 does not have independent reference clock and time source inputs. +It is possible, however, to discipline the internal reference clock using an external time (PPS) source +connected to the SYNC input pin. The E310 FPGA has a subsystem that can use the PPS signal from the +SYNC pin or the internal GPS to align edges of the reference clock to edges of a shared PPS signal. +This alignment happens automatically when the time source in UHD is set to "gpsdo" or "external". +Please note that because the SYNC input can only accept a PPS signal, the only supported value for +the reference clock source is "internal". + + \subsection e3x0_hw_pps PPS - Pulse Per Second -Using a PPS signal for timestamp synchronization requires a square wave signal with the following a 5Vpp amplitude. +Using a PPS signal for timestamp synchronization requires a LVCMOS or a 5V logic input signal. An external PPS can be used to discipline the internal reference clock. This feature is automatically enabled with the time source is set to "external". diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp index 173845fea..23eb9cdb2 100644 --- a/host/include/uhd/config.hpp +++ b/host/include/uhd/config.hpp @@ -99,4 +99,16 @@ typedef ptrdiff_t ssize_t; #define UHD_PLATFORM_BSD #endif +// Define 'stringize' preprocessor macros. The stringize macro, XSTR, takes +// variable arguments so that it can deal with strings that contain commas. +// There are two different versions because MSVC handles this syntax a bit +// differently than other compilers. +#if defined(BOOST_MSVC) + #define XSTR(x,...) #x +#else + #define XSTR(x...) #x +#endif + +#define STR(x) XSTR(x) + #endif /* INCLUDED_UHD_CONFIG_HPP */ diff --git a/host/include/uhd/transport/nirio/nifpga_lvbitx.h b/host/include/uhd/transport/nirio/nifpga_lvbitx.h index 598f7fcbe..f037ffd47 100644 --- a/host/include/uhd/transport/nirio/nifpga_lvbitx.h +++ b/host/include/uhd/transport/nirio/nifpga_lvbitx.h @@ -51,8 +51,8 @@ public: protected: std::string _get_bitstream_checksum(const std::string& file_path); - std::string _get_fpga_images_dir(const std::string search_paths); }; + }} #endif /* INCLUDED_UHD_TRANSPORT_NIRIO_NIFPGA_LVBITX_H */ diff --git a/host/include/uhd/utils/paths.hpp b/host/include/uhd/utils/paths.hpp index c1f32ba61..8edb87546 100644 --- a/host/include/uhd/utils/paths.hpp +++ b/host/include/uhd/utils/paths.hpp @@ -19,9 +19,15 @@ #define INCLUDED_UHD_UTILS_PATHS_HPP #include <uhd/config.hpp> + +#include <boost/filesystem.hpp> + #include <string> +#include <vector> -namespace uhd{ +namespace fs = boost::filesystem; + +namespace uhd { //! Get a string representing the system's temporary directory UHD_API std::string get_tmp_path(void); @@ -32,15 +38,41 @@ namespace uhd{ //! Get a string representing the system's pkg directory UHD_API std::string get_pkg_path(void); - /*! - * Search for an image in the system image paths: - * Search compiled-in paths and environment variable paths - * for a specific image file with the provided file name. - * \param image_name the name of the file + //! Get UHD library paths + std::vector<fs::path> get_module_paths(void); + + /*! Return the UHD images directory path. + * + * This function returns the UHD images installation path on this system. The + * returned directory path is guaranteed to exist (assuming a valid path is + * found). This function will look for a directory that exists using this + * order of precedence: + * + * 1) `UHD_IMAGES_DIR` environment variable + * 2) Any paths passed to this function via `search_paths' + * 3) UHD package path / share / uhd / images + * + * The `search_paths` parameter may contain Windows registry keys. If no + * directory is found, an empty string is returned. + * + * \param search_paths A comma-separated list of hints for paths to include. + * \returns A path string if one is found, or an empty string on failure. + */ + UHD_API std::string get_images_dir(const std::string search_paths); + + /*! Return the full path to particular UHD binary image. + * + * This function searches for the passed image name, and returns an absolute + * path to it. The returned path is guaranteed to exist. The caller can also + * provide a full path to the image in the argument, and this function will + * validate it and convert it to an absolute system path. + * + * \param image_name The name of the file to search for, or the full path. + * \param search_paths Hints / paths to use when calling `get_images_dir` * \return the full system path to the file - * \throw exception if the image was not found + * \throw exception uhd::io_error if the file was not found. */ - UHD_API std::string find_image_path(const std::string &image_name); + UHD_API std::string find_image_path(const std::string &image_name, const std::string search_paths = ""); /*! * Search for the location of a particular UHD utility. @@ -56,7 +88,6 @@ namespace uhd{ * \return the message suggesting the use of the named utility. */ UHD_API std::string print_utility_error(std::string name); - } //namespace uhd #endif /* INCLUDED_UHD_UTILS_PATHS_HPP */ diff --git a/host/lib/transport/nirio/lvbitx/CMakeLists.txt b/host/lib/transport/nirio/lvbitx/CMakeLists.txt index 35cfaa456..b9a2a9f15 100644 --- a/host/lib/transport/nirio/lvbitx/CMakeLists.txt +++ b/host/lib/transport/nirio/lvbitx/CMakeLists.txt @@ -27,7 +27,7 @@ MACRO(LIBUHD_LVBITX_GEN_SOURCE_AND_BITSTREAM lvbitx binfile) ENDIF( ${binfile} STREQUAL "OFF" ) SET(OUTPUT_PATH_OPT --output-src-path=${CMAKE_CURRENT_BINARY_DIR}) - SET(IMAGES_PATH_OPT --uhd-images-path=${FPGA_IMAGES_DIR}) + SET(IMAGES_PATH_OPT --uhd-images-path=${UHD_IMAGES_DIR}) ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${lvbitxprefix}_lvbitx.hpp @@ -53,11 +53,6 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) MESSAGE(STATUS "") MESSAGE(STATUS "Processing NI-RIO FPGA LVBITX Bitstreams...") -FILE(TO_NATIVE_PATH ${CMAKE_INSTALL_PREFIX}/share/uhd/images default_images_dir) -SET( FPGA_IMAGES_DIR ${default_images_dir} CACHE STRING "Path to installed FPGA image files." ) -OPTION( FPGA_IMAGES_DIR "Path to installed FPGA image files." "" ) -MESSAGE( STATUS " LVBITX install directory: ${FPGA_IMAGES_DIR}" ) - # X300 Stuff LIBUHD_LVBITX_GEN_SOURCE_AND_BITSTREAM(x300.lvbitx_base OFF) diff --git a/host/lib/transport/nirio/lvbitx/template_lvbitx.cpp b/host/lib/transport/nirio/lvbitx/template_lvbitx.cpp index a1899c771..8f1fb6b36 100644 --- a/host/lib/transport/nirio/lvbitx/template_lvbitx.cpp +++ b/host/lib/transport/nirio/lvbitx/template_lvbitx.cpp @@ -8,6 +8,7 @@ #include <boost/filesystem/path.hpp> #include <boost/algorithm/string.hpp> #include <boost/regex.hpp> +#include <uhd/utils/paths.hpp> namespace uhd {{ namespace niusrprio {{ @@ -27,8 +28,9 @@ const char* {lvbitx_classname}_lvbitx::INPUT_FIFOS[] = {{{in_fifo_list} {lvbitx_classname}_lvbitx::{lvbitx_classname}_lvbitx(const std::string& option) {{ - boost::filesystem::path fpga_path(_get_fpga_images_dir(SEARCH_PATHS)); - fpga_path /= "usrp_{lvbitx_classname}_fpga_" + option + ".lvbitx"; + std::string fpga_file = "usrp_{lvbitx_classname}_fpga_" + option + ".lvbitx"; + boost::filesystem::path fpga_path(uhd::find_image_path(fpga_file, SEARCH_PATHS)); + _fpga_file_name = fpga_path.string(); _bitstream_checksum = _get_bitstream_checksum(_fpga_file_name); }} diff --git a/host/lib/transport/nirio/nifpga_lvbitx.cpp b/host/lib/transport/nirio/nifpga_lvbitx.cpp index 189037163..8135a4d01 100644 --- a/host/lib/transport/nirio/nifpga_lvbitx.cpp +++ b/host/lib/transport/nirio/nifpga_lvbitx.cpp @@ -18,12 +18,8 @@ #include <uhd/transport/nirio/nifpga_lvbitx.h> #include <cstdlib> #include <string> -#include <iostream> #include <fstream> #include <streambuf> -#include <boost/foreach.hpp> -#include <boost/format.hpp> -#include <boost/filesystem.hpp> #include <boost/algorithm/string.hpp> #include <boost/regex.hpp> @@ -52,103 +48,4 @@ std::string nifpga_lvbitx::_get_bitstream_checksum(const std::string& file_path) return checksum; } -#ifdef UHD_PLATFORM_WIN32 -#include <windows.h> - -std::string _get_path_from_registry(const std::string& registry_key_path) -{ - boost::smatch reg_key_match; - //If a substring in the search path is enclosed in [] (square brackets) then it is interpreted as a registry path - if (not boost::regex_search(registry_key_path, reg_key_match, boost::regex("\\[(.+)\\](.*)", boost::regex::icase))) - return std::string(); - std::string reg_key_path = std::string(reg_key_match[1].first, reg_key_match[1].second); - std::string path_suffix = std::string(reg_key_match[2].first, reg_key_match[2].second); - - //Split the registry path into parent, key-path and value. - boost::smatch reg_parent_match; - if (not boost::regex_search(reg_key_path, reg_parent_match, boost::regex("^(.+?)\\\\(.+)\\\\(.+)$", boost::regex::icase))) - return std::string(); - std::string reg_parent = std::string(reg_parent_match[1].first, reg_parent_match[1].second); - std::string reg_path = std::string(reg_parent_match[2].first, reg_parent_match[2].second); - std::string reg_val_name = std::string(reg_parent_match[3].first, reg_parent_match[3].second); - - HKEY hkey_parent = HKEY_LOCAL_MACHINE; - if (reg_parent == "HKEY_LOCAL_MACHINE") hkey_parent = HKEY_LOCAL_MACHINE; - else if (reg_parent == "HKEY_CURRENT_USER") hkey_parent = HKEY_CURRENT_USER; - else if (reg_parent == "HKEY_CLASSES_ROOT") hkey_parent = HKEY_CLASSES_ROOT; - else if (reg_parent == "HKEY_CURRENT_CONFIG") hkey_parent = HKEY_CURRENT_CONFIG; - else if (reg_parent == "HKEY_USERS") hkey_parent = HKEY_CURRENT_USER; - - TCHAR value_buff[1024]; - DWORD value_buff_size = 1024*sizeof(TCHAR); - - //Get a handle to the key location - HKEY hkey_location; - if (RegOpenKeyExA(hkey_parent, reg_path.c_str(), NULL, KEY_QUERY_VALUE, &hkey_location) != ERROR_SUCCESS) - return std::string(); - - //Query key value - DWORD dw_type = REG_SZ; - if(RegQueryValueExA(hkey_location, reg_val_name.c_str(), NULL, &dw_type, (LPBYTE)value_buff, &value_buff_size) == ERROR_SUCCESS) { - RegCloseKey(hkey_location); - if (value_buff_size >= 1024*sizeof(TCHAR)) { - return std::string(); - } else { - std::string return_value(value_buff, value_buff_size-1); //value_buff_size includes the null terminator - return_value += path_suffix; - return return_value; - } - } else { - return std::string(); - } -} - -#endif /*UHD_PLATFORM_WIN32*/ - -std::string nifpga_lvbitx::_get_fpga_images_dir(const std::string search_paths) -{ - std::vector<std::string> search_path_vtr; - boost::split(search_path_vtr, search_paths, boost::is_any_of(",")); - - // - // Add the value of the UHD_IMAGES_DIR environment variable to the list of - // directories searched for a LVBITX image. - // - char* uhd_images_dir; -#if defined(UHD_PLATFORM_WIN32) && !defined(__MINGW32__) // Some versions of MinGW don't expose _dupenv_s - size_t len; - errno_t err = _dupenv_s(&uhd_images_dir, &len, "UHD_IMAGES_DIR"); - if(not err and uhd_images_dir != NULL) search_path_vtr.push_back(std::string(uhd_images_dir)); - free(uhd_images_dir); -#else - uhd_images_dir = getenv("UHD_IMAGES_DIR"); - if(uhd_images_dir != NULL) search_path_vtr.push_back(std::string(uhd_images_dir)); -#endif - - std::string lvbitx_dir; - //Traverse through the list of search paths. Priority: lexical - BOOST_FOREACH(std::string& search_path, search_path_vtr) { - boost::algorithm::trim(search_path); - if (search_path.empty()) continue; - -#ifdef UHD_PLATFORM_WIN32 - lvbitx_dir = _get_path_from_registry(search_path); - if (lvbitx_dir.empty()) { - //Could not read from the registry due to missing key, invalid values, etc - //Just use the search path. The is_directory check will fail if this is a - //registry path and we will move on to the next item in the list. - lvbitx_dir = search_path; - } -#else - lvbitx_dir = search_path; -#endif - - //If the current directory exists then stop traversing the search path list. - if (boost::filesystem::is_directory(lvbitx_dir)) break; - } - - return lvbitx_dir; -} - - }} diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index 22e68c4ed..f07b7fc6f 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -17,6 +17,7 @@ #include "b200_impl.hpp" #include "b200_regs.hpp" +#include <uhd/config.hpp> #include <uhd/transport/usb_control.hpp> #include <uhd/utils/msg.hpp> #include <uhd/utils/cast.hpp> @@ -112,13 +113,11 @@ static device_addrs_t b200_find(const device_addr_t &hint) //extract the firmware path for the b200 std::string b200_fw_image; try{ - b200_fw_image = find_image_path(hint.get("fw", B200_FW_FILE_NAME)); + b200_fw_image = hint.get("fw", B200_FW_FILE_NAME); + b200_fw_image = uhd::find_image_path(b200_fw_image, STR(UHD_IMAGES_DIR)); // FIXME } - catch(...){ - UHD_MSG(warning) << boost::format( - "Could not locate B200 firmware.\n" - "Please install the images package. %s\n" - ) % print_utility_error("uhd_images_downloader.py"); + catch(uhd::exception &e){ + UHD_MSG(warning) << e.what(); return b200_addrs; } UHD_LOG << "the firmware image: " << b200_fw_image << std::endl; diff --git a/host/lib/utils/load_modules.cpp b/host/lib/utils/load_modules.cpp index bee0d5304..aba3adeed 100644 --- a/host/lib/utils/load_modules.cpp +++ b/host/lib/utils/load_modules.cpp @@ -15,6 +15,7 @@ // along with this program. If not, see <http://www.gnu.org/licenses/>. // +#include <uhd/utils/paths.hpp> #include <uhd/utils/static.hpp> #include <uhd/exception.hpp> #include <boost/format.hpp> @@ -97,13 +98,11 @@ static void load_module_path(const fs::path &path){ } } -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()){ + BOOST_FOREACH(const fs::path &path, uhd::get_module_paths()){ load_module_path(path); } } diff --git a/host/lib/utils/paths.cpp b/host/lib/utils/paths.cpp index 282ebb566..e304555bd 100644 --- a/host/lib/utils/paths.cpp +++ b/host/lib/utils/paths.cpp @@ -16,17 +16,23 @@ // #include <uhd/config.hpp> +#include <uhd/exception.hpp> +#include <uhd/transport/nirio/nifpga_lvbitx.h> #include <uhd/utils/paths.hpp> +#include <boost/algorithm/string.hpp> #include <boost/bind.hpp> -#include <uhd/exception.hpp> #include <boost/filesystem.hpp> #include <boost/foreach.hpp> +#include <boost/format.hpp> +#include <boost/regex.hpp> #include <boost/tokenizer.hpp> -#include <cstdio> //P_tmpdir +#include <cstdio> #include <cstdlib> +#include <fstream> #include <iostream> +#include <streambuf> #include <string> #include <vector> @@ -35,22 +41,52 @@ #include <windows.h> //GetTempPath #endif +#ifdef USE_NIUSRP_WINREG_KEY +#define NIUSRP_WINREG_KEY "[HKLM\\Software\\National Instruments\\NI-USRP\\DriverBitfilesDir]" +#endif + namespace fs = boost::filesystem; -/*********************************************************************** - * Get a list of paths for an environment variable - **********************************************************************/ -static std::string get_env_var(const std::string &var_name, const std::string &def_val = ""){ - const char *var_value_ptr = std::getenv(var_name.c_str()); - return (var_value_ptr == NULL)? def_val : var_value_ptr; -} +/*! Get the value of an environment variable. + * + * The returned std::string is the full environment variable string, and thus + * may actually contain multiple fields in the string with delimiters. + * + * \param var_name The name of the variable to search for. + * \param default_val A default string value to use if the path isn't found. + * \returns The string value of the environment variable. + */ +static std::string get_env_var(const std::string &var_name, + const std::string &default_val = "") { -static std::vector<fs::path> get_env_paths(const std::string &var_name){ + std::string env_result = default_val; + char *env_var_str = NULL; -/*********************************************************************** - * Determine the paths separator - **********************************************************************/ + /* Some versions of MinGW don't expose `_dupenv_s` */ +#if defined(UHD_PLATFORM_WIN32) && !defined(__MINGW32__) + size_t len; + errno_t err = _dupenv_s(&env_var_str, &len, var_name.c_str()); + if((not err) and (env_var_str != NULL)) + env_result = std::string(env_var_str); + free(env_var_str); +#else + env_var_str = std::getenv(var_name.c_str()); + if(env_var_str != NULL) + env_result = std::string(env_var_str); +#endif + + return env_result; +} +/*! Get a vector of paths from an environment variable. + * + * Reads an environment variable, which should contain a list of paths, and + * returns a vector of those paths in the form of strings. + * + * \param var_name The environment variable name to read. + * \returns The vector of paths from the environment variable. + */ +static std::vector<std::string> get_env_paths(const std::string &var_name){ #ifdef UHD_PLATFORM_WIN32 static const std::string env_path_sep = ";"; #else @@ -63,40 +99,45 @@ static std::vector<fs::path> get_env_paths(const std::string &var_name){ std::string var_value = get_env_var(var_name); - //convert to filesystem path, filter blank paths - std::vector<fs::path> paths; - if (var_value.empty()) return paths; //FIXME boost tokenizer throws w/ blank strings on some platforms + std::vector<std::string> paths; + + //convert to full filesystem path, filter blank paths + if (var_value.empty()) return paths; BOOST_FOREACH(const std::string &path_string, path_tokenizer(var_value)){ if (path_string.empty()) continue; - paths.push_back(fs::system_complete(path_string)); + paths.push_back(fs::system_complete(path_string).string()); } + return paths; } -/*********************************************************************** - * Get a list of special purpose paths - **********************************************************************/ -std::string uhd::get_pkg_path(void) -{ - return get_env_var("UHD_PKG_PATH", UHD_PKG_PATH); -} +/*! Expand a tilde character to the $HOME path. + * + * The path passed to this function must start with the tilde character in order + * for this function to work properly. If it does not, it will simply return the + * original path. The $HOME environment variable must exist. + * + * \param path The path starting with the tilde character + * \returns The same path with the tilde expanded to contents of $HOME. + */ +static std::string expand_home_directory(std::string path) { + boost::trim(path); -std::vector<fs::path> get_image_paths(void){ - std::vector<fs::path> paths = get_env_paths("UHD_IMAGE_PATH"); - paths.push_back(fs::path(uhd::get_pkg_path()) / "share" / "uhd" / "images"); - return paths; -} + if(path.empty() || (path[0] != '~')) { + return path; + } -std::vector<fs::path> get_module_paths(void){ - std::vector<fs::path> paths = get_env_paths("UHD_MODULE_PATH"); - paths.push_back(fs::path(uhd::get_pkg_path()) / UHD_LIB_DIR / "uhd" / "modules"); - paths.push_back(fs::path(uhd::get_pkg_path()) / "share" / "uhd" / "modules"); - return paths; + std::string user_home_path = get_env_var("HOME"); + path.replace(0, 1, user_home_path); + + return path; } /*********************************************************************** * Implement the functions in paths.hpp **********************************************************************/ + + std::string uhd::get_tmp_path(void){ const char *tmp_path = NULL; @@ -141,16 +182,180 @@ std::string uhd::get_app_path(void){ return uhd::get_tmp_path(); } -std::string uhd::find_image_path(const std::string &image_name){ +std::string uhd::get_pkg_path(void) { + return get_env_var("UHD_PKG_PATH", UHD_PKG_PATH); +} + +std::vector<fs::path> uhd::get_module_paths(void){ + std::vector<fs::path> paths; + + std::vector<std::string> env_paths = get_env_paths("UHD_MODULE_PATH"); + BOOST_FOREACH(std::string &str_path, env_paths) { + paths.push_back(str_path); + } + + paths.push_back(fs::path(uhd::get_pkg_path()) / UHD_LIB_DIR / "uhd" / "modules"); + paths.push_back(fs::path(uhd::get_pkg_path()) / "share" / "uhd" / "modules"); + + return paths; +} + +#ifdef UHD_PLATFORM_WIN32 +#include <windows.h> +/*! + * On Windows, query the system registry for the UHD images install path. + * If the key isn't found in the registry, an empty string is returned. + * \param registry_key_path The registry key to look for. + * \return The images path, formatted for windows. + */ +std::string _get_images_path_from_registry(const std::string& registry_key_path) { + boost::smatch reg_key_match; + //If a substring in the search path is enclosed in [] (square brackets) then it is interpreted as a registry path + if (not boost::regex_search(registry_key_path, reg_key_match, boost::regex("\\[(.+)\\](.*)", boost::regex::icase))) + return std::string(); + std::string reg_key_path = std::string(reg_key_match[1].first, reg_key_match[1].second); + std::string path_suffix = std::string(reg_key_match[2].first, reg_key_match[2].second); + + //Split the registry path into parent, key-path and value. + boost::smatch reg_parent_match; + if (not boost::regex_search(reg_key_path, reg_parent_match, boost::regex("^(.+?)\\\\(.+)\\\\(.+)$", boost::regex::icase))) + return std::string(); + std::string reg_parent = std::string(reg_parent_match[1].first, reg_parent_match[1].second); + std::string reg_path = std::string(reg_parent_match[2].first, reg_parent_match[2].second); + std::string reg_val_name = std::string(reg_parent_match[3].first, reg_parent_match[3].second); + + HKEY hkey_parent = HKEY_LOCAL_MACHINE; + if (reg_parent == "HKEY_LOCAL_MACHINE") hkey_parent = HKEY_LOCAL_MACHINE; + else if (reg_parent == "HKEY_CURRENT_USER") hkey_parent = HKEY_CURRENT_USER; + else if (reg_parent == "HKEY_CLASSES_ROOT") hkey_parent = HKEY_CLASSES_ROOT; + else if (reg_parent == "HKEY_CURRENT_CONFIG") hkey_parent = HKEY_CURRENT_CONFIG; + else if (reg_parent == "HKEY_USERS") hkey_parent = HKEY_CURRENT_USER; + + TCHAR value_buff[1024]; + DWORD value_buff_size = 1024*sizeof(TCHAR); + + //Get a handle to the key location + HKEY hkey_location; + if (RegOpenKeyExA(hkey_parent, reg_path.c_str(), NULL, KEY_QUERY_VALUE, &hkey_location) != ERROR_SUCCESS) + return std::string(); + + //Query key value + DWORD dw_type = REG_SZ; + if(RegQueryValueExA(hkey_location, reg_val_name.c_str(), NULL, &dw_type, (LPBYTE)value_buff, &value_buff_size) == ERROR_SUCCESS) { + RegCloseKey(hkey_location); + if (value_buff_size >= 1024*sizeof(TCHAR)) { + return std::string(); + } else { + std::string return_value(value_buff, value_buff_size-1); //value_buff_size includes the null terminator + return_value += path_suffix; + return return_value; + } + } else { + return std::string(); + } +} +#endif /*UHD_PLATFORM_WIN32*/ + +std::string uhd::get_images_dir(const std::string search_paths) { + + /* This function will check for the existence of directories in this + * order: + * + * 1) `UHD_IMAGES_DIR` environment variable + * 2) Any paths passed to this function via `search_paths' (may contain + * Windows registry keys) + * 3) `UHD package path` / share / uhd / images + */ + + std::string possible_dir; + + /* We will start by looking for a path indicated by the `UHD_IMAGES_DIR` + * environment variable. */ + std::vector<std::string> env_paths = get_env_paths("UHD_IMAGES_DIR"); + BOOST_FOREACH(possible_dir, env_paths) { + if (fs::is_directory(fs::path(possible_dir))) { + return possible_dir; + } + } + + /* On Windows systems, we may need to modify the `search_paths` parameter + * (see below). Making a local copy for const correctness. */ + std::string _search_paths = search_paths; + +#ifdef USE_NIUSRP_WINREG_KEY + _search_paths = std::string(NIUSRP_WINREG_KEY) + "," + search_paths; +#endif + + /* Now we will parse and attempt to qualify the paths in the `search_paths` + * parameter. If this is Windows, we will check the system registry for + * these strings. */ + if (!_search_paths.empty()) { + std::vector<std::string> search_paths_vector; + + boost::split(search_paths_vector, _search_paths, boost::is_any_of(",;")); + BOOST_FOREACH(std::string& search_path, search_paths_vector) { + + boost::algorithm::trim(search_path); + if (search_path.empty()) continue; + +#ifdef UHD_PLATFORM_WIN32 + possible_dir = _get_images_path_from_registry(search_path); + if (possible_dir.empty()) { + //Could not read from the registry due to missing key, invalid + //values, etc Just use the search path. The is_directory check + //will fail if this is a registry path and we will move on to + //the next item in the list. + possible_dir = search_path; + } +#else + possible_dir = expand_home_directory(search_path); +#endif + + if (fs::is_directory(fs::path(possible_dir))) { + return possible_dir; + } + } + } + + /* Finally, check for the default UHD images installation path. */ + fs::path pkg_path = fs::path(uhd::get_pkg_path()) / "share" / "uhd" / "images"; + if (fs::is_directory(pkg_path)) { + return pkg_path.string(); + } else { + /* No luck. Return an empty string. */ + return std::string(""); + } +} + +std::string uhd::find_image_path(const std::string &image_name, const std::string search_paths){ + /* If a path was provided on the command-line or as a hint from the caller, + * we default to that. */ if (fs::exists(image_name)){ return fs::system_complete(image_name).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.string(); + + /* Otherwise, look for the image in the images directory. */ + std::string images_dir = get_images_dir(search_paths); + if (!images_dir.empty()) { + fs::path image_path = fs::path(images_dir) / image_name; + if (fs::exists(image_path)) { + return image_path.string(); + } else { + throw uhd::io_error( + "Could not find the image '" + image_name + "' in the image directory " + images_dir + + "\nFor more information regarding image paths, please refer to the UHD manual."); + } } + + /* If we made it this far, then we didn't find anything. */ throw uhd::io_error("Could not find path for image: " + image_name - + "\n\n" + uhd::print_utility_error("uhd_images_downloader.py")); + + "\n\n" + + "Using images directory: " + images_dir + + "\n\n" + + "Set the environment variable 'UHD_IMAGES_DIR' appropriately or" + + " follow the below instructions to download the images package." + + "\n\n" + + uhd::print_utility_error("uhd_images_downloader.py")); } std::string uhd::find_utility(std::string name) { |