aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
authorAshish Chaudhari <ashish@ettus.com>2015-04-30 18:02:02 -0700
committerAshish Chaudhari <ashish@ettus.com>2015-04-30 18:02:02 -0700
commitf2337d6fe0cca7337e0678d8f3ee31f657b608f2 (patch)
tree98c71da44375cc7c4a299e7ff1f2f70147526e8e /host
parenta7150e25f1ec5802963f44c5f748b211c6fcae8f (diff)
parentc6d0daaf034f3c1f20b8a0e6cd5c2555879760e2 (diff)
downloaduhd-f2337d6fe0cca7337e0678d8f3ee31f657b608f2.tar.gz
uhd-f2337d6fe0cca7337e0678d8f3ee31f657b608f2.tar.bz2
uhd-f2337d6fe0cca7337e0678d8f3ee31f657b608f2.zip
Merge branch 'master' into vivado
Diffstat (limited to 'host')
-rw-r--r--host/CMakeLists.txt19
-rw-r--r--host/docs/CMakeLists.txt24
-rw-r--r--host/docs/Doxyfile.in6
-rw-r--r--host/docs/mainpage.dox.in (renamed from host/docs/mainpage.dox)1
-rw-r--r--host/include/uhd/utils/paths.hpp2
-rw-r--r--host/lib/transport/libusb1_base.cpp1
-rw-r--r--host/lib/usrp/b200/b200_iface.hpp44
-rw-r--r--host/lib/usrp/b200/b200_impl.cpp138
-rw-r--r--host/lib/usrp/b200/b200_impl.hpp16
-rw-r--r--host/lib/usrp/b200/b200_io_impl.cpp57
-rw-r--r--host/lib/usrp/dboard/db_ubx.cpp2
-rw-r--r--host/lib/usrp/usrp2/fw_common.h3
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp25
-rw-r--r--host/lib/utils/paths.cpp6
-rw-r--r--host/utils/CMakeLists.txt2
-rw-r--r--host/utils/uhd_usrp_probe.cpp21
-rw-r--r--host/utils/usrp_x3xx_fpga_burner.cpp4
17 files changed, 264 insertions, 107 deletions
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt
index 8dddb6552..75635e415 100644
--- a/host/CMakeLists.txt
+++ b/host/CMakeLists.txt
@@ -24,7 +24,7 @@
# Project setup
########################################################################
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
-PROJECT(UHD CXX)
+PROJECT(UHD CXX C)
ENABLE_TESTING()
#make sure our local CMake Modules path comes first
@@ -284,8 +284,8 @@ UHD_INSTALL(FILES
#{{{IMG_SECTION
# This section is written automatically by /images/create_imgs_package.py
# Any manual changes in here will be overwritten.
-SET(UHD_IMAGES_MD5SUM "37d4899e320809951149c3670fb054ee")
-SET(UHD_IMAGES_DOWNLOAD_SRC "uhd-images_003.009.git-139-g3e3e236a.zip")
+SET(UHD_IMAGES_MD5SUM "4b30c563530a3339a1a1510762afe555")
+SET(UHD_IMAGES_DOWNLOAD_SRC "uhd-images_003.009.git-166-ged632e6a.zip")
#}}}
########################################################################
@@ -297,6 +297,19 @@ LIBUHD_REGISTER_COMPONENT("Utils" ENABLE_UTILS ON "ENABLE_LIBUHD" OFF)
LIBUHD_REGISTER_COMPONENT("Tests" ENABLE_TESTS ON "ENABLE_LIBUHD" OFF)
########################################################################
+# Check for fpga-src submodule
+########################################################################
+SET(HAS_FPGA_SUBMODULE FALSE)
+EXECUTE_PROCESS(
+ COMMAND ${PYTHON_EXECUTABLE} -c "import os; print os.path.abspath(os.path.join('${CMAKE_SOURCE_DIR}', '..', 'fpga-src'))"
+ OUTPUT_VARIABLE FPGA_SUBMODULE_DIR OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+message(STATUS ${FPGA_SUBMODULE_DIR})
+IF(EXISTS "${FPGA_SUBMODULE_DIR}/docs/fpga.md")
+ SET(HAS_FPGA_SUBMODULE TRUE)
+ENDIF(EXISTS "${FPGA_SUBMODULE_DIR}/docs/fpga.md")
+
+########################################################################
# Add the subdirectories
########################################################################
ADD_SUBDIRECTORY(docs)
diff --git a/host/docs/CMakeLists.txt b/host/docs/CMakeLists.txt
index 84ed88281..eb4b67c29 100644
--- a/host/docs/CMakeLists.txt
+++ b/host/docs/CMakeLists.txt
@@ -31,12 +31,34 @@ SET(ENABLE_MANUAL_OR_DOXYGEN false)
MESSAGE(STATUS "")
LIBUHD_REGISTER_COMPONENT("Manual" ENABLE_MANUAL ON "DOXYGEN_FOUND" OFF)
+# Check if fpga submodule is there. If yes:
+# - Add fpga-src/docs and fpga-src/README.md to inputs
+# - Add fpga-src docs dirs to strip?
+# If no:
+# - Make FPGA Manual reference link to our website
+
IF(ENABLE_MANUAL)
SET(ENABLE_MANUAL_OR_DOXYGEN true)
+ # First: Set up UHD manual only
FILE(GLOB manual_sources "*.dox")
SET(DOXYGEN_DEPENDENCIES ${manual_sources})
- SET(DOXYGEN_INPUT_DIRS ${CMAKE_SOURCE_DIR}/docs)
+ SET(DOXYGEN_INPUT_DIRS "${CMAKE_SOURCE_DIR}/docs")
SET(DOXYGEN_DEP_COMPONENT "manual")
+ SET(DOXYGEN_FPGA_MANUAL_REFERENCE "<a href=\"http://files.ettus.com/manual/page_fpga.html\">Part III: FPGA Manual</a>")
+ SET(DOXYGEN_STRIP_EXTRA "")
+ # Now, check if we have the FPGA sources as well.
+ # If so, pull them in:
+ IF(HAS_FPGA_SUBMODULE)
+ FILE(GLOB_RECURSE fpga_manual_sources "${FPGA_SUBMODULE_DIR}/docs/*.md")
+ LIST(APPEND manual_sources ${fpga_manual_sources})
+ SET(DOXYGEN_INPUT_DIRS "${DOXYGEN_INPUT_DIRS} ${FPGA_SUBMODULE_DIR}/docs")
+ SET(DOXYGEN_FPGA_MANUAL_REFERENCE "\\subpage md_fpga \"Part III: FPGA Manual\"")
+ SET(DOXYGEN_STRIP_EXTRA "${FPGA_SUBMODULE_DIR}/docs")
+ ENDIF(HAS_FPGA_SUBMODULE)
+ CONFIGURE_FILE(
+ ${CMAKE_CURRENT_SOURCE_DIR}/mainpage.dox.in
+ ${CMAKE_CURRENT_BINARY_DIR}/mainpage.dox
+ @ONLY)
ENDIF(ENABLE_MANUAL)
########################################################################
diff --git a/host/docs/Doxyfile.in b/host/docs/Doxyfile.in
index b0490c5c0..0f0a5cc27 100644
--- a/host/docs/Doxyfile.in
+++ b/host/docs/Doxyfile.in
@@ -132,7 +132,7 @@ FULL_PATH_NAMES = YES
# relative paths, which will be relative from the directory where doxygen is
# started.
-STRIP_FROM_PATH = @CMAKE_SOURCE_DIR@
+STRIP_FROM_PATH = @CMAKE_SOURCE_DIR@ @DOXYGEN_STRIP_EXTRA@
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
# the path mentioned in the documentation of a class, which tells
@@ -654,7 +654,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = @DOXYGEN_INPUT_DIRS@
+INPUT = @CMAKE_CURRENT_BINARY_DIR@/mainpage.dox @DOXYGEN_INPUT_DIRS@
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
@@ -672,7 +672,7 @@ INPUT_ENCODING = UTF-8
# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
# *.f90 *.f *.for *.vhd *.vhdl
-FILE_PATTERNS = *.hpp *.dox *.h *.ipp
+FILE_PATTERNS = *.hpp *.dox *.h *.ipp *.md
# The RECURSIVE tag can be used to turn specify whether or not subdirectories
# should be searched for input files as well. Possible values are YES and NO.
diff --git a/host/docs/mainpage.dox b/host/docs/mainpage.dox.in
index a12e62c9c..428650633 100644
--- a/host/docs/mainpage.dox
+++ b/host/docs/mainpage.dox.in
@@ -12,6 +12,7 @@ Follow these links to get to the section of the manual you wish to consult, or u
\li \subpage page_devices "Part I: Devices & Usage Manual"
\li \subpage page_uhd "Part II: UHD Development Manual"
+\li @DOXYGEN_FPGA_MANUAL_REFERENCE@
### Further Information
diff --git a/host/include/uhd/utils/paths.hpp b/host/include/uhd/utils/paths.hpp
index 8edb87546..aa31fd5a2 100644
--- a/host/include/uhd/utils/paths.hpp
+++ b/host/include/uhd/utils/paths.hpp
@@ -87,7 +87,7 @@ namespace uhd {
* The error string will include the full path to the utility to run.
* \return the message suggesting the use of the named utility.
*/
- UHD_API std::string print_utility_error(std::string name);
+ UHD_API std::string print_utility_error(const std::string &name, const std::string &args="");
} //namespace uhd
#endif /* INCLUDED_UHD_UTILS_PATHS_HPP */
diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp
index b1045ffa5..0baf8dc76 100644
--- a/host/lib/transport/libusb1_base.cpp
+++ b/host/lib/transport/libusb1_base.cpp
@@ -327,6 +327,7 @@ public:
bool firmware_loaded() {
return (get_manufacturer() == "Ettus Research LLC") or
+ (get_manufacturer() == "National Instruments Corp.") or
(get_manufacturer() == "Free Software Folks");
}
diff --git a/host/lib/usrp/b200/b200_iface.hpp b/host/lib/usrp/b200/b200_iface.hpp
index 1821865d3..1d123439a 100644
--- a/host/lib/usrp/b200/b200_iface.hpp
+++ b/host/lib/usrp/b200/b200_iface.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2012-2013 Ettus Research LLC
+// Copyright 2012-2013,2015 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,22 +21,48 @@
#include <stdint.h>
#include <uhd/transport/usb_control.hpp>
#include <uhd/types/serial.hpp> //i2c iface
+#include <uhd/types/dict.hpp>
+#include <boost/assign/list_of.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
#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;
+enum b200_type_t {
+ B200,
+ B210
+};
+
+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;
+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;
static const std::string B200_FW_FILE_NAME = "usrp_b200_fw.hex";
-static const std::string B200_FPGA_FILE_NAME = "usrp_b200_fpga.bin";
-static const std::string B210_FPGA_FILE_NAME = "usrp_b210_fpga.bin";
+
+//! Map the product ID (in the EEPROM) to a device type
+static const uhd::dict<boost::uint16_t, b200_type_t> B2X0_PRODUCT_ID = boost::assign::map_list_of
+ (0x0001, B200)
+ (0x7737, B200)
+ (B200_PRODUCT_NI_ID, B200)
+ (0x0002, B210)
+ (0x7738, B210)
+ (B210_PRODUCT_NI_ID, B210)
+;
+
+static const uhd::dict<b200_type_t, std::string> B2X0_STR_NAMES = boost::assign::map_list_of
+ (B200, "B200")
+ (B210, "B210")
+;
+
+static const uhd::dict<b200_type_t, std::string> B2X0_FPGA_FILE_NAME = boost::assign::map_list_of
+ (B200, "usrp_b200_fpga.bin")
+ (B210, "usrp_b210_fpga.bin")
+;
+
class UHD_API b200_iface: boost::noncopyable, public virtual uhd::i2c_iface {
public:
diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp
index afc21d031..2b423afa5 100644
--- a/host/lib/usrp/b200/b200_impl.cpp
+++ b/host/lib/usrp/b200/b200_impl.cpp
@@ -43,10 +43,6 @@ using namespace uhd::transport;
static const boost::posix_time::milliseconds REENUMERATION_TIMEOUT_MS(3000);
-//! mapping of frontend to radio perif index
-static const size_t FE1 = 1;
-static const size_t FE2 = 0;
-
class b200_ad9361_client_t : public ad9361_params {
public:
~b200_ad9361_client_t() {}
@@ -77,6 +73,24 @@ public:
/***********************************************************************
* Discovery
**********************************************************************/
+//! Look up the type of B-Series device we're currently running.
+// If the product ID stored in mb_eeprom is invalid, throws a
+// uhd::runtime_error.
+static b200_type_t get_b200_type(const mboard_eeprom_t &mb_eeprom)
+{
+ if (mb_eeprom["product"].empty()) {
+ throw uhd::runtime_error("B200: Missing product ID on EEPROM.");
+ }
+ boost::uint16_t product_id = boost::lexical_cast<boost::uint16_t>(mb_eeprom["product"]);
+ if (not B2X0_PRODUCT_ID.has_key(product_id)) {
+ throw uhd::runtime_error(str(
+ boost::format("B200 unknown product code: 0x%04x")
+ % product_id
+ ));
+ }
+ return B2X0_PRODUCT_ID[product_id];
+}
+
static device_addrs_t b200_find(const device_addr_t &hint)
{
device_addrs_t b200_addrs;
@@ -155,24 +169,14 @@ static device_addrs_t b200_find(const device_addr_t &hint)
new_addr["type"] = "b200";
new_addr["name"] = mb_eeprom["name"];
new_addr["serial"] = handle->get_serial();
- if (not mb_eeprom["product"].empty())
- {
- 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;
- //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;
- }
+ try {
+ // Turn the 16-Bit product ID into a string representation
+ new_addr["product"] = B2X0_STR_NAMES[get_b200_type(mb_eeprom)];
+ } catch (const uhd::runtime_error &e) {
+ // No problem if this fails -- this is just device discovery, after all.
+ UHD_MSG(error) << e.what() << std::endl;
+ // Skip this loop.
+ continue;
}
//this is a found b200 when the hint serial and name match or blank
if (
@@ -204,6 +208,7 @@ UHD_STATIC_BLOCK(register_b200_device)
* Structors
**********************************************************************/
b200_impl::b200_impl(const device_addr_t &device_addr) :
+ _revision(0),
_tick_rate(0.0) // Forces a clock initialization at startup
{
_tree = property_tree::make();
@@ -282,36 +287,55 @@ b200_impl::b200_impl(const device_addr_t &device_addr) :
.subscribe(boost::bind(&b200_impl::set_mb_eeprom, this, _1));
////////////////////////////////////////////////////////////////////
- // Load the FPGA image, then reset GPIF
+ // Identify the device type
////////////////////////////////////////////////////////////////////
std::string default_file_name;
- std::string product_name = "B200?";
- if (not mb_eeprom["product"].empty())
- {
- 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;
- //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;
- default: UHD_MSG(error) << "B200 unknown product code: " << mb_eeprom["product"] << std::endl;
+ std::string product_name;
+ try {
+ // This will throw if the product ID is invalid:
+ _b200_type = get_b200_type(mb_eeprom);
+ default_file_name = B2X0_FPGA_FILE_NAME.get(_b200_type);
+ product_name = B2X0_STR_NAMES.get(_b200_type);
+ } catch (const uhd::runtime_error &e) {
+ // The only reason we may let this pass is if the user specified
+ // the FPGA file name:
+ if (not device_addr.has_key("fpga")) {
+ throw e;
}
+ // In this case, we must provide a default product name:
+ product_name = "B200?";
+ _b200_type = B200;
}
- if (default_file_name.empty())
- {
- UHD_ASSERT_THROW(device_addr.has_key("fpga"));
+ if (not mb_eeprom["revision"].empty()) {
+ _revision = boost::lexical_cast<size_t>(mb_eeprom["revision"]);
+ }
+
+ ////////////////////////////////////////////////////////////////////
+ // Set up frontend mapping
+ ////////////////////////////////////////////////////////////////////
+ // Explanation: The AD9361 has 2 frontends, FE1 and FE2.
+ // On the B210 FE1 maps to the B-side (or radio 1), and FE2 maps
+ // to the A-side (or radio 0). So, logically, the radios are swapped
+ // between the host side and the AD9361-side.
+ // B200 is more complicated: On Revs <= 4, the A-side is connected,
+ // which means FE2 is used (like B210). On Revs >= 5, the left side
+ // ("B-side") is connected, because these revs use an AD9364, which
+ // does not have an FE2, so we don't swap FEs.
+
+ // Swapped setup:
+ _fe1 = 1;
+ _fe2 = 0;
+ _gpio_state.swap_atr = 1;
+ // Unswapped setup:
+ if (_b200_type == B200 and _revision >= 5) {
+ _fe1 = 0; //map radio0 to FE1
+ _fe2 = 1; //map radio1 to FE2
+ _gpio_state.swap_atr = 0; // ATRs for radio0 are mapped to FE1
}
+ ////////////////////////////////////////////////////////////////////
+ // Load the FPGA image, then reset GPIF
+ ////////////////////////////////////////////////////////////////////
//extract the FPGA path for the B200
std::string b200_fpga_image = find_image_path(
device_addr.has_key("fpga")? device_addr["fpga"] : default_file_name
@@ -364,7 +388,6 @@ b200_impl::b200_impl(const device_addr_t &device_addr) :
/* Initialize the GPIOs, set the default bandsels to the lower range. Note
* that calling update_bandsel calls update_gpio_state(). */
- _gpio_state = gpio_state();
update_bandsel("RX", 800e6);
update_bandsel("TX", 850e6);
@@ -481,9 +504,11 @@ b200_impl::b200_impl(const device_addr_t &device_addr) :
_tree->create<std::vector<size_t> >(mb_path / "rx_chan_dsp_mapping").set(default_map);
_tree->create<std::vector<size_t> >(mb_path / "tx_chan_dsp_mapping").set(default_map);
_tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec")
+ .coerce(boost::bind(&b200_impl::coerce_subdev_spec, this, _1))
.set(subdev_spec_t())
.subscribe(boost::bind(&b200_impl::update_subdev_spec, this, "rx", _1));
_tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec")
+ .coerce(boost::bind(&b200_impl::coerce_subdev_spec, this, _1))
.set(subdev_spec_t())
.subscribe(boost::bind(&b200_impl::update_subdev_spec, this, "tx", _1));
@@ -695,7 +720,7 @@ void b200_impl::setup_radio(const size_t dspno)
for(size_t direction = 0; direction < 2; direction++)
{
const std::string x = direction? "rx" : "tx";
- const std::string key = std::string((direction? "RX" : "TX")) + std::string(((dspno == FE1)? "1" : "2"));
+ const std::string key = std::string((direction? "RX" : "TX")) + std::string(((dspno == _fe1)? "1" : "2"));
const fs_path rf_fe_path = mb_path / "dboards" / "A" / (x+"_frontends") / (dspno? "B" : "A");
_tree->create<std::string>(rf_fe_path / "name").set("FE-"+key);
@@ -1024,6 +1049,7 @@ void b200_impl::update_bandsel(const std::string& which, double freq)
void b200_impl::update_gpio_state(void)
{
const boost::uint32_t misc_word = 0
+ | (_gpio_state.swap_atr << 8)
| (_gpio_state.tx_bandsel_a << 7)
| (_gpio_state.tx_bandsel_b << 6)
| (_gpio_state.rx_bandsel_a << 5)
@@ -1048,9 +1074,9 @@ void b200_impl::reset_codec_dcm(void)
void b200_impl::update_atrs(void)
{
- if (_radio_perifs.size() > FE1 and _radio_perifs[FE1].atr)
+ if (_radio_perifs.size() > _fe1 and _radio_perifs[_fe1].atr)
{
- radio_perifs_t &perif = _radio_perifs[FE1];
+ radio_perifs_t &perif = _radio_perifs[_fe1];
const bool enb_rx = bool(perif.rx_streamer.lock());
const bool enb_tx = bool(perif.tx_streamer.lock());
const bool is_rx2 = perif.ant_rx2;
@@ -1066,9 +1092,9 @@ void b200_impl::update_atrs(void)
atr->set_atr_reg(dboard_iface::ATR_REG_TX_ONLY, txonly);
atr->set_atr_reg(dboard_iface::ATR_REG_FULL_DUPLEX, fd);
}
- if (_radio_perifs.size() > FE2 and _radio_perifs[FE2].atr)
+ if (_radio_perifs.size() > _fe2 and _radio_perifs[_fe2].atr)
{
- radio_perifs_t &perif = _radio_perifs[FE2];
+ radio_perifs_t &perif = _radio_perifs[_fe2];
const bool enb_rx = bool(perif.rx_streamer.lock());
const bool enb_tx = bool(perif.tx_streamer.lock());
const bool is_rx2 = perif.ant_rx2;
@@ -1096,10 +1122,10 @@ void b200_impl::update_antenna_sel(const size_t which, const std::string &ant)
void b200_impl::update_enables(void)
{
//extract settings from state variables
- const bool enb_tx1 = (_radio_perifs.size() > FE1) and bool(_radio_perifs[FE1].tx_streamer.lock());
- const bool enb_rx1 = (_radio_perifs.size() > FE1) and bool(_radio_perifs[FE1].rx_streamer.lock());
- const bool enb_tx2 = (_radio_perifs.size() > FE2) and bool(_radio_perifs[FE2].tx_streamer.lock());
- const bool enb_rx2 = (_radio_perifs.size() > FE2) and bool(_radio_perifs[FE2].rx_streamer.lock());
+ const bool enb_tx1 = (_radio_perifs.size() > _fe1) and bool(_radio_perifs[_fe1].tx_streamer.lock());
+ const bool enb_rx1 = (_radio_perifs.size() > _fe1) and bool(_radio_perifs[_fe1].rx_streamer.lock());
+ const bool enb_tx2 = (_radio_perifs.size() > _fe2) and bool(_radio_perifs[_fe2].tx_streamer.lock());
+ const bool enb_rx2 = (_radio_perifs.size() > _fe2) and bool(_radio_perifs[_fe2].rx_streamer.lock());
const size_t num_rx = (enb_rx1?1:0) + (enb_rx2?1:0);
const size_t num_tx = (enb_tx1?1:0) + (enb_tx2?1:0);
const bool mimo = num_rx == 2 or num_tx == 2;
diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp
index b68293109..f5a7b62e9 100644
--- a/host/lib/usrp/b200/b200_impl.hpp
+++ b/host/lib/usrp/b200/b200_impl.hpp
@@ -47,7 +47,7 @@
#include "recv_packet_demuxer_3000.hpp"
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 = 5;
+static const boost::uint16_t B200_FPGA_COMPAT_NUM = 7;
static const double B200_BUS_CLOCK_RATE = 100e6;
static const double B200_DEFAULT_TICK_RATE = 32e6;
static const double B200_DEFAULT_FREQ = 100e6; // Hz
@@ -107,6 +107,9 @@ public:
void check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const std::string &direction = "");
private:
+ b200_type_t _b200_type;
+ size_t _revision;
+
//controllers
b200_iface::sptr _iface;
radio_ctrl_core_3000::sptr _local_ctrl;
@@ -143,6 +146,7 @@ private:
void set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &);
void check_fw_compat(void);
void check_fpga_compat(void);
+ uhd::usrp::subdev_spec_t coerce_subdev_spec(const uhd::usrp::subdev_spec_t &);
void update_subdev_spec(const std::string &tx_rx, const uhd::usrp::subdev_spec_t &);
void update_time_source(const std::string &);
void update_clock_source(const std::string &);
@@ -168,6 +172,13 @@ private:
};
std::vector<radio_perifs_t> _radio_perifs;
+ //mapping of AD936x frontends (FE1 and FE2) to radio perif index (0 and 1)
+ //FE1 corresponds to the ports labeled "RF B" on the B200/B210
+ //FE2 corresponds to the ports labeled "RF A" on the B200/B210
+ //the mapping is product and revision specific
+ size_t _fe1;
+ size_t _fe2;
+
/*! \brief Setup the DSP chain for one radio front-end.
*
*/
@@ -175,7 +186,7 @@ private:
void handle_overflow(const size_t radio_index);
struct gpio_state {
- boost::uint32_t tx_bandsel_a, tx_bandsel_b, rx_bandsel_a, rx_bandsel_b, rx_bandsel_c, codec_arst, mimo, ref_sel;
+ boost::uint32_t tx_bandsel_a, tx_bandsel_b, rx_bandsel_a, rx_bandsel_b, rx_bandsel_c, codec_arst, mimo, ref_sel, swap_atr;
gpio_state() {
tx_bandsel_a = 0;
@@ -186,6 +197,7 @@ private:
codec_arst = 0;
mimo = 0;
ref_sel = 0;
+ swap_atr = 0;
}
} _gpio_state;
diff --git a/host/lib/usrp/b200/b200_io_impl.cpp b/host/lib/usrp/b200/b200_io_impl.cpp
index d6df726af..61bcc5f64 100644
--- a/host/lib/usrp/b200/b200_io_impl.cpp
+++ b/host/lib/usrp/b200/b200_io_impl.cpp
@@ -81,6 +81,7 @@ void b200_impl::set_auto_tick_rate(
if (num_chans == 0) { // Divine them
num_chans = std::max(size_t(1), max_chan_count());
}
+ const double max_tick_rate = ad9361_device_t::AD9361_MAX_CLOCK_RATE/num_chans;
// See also the doxygen documentation for these steps in b200_impl.hpp
// Step 1: Obtain LCM and max rate from all relevant dsps
@@ -94,6 +95,13 @@ void b200_impl::set_auto_tick_rate(
continue;
}
double this_dsp_rate = _tree->access<double>(dsp_path / "rate/value").get();
+ // Check if the user selected something completely unreasonable:
+ if (this_dsp_rate > max_tick_rate) {
+ throw uhd::value_error(str(
+ boost::format("Requested sampling rate (%.2f Msps) exceeds maximum tick rate of %.2f MHz.")
+ % (this_dsp_rate / 1e6) % (max_tick_rate / 1e6)
+ ));
+ }
// 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).
@@ -118,7 +126,6 @@ void b200_impl::set_auto_tick_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 = ad9361_device_t::AD9361_MAX_CLOCK_RATE/num_chans;
double base_rate = static_cast<double>(lcm_rate);
if (base_rate > max_tick_rate) {
UHD_MSG(warning)
@@ -175,10 +182,19 @@ void b200_impl::update_tick_rate(const double new_tick_rate)
}
}
+#define CHECK_RATE_AND_THROW(rate) \
+ if (rate >ad9361_device_t::AD9361_MAX_CLOCK_RATE ) { \
+ throw uhd::value_error(str( \
+ boost::format("Requested sampling rate (%.2f Msps) exceeds maximum tick rate.") \
+ % (rate / 1e6) \
+ )); \
+ }
+
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()) {
+ CHECK_RATE_AND_THROW(rx_rate);
const std::string dsp_path = (boost::format("/mboards/0/rx_dsps/%s") % dspno).str();
set_auto_tick_rate(rx_rate, dsp_path);
}
@@ -208,6 +224,7 @@ double b200_impl::coerce_tx_samp_rate(tx_dsp_core_3000::sptr duc, size_t dspno,
{
// 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()) {
+ CHECK_RATE_AND_THROW(tx_rate);
const std::string dsp_path = (boost::format("/mboards/0/tx_dsps/%s") % dspno).str();
set_auto_tick_rate(tx_rate, dsp_path);
}
@@ -228,29 +245,31 @@ void b200_impl::update_tx_samp_rate(const size_t dspno, const double rate)
/***********************************************************************
* frontend selection
**********************************************************************/
+uhd::usrp::subdev_spec_t b200_impl::coerce_subdev_spec(const uhd::usrp::subdev_spec_t &spec_)
+{
+ uhd::usrp::subdev_spec_t spec = spec_;
+ // Because of the confusing nature of the subdevs on B200
+ // with different revs, we provide a convenience override,
+ // where both A:A and A:B are mapped to A:A.
+ //
+ // Any other spec is probably illegal and will be caught by
+ // validate_subdev_spec().
+ if (spec.size() and _b200_type == B200 and spec[0].sd_name == "B") {
+ spec[0].sd_name = "A";
+ }
+ return spec;
+}
+
void b200_impl::update_subdev_spec(const std::string &tx_rx, const uhd::usrp::subdev_spec_t &spec)
{
//sanity checking
- if (spec.size()) validate_subdev_spec(_tree, spec, tx_rx);
- UHD_ASSERT_THROW(spec.size() <= _radio_perifs.size());
-
- if (spec.size() >= 1)
- {
- UHD_ASSERT_THROW(spec[0].db_name == "A");
- UHD_ASSERT_THROW(spec[0].sd_name == "A" or spec[0].sd_name == "B");
- }
- if (spec.size() == 2)
- {
- UHD_ASSERT_THROW(spec[1].db_name == "A");
- UHD_ASSERT_THROW(
- (spec[0].sd_name == "A" and spec[1].sd_name == "B") or
- (spec[0].sd_name == "B" and spec[1].sd_name == "A")
- );
+ if (spec.size()) {
+ validate_subdev_spec(_tree, spec, tx_rx);
}
std::vector<size_t> chan_to_dsp_map(spec.size(), 0);
for (size_t i = 0; i < spec.size(); i++) {
- chan_to_dsp_map[i] = (spec[i].sd_name == "A") ? 0 : 1;
+ chan_to_dsp_map[i] = (spec[i].sd_name == "A") ? 0 : 1;
}
_tree->access<std::vector<size_t> >("/mboards/0" / (tx_rx + "_chan_dsp_mapping")).set(chan_to_dsp_map);
@@ -300,7 +319,7 @@ boost::optional<uhd::msg_task::msg_type_t> b200_impl::handle_async_task(
{
managed_recv_buffer::sptr buff = xport->get_recv_buff();
if (not buff or buff->size() < 8)
- return NULL;
+ return uhd::msg_task::msg_type_t(0, uhd::msg_task::msg_payload_t());
const boost::uint32_t sid = uhd::wtohx(buff->cast<const boost::uint32_t *>()[1]);
switch (sid) {
@@ -364,7 +383,7 @@ boost::optional<uhd::msg_task::msg_type_t> b200_impl::handle_async_task(
default:
UHD_MSG(error) << "Got a ctrl packet with unknown SID " << sid << std::endl;
}
- return NULL;
+ return uhd::msg_task::msg_type_t(0, uhd::msg_task::msg_payload_t());
}
/***********************************************************************
diff --git a/host/lib/usrp/dboard/db_ubx.cpp b/host/lib/usrp/dboard/db_ubx.cpp
index 1e79c14b0..7cb4b2d6b 100644
--- a/host/lib/usrp/dboard/db_ubx.cpp
+++ b/host/lib/usrp/dboard/db_ubx.cpp
@@ -266,6 +266,8 @@ public:
}
// Enable the reference clocks that we need
+ _rx_target_pfd_freq = pfd_freq_max;
+ _tx_target_pfd_freq = pfd_freq_max;
if (_rev >= 1)
{
// set dboard clock rates to as close to the max PFD freq as possible
diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h
index cfaee0ddc..81dd3523e 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -30,7 +30,8 @@ extern "C" {
#endif
//fpga and firmware compatibility numbers
-#define USRP2_FPGA_COMPAT_NUM 11
+#define USRP2_FPGA_COMPAT_NUM 10
+#define N200_FPGA_COMPAT_NUM 11
#define USRP2_FW_COMPAT_NUM 12
#define USRP2_FW_VER_MINOR 4
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 50b8431a1..1acc1dad3 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -395,14 +395,35 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr) :
fpga_major = fpga_minor;
fpga_minor = 0;
}
- if (fpga_major != USRP2_FPGA_COMPAT_NUM){
+ int expected_fpga_compat_num = std::min(USRP2_FPGA_COMPAT_NUM, N200_FPGA_COMPAT_NUM);
+ switch (_mbc[mb].iface->get_rev())
+ {
+ case usrp2_iface::USRP2_REV3:
+ case usrp2_iface::USRP2_REV4:
+ expected_fpga_compat_num = USRP2_FPGA_COMPAT_NUM;
+ break;
+ case usrp2_iface::USRP_N200:
+ case usrp2_iface::USRP_N200_R4:
+ case usrp2_iface::USRP_N210:
+ case usrp2_iface::USRP_N210_R4:
+ expected_fpga_compat_num = N200_FPGA_COMPAT_NUM;
+ break;
+ default:
+ // handle case where the MB EEPROM is not programmed
+ if (fpga_major == USRP2_FPGA_COMPAT_NUM or fpga_major == N200_FPGA_COMPAT_NUM)
+ {
+ UHD_MSG(warning) << "Unable to identify device - assuming USRP2/N-Series device" << std::endl;
+ expected_fpga_compat_num = fpga_major;
+ }
+ }
+ if (fpga_major != expected_fpga_compat_num){
throw uhd::runtime_error(str(boost::format(
"\nPlease update the firmware and FPGA images for your device.\n"
"See the application notes for USRP2/N-Series for instructions.\n"
"Expected FPGA compatibility number %d, but got %d:\n"
"The FPGA build is not compatible with the host code build.\n"
"%s\n"
- ) % int(USRP2_FPGA_COMPAT_NUM) % fpga_major % _mbc[mb].iface->images_warn_help_message()));
+ ) % expected_fpga_compat_num % fpga_major % _mbc[mb].iface->images_warn_help_message()));
}
_tree->create<std::string>(mb_path / "fpga_version").set(str(boost::format("%u.%u") % fpga_major % fpga_minor));
diff --git a/host/lib/utils/paths.cpp b/host/lib/utils/paths.cpp
index f29318ddd..a9c9965c8 100644
--- a/host/lib/utils/paths.cpp
+++ b/host/lib/utils/paths.cpp
@@ -367,10 +367,10 @@ std::string uhd::find_utility(std::string name) {
.string();
}
-std::string uhd::print_utility_error(std::string name){
+std::string uhd::print_utility_error(const std::string &name, const std::string &args){
#ifdef UHD_PLATFORM_WIN32
- return "As an Administrator, please run:\n\n\"" + find_utility(name) + "\"";
+ return "As an Administrator, please run:\n\n\"" + find_utility(name) + args + "\"";
#else
- return "Please run:\n\n \"" + find_utility(name) + "\"";
+ return "Please run:\n\n \"" + find_utility(name) + (args.empty() ? "" : (" " + args)) + "\"";
#endif
}
diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt
index ed8640187..e24b417c1 100644
--- a/host/utils/CMakeLists.txt
+++ b/host/utils/CMakeLists.txt
@@ -15,8 +15,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-SET(CMAKE_C_COMPILE_OBJECT ${CMAKE_CXX_COMPILE_OBJECT})
-
########################################################################
# Utilities that get installed into the runtime path
########################################################################
diff --git a/host/utils/uhd_usrp_probe.cpp b/host/utils/uhd_usrp_probe.cpp
index a03646cc0..f8a8b5665 100644
--- a/host/utils/uhd_usrp_probe.cpp
+++ b/host/utils/uhd_usrp_probe.cpp
@@ -192,7 +192,10 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("version", "print the version string and exit")
("args", po::value<std::string>()->default_value(""), "device address args")
("tree", "specify to print a complete property tree")
- ("string", po::value<std::string>(), "query a string value from the properties tree")
+ ("string", po::value<std::string>(), "query a string value from the property tree")
+ ("double", po::value<std::string>(), "query a double precision floating point value from the property tree")
+ ("int", po::value<std::string>(), "query a integer value from the property tree")
+ ("range", po::value<std::string>(), "query a range (gain, bandwidth, frequency, ...) from the property tree")
("init-only", "skip all queries, only initialize device")
;
@@ -219,6 +222,22 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
return EXIT_SUCCESS;
}
+ if (vm.count("double")){
+ std::cout << tree->access<double>(vm["double"].as<std::string>()).get() << std::endl;
+ return EXIT_SUCCESS;
+ }
+
+ if (vm.count("int")){
+ std::cout << tree->access<int>(vm["int"].as<std::string>()).get() << std::endl;
+ return EXIT_SUCCESS;
+ }
+
+ if (vm.count("range")){
+ meta_range_t range = tree->access<meta_range_t>(vm["range"].as<std::string>()).get();
+ std::cout << boost::format("%.1f:%.1f:%.1f") % range.start() % range.step() % range.stop() << std::endl;
+ return EXIT_SUCCESS;
+ }
+
if (vm.count("tree") != 0) print_tree("/", tree);
else if (not vm.count("init-only")) std::cout << make_border(get_device_pp_string(tree)) << std::endl;
diff --git a/host/utils/usrp_x3xx_fpga_burner.cpp b/host/utils/usrp_x3xx_fpga_burner.cpp
index e32e4d636..3c6225531 100644
--- a/host/utils/usrp_x3xx_fpga_burner.cpp
+++ b/host/utils/usrp_x3xx_fpga_burner.cpp
@@ -49,13 +49,9 @@
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/safe_call.hpp>
-#ifdef _MSC_VER
extern "C" {
-#endif
#include "cdecode.h"
-#ifdef _MSC_VER
}
-#endif
#define X300_FPGA_BIN_SIZE_BYTES 15877916
#define X300_FPGA_BIT_MAX_SIZE_BYTES 15878022