aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib')
-rw-r--r--host/lib/transport/CMakeLists.txt1
-rw-r--r--host/lib/transport/chdr.cpp182
-rw-r--r--host/lib/transport/libusb1_base.cpp20
-rw-r--r--host/lib/types/CMakeLists.txt1
-rw-r--r--host/lib/types/sid.cpp153
-rw-r--r--host/lib/usrp/b100/b100_impl.cpp10
-rw-r--r--host/lib/usrp/b100/b100_impl.hpp2
-rw-r--r--host/lib/usrp/b200/b200_iface.hpp3
-rw-r--r--host/lib/usrp/b200/b200_impl.cpp121
-rw-r--r--host/lib/usrp/b200/b200_impl.hpp61
-rw-r--r--host/lib/usrp/b200/b200_io_impl.cpp156
-rw-r--r--host/lib/usrp/e100/e100_impl.cpp4
-rw-r--r--host/lib/usrp/e300/e300_impl.cpp4
-rw-r--r--host/lib/usrp/e300/e300_network.cpp2
-rw-r--r--host/lib/usrp/multi_usrp.cpp3
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.cpp4
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp8
-rw-r--r--host/lib/usrp/x300/x300_impl.cpp18
-rw-r--r--host/lib/usrp/x300/x300_io_impl.cpp52
-rw-r--r--host/lib/usrp_clock/octoclock/octoclock_impl.cpp6
-rw-r--r--host/lib/utils/CMakeLists.txt1
-rw-r--r--host/lib/utils/images.cpp54
-rw-r--r--host/lib/utils/paths.cpp37
23 files changed, 708 insertions, 195 deletions
diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt
index 5920f3d78..9ec8a5c0b 100644
--- a/host/lib/transport/CMakeLists.txt
+++ b/host/lib/transport/CMakeLists.txt
@@ -129,6 +129,7 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/if_addrs.cpp
${CMAKE_CURRENT_SOURCE_DIR}/udp_simple.cpp
${CMAKE_CURRENT_SOURCE_DIR}/nirio_zero_copy.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/chdr.cpp
)
# Verbose Debug output for send/recv
diff --git a/host/lib/transport/chdr.cpp b/host/lib/transport/chdr.cpp
new file mode 100644
index 000000000..47ac961b9
--- /dev/null
+++ b/host/lib/transport/chdr.cpp
@@ -0,0 +1,182 @@
+//
+// Copyright 2014 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/transport/chdr.hpp>
+#include <uhd/utils/byteswap.hpp>
+#include <uhd/exception.hpp>
+
+//define the endian macros to convert integers
+#ifdef BOOST_BIG_ENDIAN
+ #define BE_MACRO(x) (x)
+ #define LE_MACRO(x) uhd::byteswap(x)
+#else
+ #define BE_MACRO(x) uhd::byteswap(x)
+ #define LE_MACRO(x) (x)
+#endif
+
+using namespace uhd::transport::vrt;
+
+static const boost::uint32_t HDR_FLAG_TSF = (1 << 29);
+static const boost::uint32_t HDR_FLAG_EOB = (1 << 28);
+static const boost::uint32_t HDR_FLAG_ERROR = (1 << 28);
+
+/***************************************************************************/
+/* Packing */
+/***************************************************************************/
+/*! Translate the contents of \p if_packet_info into a 32-Bit word and return it.
+ */
+UHD_INLINE boost::uint32_t _hdr_pack_chdr(
+ if_packet_info_t &if_packet_info
+) {
+ // Set fields in if_packet_info
+ if_packet_info.num_header_words32 = 2 + (if_packet_info.has_tsf ? 2 : 0);
+ if_packet_info.num_packet_words32 =
+ if_packet_info.num_header_words32 +
+ if_packet_info.num_payload_words32;
+
+ boost::uint16_t pkt_length =
+ if_packet_info.num_payload_bytes + (4 * if_packet_info.num_header_words32);
+ boost::uint32_t chdr = 0
+ // 2 Bits: Packet type
+ | (if_packet_info.packet_type << 30)
+ // 1 Bit: Has time
+ | (if_packet_info.has_tsf ? HDR_FLAG_TSF : 0)
+ // 1 Bit: EOB or Error
+ | ((if_packet_info.eob or if_packet_info.error) ? HDR_FLAG_EOB : 0)
+ // 12 Bits: Sequence number
+ | ((if_packet_info.packet_count & 0xFFF) << 16)
+ // 16 Bits: Total packet length
+ | pkt_length;
+ return chdr;
+}
+
+void chdr::if_hdr_pack_be(
+ boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+) {
+ // Write header and update if_packet_info
+ packet_buff[0] = BE_MACRO(_hdr_pack_chdr(if_packet_info));
+
+ // Write SID
+ packet_buff[1] = BE_MACRO(if_packet_info.sid);
+
+ // Write time
+ if (if_packet_info.has_tsf) {
+ packet_buff[2] = BE_MACRO(boost::uint32_t(if_packet_info.tsf >> 32));
+ packet_buff[3] = BE_MACRO(boost::uint32_t(if_packet_info.tsf >> 0));
+ }
+}
+
+void chdr::if_hdr_pack_le(
+ boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+) {
+ // Write header and update if_packet_info
+ packet_buff[0] = LE_MACRO(_hdr_pack_chdr(if_packet_info));
+
+ // Write SID
+ packet_buff[1] = LE_MACRO(if_packet_info.sid);
+
+ // Write time
+ if (if_packet_info.has_tsf) {
+ packet_buff[2] = LE_MACRO(boost::uint32_t(if_packet_info.tsf >> 32));
+ packet_buff[3] = LE_MACRO(boost::uint32_t(if_packet_info.tsf >> 0));
+ }
+}
+
+
+/***************************************************************************/
+/* Unpacking */
+/***************************************************************************/
+UHD_INLINE void _hdr_unpack_chdr(
+ const boost::uint32_t chdr,
+ if_packet_info_t &if_packet_info
+) {
+ // Set constant members
+ if_packet_info.link_type = if_packet_info_t::LINK_TYPE_CHDR;
+ if_packet_info.has_cid = false;
+ if_packet_info.has_sid = true;
+ if_packet_info.has_tsi = false;
+ if_packet_info.has_tlr = false;
+ if_packet_info.sob = false;
+
+ // Set configurable members
+ if_packet_info.has_tsf = bool(chdr & HDR_FLAG_TSF);
+ if_packet_info.packet_type = if_packet_info_t::packet_type_t((chdr >> 30) & 0x3);
+ if_packet_info.eob = (if_packet_info.packet_type == if_packet_info_t::PACKET_TYPE_DATA)
+ && bool(chdr & HDR_FLAG_EOB);
+ if_packet_info.error = (if_packet_info.packet_type == if_packet_info_t::PACKET_TYPE_RESP)
+ && bool(chdr & HDR_FLAG_ERROR);
+ if_packet_info.packet_count = (chdr >> 16) & 0xFFF;
+
+ // Set packet length variables
+ if (if_packet_info.has_tsf) {
+ if_packet_info.num_header_words32 = 4;
+ } else {
+ if_packet_info.num_header_words32 = 2;
+ }
+ size_t pkt_size_bytes = (chdr & 0xFFFF);
+ size_t pkt_size_word32 = (pkt_size_bytes / 4) + ((pkt_size_bytes % 4) ? 1 : 0);
+ // Check lengths match:
+ if (pkt_size_word32 < if_packet_info.num_header_words32) {
+ throw uhd::value_error("Bad CHDR or invalid packet length");
+ }
+ if (if_packet_info.num_packet_words32 < pkt_size_word32) {
+ throw uhd::value_error("Bad CHDR or packet fragment");
+ }
+ if_packet_info.num_payload_bytes = pkt_size_bytes - (4 * if_packet_info.num_header_words32);
+ if_packet_info.num_payload_words32 = pkt_size_word32 - if_packet_info.num_header_words32;
+}
+
+void chdr::if_hdr_unpack_be(
+ const boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+) {
+ // Read header and update if_packet_info
+ boost::uint32_t chdr = BE_MACRO(packet_buff[0]);
+ _hdr_unpack_chdr(chdr, if_packet_info);
+
+ // Read SID
+ if_packet_info.sid = BE_MACRO(packet_buff[1]);
+
+ // Read time (has_tsf was updated earlier)
+ if (if_packet_info.has_tsf) {
+ if_packet_info.tsf = 0
+ | boost::uint64_t(BE_MACRO(packet_buff[2])) << 32
+ | BE_MACRO(packet_buff[3]);
+ }
+}
+
+void chdr::if_hdr_unpack_le(
+ const boost::uint32_t *packet_buff,
+ if_packet_info_t &if_packet_info
+) {
+ // Read header and update if_packet_info
+ boost::uint32_t chdr = LE_MACRO(packet_buff[0]);
+ _hdr_unpack_chdr(chdr, if_packet_info);
+
+ // Read SID
+ if_packet_info.sid = LE_MACRO(packet_buff[1]);
+
+ // Read time (has_tsf was updated earlier)
+ if (if_packet_info.has_tsf) {
+ if_packet_info.tsf = 0
+ | boost::uint64_t(LE_MACRO(packet_buff[2])) << 32
+ | LE_MACRO(packet_buff[3]);
+ }
+}
+
diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp
index ee4e20adb..18acb1fdc 100644
--- a/host/lib/transport/libusb1_base.cpp
+++ b/host/lib/transport/libusb1_base.cpp
@@ -343,15 +343,21 @@ libusb::special_handle::sptr libusb::special_handle::make(device::sptr dev){
std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list(
boost::uint16_t vid, boost::uint16_t pid
){
- std::vector<usb_device_handle::sptr> handles;
+ return usb_device_handle::get_device_list(std::vector<usb_device_handle::vid_pid_pair_t>(1,usb_device_handle::vid_pid_pair_t(vid,pid)));
+}
+std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list(const std::vector<usb_device_handle::vid_pid_pair_t>& vid_pid_pair_list)
+{
+ std::vector<usb_device_handle::sptr> handles;
libusb::device_list::sptr dev_list = libusb::device_list::make();
- for (size_t i = 0; i < dev_list->size(); i++){
- usb_device_handle::sptr handle = libusb::special_handle::make(dev_list->at(i));
- if (handle->get_vendor_id() == vid and handle->get_product_id() == pid){
- handles.push_back(handle);
- }
+ for(size_t iter = 0; iter < vid_pid_pair_list.size(); ++iter)
+ {
+ for (size_t i = 0; i < dev_list->size(); i++){
+ usb_device_handle::sptr handle = libusb::special_handle::make(dev_list->at(i));
+ if (handle->get_vendor_id() == vid_pid_pair_list[iter].first and handle->get_product_id() == vid_pid_pair_list[iter].second){
+ handles.push_back(handle);
+ }
+ }
}
-
return handles;
}
diff --git a/host/lib/types/CMakeLists.txt b/host/lib/types/CMakeLists.txt
index f19043c1e..853da3fe2 100644
--- a/host/lib/types/CMakeLists.txt
+++ b/host/lib/types/CMakeLists.txt
@@ -86,6 +86,7 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/ranges.cpp
${CMAKE_CURRENT_SOURCE_DIR}/sensors.cpp
${CMAKE_CURRENT_SOURCE_DIR}/serial.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/sid.cpp
${CMAKE_CURRENT_SOURCE_DIR}/time_spec.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tune.cpp
${CMAKE_CURRENT_SOURCE_DIR}/types.cpp
diff --git a/host/lib/types/sid.cpp b/host/lib/types/sid.cpp
new file mode 100644
index 000000000..2fc3781cf
--- /dev/null
+++ b/host/lib/types/sid.cpp
@@ -0,0 +1,153 @@
+//
+// Copyright 2014 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 <boost/format.hpp>
+#include <boost/regex.hpp>
+#include <boost/lexical_cast.hpp>
+#include <uhd/exception.hpp>
+#include <uhd/types/sid.hpp>
+#include <uhd/utils/cast.hpp>
+
+using namespace uhd;
+
+sid_t::sid_t()
+ : _sid(0x0000), _set(false)
+{
+}
+
+sid_t::sid_t(boost::uint32_t sid)
+ : _sid(sid), _set(true)
+{
+}
+
+sid_t::sid_t(boost::uint8_t src_addr, boost::uint8_t src_ep, boost::uint8_t dst_addr, boost::uint8_t dst_ep)
+ : _sid(0x0000), _set(true)
+{
+ set_src_addr(src_addr);
+ set_src_endpoint(src_ep);
+ set_dst_addr(dst_addr);
+ set_dst_endpoint(dst_ep);
+}
+
+sid_t::sid_t(const std::string &sid_str)
+ : _sid(0x0000), _set(false)
+{
+ set_from_str(sid_str);
+}
+
+std::string sid_t::to_pp_string() const
+{
+ if (not _set) {
+ return "x.x>x.x";
+ }
+ return str(boost::format("%d.%d>%d.%d")
+ % get_src_addr()
+ % get_src_endpoint()
+ % get_dst_addr()
+ % get_dst_endpoint()
+ );
+}
+
+std::string sid_t::to_pp_string_hex() const
+{
+ if (not _set) {
+ return "xx:xx>xx:xx";
+ }
+ return str(boost::format("%02x:%02x>%02x:%02x")
+ % get_src_addr()
+ % get_src_endpoint()
+ % get_dst_addr()
+ % get_dst_endpoint()
+ );
+}
+
+
+void sid_t::set_sid(boost::uint32_t new_sid)
+{
+ _set = true;
+ _sid = new_sid;
+}
+
+void sid_t::set_from_str(const std::string &sid_str)
+{
+ const std::string dec_regex = "(\\d{1,3})\\.(\\d{1,3})[.:/><](\\d{1,3})\\.(\\d{1,3})";
+ const std::string hex_regex = "([[:xdigit:]]{2}):([[:xdigit:]]{2})[.:/><]([[:xdigit:]]{2}):([[:xdigit:]]{2})";
+
+ boost::cmatch matches;
+ if (boost::regex_match(sid_str.c_str(), matches, boost::regex(dec_regex))) {
+ set_src_addr(boost::lexical_cast<size_t>(matches[1]));
+ set_src_endpoint(boost::lexical_cast<size_t>(matches[2]));
+ set_dst_addr(boost::lexical_cast<size_t>(matches[3]));
+ set_dst_endpoint(boost::lexical_cast<size_t>(matches[4]));
+ return;
+ }
+
+ if (boost::regex_match(sid_str.c_str(), matches, boost::regex(hex_regex))) {
+ set_src_addr(uhd::cast::hexstr_cast<size_t>(matches[1]));
+ set_src_endpoint(uhd::cast::hexstr_cast<size_t>(matches[2]));
+ set_dst_addr(uhd::cast::hexstr_cast<size_t>(matches[3]));
+ set_dst_endpoint(uhd::cast::hexstr_cast<size_t>(matches[4]));
+ return;
+ }
+
+ throw uhd::value_error(str(boost::format("Invalid SID representation: %s") % sid_str));
+}
+
+void sid_t::set_src(boost::uint32_t new_addr) {
+ set_sid((_sid & 0x0000FFFF) | ((new_addr & 0xFFFF) << 16));
+}
+
+void sid_t::set_dst(boost::uint32_t new_addr) {
+ set_sid((_sid & 0xFFFF0000) | (new_addr & 0xFFFF));
+}
+
+void sid_t::set_src_addr(boost::uint32_t new_addr) {
+ set_sid((_sid & 0x00FFFFFF) | ((new_addr & 0xFF) << 24));
+}
+
+void sid_t::set_src_endpoint(boost::uint32_t new_addr) {
+ set_sid((_sid & 0xFF00FFFF) | ((new_addr & 0xFF) << 16));
+}
+
+void sid_t::set_dst_addr(boost::uint32_t new_addr) {
+ set_sid((_sid & 0xFFFF00FF) | ((new_addr & 0xFF) << 8));
+}
+
+void sid_t::set_dst_endpoint(boost::uint32_t new_addr) {
+ set_sid((_sid & 0xFFFFFF00) | ((new_addr & 0xFF) << 0));
+}
+
+void sid_t::set_dst_xbarport(boost::uint32_t new_xbarport)
+{
+ set_sid((_sid & 0xFFFFFF0F) | ((new_xbarport & 0xF) << 4));
+}
+
+void sid_t::set_dst_blockport(boost::uint32_t new_blockport)
+{
+ set_sid((_sid & 0xFFFFFFF0) | ((new_blockport & 0xF) << 0));
+}
+
+sid_t sid_t::reversed()
+{
+ return sid_t((get_dst() << 16) | get_src());
+}
+
+void sid_t::reverse()
+{
+ set_sid((get_dst() << 16) | get_src());
+}
+
diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp
index 24a87a3c8..c4279913c 100644
--- a/host/lib/usrp/b100/b100_impl.cpp
+++ b/host/lib/usrp/b100/b100_impl.cpp
@@ -23,7 +23,7 @@
#include <uhd/utils/cast.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/static.hpp>
-#include <uhd/utils/images.hpp>
+#include <uhd/utils/paths.hpp>
#include <uhd/utils/safe_call.hpp>
#include <boost/format.hpp>
#include <boost/assign/list_of.hpp>
@@ -82,7 +82,7 @@ static device_addrs_t b100_find(const device_addr_t &hint)
b100_fw_image = find_image_path(hint.get("fw", B100_FW_FILE_NAME));
}
catch(...){
- UHD_MSG(warning) << boost::format("Could not locate B100 firmware. %s\n") % print_images_error();
+ UHD_MSG(warning) << boost::format("Could not locate B100 firmware. %s\n") % print_utility_error("uhd_images_downloader.py");
return b100_addrs;
}
UHD_LOG << "the firmware image: " << b100_fw_image << std::endl;
@@ -532,10 +532,10 @@ void b100_impl::check_fw_compat(void){
);
if (fw_compat_num != B100_FW_COMPAT_NUM){
throw uhd::runtime_error(str(boost::format(
- "Expected firmware compatibility number 0x%x, but got 0x%x:\n"
+ "Expected firmware compatibility number %d, but got %d:\n"
"The firmware build is not compatible with the host code build.\n"
"%s"
- ) % B100_FW_COMPAT_NUM % fw_compat_num % print_images_error()));
+ ) % int(B100_FW_COMPAT_NUM) % fw_compat_num % print_utility_error("uhd_images_downloader.py")));
}
_tree->create<std::string>("/mboards/0/fw_version").set(str(boost::format("%u.0") % fw_compat_num));
}
@@ -552,7 +552,7 @@ void b100_impl::check_fpga_compat(void){
"Expected FPGA compatibility number %d, but got %d:\n"
"The FPGA build is not compatible with the host code build."
"%s"
- ) % int(B100_FPGA_COMPAT_NUM) % fpga_major % print_images_error()));
+ ) % int(B100_FPGA_COMPAT_NUM) % fpga_major % print_utility_error("uhd_images_downloader.py")));
}
_tree->create<std::string>("/mboards/0/fpga_version").set(str(boost::format("%u.%u") % fpga_major % fpga_minor));
}
diff --git a/host/lib/usrp/b100/b100_impl.hpp b/host/lib/usrp/b100/b100_impl.hpp
index 59ea2202e..dbca543be 100644
--- a/host/lib/usrp/b100/b100_impl.hpp
+++ b/host/lib/usrp/b100/b100_impl.hpp
@@ -46,7 +46,7 @@
static const double B100_LINK_RATE_BPS = 256e6/5; //pratical link rate (< 480 Mbps)
static const std::string B100_FW_FILE_NAME = "usrp_b100_fw.ihx";
static const std::string B100_FPGA_FILE_NAME = "usrp_b100_fpga.bin";
-static const boost::uint16_t B100_FW_COMPAT_NUM = 0x04;
+static const boost::uint16_t B100_FW_COMPAT_NUM = 4;
static const boost::uint16_t B100_FPGA_COMPAT_NUM = 11;
static const boost::uint32_t B100_RX_SID_BASE = 30;
static const boost::uint32_t B100_TX_ASYNC_SID = 10;
diff --git a/host/lib/usrp/b200/b200_iface.hpp b/host/lib/usrp/b200/b200_iface.hpp
index 83adfdd64..1821865d3 100644
--- a/host/lib/usrp/b200/b200_iface.hpp
+++ b/host/lib/usrp/b200/b200_iface.hpp
@@ -26,7 +26,10 @@
#include "ad9361_ctrl.hpp"
const static boost::uint16_t B200_VENDOR_ID = 0x2500;
+const static boost::uint16_t B200_VENDOR_NI_ID = 0x3923;
const static boost::uint16_t B200_PRODUCT_ID = 0x0020;
+const static boost::uint16_t B200_PRODUCT_NI_ID = 0x7813;
+const static boost::uint16_t B210_PRODUCT_NI_ID = 0x7814;
const static boost::uint16_t FX3_VID = 0x04b4;
const static boost::uint16_t FX3_DEFAULT_PID = 0x00f3;
const static boost::uint16_t FX3_REENUM_PID = 0x00f0;
diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp
index 01c0f5cbf..9b323cb13 100644
--- a/host/lib/usrp/b200/b200_impl.cpp
+++ b/host/lib/usrp/b200/b200_impl.cpp
@@ -22,7 +22,7 @@
#include <uhd/utils/cast.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/static.hpp>
-#include <uhd/utils/images.hpp>
+#include <uhd/utils/paths.hpp>
#include <uhd/utils/safe_call.hpp>
#include <uhd/usrp/dboard_eeprom.hpp>
#include <boost/format.hpp>
@@ -87,14 +87,16 @@ static device_addrs_t b200_find(const device_addr_t &hint)
//since an address and resource is intended for a different, non-USB, device.
if (hint.has_key("addr") || hint.has_key("resource")) return b200_addrs;
- boost::uint16_t vid, pid;
+ size_t found = 0;
+ std::vector<usb_device_handle::vid_pid_pair_t> vid_pid_pair_list;//vid pid pair search list for devices.
if(hint.has_key("vid") && hint.has_key("pid") && hint.has_key("type") && hint["type"] == "b200") {
- vid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("vid"));
- pid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("pid"));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("vid")),
+ uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("pid"))));
} else {
- vid = B200_VENDOR_ID;
- pid = B200_PRODUCT_ID;
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID, B200_PRODUCT_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B200_PRODUCT_NI_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B210_PRODUCT_NI_ID));
}
// Important note:
@@ -104,8 +106,9 @@ static device_addrs_t b200_find(const device_addr_t &hint)
// This requirement is a courtesy of libusb1.0 on windows.
//find the usrps and load firmware
- size_t found = 0;
- BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid)) {
+ std::vector<usb_device_handle::sptr> uhd_usb_device_vector = usb_device_handle::get_device_list(vid_pid_pair_list);
+
+ BOOST_FOREACH(usb_device_handle::sptr handle, uhd_usb_device_vector) {
//extract the firmware path for the b200
std::string b200_fw_image;
try{
@@ -115,7 +118,7 @@ static device_addrs_t b200_find(const device_addr_t &hint)
UHD_MSG(warning) << boost::format(
"Could not locate B200 firmware.\n"
"Please install the images package. %s\n"
- ) % print_images_error();
+ ) % print_utility_error("uhd_images_downloader.py");
return b200_addrs;
}
UHD_LOG << "the firmware image: " << b200_fw_image << std::endl;
@@ -138,7 +141,7 @@ static device_addrs_t b200_find(const device_addr_t &hint)
//search for the device until found or timeout
while (boost::get_system_time() < timeout_time and b200_addrs.empty() and found != 0)
{
- BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid))
+ BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid_pid_pair_list))
{
usb_control::sptr control;
try{control = usb_control::make(handle, 0);}
@@ -155,12 +158,16 @@ static device_addrs_t b200_find(const device_addr_t &hint)
{
switch (boost::lexical_cast<boost::uint16_t>(mb_eeprom["product"]))
{
+ //0x0001 and 0x7737 are Ettus B200 product Ids.
case 0x0001:
case 0x7737:
+ case B200_PRODUCT_NI_ID:
new_addr["product"] = "B200";
break;
- case 0x7738:
+ //0x0002 and 0x7738 are Ettus B210 product Ids.
case 0x0002:
+ case 0x7738:
+ case B210_PRODUCT_NI_ID:
new_addr["product"] = "B210";
break;
default: UHD_MSG(error) << "B200 unknown product code: " << mb_eeprom["product"] << std::endl;
@@ -204,13 +211,50 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
//try to match the given device address with something on the USB bus
boost::uint16_t vid = B200_VENDOR_ID;
boost::uint16_t pid = B200_PRODUCT_ID;
+ bool specified_vid = false;
+ bool specified_pid = false;
+
if (device_addr.has_key("vid"))
+ {
vid = uhd::cast::hexstr_cast<boost::uint16_t>(device_addr.get("vid"));
+ specified_vid = true;
+ }
+
if (device_addr.has_key("pid"))
+ {
pid = uhd::cast::hexstr_cast<boost::uint16_t>(device_addr.get("pid"));
+ specified_pid = true;
+ }
- std::vector<usb_device_handle::sptr> device_list =
- usb_device_handle::get_device_list(vid, pid);
+ std::vector<usb_device_handle::vid_pid_pair_t> vid_pid_pair_list;//search list for devices.
+
+ // Search only for specified VID and PID if both specified
+ if (specified_vid && specified_pid)
+ {
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,pid));
+ }
+ // Search for all supported PIDs limited to specified VID if only VID specified
+ else if (specified_vid)
+ {
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B200_PRODUCT_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B200_PRODUCT_NI_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B210_PRODUCT_NI_ID));
+ }
+ // Search for all supported VIDs limited to specified PID if only PID specified
+ else if (specified_pid)
+ {
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID,pid));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,pid));
+ }
+ // Search for all supported devices if neither VID nor PID specified
+ else
+ {
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID,B200_PRODUCT_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,B200_PRODUCT_NI_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,B210_PRODUCT_NI_ID));
+ }
+
+ std::vector<usb_device_handle::sptr> device_list = usb_device_handle::get_device_list(vid_pid_pair_list);
//locate the matching handle in the device list
usb_device_handle::sptr handle;
@@ -244,13 +288,17 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
{
switch (boost::lexical_cast<boost::uint16_t>(mb_eeprom["product"]))
{
+ //0x0001 and 0x7737 are Ettus B200 product Ids.
case 0x0001:
case 0x7737:
+ case B200_PRODUCT_NI_ID:
product_name = "B200";
default_file_name = B200_FPGA_FILE_NAME;
break;
- case 0x7738:
+ //0x0002 and 0x7738 are Ettus B210 product Ids.
case 0x0002:
+ case 0x7738:
+ case B210_PRODUCT_NI_ID:
product_name = "B210";
default_file_name = B210_FPGA_FILE_NAME;
break;
@@ -416,6 +464,7 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
.publish(boost::bind(&b200_impl::get_tick_rate, this))
.subscribe(boost::bind(&b200_impl::update_tick_rate, this, _1));
_tree->create<time_spec_t>(mb_path / "time" / "cmd");
+ _tree->create<bool>(mb_path / "auto_tick_rate").set(false);
////////////////////////////////////////////////////////////////////
// and do the misc mboard sensors
@@ -516,6 +565,11 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
_tree->access<double>(mb_path / "rx_dsps" / str(boost::format("%u") % i)/ "rate/value").set(B200_DEFAULT_RATE);
_tree->access<double>(mb_path / "tx_dsps" / str(boost::format("%u") % i) / "rate/value").set(B200_DEFAULT_RATE);
}
+ // We can automatically choose a master clock rate, but not if the user specifies one
+ _tree->access<bool>(mb_path / "auto_tick_rate").set(not device_addr.has_key("master_clock_rate"));
+ if (not device_addr.has_key("master_clock_rate")) {
+ UHD_MSG(status) << "Setting master clock rate selection to 'automatic'." << std::endl;
+ }
//GPS installed: use external ref, time, and init time spec
if (_gps and _gps->gps_detected())
@@ -579,7 +633,7 @@ void b200_impl::setup_radio(const size_t dspno)
_tree->create<meta_range_t>(rx_dsp_path / "rate" / "range")
.publish(boost::bind(&rx_dsp_core_3000::get_host_rates, perif.ddc));
_tree->create<double>(rx_dsp_path / "rate" / "value")
- .coerce(boost::bind(&rx_dsp_core_3000::set_host_rate, perif.ddc, _1))
+ .coerce(boost::bind(&b200_impl::coerce_rx_samp_rate, this, perif.ddc, dspno, _1))
.subscribe(boost::bind(&b200_impl::update_rx_samp_rate, this, dspno, _1))
.set(0.0); // Can only set this after tick rate is initialized.
_tree->create<double>(rx_dsp_path / "freq" / "value")
@@ -603,7 +657,7 @@ void b200_impl::setup_radio(const size_t dspno)
_tree->create<meta_range_t>(tx_dsp_path / "rate" / "range")
.publish(boost::bind(&tx_dsp_core_3000::get_host_rates, perif.duc));
_tree->create<double>(tx_dsp_path / "rate" / "value")
- .coerce(boost::bind(&tx_dsp_core_3000::set_host_rate, perif.duc, _1))
+ .coerce(boost::bind(&b200_impl::coerce_tx_samp_rate, this, perif.duc, dspno, _1))
.subscribe(boost::bind(&b200_impl::update_tx_samp_rate, this, dspno, _1))
.set(0.0); // Can only set this after tick rate is initialized.
_tree->create<double>(tx_dsp_path / "freq" / "value")
@@ -719,7 +773,7 @@ void b200_impl::codec_loopback_self_test(wb_iface::sptr iface)
/***********************************************************************
* Sample and tick rate comprehension below
**********************************************************************/
-void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, const char* direction /*= NULL*/)
+void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, const std::string &direction /*= ""*/)
{
const size_t max_chans = 2;
if (chan_count > max_chans)
@@ -727,7 +781,7 @@ void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, co
throw uhd::value_error(boost::str(
boost::format("cannot not setup %d %s channels (maximum is %d)")
% chan_count
- % (direction ? direction : "data")
+ % (direction.empty() ? "data" : direction)
% max_chans
));
}
@@ -741,20 +795,26 @@ void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, co
% (tick_rate/1e6)
% (max_tick_rate/1e6)
% chan_count
- % (direction ? direction : "data")
+ % (direction.empty() ? "data" : direction)
));
}
}
}
-double b200_impl::set_tick_rate(const double rate)
+double b200_impl::set_tick_rate(const double new_tick_rate)
{
- UHD_MSG(status) << (boost::format("Asking for clock rate %.6f MHz\n") % (rate/1e6));
-
- check_tick_rate_with_current_streamers(rate); // Defined in b200_io_impl.cpp
+ UHD_MSG(status) << (boost::format("Asking for clock rate %.6f MHz... ") % (new_tick_rate/1e6)) << std::flush;
+ check_tick_rate_with_current_streamers(new_tick_rate); // Defined in b200_io_impl.cpp
+
+ // Make sure the clock rate is actually changed before doing
+ // the full Monty of setting regs and loopback tests etc.
+ if (std::abs(new_tick_rate - _tick_rate) < 1.0) {
+ UHD_MSG(status) << "OK" << std::endl;
+ return _tick_rate;
+ }
- _tick_rate = _codec_ctrl->set_clock_rate(rate);
- UHD_MSG(status) << (boost::format("Actually got clock rate %.6f MHz\n") % (_tick_rate/1e6));
+ _tick_rate = _codec_ctrl->set_clock_rate(new_tick_rate);
+ UHD_MSG(status) << std::endl << (boost::format("Actually got clock rate %.6f MHz.") % (_tick_rate/1e6)) << std::endl;
//reset after clock rate change
this->reset_codec_dcm();
@@ -779,11 +839,11 @@ void b200_impl::check_fw_compat(void)
if (compat_major != B200_FW_COMPAT_NUM_MAJOR){
throw uhd::runtime_error(str(boost::format(
- "Expected firmware compatibility number 0x%x, but got 0x%x.%x:\n"
+ "Expected firmware compatibility number %d.%d, but got %d.%d:\n"
"The firmware build is not compatible with the host code build.\n"
"%s"
- ) % int(B200_FW_COMPAT_NUM_MAJOR) % compat_major % compat_minor
- % print_images_error()));
+ ) % int(B200_FW_COMPAT_NUM_MAJOR) % int(B200_FW_COMPAT_NUM_MINOR)
+ % compat_major % compat_minor % print_utility_error("uhd_images_downloader.py")));
}
_tree->create<std::string>("/mboards/0/fw_version").set(str(boost::format("%u.%u")
% compat_major % compat_minor));
@@ -800,11 +860,10 @@ void b200_impl::check_fpga_compat(void)
if (compat_major != B200_FPGA_COMPAT_NUM){
throw uhd::runtime_error(str(boost::format(
- "Expected FPGA compatibility number 0x%x, but got 0x%x.%x:\n"
+ "Expected FPGA compatibility number %d, but got %d:\n"
"The FPGA build is not compatible with the host code build.\n"
"%s"
- ) % int(B200_FPGA_COMPAT_NUM) % compat_major % compat_minor
- % print_images_error()));
+ ) % int(B200_FPGA_COMPAT_NUM) % compat_major % print_utility_error("uhd_images_downloader.py")));
}
_tree->create<std::string>("/mboards/0/fpga_version").set(str(boost::format("%u.%u")
% compat_major % compat_minor));
diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp
index 8f03d81ad..71592f60b 100644
--- a/host/lib/usrp/b200/b200_impl.hpp
+++ b/host/lib/usrp/b200/b200_impl.hpp
@@ -45,9 +45,9 @@
#include <uhd/transport/bounded_buffer.hpp>
#include <boost/weak_ptr.hpp>
#include "recv_packet_demuxer_3000.hpp"
-static const boost::uint8_t B200_FW_COMPAT_NUM_MAJOR = 0x07;
-static const boost::uint8_t B200_FW_COMPAT_NUM_MINOR = 0x00;
-static const boost::uint16_t B200_FPGA_COMPAT_NUM = 0x04;
+static const boost::uint8_t B200_FW_COMPAT_NUM_MAJOR = 7;
+static const boost::uint8_t B200_FW_COMPAT_NUM_MINOR = 0;
+static const boost::uint16_t B200_FPGA_COMPAT_NUM = 4;
static const double B200_BUS_CLOCK_RATE = 100e6;
static const double B200_DEFAULT_TICK_RATE = 32e6;
static const double B200_DEFAULT_FREQ = 100e6; // Hz
@@ -98,7 +98,13 @@ public:
uhd::rx_streamer::sptr get_rx_stream(const uhd::stream_args_t &args);
uhd::tx_streamer::sptr get_tx_stream(const uhd::stream_args_t &args);
bool recv_async_msg(uhd::async_metadata_t &, double);
- void check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const char* direction = NULL);
+
+ //! Check that the combination of stream args and tick rate are valid.
+ //
+ // Basically figures out the arguments for enforce_tick_rate_limits()
+ // and calls said method. If arguments are invalid, throws a
+ // uhd::value_error.
+ void check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const std::string &direction = "");
private:
//controllers
@@ -190,11 +196,56 @@ private:
double _tick_rate;
double get_tick_rate(void){return _tick_rate;}
double set_tick_rate(const double rate);
+
+ /*! \brief Choose a tick rate (master clock rate) that works well for the given sampling rate.
+ *
+ * This function will try and choose a master clock rate automatically.
+ * See the function definition for details on the algorithm.
+ *
+ * The chosen tick rate is the largest multiple of two that is smaler
+ * than the max tick rate.
+ * The base rate is either given explicitly, or is the lcm() of the tx
+ * and rx sampling rates. In that case, it reads the rates directly
+ * from the property tree. It also tries to guess the number of channels
+ * (for the max possible tick rate) by checking the available streamers.
+ * This value, too, can explicitly be given.
+ *
+ * \param rate If this is given, it will be used as a minimum rate, or
+ * argument to lcm().
+ * \param tree_dsp_path The sampling rate from this property tree path
+ * will be ignored.
+ * \param num_chans If given, specifies the number of channels.
+ */
+ void set_auto_tick_rate(
+ const double rate=0,
+ const uhd::fs_path &tree_dsp_path="",
+ size_t num_chans=0
+ );
+
void update_tick_rate(const double);
- void enforce_tick_rate_limits(size_t chan_count, double tick_rate, const char* direction = NULL);
+
+ /*! Check if \p tick_rate works with \p chan_count channels.
+ *
+ * Throws a uhd::value_error if not.
+ */
+ void enforce_tick_rate_limits(size_t chan_count, double tick_rate, const std::string &direction = "");
void check_tick_rate_with_current_streamers(double rate);
+ /*! Return the max number of channels on active rx_streamer or tx_streamer objects associated with this device.
+ *
+ * \param direction Set to "TX" to only check tx_streamers, "RX" to only check
+ * rx_streamers. Any other value will check if \e any active
+ * streamers are available.
+ * \return Return the number of tx streamers (direction=="TX"), the number of rx
+ * streamers (direction=="RX") or the total number of streamers.
+ */
+ size_t max_chan_count(const std::string &direction="");
+
+ //! Coercer, attached to the "rate/value" property on the rx dsps.
+ double coerce_rx_samp_rate(rx_dsp_core_3000::sptr, size_t, const double);
void update_rx_samp_rate(const size_t, const double);
+ //! Coercer, attached to the "rate/value" property on the tx dsps.
+ double coerce_tx_samp_rate(tx_dsp_core_3000::sptr, size_t, const double);
void update_tx_samp_rate(const size_t, const double);
};
diff --git a/host/lib/usrp/b200/b200_io_impl.cpp b/host/lib/usrp/b200/b200_io_impl.cpp
index 262c95f0d..60b925517 100644
--- a/host/lib/usrp/b200/b200_io_impl.cpp
+++ b/host/lib/usrp/b200/b200_io_impl.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2012-2013 Ettus Research LLC
+// Copyright 2012-2014 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
@@ -21,8 +21,10 @@
#include "../../transport/super_recv_packet_handler.hpp"
#include "../../transport/super_send_packet_handler.hpp"
#include "async_packet_handler.hpp"
+#include <uhd/utils/math.hpp>
#include <boost/bind.hpp>
#include <boost/make_shared.hpp>
+#include <boost/math/common_factor.hpp>
#include <set>
using namespace uhd;
@@ -34,30 +36,32 @@ using namespace uhd::transport;
**********************************************************************/
void b200_impl::check_tick_rate_with_current_streamers(double rate)
{
- size_t max_tx_chan_count = 0, max_rx_chan_count = 0;
+ // Defined in b200_impl.cpp
+ enforce_tick_rate_limits(max_chan_count("RX"), rate, "RX");
+ enforce_tick_rate_limits(max_chan_count("TX"), rate, "TX");
+}
+
+// direction can either be "TX", "RX", or empty (default)
+size_t b200_impl::max_chan_count(const std::string &direction /* = "" */)
+{
+ size_t max_count = 0;
BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs)
{
- {
+ if ((direction == "RX" or direction.empty()) and not perif.rx_streamer.expired()) {
boost::shared_ptr<sph::recv_packet_streamer> rx_streamer =
boost::dynamic_pointer_cast<sph::recv_packet_streamer>(perif.rx_streamer.lock());
- if (rx_streamer)
- max_rx_chan_count = std::max(max_rx_chan_count, rx_streamer->get_num_channels());
+ max_count = std::max(max_count, rx_streamer->get_num_channels());
}
-
- {
+ if ((direction == "TX" or direction.empty()) and not perif.tx_streamer.expired()) {
boost::shared_ptr<sph::send_packet_streamer> tx_streamer =
boost::dynamic_pointer_cast<sph::send_packet_streamer>(perif.tx_streamer.lock());
- if (tx_streamer)
- max_tx_chan_count = std::max(max_tx_chan_count, tx_streamer->get_num_channels());
+ max_count = std::max(max_count, tx_streamer->get_num_channels());
}
}
-
- // Defined in b200_impl.cpp
- enforce_tick_rate_limits(max_rx_chan_count, rate, "RX");
- enforce_tick_rate_limits(max_tx_chan_count, rate, "TX");
+ return max_count;
}
-void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const char* direction /*= NULL*/)
+void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const std::string &direction /*= ""*/)
{
std::set<size_t> chans_set;
for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++)
@@ -69,26 +73,120 @@ void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_
enforce_tick_rate_limits(chans_set.size(), tick_rate, direction); // Defined in b200_impl.cpp
}
-void b200_impl::update_tick_rate(const double rate)
+void b200_impl::set_auto_tick_rate(
+ const double rate,
+ const fs_path &tree_dsp_path,
+ size_t num_chans
+) {
+ if (num_chans == 0) { // Divine them
+ num_chans = std::max(size_t(1), max_chan_count());
+ }
+
+ // See also the doxygen documentation for these steps in b200_impl.hpp
+ // Step 1: Obtain LCM and max rate from all relevant dsps
+ boost::uint32_t lcm_rate = (rate == 0) ? 1 : static_cast<boost::uint32_t>(floor(rate + 0.5));
+ for (int i = 0; i < 2; i++) { // Loop through rx and tx
+ std::string dir = (i == 0) ? "tx" : "rx";
+ // We have no way of knowing which DSPs are used, so we check them all.
+ BOOST_FOREACH(const std::string &dsp_no, _tree->list(str(boost::format("/mboards/0/%s_dsps") % dir))) {
+ fs_path dsp_path = str(boost::format("/mboards/0/%s_dsps/%s") % dir % dsp_no);
+ if (dsp_path == tree_dsp_path) {
+ continue;
+ }
+ double this_dsp_rate = _tree->access<double>(dsp_path / "rate/value").get();
+ // If this_dsp_rate == B200_DEFAULT_RATE, we assume the user did not actually set
+ // the sampling rate. If the user *did* set the rate to
+ // B200_DEFAULT_RATE on all DSPs, then this will still work (see below).
+ // If the user set one DSP to B200_DEFAULT_RATE and the other to
+ // a different rate, this also works if the rates are integer multiples
+ // of one another. Only for certain configurations of B200_DEFAULT_RATE
+ // and another rate that is not an integer multiple, this will be problematic.
+ // Since this case is less common than the case where a rate is left unset,
+ // we don't handle that but rather explain that corner case in the documentation.
+ if (this_dsp_rate == B200_DEFAULT_RATE) {
+ continue;
+ }
+ lcm_rate = boost::math::lcm<boost::uint32_t>(
+ lcm_rate,
+ static_cast<boost::uint32_t>(floor(this_dsp_rate + 0.5))
+ );
+ }
+ }
+ if (lcm_rate == 1) {
+ lcm_rate = static_cast<boost::uint32_t>(B200_DEFAULT_RATE);
+ }
+
+ // Step 2: Determine whether if we can use lcm_rate (preferred),
+ // or have to give up because too large:
+ const double max_tick_rate =
+ ((num_chans <= 1) ? ad9361_device_t::AD9361_RECOMMENDED_MAX_CLOCK_RATE : ad9361_device_t::AD9361_MAX_CLOCK_RATE/2);
+ double base_rate = static_cast<double>(lcm_rate);
+ if (base_rate > max_tick_rate) {
+ UHD_MSG(warning)
+ << "Cannot automatically determine an appropriate tick rate for these sampling rates." << std::endl
+ << "Consider using different sampling rates, or manually specify a suitable master clock rate." << std::endl;
+ return; // Let the others handle this
+ }
+
+ // Step 3: Choose the new rate
+ // Rules for choosing the tick rate:
+ // Choose a rate that is a power of 2 larger than the sampling rate,
+ // but at least 4. Cannot exceed the max tick rate, of course, but must
+ // be larger than the minimum tick rate.
+ // An equation that does all that is:
+ //
+ // f_auto = r * 2^floor(log2(f_max/r))
+ //
+ // where r is the base rate and f_max is the maximum tick rate. The case
+ // where floor() yields 1 must be caught.
+ const double min_tick_rate = _codec_ctrl->get_clock_rate_range().start();
+ // We use shifts here instead of 2^x because exp2() is not available in all compilers,
+ // also this guarantees no rounding issues. The type cast to int32_t serves as floor():
+ boost::int32_t multiplier = (1 << boost::int32_t(uhd::math::log2(max_tick_rate / base_rate)));
+ if (multiplier == 2 and base_rate >= min_tick_rate) {
+ // Don't bother (see above)
+ multiplier = 1;
+ }
+ double new_rate = base_rate * multiplier;
+ UHD_ASSERT_THROW(new_rate >= min_tick_rate);
+ UHD_ASSERT_THROW(new_rate <= max_tick_rate);
+
+ if (_tree->access<double>("/mboards/0/tick_rate").get() != new_rate) {
+ _tree->access<double>("/mboards/0/tick_rate").set(new_rate);
+ }
+}
+
+void b200_impl::update_tick_rate(const double new_tick_rate)
{
- check_tick_rate_with_current_streamers(rate);
+ check_tick_rate_with_current_streamers(new_tick_rate);
BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs)
{
boost::shared_ptr<sph::recv_packet_streamer> my_streamer =
boost::dynamic_pointer_cast<sph::recv_packet_streamer>(perif.rx_streamer.lock());
- if (my_streamer) my_streamer->set_tick_rate(rate);
- perif.framer->set_tick_rate(_tick_rate);
+ if (my_streamer) my_streamer->set_tick_rate(new_tick_rate);
+ perif.framer->set_tick_rate(new_tick_rate);
}
BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs)
{
boost::shared_ptr<sph::send_packet_streamer> my_streamer =
boost::dynamic_pointer_cast<sph::send_packet_streamer>(perif.tx_streamer.lock());
- if (my_streamer) my_streamer->set_tick_rate(rate);
- perif.deframer->set_tick_rate(_tick_rate);
+ if (my_streamer) my_streamer->set_tick_rate(new_tick_rate);
+ perif.deframer->set_tick_rate(new_tick_rate);
}
}
+
+double b200_impl::coerce_rx_samp_rate(rx_dsp_core_3000::sptr ddc, size_t dspno, const double rx_rate)
+{
+ // Have to set tick rate first, or the ddc will change the requested rate based on default tick rate
+ if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) {
+ const std::string dsp_path = (boost::format("/mboards/0/rx_dsps/%s") % dspno).str();
+ set_auto_tick_rate(rx_rate, dsp_path);
+ }
+ return ddc->set_host_rate(rx_rate);
+}
+
void b200_impl::update_rx_samp_rate(const size_t dspno, const double rate)
{
boost::shared_ptr<sph::recv_packet_streamer> my_streamer =
@@ -99,6 +197,16 @@ void b200_impl::update_rx_samp_rate(const size_t dspno, const double rate)
my_streamer->set_scale_factor(adj);
}
+double b200_impl::coerce_tx_samp_rate(tx_dsp_core_3000::sptr duc, size_t dspno, const double tx_rate)
+{
+ // Have to set tick rate first, or the duc will change the requested rate based on default tick rate
+ if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) {
+ const std::string dsp_path = (boost::format("/mboards/0/tx_dsps/%s") % dspno).str();
+ set_auto_tick_rate(tx_rate, dsp_path);
+ }
+ return duc->set_host_rate(tx_rate);
+}
+
void b200_impl::update_tx_samp_rate(const size_t dspno, const double rate)
{
boost::shared_ptr<sph::send_packet_streamer> my_streamer =
@@ -264,6 +372,9 @@ rx_streamer::sptr b200_impl::get_rx_stream(const uhd::stream_args_t &args_)
if (args.otw_format.empty()) args.otw_format = "sc16";
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
+ if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) {
+ set_auto_tick_rate(0, "", args.channels.size());
+ }
check_streamer_args(args, this->get_tick_rate(), "RX");
boost::shared_ptr<sph::recv_packet_streamer> my_streamer;
@@ -371,7 +482,10 @@ tx_streamer::sptr b200_impl::get_tx_stream(const uhd::stream_args_t &args_)
if (args.otw_format.empty()) args.otw_format = "sc16";
args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels;
- check_streamer_args(args, this->get_tick_rate(), "TX");
+ if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) {
+ set_auto_tick_rate(0, "", args.channels.size());
+ }
+ check_streamer_args(args, this->get_tick_rate(), "RX");
boost::shared_ptr<sph::send_packet_streamer> my_streamer;
for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++)
diff --git a/host/lib/usrp/e100/e100_impl.cpp b/host/lib/usrp/e100/e100_impl.cpp
index 8b4f2316c..ac419e0e0 100644
--- a/host/lib/usrp/e100/e100_impl.cpp
+++ b/host/lib/usrp/e100/e100_impl.cpp
@@ -21,7 +21,7 @@
#include <uhd/utils/msg.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/static.hpp>
-#include <uhd/utils/images.hpp>
+#include <uhd/utils/paths.hpp>
#include <boost/bind.hpp>
#include <boost/format.hpp>
#include <boost/filesystem.hpp>
@@ -132,7 +132,7 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){
e100_fpga_image = find_image_path(device_addr.get("fpga", default_fpga_file_name));
}
catch(...){
- UHD_MSG(error) << boost::format("Could not find FPGA image. %s\n") % print_images_error();
+ UHD_MSG(error) << boost::format("Could not find FPGA image. %s\n") % print_utility_error("uhd_images_downloader.py");
throw;
}
e100_load_fpga(e100_fpga_image);
diff --git a/host/lib/usrp/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp
index e42ac390e..8807a56e4 100644
--- a/host/lib/usrp/e300/e300_impl.cpp
+++ b/host/lib/usrp/e300/e300_impl.cpp
@@ -28,7 +28,7 @@
#include <uhd/utils/msg.hpp>
#include <uhd/utils/log.hpp>
#include <uhd/utils/static.hpp>
-#include <uhd/utils/images.hpp>
+#include <uhd/utils/paths.hpp>
#include <uhd/usrp/dboard_eeprom.hpp>
#include <uhd/transport/if_addrs.hpp>
#include <uhd/transport/udp_zero_copy.hpp>
@@ -397,7 +397,7 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr)
"%s"
) % fpga::COMPAT_MAJOR
% _get_version(FPGA_MAJOR) % _get_version(FPGA_MINOR)
- % print_images_error()));
+ % print_utility_error("uhd_images_downloader.py")));
}
////////////////////////////////////////////////////////////////////
diff --git a/host/lib/usrp/e300/e300_network.cpp b/host/lib/usrp/e300/e300_network.cpp
index 883ff0c4f..59e1eec86 100644
--- a/host/lib/usrp/e300/e300_network.cpp
+++ b/host/lib/usrp/e300/e300_network.cpp
@@ -33,7 +33,7 @@
#include <uhd/utils/msg.hpp>
#include <uhd/utils/byteswap.hpp>
-#include <uhd/utils/images.hpp>
+#include <uhd/utils/paths.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp
index 0c128dd22..7f27bdc64 100644
--- a/host/lib/usrp/multi_usrp.cpp
+++ b/host/lib/usrp/multi_usrp.cpp
@@ -431,6 +431,9 @@ public:
******************************************************************/
void set_master_clock_rate(double rate, size_t mboard){
if (mboard != ALL_MBOARDS){
+ if (_tree->exists(mb_root(mboard) / "auto_tick_rate")) {
+ _tree->access<bool>(mb_root(mboard) / "auto_tick_rate").set(false);
+ }
_tree->access<double>(mb_root(mboard) / "tick_rate").set(rate);
return;
}
diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp
index 709092e42..dbd5408e8 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.cpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.cpp
@@ -23,7 +23,7 @@
#include <uhd/utils/cast.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/static.hpp>
-#include <uhd/utils/images.hpp>
+#include <uhd/utils/paths.hpp>
#include <boost/format.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/filesystem.hpp>
@@ -85,7 +85,7 @@ static device_addrs_t usrp1_find(const device_addr_t &hint)
usrp1_fw_image = find_image_path(hint.get("fw", "usrp1_fw.ihx"));
}
catch(...){
- UHD_MSG(warning) << boost::format("Could not locate USRP1 firmware. %s") % print_images_error();
+ UHD_MSG(warning) << boost::format("Could not locate USRP1 firmware. %s") % print_utility_error("uhd_images_downloader.py");
}
UHD_LOG << "USRP1 firmware image: " << usrp1_fw_image << std::endl;
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
index b2085807f..65cf90a17 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.cpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -23,7 +23,7 @@
#include <uhd/utils/msg.hpp>
#include <uhd/utils/paths.hpp>
#include <uhd/utils/tasks.hpp>
-#include <uhd/utils/images.hpp>
+#include <uhd/utils/paths.hpp>
#include <uhd/utils/safe_call.hpp>
#include <uhd/types/dict.hpp>
#include <boost/thread.hpp>
@@ -375,7 +375,7 @@ public:
fpga_image_path = uhd::find_image_path(fpga_image);
}
catch(const std::exception &){
- return str(boost::format("Could not find %s and %s in your images path!\n%s") % fw_image % fpga_image % print_images_error());
+ return str(boost::format("Could not find %s and %s in your images path!\n%s") % fw_image % fpga_image % print_utility_error("uhd_images_downloader.py"));
}
//escape char for multi-line cmd + newline + indent?
@@ -389,13 +389,13 @@ public:
if (this->get_rev() == USRP2_REV3 or this->get_rev() == USRP2_REV4){
const std::string card_burner = (fs::path(uhd::get_pkg_path()) / UHD_LIB_DIR / "uhd" / "utils" / "usrp2_card_burner.py").string();
const std::string card_burner_cmd = str(boost::format("\"%s%s\" %s--fpga=\"%s\" %s--fw=\"%s\"") % sudo % card_burner % ml % fpga_image_path % ml % fw_image_path);
- return str(boost::format("%s\n%s") % print_images_error() % card_burner_cmd);
+ return str(boost::format("%s\n%s") % print_utility_error("uhd_images_downloader.py") % card_burner_cmd);
}
else{
const std::string addr = _ctrl_transport->get_recv_addr();
const std::string net_burner_path = (fs::path(uhd::get_pkg_path()) / UHD_LIB_DIR / "uhd" / "utils" / "usrp_n2xx_simple_net_burner").string();
const std::string net_burner_cmd = str(boost::format("\"%s\" %s--addr=\"%s\"") % net_burner_path % ml % addr);
- return str(boost::format("%s\n%s") % print_images_error() % net_burner_cmd);
+ return str(boost::format("%s\n%s") % print_utility_error("uhd_images_downloader.py") % net_burner_cmd);
}
}
diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp
index a879ae02d..c7980c997 100644
--- a/host/lib/usrp/x300/x300_impl.cpp
+++ b/host/lib/usrp/x300/x300_impl.cpp
@@ -24,7 +24,7 @@
#include "apply_corrections.hpp"
#include <uhd/utils/static.hpp>
#include <uhd/utils/msg.hpp>
-#include <uhd/utils/images.hpp>
+#include <uhd/utils/paths.hpp>
#include <uhd/utils/safe_call.hpp>
#include <uhd/usrp/subdev_spec.hpp>
#include <uhd/transport/if_addrs.hpp>
@@ -171,7 +171,7 @@ static device_addrs_t x300_find_pcie(const device_addr_t &hint, bool explicit_qu
default:
continue;
}
-
+
niriok_proxy::sptr kernel_proxy = niriok_proxy::make_and_open(dev_info.interface_path);
//Attempt to read the name from the EEPROM and perform filtering.
@@ -1434,8 +1434,8 @@ bool x300_impl::wait_for_ref_locked(wb_iface::sptr ctrl, double timeout)
boost::this_thread::sleep(boost::posix_time::milliseconds(1));
} while (boost::get_system_time() < timeout_time);
- //failed to lock on reference
- return false;
+ //Check one last time
+ return get_ref_locked(ctrl).to_bool();
}
sensor_value_t x300_impl::get_ref_locked(wb_iface::sptr ctrl)
@@ -1670,11 +1670,11 @@ void x300_impl::check_fw_compat(const fs_path &mb_path, wb_iface::sptr iface)
if (compat_major != X300_FW_COMPAT_MAJOR)
{
throw uhd::runtime_error(str(boost::format(
- "Expected firmware compatibility number 0x%x, but got 0x%x.%x:\n"
+ "Expected firmware compatibility number %d.%d, but got %d.%d:\n"
"The firmware build is not compatible with the host code build.\n"
"%s"
- ) % int(X300_FW_COMPAT_MAJOR) % compat_major % compat_minor
- % print_images_error()));
+ ) % int(X300_FW_COMPAT_MAJOR) % int(X300_FW_COMPAT_MINOR)
+ % compat_major % compat_minor % print_utility_error("uhd_images_downloader.py")));
}
_tree->create<std::string>(mb_path / "fw_version").set(str(boost::format("%u.%u")
% compat_major % compat_minor));
@@ -1694,11 +1694,11 @@ void x300_impl::check_fpga_compat(const fs_path &mb_path, wb_iface::sptr iface)
"Download the appropriate FPGA images for this version of UHD.\n"
"%s\n\n"
"Then burn a new image to the on-board flash storage of your\n"
- "USRP X3xx device using the burner utility. \n\n"
+ "USRP X3xx device using the burner utility. %s\n\n"
"For more information, refer to the UHD manual:\n\n"
" http://files.ettus.com/manual/page_usrp_x3x0.html#x3x0_flash"
) % int(X300_FPGA_COMPAT_MAJOR) % compat_major
- % print_images_error()));
+ % print_utility_error("uhd_images_downloader.py") % print_utility_error("usrp_x3xx_fpga_burner")));
}
_tree->create<std::string>(mb_path / "fpga_version").set(str(boost::format("%u.%u")
% compat_major % compat_minor));
diff --git a/host/lib/usrp/x300/x300_io_impl.cpp b/host/lib/usrp/x300/x300_io_impl.cpp
index 334ae8168..e3515af0c 100644
--- a/host/lib/usrp/x300/x300_io_impl.cpp
+++ b/host/lib/usrp/x300/x300_io_impl.cpp
@@ -23,6 +23,7 @@
#include <uhd/transport/nirio_zero_copy.hpp>
#include "async_packet_handler.hpp"
#include <uhd/transport/bounded_buffer.hpp>
+#include <uhd/transport/chdr.hpp>
#include <boost/bind.hpp>
#include <uhd/utils/tasks.hpp>
#include <uhd/utils/log.hpp>
@@ -124,41 +125,6 @@ void x300_impl::update_subdev_spec(const std::string &tx_rx, const size_t mb_i,
/***********************************************************************
- * VITA stuff
- **********************************************************************/
-static void x300_if_hdr_unpack_be(
- const boost::uint32_t *packet_buff,
- vrt::if_packet_info_t &if_packet_info
-){
- if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR;
- return vrt::if_hdr_unpack_be(packet_buff, if_packet_info);
-}
-
-static void x300_if_hdr_pack_be(
- boost::uint32_t *packet_buff,
- vrt::if_packet_info_t &if_packet_info
-){
- if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR;
- return vrt::if_hdr_pack_be(packet_buff, if_packet_info);
-}
-
-static void x300_if_hdr_unpack_le(
- const boost::uint32_t *packet_buff,
- vrt::if_packet_info_t &if_packet_info
-){
- if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR;
- return vrt::if_hdr_unpack_le(packet_buff, if_packet_info);
-}
-
-static void x300_if_hdr_pack_le(
- boost::uint32_t *packet_buff,
- vrt::if_packet_info_t &if_packet_info
-){
- if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR;
- return vrt::if_hdr_pack_le(packet_buff, if_packet_info);
-}
-
-/***********************************************************************
* RX flow control handler
**********************************************************************/
static size_t get_rx_flow_control_window(size_t frame_size, size_t sw_buff_size, const device_addr_t& rx_args)
@@ -209,9 +175,9 @@ static void handle_rx_flowctrl(const boost::uint32_t sid, zero_copy_if::sptr xpo
//load header
if (big_endian)
- x300_if_hdr_pack_be(pkt, packet_info);
+ vrt::chdr::if_hdr_pack_be(pkt, packet_info);
else
- x300_if_hdr_pack_le(pkt, packet_info);
+ vrt::chdr::if_hdr_pack_le(pkt, packet_info);
//load payload
pkt[packet_info.num_header_words32+0] = uhd::htonx<boost::uint32_t>(0);
@@ -276,12 +242,12 @@ static void handle_tx_async_msgs(boost::shared_ptr<x300_tx_fc_guts_t> guts, zero
{
if (big_endian)
{
- x300_if_hdr_unpack_be(packet_buff, if_packet_info);
+ vrt::chdr::if_hdr_unpack_be(packet_buff, if_packet_info);
endian_conv = uhd::ntohx;
}
else
{
- x300_if_hdr_unpack_le(packet_buff, if_packet_info);
+ vrt::chdr::if_hdr_unpack_le(packet_buff, if_packet_info);
endian_conv = uhd::wtohx;
}
}
@@ -430,10 +396,10 @@ rx_streamer::sptr x300_impl::get_rx_stream(const uhd::stream_args_t &args_)
//init some streamer stuff
std::string conv_endianness;
if (mb.if_pkt_is_big_endian) {
- my_streamer->set_vrt_unpacker(&x300_if_hdr_unpack_be);
+ my_streamer->set_vrt_unpacker(&vrt::chdr::if_hdr_unpack_be);
conv_endianness = "be";
} else {
- my_streamer->set_vrt_unpacker(&x300_if_hdr_unpack_le);
+ my_streamer->set_vrt_unpacker(&vrt::chdr::if_hdr_unpack_le);
conv_endianness = "le";
}
@@ -594,10 +560,10 @@ tx_streamer::sptr x300_impl::get_tx_stream(const uhd::stream_args_t &args_)
std::string conv_endianness;
if (mb.if_pkt_is_big_endian) {
- my_streamer->set_vrt_packer(&x300_if_hdr_pack_be);
+ my_streamer->set_vrt_packer(&vrt::chdr::if_hdr_pack_be);
conv_endianness = "be";
} else {
- my_streamer->set_vrt_packer(&x300_if_hdr_pack_le);
+ my_streamer->set_vrt_packer(&vrt::chdr::if_hdr_pack_le);
conv_endianness = "le";
}
diff --git a/host/lib/usrp_clock/octoclock/octoclock_impl.cpp b/host/lib/usrp_clock/octoclock/octoclock_impl.cpp
index 8c207dd9f..d55fab10e 100644
--- a/host/lib/usrp_clock/octoclock/octoclock_impl.cpp
+++ b/host/lib/usrp_clock/octoclock/octoclock_impl.cpp
@@ -33,7 +33,7 @@
#include <uhd/usrp/gps_ctrl.hpp>
#include <uhd/usrp_clock/octoclock_eeprom.hpp>
#include <uhd/utils/byteswap.hpp>
-#include <uhd/utils/images.hpp>
+#include <uhd/utils/paths.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/utils/paths.hpp>
#include <uhd/utils/static.hpp>
@@ -420,7 +420,7 @@ std::string octoclock_impl::_get_images_help_message(const std::string &addr){
catch(const std::exception &e){
return str(boost::format("Could not find %s in your images path.\n%s")
% image_name
- % uhd::print_images_error());
+ % uhd::print_utility_error("uhd_images_downloader.py"));
}
//Get escape character
@@ -433,5 +433,5 @@ std::string octoclock_impl::_get_images_help_message(const std::string &addr){
//Get burner command
const std::string burner_path = (fs::path(uhd::get_pkg_path()) / "bin" / "octoclock_firmware_burner").string();
const std::string burner_cmd = str(boost::format("%s %s--addr=\"%s\"") % burner_path % ml % addr);
- return str(boost::format("%s\n%s") % uhd::print_images_error() % burner_cmd);
+ return str(boost::format("%s\n%s") % uhd::print_utility_error("uhd_images_downloader.py") % burner_cmd);
}
diff --git a/host/lib/utils/CMakeLists.txt b/host/lib/utils/CMakeLists.txt
index 106e2b650..369920ac1 100644
--- a/host/lib/utils/CMakeLists.txt
+++ b/host/lib/utils/CMakeLists.txt
@@ -132,7 +132,6 @@ SET_SOURCE_FILES_PROPERTIES(
LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/csv.cpp
${CMAKE_CURRENT_SOURCE_DIR}/gain_group.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/images.cpp
${CMAKE_CURRENT_SOURCE_DIR}/load_modules.cpp
${CMAKE_CURRENT_SOURCE_DIR}/log.cpp
${CMAKE_CURRENT_SOURCE_DIR}/msg.cpp
diff --git a/host/lib/utils/images.cpp b/host/lib/utils/images.cpp
deleted file mode 100644
index 1ba2f81e6..000000000
--- a/host/lib/utils/images.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// Copyright 2010-2012 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/images.hpp>
-#include <uhd/exception.hpp>
-#include <uhd/utils/paths.hpp>
-#include <boost/foreach.hpp>
-#include <boost/filesystem.hpp>
-#include <vector>
-#include <iostream>
-
-namespace fs = boost::filesystem;
-
-std::vector<fs::path> get_image_paths(void); //defined in paths.cpp
-
-/***********************************************************************
- * Find an image in the image paths
- **********************************************************************/
-std::string uhd::find_image_path(const std::string &image_name){
- 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();
- }
- throw uhd::io_error("Could not find path for image: " + image_name + "\n\n" + uhd::print_images_error());
-}
-
-std::string uhd::find_images_downloader(void){
- return fs::path(fs::path(uhd::get_pkg_path()) / UHD_LIB_DIR / "uhd" / "utils" / "uhd_images_downloader.py").string();
-}
-
-std::string uhd::print_images_error(void){
- #ifdef UHD_PLATFORM_WIN32
- return "As an Administrator, please run:\n\n\"" + find_images_downloader() + "\"";
- #else
- return "Please run:\n\nsudo \"" + find_images_downloader() + "\"";
- #endif
-}
diff --git a/host/lib/utils/paths.cpp b/host/lib/utils/paths.cpp
index 3e2bea1c6..282ebb566 100644
--- a/host/lib/utils/paths.cpp
+++ b/host/lib/utils/paths.cpp
@@ -17,15 +17,19 @@
#include <uhd/config.hpp>
#include <uhd/utils/paths.hpp>
-#include <boost/tokenizer.hpp>
+
+#include <boost/bind.hpp>
+#include <uhd/exception.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
-#include <boost/bind.hpp>
+#include <boost/tokenizer.hpp>
+
+#include <cstdio> //P_tmpdir
#include <cstdlib>
+#include <iostream>
#include <string>
#include <vector>
-#include <cstdlib> //getenv
-#include <cstdio> //P_tmpdir
+
#ifdef BOOST_MSVC
#define USE_GET_TEMP_PATH
#include <windows.h> //GetTempPath
@@ -136,3 +140,28 @@ std::string uhd::get_app_path(void){
return uhd::get_tmp_path();
}
+
+std::string uhd::find_image_path(const std::string &image_name){
+ 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();
+ }
+ throw uhd::io_error("Could not find path for image: " + image_name
+ + "\n\n" + uhd::print_utility_error("uhd_images_downloader.py"));
+}
+
+std::string uhd::find_utility(std::string name) {
+ return fs::path(fs::path(uhd::get_pkg_path()) / UHD_LIB_DIR / "uhd" / "utils" / name)
+ .string();
+}
+
+std::string uhd::print_utility_error(std::string name){
+ #ifdef UHD_PLATFORM_WIN32
+ return "As an Administrator, please run:\n\n\"" + find_utility(name) + "\"";
+ #else
+ return "Please run:\n\n \"" + find_utility(name) + "\"";
+ #endif
+}