summaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
Diffstat (limited to 'host')
-rw-r--r--host/.gitignore2
-rw-r--r--host/AUTHORS.txt40
-rw-r--r--host/CMakeLists.txt11
-rw-r--r--host/LICENSE (renamed from host/LICENSE.txt)0
-rw-r--r--host/README.txt43
-rw-r--r--host/apps/omap_debug/README1
-rw-r--r--host/cmake/Modules/FindUSB1.cmake3
-rw-r--r--host/cmake/Modules/UHDPackage.cmake5
-rw-r--r--host/cmake/Modules/UHDUnitTest.cmake6
-rw-r--r--host/cmake/Modules/UHDVersion.cmake6
-rw-r--r--host/cmake/Toolchains/armv7athf_native.cmake8
-rw-r--r--host/cmake/Toolchains/oe-sdk_cross.cmake13
-rw-r--r--host/docs/CMakeLists.txt1
-rw-r--r--host/docs/build.rst6
-rw-r--r--host/docs/gpsdo.rst2
-rw-r--r--host/docs/gpsdo_b2x0.rst80
-rw-r--r--host/docs/index.rst3
-rw-r--r--host/docs/uhd_find_devices.13
-rw-r--r--host/docs/uhd_images_downloader.13
-rw-r--r--host/docs/uhd_usrp_probe.12
-rw-r--r--host/examples/network_relay.cpp20
-rw-r--r--host/examples/rx_samples_to_file.cpp4
-rw-r--r--host/examples/test_dboard_coercion.cpp18
-rw-r--r--host/examples/test_messages.cpp5
-rw-r--r--host/include/uhd/config.hpp3
-rw-r--r--host/include/uhd/transport/usb_device_handle.hpp6
-rw-r--r--host/include/uhd/transport/zero_copy.hpp5
-rw-r--r--host/include/uhd/types/CMakeLists.txt1
-rw-r--r--host/include/uhd/types/wb_iface.hpp (renamed from host/lib/usrp/cores/wb_iface.hpp)15
-rw-r--r--host/include/uhd/utils/CMakeLists.txt1
-rw-r--r--host/include/uhd/utils/atomic.hpp4
-rw-r--r--host/include/uhd/utils/msg_task.hpp74
-rw-r--r--host/include/uhd/utils/tasks.hpp1
-rw-r--r--host/lib/convert/convert_fc32_item32.cpp17
-rw-r--r--host/lib/convert/convert_pack_sc12.cpp2
-rw-r--r--host/lib/convert/convert_unpack_sc12.cpp63
-rw-r--r--host/lib/convert/sse2_fc32_to_sc16.cpp38
-rw-r--r--host/lib/convert/sse2_sc16_to_fc32.cpp38
-rw-r--r--host/lib/transport/libusb1_base.cpp23
-rw-r--r--host/lib/transport/libusb1_zero_copy.cpp99
-rw-r--r--host/lib/transport/super_recv_packet_handler.hpp3
-rw-r--r--host/lib/transport/super_send_packet_handler.hpp2
-rw-r--r--host/lib/transport/udp_zero_copy.cpp3
-rw-r--r--host/lib/types/CMakeLists.txt3
-rw-r--r--host/lib/types/tune.cpp7
-rw-r--r--host/lib/types/wb_iface.cpp (renamed from host/lib/usrp/cores/wb_iface.cpp)7
-rw-r--r--host/lib/usrp/README15
-rw-r--r--host/lib/usrp/b100/b100_impl.cpp6
-rw-r--r--host/lib/usrp/b100/b100_impl.hpp2
-rw-r--r--host/lib/usrp/b100/usb_zero_copy_wrapper.cpp1
-rw-r--r--host/lib/usrp/b200/b200_iface.cpp314
-rw-r--r--host/lib/usrp/b200/b200_iface.hpp18
-rw-r--r--host/lib/usrp/b200/b200_impl.cpp21
-rw-r--r--host/lib/usrp/b200/b200_impl.hpp16
-rw-r--r--host/lib/usrp/b200/b200_io_impl.cpp34
-rw-r--r--host/lib/usrp/common/fifo_ctrl_excelsior.hpp5
-rw-r--r--host/lib/usrp/common/fx2_ctrl.cpp6
-rw-r--r--host/lib/usrp/cores/CMakeLists.txt1
-rw-r--r--host/lib/usrp/cores/gpio_core_200.hpp6
-rw-r--r--host/lib/usrp/cores/i2c_core_100.hpp4
-rw-r--r--host/lib/usrp/cores/i2c_core_100_wb32.hpp4
-rw-r--r--host/lib/usrp/cores/i2c_core_200.hpp4
-rw-r--r--host/lib/usrp/cores/radio_ctrl_core_3000.cpp130
-rw-r--r--host/lib/usrp/cores/radio_ctrl_core_3000.hpp7
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_200.cpp5
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_200.hpp4
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_3000.cpp5
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_3000.hpp4
-rw-r--r--host/lib/usrp/cores/rx_frontend_core_200.cpp4
-rw-r--r--host/lib/usrp/cores/rx_frontend_core_200.hpp4
-rw-r--r--host/lib/usrp/cores/rx_vita_core_3000.hpp4
-rw-r--r--host/lib/usrp/cores/spi_core_100.hpp4
-rw-r--r--host/lib/usrp/cores/spi_core_3000.hpp4
-rw-r--r--host/lib/usrp/cores/time64_core_200.cpp1
-rw-r--r--host/lib/usrp/cores/time64_core_200.hpp4
-rw-r--r--host/lib/usrp/cores/time_core_3000.hpp4
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_200.cpp3
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_200.hpp4
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_3000.cpp3
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_3000.hpp4
-rw-r--r--host/lib/usrp/cores/tx_frontend_core_200.cpp2
-rw-r--r--host/lib/usrp/cores/tx_frontend_core_200.hpp4
-rw-r--r--host/lib/usrp/cores/tx_vita_core_3000.hpp4
-rw-r--r--host/lib/usrp/cores/user_settings_core_200.cpp2
-rw-r--r--host/lib/usrp/cores/user_settings_core_200.hpp4
-rw-r--r--host/lib/usrp/dboard/db_dbsrx.cpp22
-rw-r--r--host/lib/usrp/dboard/db_dbsrx2.cpp6
-rw-r--r--host/lib/usrp/dboard/db_sbx_common.cpp132
-rw-r--r--host/lib/usrp/dboard/db_sbx_common.hpp28
-rw-r--r--host/lib/usrp/dboard/db_sbx_version3.cpp118
-rw-r--r--host/lib/usrp/dboard/db_sbx_version4.cpp120
-rw-r--r--host/lib/usrp/dboard/db_tvrx.cpp2
-rw-r--r--host/lib/usrp/dboard/db_wbx_common.hpp2
-rw-r--r--host/lib/usrp/e100/e100_impl.hpp2
-rw-r--r--host/lib/usrp/gps_ctrl.cpp2
-rw-r--r--host/lib/usrp/usrp1/io_impl.cpp2
-rw-r--r--host/lib/usrp/usrp1/usrp1_iface.cpp12
-rw-r--r--host/lib/usrp/usrp1/usrp1_iface.hpp7
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.cpp8
-rw-r--r--host/lib/usrp/usrp2/usrp2_clk_regs.hpp14
-rw-r--r--host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp5
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp2
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.hpp7
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp4
-rw-r--r--host/lib/utils/paths.cpp27
-rw-r--r--host/lib/utils/tasks.cpp99
-rw-r--r--host/tests/sph_recv_test.cpp8
-rw-r--r--host/tests/time_spec_test.cpp2
-rw-r--r--host/utils/CMakeLists.txt2
-rw-r--r--host/utils/b2xx_fx3_utils.cpp943
-rw-r--r--host/utils/uhd_images_downloader.py.in412
-rw-r--r--host/utils/usrp_burn_mb_eeprom.cpp43
-rw-r--r--host/utils/usrp_n2xx_simple_net_burner.cpp12
113 files changed, 2055 insertions, 1359 deletions
diff --git a/host/.gitignore b/host/.gitignore
index 796b96d1c..9b0584c23 100644
--- a/host/.gitignore
+++ b/host/.gitignore
@@ -1 +1,3 @@
/build
+tags
+*~
diff --git a/host/AUTHORS.txt b/host/AUTHORS.txt
deleted file mode 100644
index 44b7516cd..000000000
--- a/host/AUTHORS.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-Matt Ettus - matt@ettus.com
- USRP1 FPGA code
- USRP2/N200 FPGA code
- USRP-E100 FPGA code
-
-Josh Blum - josh@ettus.com
- driver framework
- USRP2/N200 firmware
- USRP2/N200 host code
- USRP-E100 host code
- Basic/LF host code
- XCVR2450 host code
- RFX Series host code
-
-Jason Abele - jason@ettus.com
- RFX Series host code
- WBX host code
- DBSRX host code
- DBSRX2 host code
-
-Eric Blossom - eb@comsec.com
- USRP1 firmware
- USRP2 firmware
-
-Tom Tsou - ttsou@vt.edu
- UHD-USB framework
- LIBUSB host code
- USRP1 host code
- USRP1 firmware
-
-Nick Foster - nick@ettus.com
- LIBUSB host code
- USRP1 host code
- TVRX host code
- USRP-N200 firmware
- USRP-N200 host code
-
-Philip Balister - philip@opensdr.com
- USRP-E100 kernel module
- USRP-E100 utilities
diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt
index d5301bce3..103266edd 100644
--- a/host/CMakeLists.txt
+++ b/host/CMakeLists.txt
@@ -201,9 +201,8 @@ ADD_CUSTOM_TARGET(uninstall
# Install Package Docs
########################################################################
UHD_INSTALL(FILES
- ${CMAKE_CURRENT_SOURCE_DIR}/README.txt
- ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt
- ${CMAKE_CURRENT_SOURCE_DIR}/AUTHORS.txt
+ ${CMAKE_CURRENT_SOURCE_DIR}/../README.md
+ ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE
DESTINATION ${PKG_DOC_DIR}
COMPONENT readme
)
@@ -212,8 +211,8 @@ UHD_INSTALL(FILES
# Images download directory for utils/uhd_images_downloader.py
########################################################################
-SET(UHD_IMAGES_MD5SUM "3da7fc23661b7e612815dcae1ac95efa")
-SET(UHD_IMAGES_DOWNLOAD_SRC "http://files.ettus.com/binaries/master_images/archive/uhd-images_003.005.003-159-g0159006c.zip")
+SET(UHD_IMAGES_MD5SUM "61db1170aaaadd787f5150b3eceab6f2")
+SET(UHD_IMAGES_DOWNLOAD_SRC "http://files.ettus.com/binaries/maint_images/archive/uhd-images_003.006.002-rc1.zip")
########################################################################
# Register top level components
@@ -285,7 +284,7 @@ ENDIF(NOT LIBUHD_PKG AND NOT UHDHOST_PKG)
# Handle pre-built images
########################################################################
IF(DEFINED UHD_IMAGES_DIR AND EXISTS "${UHD_IMAGES_DIR}")
- FILE(GLOB _image_files "${UHD_IMAGES_DIR}/*.*")
+ FILE(GLOB_RECURSE _image_files "${UHD_IMAGES_DIR}/*")
MESSAGE(STATUS "Using images:")
FOREACH(_img ${_image_files})
MESSAGE(STATUS " ${_img}")
diff --git a/host/LICENSE.txt b/host/LICENSE
index 9aa03b39b..9aa03b39b 100644
--- a/host/LICENSE.txt
+++ b/host/LICENSE
diff --git a/host/README.txt b/host/README.txt
deleted file mode 100644
index 0e8e62ac1..000000000
--- a/host/README.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-###############################################
-# Ettus Research - USRP Hardware Driver
-###############################################
-The hardware driver for Ettus Research products.
-
-###############################################
-# Supported USRP Motherboards
-###############################################
-USRP1
-USRP2
-N200
-N210
-E100
-E110
-B100
-B200
-
-###############################################
-# Supported USRP Daughterboards
-###############################################
-Basic RX
-Basic TX
-LF RX
-LF TX
-RFX Series
-XCVR 2450
-WBX + Simple GDB
-DBSRX
-DBSRX2
-TVRX
-TVRX2
-SBX
-CBX
-
-###############################################
-# Documentation
-###############################################
-Online documentation available at:
-http://code.ettus.com/redmine/ettus/projects/uhd/wiki
-
-The build system can generate the html for the manual and Doxygen.
-Docutils and Doxygen are required to build the html docs.
-See the docs directory for the manual source (reStructuredText).
diff --git a/host/apps/omap_debug/README b/host/apps/omap_debug/README
deleted file mode 100644
index bbe0c2cc4..000000000
--- a/host/apps/omap_debug/README
+++ /dev/null
@@ -1 +0,0 @@
-OMAP development tools go here
diff --git a/host/cmake/Modules/FindUSB1.cmake b/host/cmake/Modules/FindUSB1.cmake
index a494e1350..b2e4d118c 100644
--- a/host/cmake/Modules/FindUSB1.cmake
+++ b/host/cmake/Modules/FindUSB1.cmake
@@ -8,7 +8,8 @@ PKG_CHECK_MODULES(PC_LIBUSB QUIET libusb-1.0)
FIND_PATH(LIBUSB_INCLUDE_DIRS
NAMES libusb.h
- HINTS $ENV{LIBUSB_DIR}/include ${PC_LIBUSB_INCLUDEDIR}
+ HINTS $ENV{LIBUSB_DIR}/include $ENV{LIBUSB_DIR}/include/libusb-1.0
+ ${PC_LIBUSB_INCLUDEDIR} ${PC_LIBUSB_INCLUDEDIR}/libusb-1.0
PATHS /usr/local/include/libusb-1.0 /usr/local/include
/usr/include/libusb-1.0 /usr/include
/opt/local/include/libusb-1.0
diff --git a/host/cmake/Modules/UHDPackage.cmake b/host/cmake/Modules/UHDPackage.cmake
index 6af474f7a..4968571b5 100644
--- a/host/cmake/Modules/UHDPackage.cmake
+++ b/host/cmake/Modules/UHDPackage.cmake
@@ -99,9 +99,8 @@ SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Ettus Research - USRP Hardware Driver")
SET(CPACK_PACKAGE_VENDOR "Ettus Research LLC")
SET(CPACK_PACKAGE_CONTACT "Ettus Research <support@ettus.com>")
SET(CPACK_PACKAGE_VERSION "${UHD_VERSION}")
-SET(CPACK_RESOURCE_FILE_WELCOME ${CMAKE_SOURCE_DIR}/README.txt)
-SET(CPACK_RESOURCE_FILE_README ${CMAKE_SOURCE_DIR}/AUTHORS.txt)
-SET(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/LICENSE.txt)
+SET(CPACK_RESOURCE_FILE_WELCOME ${CMAKE_SOURCE_DIR}/../README.md)
+SET(CPACK_RESOURCE_FILE_LICENSE ${CMAKE_SOURCE_DIR}/LICENSE)
########################################################################
# Setup CPack Source
diff --git a/host/cmake/Modules/UHDUnitTest.cmake b/host/cmake/Modules/UHDUnitTest.cmake
index 47cddc521..76fec14b8 100644
--- a/host/cmake/Modules/UHDUnitTest.cmake
+++ b/host/cmake/Modules/UHDUnitTest.cmake
@@ -64,7 +64,11 @@ function(UHD_ADD_TEST test_name)
list(APPEND environs "PATH=${binpath}" "${LD_PATH_VAR}=${libpath}")
#generate a bat file that sets the environment and runs the test
- find_program(SHELL sh)
+ if (CMAKE_CROSSCOMPILING)
+ set(SHELL "/bin/sh")
+ else(CMAKE_CROSSCOMPILING)
+ find_program(SHELL sh)
+ endif(CMAKE_CROSSCOMPILING)
set(sh_file ${CMAKE_CURRENT_BINARY_DIR}/${test_name}_test.sh)
file(WRITE ${sh_file} "#!${SHELL}\n")
#each line sets an environment variable
diff --git a/host/cmake/Modules/UHDVersion.cmake b/host/cmake/Modules/UHDVersion.cmake
index 8e14b26bf..b0d04fe70 100644
--- a/host/cmake/Modules/UHDVersion.cmake
+++ b/host/cmake/Modules/UHDVersion.cmake
@@ -26,8 +26,8 @@ FIND_PACKAGE(Git QUIET)
# - increment patch on for bug fixes and docs
########################################################################
SET(UHD_VERSION_MAJOR 003)
-SET(UHD_VERSION_MINOR 005)
-SET(UHD_VERSION_PATCH 004)
+SET(UHD_VERSION_MINOR 006)
+SET(UHD_VERSION_PATCH 002)
########################################################################
# Set up trimmed version numbers for DLL resource files and packages
@@ -87,7 +87,7 @@ IF(UHD_RELEASE_MODE)
#Ignore UHD_GIT_COUNT in UHD_VERSION if the string 'release' is in UHD_RELEASE_MODE
EXECUTE_PROCESS(
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
- COMMAND ${PYTHON_EXECUTABLE} -c "print 'release' in '${UHD_RELEASE_MODE}'"
+ COMMAND ${PYTHON_EXECUTABLE} -c "print ('release' in '${UHD_RELEASE_MODE}') or ('rc' in '${UHD_RELEASE_MODE}')"
OUTPUT_VARIABLE TRIM_UHD_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE
)
ENDIF()
diff --git a/host/cmake/Toolchains/armv7athf_native.cmake b/host/cmake/Toolchains/armv7athf_native.cmake
new file mode 100644
index 000000000..d9d1e2598
--- /dev/null
+++ b/host/cmake/Toolchains/armv7athf_native.cmake
@@ -0,0 +1,8 @@
+########################################################################
+# Toolchain file for building native on a ARM Cortex A8 w/ NEON
+# Usage: cmake -DCMAKE_TOOLCHAIN_FILE=<this file> <source directory>
+########################################################################
+set(CMAKE_CXX_COMPILER g++)
+set(CMAKE_C_COMPILER gcc)
+set(CMAKE_CXX_FLAGS "-march=armv7-a -mthumb -mfpu=neon -mfloat-abi=hard" CACHE STRING "" FORCE)
+set(CMAKE_C_FLAGS ${CMAKE_CXX_FLAGS} CACHE STRING "" FORCE) #same flags for C sources
diff --git a/host/cmake/Toolchains/oe-sdk_cross.cmake b/host/cmake/Toolchains/oe-sdk_cross.cmake
new file mode 100644
index 000000000..ea77815c9
--- /dev/null
+++ b/host/cmake/Toolchains/oe-sdk_cross.cmake
@@ -0,0 +1,13 @@
+set( CMAKE_SYSTEM_NAME Linux )
+#set( CMAKE_C_COMPILER $ENV{CC} )
+#set( CMAKE_CXX_COMPILER $ENV{CXX} )
+set( CMAKE_CXX_FLAGS $ENV{CXXFLAGS} CACHE STRING "" FORCE )
+set( CMAKE_C_FLAGS $ENV{CFLAGS} CACHE STRING "" FORCE ) #same flags for C sources
+set( CMAKE_LDFLAGS_FLAGS ${CMAKE_CXX_FLAGS} CACHE STRING "" FORCE ) #same flags for C sources
+set( CMAKE_LIBRARY_PATH ${OECORE_TARGET_SYSROOT}/usr/lib )
+set( CMAKE_FIND_ROOT_PATH $ENV{OECORE_NATIVE_SYSROOT} $ENV{OECORE_TARGET_SYSROOT} )
+set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER )
+set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY )
+set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY )
+set ( ORC_INCLUDE_DIRS $ENV{OECORE_TARGET_SYSROOT}/usr/include/orc-0.4 )
+set ( ORC_LIBRARY_DIRS $ENV{OECORE_TARGET_SYSROOT}/usr/lib )
diff --git a/host/docs/CMakeLists.txt b/host/docs/CMakeLists.txt
index 17744db7d..fa6e98918 100644
--- a/host/docs/CMakeLists.txt
+++ b/host/docs/CMakeLists.txt
@@ -26,6 +26,7 @@ SET(manual_sources
coding.rst
dboards.rst
gpsdo.rst
+ gpsdo_b2x0.rst
general.rst
images.rst
stream.rst
diff --git a/host/docs/build.rst b/host/docs/build.rst
index 00f79aaaa..5512e71ae 100644
--- a/host/docs/build.rst
+++ b/host/docs/build.rst
@@ -64,7 +64,7 @@ LibUSB
* **Minimum Version:** 1.0
* **Usage:** build time + runtime (optional)
* **Download URL:** http://sourceforge.net/projects/libusb/files/libusb-1.0/
-* **Download URL (Windows binaries):** http://www.libusb.org/wiki/windows_backend#LatestBinarySnapshots
+* **Download URL (Windows):** https://github.com/libusbx/libusbx
^^^^^^^^^^^^^^^^
Python
@@ -169,7 +169,7 @@ Generate the project with CMake
* Click "Generate", and a project file will be created in the build directory.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LibUSB CMake notes
+LibUSB notes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
On Windows, CMake does not have the advantage of **pkg-config**,
so we must manually tell CMake how to locate the LibUSB header and lib.
@@ -182,6 +182,8 @@ so we must manually tell CMake how to locate the LibUSB header and lib.
* Check the box to enable USB support, click "Configure" and "Generate".
+**Note:** On Windows, LibUSBx is required to use most USB3 controllers.
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Build the project in MSVC
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/host/docs/gpsdo.rst b/host/docs/gpsdo.rst
index 1e9019a0f..1cf1dae29 100644
--- a/host/docs/gpsdo.rst
+++ b/host/docs/gpsdo.rst
@@ -1,5 +1,5 @@
========================================================================
-UHD - Internal GPSDO Application Notes
+UHD - Internal GPSDO Application Notes (USRP-N2x0/E1X0 Models)
========================================================================
.. contents:: Table of Contents
diff --git a/host/docs/gpsdo_b2x0.rst b/host/docs/gpsdo_b2x0.rst
new file mode 100644
index 000000000..bca10e99a
--- /dev/null
+++ b/host/docs/gpsdo_b2x0.rst
@@ -0,0 +1,80 @@
+========================================================================
+UHD - Internal GPSDO Application Notes (USRP-B2X0 Models)
+========================================================================
+
+.. contents:: Table of Contents
+
+This application note describes the use of integrated GPS-disciplined
+oscillators with Ettus Research USRP devices. It pertains specifically
+to the Jackson Labs LC_XO device unless noted otherwise.
+
+------------------------------------------------------------------------
+Specifications
+------------------------------------------------------------------------
+* **Receiver type**: 50 channel with WAAS, EGNOS, MSAS
+* **10MHz ADEV**: 5e-11 over >24h
+* **1PPS RMS jitter**: <50ns 1-sigma
+* **Holdover**: <20us over 3h
+
+**Phase noise**:
+
++------------+-------------+------------+
+| | TCXO | OXCO |
++============+=============+============+
+| **1Hz** | -65dBc/Hz | -75dBc/Hz |
++------------+-------------+------------+
+| **10Hz** | -102dBc/Hz | -110dBc/Hz |
++------------+-------------+------------+
+| **100Hz** | -132dBc/Hz | -132dBc/Hz |
++------------+-------------+------------+
+| **1kHz** | -148dBc/Hz | -142dBc/Hz |
++------------+-------------+------------+
+| **10kHz** | -152dBc/Hz | -145dBc/Hz |
++------------+-------------+------------+
+| **100kHz** | <-155dBc/Hz | -150dBc/Hz |
++------------+-------------+------------+
+
+**Antenna Types:**
+
+The GPSDO is capable of supplying a 3V for active GPS antennas or supporting passive antennas.
+
+------------------------------------------------------------------------
+Installation Instructions
+------------------------------------------------------------------------
+To install the GPSDO, you must insert it into the slot on the board
+near the 10 MHz Reference SMA. Keep in mind that the two sides of the
+GPSDO have a different number of pins. When inserting the GPSDO, make
+sure to press down firmly and evenly. When turning on the USRP B2X0 device,
+a green LED should illuminate on the GPSDO. This signifies that the unit
+has successfully been placed.
+
+**NOTE: The pins on the GPSDO are very fragile. Be sure to press down
+evenly, or the pins may bend or break. Once the GPSDO is in place,
+we very highly discourage further removal, as this also risks damaging
+the pins.**
+
+------------------------------------------------------------------------
+Using the GPSDO in Your Application
+------------------------------------------------------------------------
+By default, if a GPSDO is detected at startup, the USRP will be configured
+to use it as a frequency and time reference. The internal VITA timestamp
+will be initialized to the GPS time, and the internal oscillator will be
+phase-locked to the 10MHz GPSDO reference. If the GPSDO is not locked to
+satellites, the VITA time will not be initialized.
+
+GPS data is obtained through the **mboard_sensors** interface. To retrieve
+the current GPS time, use the **gps_time** sensor:
+
+::
+
+ usrp->get_mboard_sensor("gps_time");
+
+The returned value will be the current epoch time, in seconds since
+January 1, 1970. This value is readily converted into human-readable
+format using the **time.h** library in C, **boost::posix_time** in C++, etc.
+
+Other information can be fetched as well. You can query the lock status
+with the **gps_locked** sensor, as well as obtain raw NMEA sentences using
+the **gps_gprmc**, and **gps_gpgga** sensors. Location
+information can be parsed out of the **gps_gpgga** sensor by using **gpsd** or
+another NMEA parser.
diff --git a/host/docs/index.rst b/host/docs/index.rst
index 27523c139..65069059f 100644
--- a/host/docs/index.rst
+++ b/host/docs/index.rst
@@ -32,7 +32,8 @@ Application Notes
* `Daughterboard Application Notes <./dboards.html>`_
* `Transport Application Notes <./transport.html>`_
* `Synchronization Application Notes <./sync.html>`_
-* `Internal GPSDO Application Notes <./gpsdo.html>`_
+* `Internal GPSDO Application Notes (USRP-N2X0/E1X0 Models) <./gpsdo.html>`_
+* `Internal GPSDO Application Notes (USRP-B2X0 Models) <./gpsdo_b2x0.html>`_
* `Calibration Application Notes <./calibration.html>`_
^^^^^^^^^^^^^^^^^^^^^
diff --git a/host/docs/uhd_find_devices.1 b/host/docs/uhd_find_devices.1
index 7dc0dd470..08f9a789c 100644
--- a/host/docs/uhd_find_devices.1
+++ b/host/docs/uhd_find_devices.1
@@ -9,9 +9,6 @@ The UHD package is the universal hardware driver for Ettus Research
products. The goal is to provide a host driver and API for
current and future Ettus Research products. Users will be able to use
the UHD driver standalone or with 3rd party applications.
-.LP
-Hardware supporting UHD drivers includes the Universal Software Radio
-Peripheral, or USRP, available in several models.
.SH SYNOPSIS
.B uhd_find_devices [OPTIONS]
.SH OPTIONS
diff --git a/host/docs/uhd_images_downloader.1 b/host/docs/uhd_images_downloader.1
index ece826cb5..28310dd37 100644
--- a/host/docs/uhd_images_downloader.1
+++ b/host/docs/uhd_images_downloader.1
@@ -7,9 +7,6 @@ products. The goal of the UHD is to provide a host driver and API for
current and future Ettus Research products. Users will be able to use
the UHD driver standalone or with 3rd party applications.
.LP
-Hardware supporting UHD drivers includes the Universal Software Radio
-Peripheral, or USRP, available in several models.
-.LP
This program installs the firmware and FPGA binaries from Ettus Research
matching this UHD driver release onto the host system. If the uhd-images
package is installed, there is no need to run this installer.
diff --git a/host/docs/uhd_usrp_probe.1 b/host/docs/uhd_usrp_probe.1
index 7e82bf99a..a6c7150ee 100644
--- a/host/docs/uhd_usrp_probe.1
+++ b/host/docs/uhd_usrp_probe.1
@@ -1,6 +1,6 @@
.TH "uhd_usrp_probe" 1 "3.5.1" UHD "User Commands"
.SH NAME
-uhd_usrp_probe \- Universal Hardware Driver Peripheral Report Utility
+uhd_usrp_probe \- USRP Hardware Driver Peripheral Report Utility
.SH DESCRIPTION
Report detailed information on UHD-supported Software Radio Peripherals
attached by USB, network, or embedded configuration.
diff --git a/host/examples/network_relay.cpp b/host/examples/network_relay.cpp
index bb09296b3..0a67bbf09 100644
--- a/host/examples/network_relay.cpp
+++ b/host/examples/network_relay.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2012 Ettus Research LLC
+// Copyright 2010-2013 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
@@ -18,6 +18,7 @@
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
#include <boost/program_options.hpp>
+#include <boost/thread/condition_variable.hpp>
#include <boost/thread/thread.hpp>
#include <boost/format.hpp>
#include <boost/asio.hpp>
@@ -33,8 +34,6 @@ typedef boost::shared_ptr<asio::ip::udp::socket> socket_type;
static const size_t insane_mtu = 9000;
-boost::mutex spawn_mutex;
-
#if defined(UHD_PLATFORM_MACOS)
//limit buffer resize on macos or it will error
const size_t rx_dsp_buff_size = size_t(1e6);
@@ -100,14 +99,11 @@ public:
}
std::cout << "spawning relay threads... " << _port << std::endl;
+ boost::unique_lock<boost::mutex> lock(spawn_mutex); // lock in preparation to wait for threads to spawn
_thread_group.create_thread(boost::bind(&udp_relay_type::server_thread, this));
- spawn_mutex.lock();
- spawn_mutex.lock();
- spawn_mutex.unlock();
+ wait_for_thread.wait(lock); // wait for thread to spin up
_thread_group.create_thread(boost::bind(&udp_relay_type::client_thread, this));
- spawn_mutex.lock();
- spawn_mutex.lock();
- spawn_mutex.unlock();
+ wait_for_thread.wait(lock); // wait for thread to spin up
std::cout << " done!" << std::endl << std::endl;
}
@@ -128,7 +124,7 @@ private:
void server_thread(void){
uhd::set_thread_priority_safe();
std::cout << " entering server_thread..." << std::endl;
- spawn_mutex.unlock();
+ wait_for_thread.notify_one(); // notify constructor that this thread has started
std::vector<char> buff(insane_mtu);
while (not boost::this_thread::interruption_requested()){
if (wait_for_recv_ready(_server_socket->native())){
@@ -154,7 +150,7 @@ private:
void client_thread(void){
uhd::set_thread_priority_safe();
std::cout << " entering client_thread..." << std::endl;
- spawn_mutex.unlock();
+ wait_for_thread.notify_one(); // notify constructor that this thread has started
std::vector<char> buff(insane_mtu);
while (not boost::this_thread::interruption_requested()){
if (wait_for_recv_ready(_client_socket->native())){
@@ -172,6 +168,8 @@ private:
asio::ip::udp::endpoint _endpoint;
boost::mutex _endpoint_mutex;
socket_type _server_socket, _client_socket;
+ boost::mutex spawn_mutex;
+ boost::condition_variable wait_for_thread;
};
diff --git a/host/examples/rx_samples_to_file.cpp b/host/examples/rx_samples_to_file.cpp
index b0e498125..a28d1d628 100644
--- a/host/examples/rx_samples_to_file.cpp
+++ b/host/examples/rx_samples_to_file.cpp
@@ -236,8 +236,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("ref", po::value<std::string>(&ref)->default_value("internal"), "waveform type (internal, external, mimo)")
("wirefmt", po::value<std::string>(&wirefmt)->default_value("sc16"), "wire format (sc8 or sc16)")
("setup", po::value<double>(&setup_time)->default_value(1.0), "seconds of setup time")
- ("progress", "show average bandwidth on exit")
- ("stats", "periodically display short-term bandwidth")
+ ("progress", "periodically display short-term bandwidth")
+ ("stats", "show average bandwidth on exit")
("sizemap", "track packet size and display breakdown on exit")
("null", "run without writing to file")
("continue", "don't abort on a bad packet")
diff --git a/host/examples/test_dboard_coercion.cpp b/host/examples/test_dboard_coercion.cpp
index cfc745147..86c59d9d7 100644
--- a/host/examples/test_dboard_coercion.cpp
+++ b/host/examples/test_dboard_coercion.cpp
@@ -53,7 +53,7 @@ std::string return_USRP_config_string(uhd::usrp::multi_usrp::sptr usrp, bool tes
if(test_tx){
if(tx_info.get("tx_serial") != "") tx_serial = tx_info.get("tx_serial");
- else tx_serial = "no serial";
+ else tx_serial = "no serial";
tx_subdev_name = tx_info.get("tx_subdev_name");
tx_subdev_spec = tx_info.get("tx_subdev_spec");
@@ -121,7 +121,7 @@ std::string tx_test(uhd::usrp::multi_usrp::sptr usrp, bool test_gain, bool verbo
gains.push_back(current_gain);
current_gain++;
}
- if(gain_end != *gains.end()) gains.push_back(gain_end);
+ gains.push_back(gain_end);
}
@@ -182,19 +182,19 @@ std::string tx_test(uhd::usrp::multi_usrp::sptr usrp, bool test_gain, bool verbo
}
if(test_gain){
-
+
//Testing for successful gain tune
for(std::vector<double>::iterator g = gains.begin(); g != gains.end(); ++g){
usrp->set_tx_gain(*g);
boost::this_thread::sleep(boost::posix_time::microseconds(1000));
-
+
double actual_gain = usrp->get_tx_gain();
if(*g == 0.0){
if(actual_gain == 0.0){
if(verbose) std::cout << boost::format("TX gain successfully set to %5.2f at TX frequency %s.") % *g % return_MHz_string(*f) << std::endl;
- }
+ }
else{
if(verbose) std::cout << boost::format("TX gain set to %5.2f instead of %5.2f at TX frequency %s.") % actual_gain % *g % return_MHz_string(*f) << std::endl;
std::vector<double> bad_gain_freq;
@@ -313,7 +313,7 @@ std::string rx_test(uhd::usrp::multi_usrp::sptr usrp, bool test_gain, bool verbo
gains.push_back(current_gain);
current_gain++;
}
- if(gain_end != *gains.end()) gains.push_back(gain_end);
+ gains.push_back(gain_end);
}
@@ -518,7 +518,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << "REF must equal internal, external, or mimo." << std::endl;
return ~0;
}
-
+
if(vm.count("tx") + vm.count("rx") == 0){
std::cout << desc << std::endl;
std::cout << "Specify --tx to test for TX frequency coercion\n"
@@ -557,12 +557,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
uhd::sensor_value_t mimo_locked = usrp->get_mboard_sensor("mimo_locked",0);
std::cout << boost::format("Checking MIMO lock: %s ...") % mimo_locked.to_pp_string() << std::endl;
UHD_ASSERT_THROW(mimo_locked.to_bool());
- }
+ }
if ((ref == "external") and (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end())) {
uhd::sensor_value_t ref_locked = usrp->get_mboard_sensor("ref_locked",0);
std::cout << boost::format("Checking REF lock: %s ...") % ref_locked.to_pp_string() << std::endl;
UHD_ASSERT_THROW(ref_locked.to_bool());
- }
+ }
usrp_config = return_USRP_config_string(usrp, test_tx, test_rx);
if(test_tx) tx_results = tx_test(usrp, test_tx_gain, verbose);
if(test_rx) rx_results = rx_test(usrp, test_rx_gain, verbose);
diff --git a/host/examples/test_messages.cpp b/host/examples/test_messages.cpp
index e39a8bd30..4240e830b 100644
--- a/host/examples/test_messages.cpp
+++ b/host/examples/test_messages.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2013 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
@@ -15,6 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
+#include <uhd/config.hpp>
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/static.hpp>
@@ -84,7 +85,7 @@ bool test_late_command_message(uhd::usrp::multi_usrp::sptr usrp, uhd::rx_streame
* Issue a stream command with num samps and more.
* We expect to get an inline broken chain message.
*/
-bool test_broken_chain_message(uhd::usrp::multi_usrp::sptr usrp, uhd::rx_streamer::sptr rx_stream, uhd::tx_streamer::sptr){
+bool test_broken_chain_message(UHD_UNUSED(uhd::usrp::multi_usrp::sptr usrp), uhd::rx_streamer::sptr rx_stream, uhd::tx_streamer::sptr){
std::cout << "Test broken chain message... " << std::flush;
uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE);
diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp
index 6fd2932cf..619bd0787 100644
--- a/host/include/uhd/config.hpp
+++ b/host/include/uhd/config.hpp
@@ -55,18 +55,21 @@ typedef ptrdiff_t ssize_t;
#define UHD_INLINE __forceinline
#define UHD_DEPRECATED __declspec(deprecated)
#define UHD_ALIGNED(x) __declspec(align(x))
+ #define UHD_UNUSED(x) x
#elif defined(__GNUG__) && __GNUG__ >= 4
#define UHD_EXPORT __attribute__((visibility("default")))
#define UHD_IMPORT __attribute__((visibility("default")))
#define UHD_INLINE inline __attribute__((always_inline))
#define UHD_DEPRECATED __attribute__((deprecated))
#define UHD_ALIGNED(x) __attribute__((aligned(x)))
+ #define UHD_UNUSED(x) x __attribute__((unused))
#else
#define UHD_EXPORT
#define UHD_IMPORT
#define UHD_INLINE inline
#define UHD_DEPRECATED
#define UHD_ALIGNED(x)
+ #define UHD_UNUSED(x) x
#endif
// Define API declaration macro
diff --git a/host/include/uhd/transport/usb_device_handle.hpp b/host/include/uhd/transport/usb_device_handle.hpp
index 2951d7fbb..fdea9e2be 100644
--- a/host/include/uhd/transport/usb_device_handle.hpp
+++ b/host/include/uhd/transport/usb_device_handle.hpp
@@ -73,6 +73,12 @@ public:
virtual boost::uint16_t get_product_id() const = 0;
/*!
+ * Test whether the firmware is loaded on the device.
+ * \return true if firmware is loaded
+ */
+ virtual bool firmware_loaded() = 0;
+
+ /*!
* Return a vector of USB devices on this host
* \return a vector of USB device handles that match vid and pid
*/
diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp
index 1dc0e8e26..40d7b8c59 100644
--- a/host/include/uhd/transport/zero_copy.hpp
+++ b/host/include/uhd/transport/zero_copy.hpp
@@ -29,7 +29,9 @@ namespace uhd{ namespace transport{
//! Simple managed buffer with release interface
class UHD_API managed_buffer{
public:
- managed_buffer(void):_ref_count(0){}
+ managed_buffer(void):_ref_count(0),_buffer(NULL),_length(0){}
+
+ virtual ~managed_buffer(void) {}
/*!
* Signal to the transport that we are done with the buffer.
@@ -72,6 +74,7 @@ namespace uhd{ namespace transport{
}
boost::detail::atomic_count _ref_count;
+ typedef boost::intrusive_ptr<managed_buffer> sptr;
protected:
void *_buffer;
diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt
index 28e646117..334f1b41b 100644
--- a/host/include/uhd/types/CMakeLists.txt
+++ b/host/include/uhd/types/CMakeLists.txt
@@ -33,6 +33,7 @@ UHD_INSTALL(FILES
time_spec.hpp
tune_request.hpp
tune_result.hpp
+ wb_iface.hpp
DESTINATION ${INCLUDE_DIR}/uhd/types
COMPONENT headers
)
diff --git a/host/lib/usrp/cores/wb_iface.hpp b/host/include/uhd/types/wb_iface.hpp
index 197788180..c508062e4 100644
--- a/host/lib/usrp/cores/wb_iface.hpp
+++ b/host/include/uhd/types/wb_iface.hpp
@@ -15,19 +15,24 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#ifndef INCLUDED_LIBUHD_USRP_WB_IFACE_HPP
-#define INCLUDED_LIBUHD_USRP_WB_IFACE_HPP
+#ifndef INCLUDED_UHD_TYPES_WB_IFACE_HPP
+#define INCLUDED_UHD_TYPES_WB_IFACE_HPP
#include <uhd/config.hpp>
#include <boost/cstdint.hpp>
#include <boost/shared_ptr.hpp>
-class /*UHD_API*/ wb_iface
+namespace uhd
+{
+
+class UHD_API wb_iface
{
public:
typedef boost::shared_ptr<wb_iface> sptr;
typedef boost::uint32_t wb_addr_type;
+ virtual ~wb_iface(void);
+
/*!
* Write a register (64 bits)
* \param addr the address
@@ -72,4 +77,6 @@ public:
};
-#endif /* INCLUDED_LIBUHD_USRP_WB_IFACE_HPP */
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_TYPES_WB_IFACE_HPP */
diff --git a/host/include/uhd/utils/CMakeLists.txt b/host/include/uhd/utils/CMakeLists.txt
index cdef2e946..e86826435 100644
--- a/host/include/uhd/utils/CMakeLists.txt
+++ b/host/include/uhd/utils/CMakeLists.txt
@@ -27,6 +27,7 @@ UHD_INSTALL(FILES
images.hpp
log.hpp
msg.hpp
+ msg_task.hpp
paths.hpp
pimpl.hpp
safe_call.hpp
diff --git a/host/include/uhd/utils/atomic.hpp b/host/include/uhd/utils/atomic.hpp
index 8ddee73ca..55769d2fd 100644
--- a/host/include/uhd/utils/atomic.hpp
+++ b/host/include/uhd/utils/atomic.hpp
@@ -78,6 +78,10 @@ namespace uhd{
class UHD_API reusable_barrier{
public:
+ reusable_barrier():_size (0) {}
+
+ reusable_barrier(const size_t size):_size(size) {}
+
//! Resize the barrier for N threads
void resize(const size_t size){
_size = size;
diff --git a/host/include/uhd/utils/msg_task.hpp b/host/include/uhd/utils/msg_task.hpp
new file mode 100644
index 000000000..ebb29af08
--- /dev/null
+++ b/host/include/uhd/utils/msg_task.hpp
@@ -0,0 +1,74 @@
+//
+// Copyright 2011-2013 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/>.
+//
+
+#ifndef INCLUDED_UHD_UTILS_MSG_TASK_HPP
+#define INCLUDED_UHD_UTILS_MSG_TASK_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/transport/zero_copy.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <boost/utility.hpp>
+#include <boost/optional/optional.hpp>
+#include <vector>
+
+namespace uhd{
+ class UHD_API msg_task : boost::noncopyable{
+ public:
+ typedef boost::shared_ptr<msg_task> sptr;
+ typedef std::vector<uint8_t> msg_payload_t;
+ typedef std::pair<uint32_t, msg_payload_t > msg_type_t;
+ typedef boost::function<boost::optional<msg_type_t>(void)> task_fcn_type;
+
+ /*
+ * During shutdown message queues for radio control cores might not be available anymore.
+ * Such stranded messages get pushed into a dump queue.
+ * With this function radio_ctrl_core can check if one of the messages meant for it got stranded.
+ */
+ virtual msg_payload_t get_msg_from_dump_queue(boost::uint32_t sid) = 0;
+
+ inline static std::vector<uint8_t> buff_to_vector(uint8_t* p, size_t n) {
+ if(p and n > 0){
+ std::vector<uint8_t> v(n);
+ memcpy(&v.front(), p, n);
+ return v;
+ }
+ return std::vector<uint8_t>();
+ }
+
+ /*!
+ * Create a new task object with function callback.
+ * The task function callback will be run in a loop.
+ * until the thread is interrupted by the deconstructor.
+ *
+ * A function may return payload which is then pushed to
+ * a synchronized message queue.
+ *
+ * A task should return in a reasonable amount of time
+ * or may block forever under the following conditions:
+ * - The blocking call is interruptible.
+ * - The task polls the interrupt condition.
+ *
+ * \param task_fcn the task callback function
+ * \return a new task object
+ */
+ static sptr make(const task_fcn_type &task_fcn);
+ };
+} //namespace uhd
+
+#endif /* INCLUDED_UHD_UTILS_MSG_TASK_HPP */
+
diff --git a/host/include/uhd/utils/tasks.hpp b/host/include/uhd/utils/tasks.hpp
index dcb003e39..a1f682a83 100644
--- a/host/include/uhd/utils/tasks.hpp
+++ b/host/include/uhd/utils/tasks.hpp
@@ -46,7 +46,6 @@ namespace uhd{
static sptr make(const task_fcn_type &task_fcn);
};
-
} //namespace uhd
#endif /* INCLUDED_UHD_UTILS_TASKS_HPP */
diff --git a/host/lib/convert/convert_fc32_item32.cpp b/host/lib/convert/convert_fc32_item32.cpp
index 29bfefd46..641fc2608 100644
--- a/host/lib/convert/convert_fc32_item32.cpp
+++ b/host/lib/convert/convert_fc32_item32.cpp
@@ -28,7 +28,7 @@ typedef boost::uint32_t (*to32_type)(boost::uint32_t);
template <typename type, to32_type tohost>
struct convert_fc32_item32_1_to_star_1 : public converter
{
- convert_fc32_item32_1_to_star_1(void)
+ convert_fc32_item32_1_to_star_1(void):_scalar(0.0)
{
//NOP
}
@@ -48,9 +48,9 @@ struct convert_fc32_item32_1_to_star_1 : public converter
{
const item32_t i32 = tohost(input[i++]);
const item32_t q32 = tohost(input[i++]);
- const float i_f32 = reinterpret_cast<const float &>(i32);
- const float q_f32 = reinterpret_cast<const float &>(q32);
- output[o] = std::complex<type>(type(i_f32*_scalar), type(q_f32*_scalar));
+ const float *i_f32p = reinterpret_cast<const float *>(&i32);
+ const float *q_f32p = reinterpret_cast<const float *>(&q32);
+ output[o] = std::complex<type>(type((*i_f32p)*_scalar), type((*q_f32p)*_scalar));
}
}
@@ -60,7 +60,7 @@ struct convert_fc32_item32_1_to_star_1 : public converter
template <typename type, to32_type towire>
struct convert_star_1_to_fc32_item32_1 : public converter
{
- convert_star_1_to_fc32_item32_1(void)
+ convert_star_1_to_fc32_item32_1(void):_scalar(0.0)
{
//NOP
}
@@ -80,9 +80,10 @@ struct convert_star_1_to_fc32_item32_1 : public converter
{
const float i_f32 = type(input[i].real()*_scalar);
const float q_f32 = type(input[i].imag()*_scalar);
- const item32_t i32 = towire(reinterpret_cast<const item32_t &>(i_f32));
- const item32_t q32 = towire(reinterpret_cast<const item32_t &>(q_f32));
- output[o++] = i32; output[o++] = q32;
+ const item32_t *i32p = reinterpret_cast<const item32_t *>(&i_f32);
+ const item32_t *q32p = reinterpret_cast<const item32_t *>(&q_f32);
+ output[o++] = towire(*i32p);
+ output[o++] = towire(*q32p);
}
}
diff --git a/host/lib/convert/convert_pack_sc12.cpp b/host/lib/convert/convert_pack_sc12.cpp
index 680814994..92cd5d152 100644
--- a/host/lib/convert/convert_pack_sc12.cpp
+++ b/host/lib/convert/convert_pack_sc12.cpp
@@ -67,7 +67,7 @@ void convert_star_4_to_sc12_item32_3
template <typename type, towire32_type towire>
struct convert_star_1_to_sc12_item32_1 : public converter
{
- convert_star_1_to_sc12_item32_1(void)
+ convert_star_1_to_sc12_item32_1(void):_scalar(0.0)
{
//NOP
}
diff --git a/host/lib/convert/convert_unpack_sc12.cpp b/host/lib/convert/convert_unpack_sc12.cpp
index f578b6c95..a2aec2ae5 100644
--- a/host/lib/convert/convert_unpack_sc12.cpp
+++ b/host/lib/convert/convert_unpack_sc12.cpp
@@ -32,6 +32,17 @@ struct item32_sc12_3x
item32_t line2;
};
+/*
+ * convert_sc12_item32_3_to_star_4 takes in 3 lines with 32 bit each
+ * and converts them 4 samples of type 'std::complex<type>'.
+ * The structure of the 3 lines is as follows:
+ * _ _ _ _ _ _ _ _
+ * |_ _ _1_ _ _|_ _|
+ * |_2_ _ _|_ _ _3_|
+ * |_ _|_ _ _4_ _ _|
+ *
+ * The numbers mark the position of one complex sample.
+ */
template <typename type, tohost32_type tohost>
void convert_sc12_item32_3_to_star_4
(
@@ -73,7 +84,7 @@ void convert_sc12_item32_3_to_star_4
template <typename type, tohost32_type tohost>
struct convert_sc12_item32_1_to_star_1 : public converter
{
- convert_sc12_item32_1_to_star_1(void)
+ convert_sc12_item32_1_to_star_1(void):_scalar(0.0)
{
//NOP
}
@@ -84,17 +95,48 @@ struct convert_sc12_item32_1_to_star_1 : public converter
_scalar = scalar/unpack_growth;
}
+ /*
+ * This converter takes in 24 bits complex samples, 12 bits I and 12 bits Q, and converts them to type 'std::complex<type>'.
+ * 'type' is usually 'float'.
+ * For the converter to work correctly the used managed_buffer which holds all samples of one packet has to be 32 bits aligned.
+ * We assume 32 bits to be one line. This said the converter must be aware where it is supposed to start within 3 lines.
+ *
+ */
void operator()(const input_type &inputs, const output_type &outputs, const size_t nsamps)
{
- const item32_sc12_3x *input = reinterpret_cast<const item32_sc12_3x *>(size_t(inputs[0]) & ~0x3);
+ /*
+ * Looking at the line structure above we can identify 4 cases.
+ * Each corresponds to the start of a different sample within a 3 line block.
+ * head_samps derives the number of samples left within one block.
+ * Then the number of bytes the converter has to rewind are calculated.
+ */
+ const size_t head_samps = size_t(inputs[0]) & 0x3;
+ size_t rewind = 0;
+ switch(head_samps)
+ {
+ case 0: break;
+ case 1: rewind = 9; break;
+ case 2: rewind = 6; break;
+ case 3: rewind = 3; break;
+ }
+
+ /*
+ * The pointer *input now points to the head of a 3 line block.
+ */
+ const item32_sc12_3x *input = reinterpret_cast<const item32_sc12_3x *>(size_t(inputs[0]) - rewind);
std::complex<type> *output = reinterpret_cast<std::complex<type> *>(outputs[0]);
//helper variables
std::complex<type> dummy0, dummy1, dummy2;
size_t i = 0, o = 0;
- //handle the head case
- const size_t head_samps = size_t(inputs[0]) & 0x3;
+ /*
+ * handle the head case
+ * head_samps holds the number of samples left in a block.
+ * The 3 line converter is called for the whole block and already processed samples are dumped.
+ * We don't run into the risk of a SIGSEGV because input will always point to valid memory within a managed_buffer.
+ * Furthermore the bytes in a buffer remain unchanged after they have been copied into it.
+ */
switch (head_samps)
{
case 0: break; //no head
@@ -111,7 +153,18 @@ struct convert_sc12_item32_1_to_star_1 : public converter
i++; o += 4;
}
- //handle the tail case
+ /*
+ * handle the tail case
+ * The converter can be called with any number of samples to be converted.
+ * This can end up in only a part of a block to be converted in one call.
+ * We never have to worry about SIGSEGVs here as long as we end in the middle of a managed_buffer.
+ * If we are at the end of managed_buffer there are 2 precautions to prevent SIGSEGVs.
+ * Firstly only a read operation is performed.
+ * Secondly managed_buffers allocate a fixed size memory which is always larger than the actually used size.
+ * e.g. The current sample maximum is 2000 samples in a packet over USB.
+ * With sc12 samples a packet consists of 6000kb but managed_buffers allocate 16kb each.
+ * Thus we don't run into problems here either.
+ */
const size_t tail_samps = nsamps - o;
switch (tail_samps)
{
diff --git a/host/lib/convert/sse2_fc32_to_sc16.cpp b/host/lib/convert/sse2_fc32_to_sc16.cpp
index 90bf0ed04..69786d7ce 100644
--- a/host/lib/convert/sse2_fc32_to_sc16.cpp
+++ b/host/lib/convert/sse2_fc32_to_sc16.cpp
@@ -27,6 +27,7 @@ DECLARE_CONVERTER(fc32, 1, sc16_item32_le, 1, PRIORITY_SIMD){
const __m128 scalar = _mm_set_ps1(float(scale_factor));
+ // this macro converts values faster by using SSE intrinsics to convert 4 values at a time
#define convert_fc32_1_to_item32_1_nswap_guts(_al_) \
for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
@@ -48,17 +49,25 @@ DECLARE_CONVERTER(fc32, 1, sc16_item32_le, 1, PRIORITY_SIMD){
size_t i = 0;
- //dispatch according to alignment
+ // need to dispatch according to alignment for fastest conversion
switch (size_t(input) & 0xf){
- case 0x8:
- xx_to_item32_sc16<uhd::htowx>(input, output, 1, scale_factor); i++;
case 0x0:
+ // the data is 16-byte aligned, so do the fast processing of the bulk of the samples
+ convert_fc32_1_to_item32_1_nswap_guts(_)
+ break;
+ case 0x8:
+ // the first sample is 8-byte aligned - process it to align the remainder of the samples to 16-bytes
+ xx_to_item32_sc16<uhd::htowx>(input, output, 1, scale_factor);
+ i++;
+ // do faster processing of the bulk of the samples now that we are 16-byte aligned
convert_fc32_1_to_item32_1_nswap_guts(_)
break;
- default: convert_fc32_1_to_item32_1_nswap_guts(u_)
+ default:
+ // we are not 8 or 16-byte aligned, so do fast processing with the unaligned load
+ convert_fc32_1_to_item32_1_nswap_guts(u_)
}
- //convert remainder
+ // convert any remaining samples
xx_to_item32_sc16<uhd::htowx>(input+i, output+i, nsamps-i, scale_factor);
}
@@ -68,6 +77,7 @@ DECLARE_CONVERTER(fc32, 1, sc16_item32_be, 1, PRIORITY_SIMD){
const __m128 scalar = _mm_set_ps1(float(scale_factor));
+ // this macro converts values faster by using SSE intrinsics to convert 4 values at a time
#define convert_fc32_1_to_item32_1_bswap_guts(_al_) \
for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
@@ -88,16 +98,24 @@ DECLARE_CONVERTER(fc32, 1, sc16_item32_be, 1, PRIORITY_SIMD){
size_t i = 0;
- //dispatch according to alignment
+ // need to dispatch according to alignment for fastest conversion
switch (size_t(input) & 0xf){
- case 0x8:
- xx_to_item32_sc16<uhd::htonx>(input, output, 1, scale_factor); i++;
case 0x0:
+ // the data is 16-byte aligned, so do the fast processing of the bulk of the samples
+ convert_fc32_1_to_item32_1_bswap_guts(_)
+ break;
+ case 0x8:
+ // the first value is 8-byte aligned - process it and prepare the bulk of the data for fast conversion
+ xx_to_item32_sc16<uhd::htonx>(input, output, 1, scale_factor);
+ i++;
+ // do faster processing of the remaining samples now that we are 16-byte aligned
convert_fc32_1_to_item32_1_bswap_guts(_)
break;
- default: convert_fc32_1_to_item32_1_bswap_guts(u_)
+ default:
+ // we are not 8 or 16-byte aligned, so do fast processing with the unaligned load
+ convert_fc32_1_to_item32_1_bswap_guts(u_)
}
- //convert remainder
+ // convert any remaining samples
xx_to_item32_sc16<uhd::htonx>(input+i, output+i, nsamps-i, scale_factor);
}
diff --git a/host/lib/convert/sse2_sc16_to_fc32.cpp b/host/lib/convert/sse2_sc16_to_fc32.cpp
index c03e41585..0ac7f1798 100644
--- a/host/lib/convert/sse2_sc16_to_fc32.cpp
+++ b/host/lib/convert/sse2_sc16_to_fc32.cpp
@@ -28,6 +28,7 @@ DECLARE_CONVERTER(sc16_item32_le, 1, fc32, 1, PRIORITY_SIMD){
const __m128 scalar = _mm_set_ps1(float(scale_factor)/(1 << 16));
const __m128i zeroi = _mm_setzero_si128();
+ // this macro converts values faster by using SSE intrinsics to convert 4 values at a time
#define convert_item32_1_to_fc32_1_nswap_guts(_al_) \
for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
@@ -50,17 +51,25 @@ DECLARE_CONVERTER(sc16_item32_le, 1, fc32, 1, PRIORITY_SIMD){
size_t i = 0;
- //dispatch according to alignment
+ // need to dispatch according to alignment for fastest conversion
switch (size_t(output) & 0xf){
- case 0x8:
- item32_sc16_to_xx<uhd::htowx>(input, output, 1, scale_factor); i++;
case 0x0:
+ // the data is 16-byte aligned, so do the fast processing of the bulk of the samples
+ convert_item32_1_to_fc32_1_nswap_guts(_)
+ break;
+ case 0x8:
+ // the first sample is 8-byte aligned - process it to align the remainder of the samples to 16-bytes
+ item32_sc16_to_xx<uhd::htowx>(input, output, 1, scale_factor);
+ i++;
+ // do faster processing of the bulk of the samples now that we are 16-byte aligned
convert_item32_1_to_fc32_1_nswap_guts(_)
break;
- default: convert_item32_1_to_fc32_1_nswap_guts(u_)
+ default:
+ // we are not 8 or 16-byte aligned, so do fast processing with the unaligned load and store
+ convert_item32_1_to_fc32_1_nswap_guts(u_)
}
- //convert remainder
+ // convert any remaining samples
item32_sc16_to_xx<uhd::htowx>(input+i, output+i, nsamps-i, scale_factor);
}
@@ -71,6 +80,7 @@ DECLARE_CONVERTER(sc16_item32_be, 1, fc32, 1, PRIORITY_SIMD){
const __m128 scalar = _mm_set_ps1(float(scale_factor)/(1 << 16));
const __m128i zeroi = _mm_setzero_si128();
+ // this macro converts values faster by using SSE intrinsics to convert 4 values at a time
#define convert_item32_1_to_fc32_1_bswap_guts(_al_) \
for (; i+3 < nsamps; i+=4){ \
/* load from input */ \
@@ -92,16 +102,24 @@ DECLARE_CONVERTER(sc16_item32_be, 1, fc32, 1, PRIORITY_SIMD){
size_t i = 0;
- //dispatch according to alignment
+ // need to dispatch according to alignment for fastest conversion
switch (size_t(output) & 0xf){
- case 0x8:
- item32_sc16_to_xx<uhd::htonx>(input, output, 1, scale_factor); i++;
case 0x0:
+ // the data is 16-byte aligned, so do the fast processing of the bulk of the samples
+ convert_item32_1_to_fc32_1_bswap_guts(_)
+ break;
+ case 0x8:
+ // the first sample is 8-byte aligned - process it to align the remainder of the samples to 16-bytes
+ item32_sc16_to_xx<uhd::htonx>(input, output, 1, scale_factor);
+ i++;
+ // do faster processing of the bulk of the samples now that we are 16-byte aligned
convert_item32_1_to_fc32_1_bswap_guts(_)
break;
- default: convert_item32_1_to_fc32_1_bswap_guts(u_)
+ default:
+ // we are not 8 or 16-byte aligned, so do fast processing with the unaligned load and store
+ convert_item32_1_to_fc32_1_bswap_guts(u_)
}
- //convert remainder
+ // convert any remaining samples
item32_sc16_to_xx<uhd::htonx>(input+i, output+i, nsamps-i, scale_factor);
}
diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp
index 0ef53db0a..8bd0f4354 100644
--- a/host/lib/transport/libusb1_base.cpp
+++ b/host/lib/transport/libusb1_base.cpp
@@ -19,10 +19,12 @@
#include <uhd/exception.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/utils/log.hpp>
+#include <uhd/utils/tasks.hpp>
#include <uhd/types/dict.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/foreach.hpp>
+#include <boost/bind.hpp>
#include <cstdlib>
#include <iostream>
@@ -37,9 +39,11 @@ public:
libusb_session_impl(void){
UHD_ASSERT_THROW(libusb_init(&_context) == 0);
libusb_set_debug(_context, debug_level);
+ task_handler = task::make(boost::bind(&libusb_session_impl::libusb_event_handler_task, this, _context));
}
~libusb_session_impl(void){
+ task_handler.reset();
libusb_exit(_context);
}
@@ -49,6 +53,21 @@ public:
private:
libusb_context *_context;
+ task::sptr task_handler;
+
+ /*
+ * Task to handle libusb events. There should only be one thread per libusb_context handling events.
+ * Using more than one thread can result in excessive CPU usage in kernel space (presumably from locking/waiting).
+ * The libusb documentation says it is safe, which it is, but it neglects to state the cost in CPU usage.
+ * Just don't do it!
+ */
+ UHD_INLINE void libusb_event_handler_task(libusb_context *context)
+ {
+ timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
+ libusb_handle_events_timeout(context, &tv);
+ }
};
libusb::session::sptr libusb::session::get_global_session(void){
@@ -274,6 +293,10 @@ public:
return libusb::device_descriptor::make(this->get_device())->get().idProduct;
}
+ bool firmware_loaded() {
+ return (get_manufacturer() == "Ettus Research LLC");
+ }
+
private:
libusb::device::sptr _dev; //always keep a reference to device
};
diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp
index 197e257da..2d18e1623 100644
--- a/host/lib/transport/libusb1_zero_copy.cpp
+++ b/host/lib/transport/libusb1_zero_copy.cpp
@@ -73,6 +73,15 @@ struct lut_result_t
int completed;
libusb_transfer_status status;
int actual_length;
+ boost::mutex mut;
+ boost::condition_variable usb_transfer_complete;
+};
+
+// Created to be used as an argument to boost::condition_variable::timed_wait() function
+struct lut_result_completed {
+ const lut_result_t& _result;
+ lut_result_completed(const lut_result_t& result):_result(result) {}
+ bool operator()() const {return (_result.completed ? true : false);}
};
/*!
@@ -84,48 +93,11 @@ struct lut_result_t
static void LIBUSB_CALL libusb_async_cb(libusb_transfer *lut)
{
lut_result_t *r = (lut_result_t *)lut->user_data;
- r->completed = 1;
+ boost::lock_guard<boost::mutex> lock(r->mut);
r->status = lut->status;
r->actual_length = lut->actual_length;
-}
-
-/*!
- * Wait for a managed buffer to become complete.
- *
- * This routine processes async events until the transaction completes.
- * We must call the libusb handle events in a loop because the handler
- * may complete managed buffers other than the one we are waiting on.
- *
- * We cannot determine if handle events timed out or processed an event.
- * Therefore, the timeout condition is handled by using boost system time.
- *
- * \param ctx the libusb context structure
- * \param timeout the wait timeout in seconds
- * \param completed a reference to the completed flag
- * \return true for completion, false for timeout
- */
-UHD_INLINE bool wait_for_completion(libusb_context *ctx, const double timeout, int &completed)
-{
- //already completed by a previous call?
- if (completed) return true;
-
- //perform a non-blocking event handle
- timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- libusb_handle_events_timeout_completed(ctx, &tv, &completed);
- if (completed) return true;
-
- //finish the rest with a timeout loop
- const boost::system_time timeout_time = boost::get_system_time() + boost::posix_time::microseconds(long(timeout*1000000));
- while (not completed and (boost::get_system_time() < timeout_time)){
- timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 10000; /*10ms*/
- libusb_handle_events_timeout_completed(ctx, &tv, &completed);
- }
-
- return completed;
+ r->completed = 1;
+ r->usb_transfer_complete.notify_one(); // wake up thread waiting in wait_for_completion() member function below
}
/***********************************************************************
@@ -154,7 +126,7 @@ public:
template <typename buffer_type>
UHD_INLINE typename buffer_type::sptr get_new(const double timeout)
{
- if (wait_for_completion(_ctx, timeout, result.completed))
+ if (wait_for_completion(timeout))
{
if (result.status != LIBUSB_TRANSFER_COMPLETED) throw uhd::runtime_error(str(boost::format(
"usb %s transfer status: %d") % _name % int(result.status)));
@@ -164,9 +136,31 @@ public:
return typename buffer_type::sptr();
}
+ // This is public because it is accessed from the libusb_zero_copy_single constructor
lut_result_t result;
+ /*!
+ * Wait for a managed buffer to become complete.
+ *
+ * \param timeout the wait timeout in seconds. A negative value will wait forever.
+ * \return true for completion, false for timeout
+ */
+ UHD_INLINE bool wait_for_completion(const double timeout)
+ {
+ boost::unique_lock<boost::mutex> lock(result.mut);
+ if (!result.completed) {
+ if (timeout < 0.0) {
+ result.usb_transfer_complete.wait(lock);
+ } else {
+ const boost::system_time timeout_time = boost::get_system_time() + boost::posix_time::microseconds(long(timeout*1000000));
+ result.usb_transfer_complete.timed_wait(lock, timeout_time, lut_result_completed(result));
+ }
+ }
+ return result.completed;
+ }
+
private:
+
boost::function<void(libusb_zero_copy_mb *)> _release_cb;
const bool _is_recv;
const std::string _name;
@@ -252,8 +246,6 @@ public:
~libusb_zero_copy_single(void)
{
- libusb_context *ctx = libusb::session::get_global_session()->get_context();
-
//cancel all transfers
BOOST_FOREACH(libusb_transfer *lut, _all_luts)
{
@@ -261,8 +253,10 @@ public:
}
//process all transfers until timeout occurs
- int completed = 0;
- wait_for_completion(ctx, 0.01, completed);
+ BOOST_FOREACH(libusb_zero_copy_mb *mb, _enqueued)
+ {
+ mb->wait_for_completion(0.01);
+ }
//free all transfers
BOOST_FOREACH(libusb_transfer *lut, _all_luts)
@@ -276,19 +270,18 @@ public:
{
typename buffer_type::sptr buff;
libusb_zero_copy_mb *front = NULL;
+ boost::mutex::scoped_lock lock(_mutex);
+ if (_enqueued.empty())
{
- boost::mutex::scoped_lock l(_mutex);
- if (_enqueued.empty())
- {
- _cond.timed_wait(l, boost::posix_time::microseconds(long(timeout*1e6)));
- }
- if (_enqueued.empty()) return buff;
- front = _enqueued.front();
+ _cond.timed_wait(lock, boost::posix_time::microseconds(long(timeout*1e6)));
}
+ if (_enqueued.empty()) return buff;
+ front = _enqueued.front();
+ lock.unlock();
buff = front->get_new<buffer_type>(timeout);
+ lock.lock();
- boost::mutex::scoped_lock l(_mutex);
if (buff) _enqueued.pop_front();
this->submit_what_we_can();
return buff;
diff --git a/host/lib/transport/super_recv_packet_handler.hpp b/host/lib/transport/super_recv_packet_handler.hpp
index 688228e49..5080182d6 100644
--- a/host/lib/transport/super_recv_packet_handler.hpp
+++ b/host/lib/transport/super_recv_packet_handler.hpp
@@ -246,7 +246,8 @@ private:
struct xport_chan_props_type{
xport_chan_props_type(void):
packet_count(0),
- handle_overflow(&handle_overflow_nop)
+ handle_overflow(&handle_overflow_nop),
+ fc_update_window(0)
{}
get_buff_type get_buff;
issue_stream_cmd_type issue_stream_cmd;
diff --git a/host/lib/transport/super_send_packet_handler.hpp b/host/lib/transport/super_send_packet_handler.hpp
index 41f030ea6..ae483d1f3 100644
--- a/host/lib/transport/super_send_packet_handler.hpp
+++ b/host/lib/transport/super_send_packet_handler.hpp
@@ -239,7 +239,7 @@ private:
size_t _header_offset_words32;
double _tick_rate, _samp_rate;
struct xport_chan_props_type{
- xport_chan_props_type(void):has_sid(false){}
+ xport_chan_props_type(void):has_sid(false),sid(0){}
get_buff_type get_buff;
bool has_sid;
boost::uint32_t sid;
diff --git a/host/lib/transport/udp_zero_copy.cpp b/host/lib/transport/udp_zero_copy.cpp
index 166177177..7b6a476f5 100644
--- a/host/lib/transport/udp_zero_copy.cpp
+++ b/host/lib/transport/udp_zero_copy.cpp
@@ -68,7 +68,7 @@ static void check_registry_for_fast_send_threshold(const size_t mtu){
class udp_zero_copy_asio_mrb : public managed_recv_buffer{
public:
udp_zero_copy_asio_mrb(void *mem, int sock_fd, const size_t frame_size):
- _mem(mem), _sock_fd(sock_fd), _frame_size(frame_size) { /*NOP*/ }
+ _mem(mem), _sock_fd(sock_fd), _frame_size(frame_size), _len(0) { /*NOP*/ }
void release(void){
_claimer.release();
@@ -87,6 +87,7 @@ public:
if (wait_for_recv_ready(_sock_fd, timeout)){
_len = ::recv(_sock_fd, (char *)_mem, _frame_size, 0);
+ UHD_ASSERT_THROW(_len > 0); // TODO: Handle case of recv error
index++; //advances the caller's buffer
return make(this, _mem, size_t(_len));
}
diff --git a/host/lib/types/CMakeLists.txt b/host/lib/types/CMakeLists.txt
index 2ca0faef7..b69c8e487 100644
--- a/host/lib/types/CMakeLists.txt
+++ b/host/lib/types/CMakeLists.txt
@@ -1,5 +1,5 @@
#
-# Copyright 2011 Ettus Research LLC
+# Copyright 2011-2013 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
@@ -88,4 +88,5 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/time_spec.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tune.cpp
${CMAKE_CURRENT_SOURCE_DIR}/types.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/wb_iface.cpp
)
diff --git a/host/lib/types/tune.cpp b/host/lib/types/tune.cpp
index 154f0990f..7697bd966 100644
--- a/host/lib/types/tune.cpp
+++ b/host/lib/types/tune.cpp
@@ -24,7 +24,9 @@ using namespace uhd;
tune_request_t::tune_request_t(double target_freq):
target_freq(target_freq),
rf_freq_policy(POLICY_AUTO),
- dsp_freq_policy(POLICY_AUTO)
+ rf_freq(0.0),
+ dsp_freq_policy(POLICY_AUTO),
+ dsp_freq(0.0)
{
/* NOP */
}
@@ -33,7 +35,8 @@ tune_request_t::tune_request_t(double target_freq, double lo_off):
target_freq(target_freq),
rf_freq_policy(POLICY_MANUAL),
rf_freq(target_freq + lo_off),
- dsp_freq_policy(POLICY_AUTO)
+ dsp_freq_policy(POLICY_AUTO),
+ dsp_freq(0.0)
{
/* NOP */
}
diff --git a/host/lib/usrp/cores/wb_iface.cpp b/host/lib/types/wb_iface.cpp
index 9aa6d18d4..6edfdfe2f 100644
--- a/host/lib/usrp/cores/wb_iface.cpp
+++ b/host/lib/types/wb_iface.cpp
@@ -15,11 +15,16 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <uhd/exception.hpp>
using namespace uhd;
+wb_iface::~wb_iface(void)
+{
+ //NOP
+}
+
void wb_iface::poke64(const wb_iface::wb_addr_type, const boost::uint64_t)
{
throw uhd::not_implemented_error("poke64 not implemented");
diff --git a/host/lib/usrp/README b/host/lib/usrp/README
deleted file mode 100644
index 344209179..000000000
--- a/host/lib/usrp/README
+++ /dev/null
@@ -1,15 +0,0 @@
-########################################################################
-# lib USRP directories:
-########################################################################
-
-dboard:
- Daughterboard implementation code for all USRP daughterboards
-
-usrp1:
- Implementation code for the USB-based USRP Classic motherboard.
-
-usrp2:
- Implementation code for USRP2, USRP-N200, and USRP-N210.
-
-usrp_e100:
- Implementation code for USRP-E100.
diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp
index 19df3d6af..305ba42a7 100644
--- a/host/lib/usrp/b100/b100_impl.cpp
+++ b/host/lib/usrp/b100/b100_impl.cpp
@@ -310,12 +310,14 @@ b100_impl::b100_impl(const device_addr_t &device_addr){
_tree->create<std::string>(rx_codec_path / "name").set("ad9522");
_tree->create<meta_range_t>(rx_codec_path / "gains/pga/range").set(b100_codec_ctrl::rx_pga_gain_range);
_tree->create<double>(rx_codec_path / "gains/pga/value")
- .coerce(boost::bind(&b100_impl::update_rx_codec_gain, this, _1));
+ .coerce(boost::bind(&b100_impl::update_rx_codec_gain, this, _1))
+ .set(0.0);
_tree->create<std::string>(tx_codec_path / "name").set("ad9522");
_tree->create<meta_range_t>(tx_codec_path / "gains/pga/range").set(b100_codec_ctrl::tx_pga_gain_range);
_tree->create<double>(tx_codec_path / "gains/pga/value")
.subscribe(boost::bind(&b100_codec_ctrl::set_tx_pga_gain, _codec_ctrl, _1))
- .publish(boost::bind(&b100_codec_ctrl::get_tx_pga_gain, _codec_ctrl));
+ .publish(boost::bind(&b100_codec_ctrl::get_tx_pga_gain, _codec_ctrl))
+ .set(0.0);
////////////////////////////////////////////////////////////////////
// and do the misc mboard sensors
diff --git a/host/lib/usrp/b100/b100_impl.hpp b/host/lib/usrp/b100/b100_impl.hpp
index f81aa3568..ab83c80a3 100644
--- a/host/lib/usrp/b100/b100_impl.hpp
+++ b/host/lib/usrp/b100/b100_impl.hpp
@@ -67,7 +67,7 @@ static const std::string B100_EEPROM_MAP_KEY = "B100";
//! Make a b100 dboard interface
uhd::usrp::dboard_iface::sptr make_b100_dboard_iface(
- wb_iface::sptr wb_iface,
+ uhd::wb_iface::sptr wb_iface,
uhd::i2c_iface::sptr i2c_iface,
uhd::spi_iface::sptr spi_iface,
b100_clock_ctrl::sptr clock,
diff --git a/host/lib/usrp/b100/usb_zero_copy_wrapper.cpp b/host/lib/usrp/b100/usb_zero_copy_wrapper.cpp
index 2096e4ef4..451cdae50 100644
--- a/host/lib/usrp/b100/usb_zero_copy_wrapper.cpp
+++ b/host/lib/usrp/b100/usb_zero_copy_wrapper.cpp
@@ -167,6 +167,7 @@ public:
usb_zero_copy_wrapper(zero_copy_if::sptr usb_zc, const size_t frame_boundary):
_internal_zc(usb_zc),
_frame_boundary(frame_boundary),
+ _last_recv_offset(0),
_next_recv_buff_index(0)
{
for (size_t i = 0; i < this->get_num_recv_frames(); i++){
diff --git a/host/lib/usrp/b200/b200_iface.cpp b/host/lib/usrp/b200/b200_iface.cpp
index 1d05e159c..5d799bf01 100644
--- a/host/lib/usrp/b200/b200_iface.cpp
+++ b/host/lib/usrp/b200/b200_iface.cpp
@@ -17,6 +17,7 @@
#include "b200_iface.hpp"
+#include <uhd/config.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/exception.hpp>
#include <boost/functional/hash.hpp>
@@ -62,6 +63,7 @@ const static boost::uint8_t B200_VREQ_FX3_RESET = 0x99;
const static boost::uint8_t B200_VREQ_EEPROM_WRITE = 0xBA;
const static boost::uint8_t B200_VREQ_EEPROM_READ = 0xBB;
+const static boost::uint8_t FX3_STATE_UNDEFINED = 0x00;
const static boost::uint8_t FX3_STATE_FPGA_READY = 0x01;
const static boost::uint8_t FX3_STATE_CONFIGURING_FPGA = 0x02;
const static boost::uint8_t FX3_STATE_BUSY = 0x03;
@@ -69,6 +71,11 @@ const static boost::uint8_t FX3_STATE_RUNNING = 0x04;
const static boost::uint8_t FX3_STATE_UNCONFIGURED = 0x05;
const static boost::uint8_t FX3_STATE_ERROR = 0x06;
+const static int VREQ_MAX_SIZE_USB2 = 64;
+const static int VREQ_MAX_SIZE_USB3 = 512;
+const static int VREQ_DEFAULT_SIZE = VREQ_MAX_SIZE_USB2;
+const static int VREQ_MAX_SIZE = VREQ_MAX_SIZE_USB3;
+
typedef boost::uint32_t hash_type;
@@ -83,6 +90,9 @@ typedef boost::uint32_t hash_type;
*/
static hash_type generate_hash(const char *filename)
{
+ if (filename == NULL)
+ return hash_type(0);
+
std::ifstream file(filename);
if (not file){
throw uhd::io_error(std::string("cannot open input file ") + filename);
@@ -115,15 +125,15 @@ static hash_type generate_hash(const char *filename)
* \param record a line from an Intel HEX file
* \return true if record is valid, false otherwise
*/
-bool checksum(std::string *record) {
+bool checksum(const std::string& record) {
- size_t len = record->length();
+ size_t len = record.length();
unsigned int i;
unsigned char sum = 0;
unsigned int val;
for (i = 1; i < len; i += 2) {
- std::istringstream(record->substr(i, 2)) >> std::hex >> val;
+ std::istringstream(record.substr(i, 2)) >> std::hex >> val;
sum += val;
}
@@ -144,22 +154,25 @@ bool checksum(std::string *record) {
* \param data output data
* \return true if record is sucessfully read, false on error
*/
-bool parse_record(std::string *record, boost::uint16_t &len, \
+bool parse_record(const std::string& record, boost::uint16_t &len, \
boost::uint16_t &addr, boost::uint16_t &type, unsigned char* data) {
unsigned int i;
std::string _data;
unsigned int val;
- if (record->substr(0, 1) != ":")
+ if (record.substr(0, 1) != ":")
return false;
- std::istringstream(record->substr(1, 2)) >> std::hex >> len;
- std::istringstream(record->substr(3, 4)) >> std::hex >> addr;
- std::istringstream(record->substr(7, 2)) >> std::hex >> type;
+ std::istringstream(record.substr(1, 2)) >> std::hex >> len;
+ std::istringstream(record.substr(3, 4)) >> std::hex >> addr;
+ std::istringstream(record.substr(7, 2)) >> std::hex >> type;
+
+ if (len > (2 * (record.length() - 9))) // sanity check to prevent buffer overrun
+ return false;
for (i = 0; i < len; i++) {
- std::istringstream(record->substr(9 + 2 * i, 2)) >> std::hex >> val;
+ std::istringstream(record.substr(9 + 2 * i, 2)) >> std::hex >> val;
data[i] = (unsigned char) val;
}
@@ -174,19 +187,16 @@ class b200_iface_impl : public b200_iface{
public:
b200_iface_impl(usb_control::sptr usb_ctrl):
- _usb_ctrl(usb_ctrl)
- {
+ _usb_ctrl(usb_ctrl) {
//NOP
}
-
int fx3_control_write(boost::uint8_t request,
boost::uint16_t value,
boost::uint16_t index,
unsigned char *buff,
boost::uint16_t length,
- boost::int32_t timeout = 0)
- {
+ boost::int32_t timeout = 0) {
return _usb_ctrl->submit(VRT_VENDOR_OUT, // bmReqeustType
request, // bRequest
value, // wValue
@@ -196,14 +206,12 @@ public:
timeout); // timeout
}
-
int fx3_control_read(boost::uint8_t request,
boost::uint16_t value,
boost::uint16_t index,
unsigned char *buff,
boost::uint16_t length,
- boost::int32_t timeout = 0)
- {
+ boost::int32_t timeout = 0) {
return _usb_ctrl->submit(VRT_VENDOR_IN, // bmReqeustType
request, // bRequest
value, // wValue
@@ -213,37 +221,45 @@ public:
timeout); // timeout
}
-
- void write_i2c(boost::uint16_t addr, const byte_vector_t &bytes)
+ void write_i2c(UHD_UNUSED(boost::uint16_t addr), UHD_UNUSED(const byte_vector_t &bytes))
{
throw uhd::not_implemented_error("b200 write i2c");
}
- byte_vector_t read_i2c(boost::uint16_t addr, size_t num_bytes)
+ byte_vector_t read_i2c(UHD_UNUSED(boost::uint16_t addr), UHD_UNUSED(size_t num_bytes))
{
throw uhd::not_implemented_error("b200 read i2c");
}
void write_eeprom(boost::uint16_t addr, boost::uint16_t offset,
- const byte_vector_t &bytes)
- {
- fx3_control_write(B200_VREQ_EEPROM_WRITE,
+ const byte_vector_t &bytes) {
+ int ret = fx3_control_write(B200_VREQ_EEPROM_WRITE,
0, offset | (boost::uint16_t(addr) << 8),
(unsigned char *) &bytes[0],
bytes.size());
+
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to write EEPROM (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if ((size_t)ret != bytes.size())
+ throw uhd::io_error((boost::format("Short write on write EEPROM (expecting: %d, returned: %d)") % bytes.size() % ret).str());
}
byte_vector_t read_eeprom(
boost::uint16_t addr,
boost::uint16_t offset,
- size_t num_bytes
- ){
+ size_t num_bytes) {
byte_vector_t recv_bytes(num_bytes);
- fx3_control_read(B200_VREQ_EEPROM_READ,
+ int bytes_read = fx3_control_read(B200_VREQ_EEPROM_READ,
0, offset | (boost::uint16_t(addr) << 8),
(unsigned char*) &recv_bytes[0],
num_bytes);
+
+ if (bytes_read < 0)
+ throw uhd::io_error((boost::format("Failed to read EEPROM (%d: %s)") % bytes_read % libusb_error_name(bytes_read)).str());
+ else if ((size_t)bytes_read != num_bytes)
+ throw uhd::io_error((boost::format("Short read on read EEPROM (expecting: %d, returned: %d)") % num_bytes % bytes_read).str());
+
return recv_bytes;
}
@@ -251,8 +267,7 @@ public:
unsigned char *tx_data,
size_t num_tx_bits,
unsigned char *rx_data,
- size_t num_rx_bits
- ){
+ size_t num_rx_bits) {
int ret = 0;
boost::uint16_t tx_length = num_tx_bits / 8;
@@ -264,9 +279,10 @@ public:
0x00, tx_data, tx_length);
}
- if(ret < 0) {
- throw uhd::io_error("transact_spi: fx3_control_write failed!");
- }
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to write SPI (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != tx_length)
+ throw uhd::io_error((boost::format("Short write on write SPI (expecting: %d, returned: %d)") % tx_length % ret).str());
if(num_rx_bits) {
@@ -275,25 +291,38 @@ public:
ret = fx3_control_read(B200_VREQ_LOOP, 0x00, \
0x00, rx_data, total_length);
- if(ret < 0) {
- throw uhd::io_error("transact_spi: readback failed!");
- }
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to readback (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != total_length)
+ throw uhd::io_error((boost::format("Short read on readback (expecting: %d, returned: %d)") % total_length % ret).str());
}
}
void ad9361_transact(const unsigned char in_buff[64], unsigned char out_buff[64]) {
- fx3_control_write(B200_VREQ_AD9361_CTRL_WRITE, 0x00, 0x00, (unsigned char *)in_buff, 64);
- int ret = 0;
- for (size_t i = 0; i < 30; i++)
+ const int bytes_to_write = 64;
+ const int bytes_to_read = 64;
+ const size_t read_retries = 30;
+
+ int ret = fx3_control_write(B200_VREQ_AD9361_CTRL_WRITE, 0x00, 0x00, (unsigned char *)in_buff, bytes_to_write);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to write AD9361 (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_write)
+ throw uhd::io_error((boost::format("Short write on write AD9361 (expecting: %d, returned: %d)") % bytes_to_write % ret).str());
+
+ for (size_t i = 0; i < read_retries; i++)
{
- ret = fx3_control_read(B200_VREQ_AD9361_CTRL_READ, 0x00, 0x00, out_buff, 64, 1000);
- if (ret == 64) return;
+ ret = fx3_control_read(B200_VREQ_AD9361_CTRL_READ, 0x00, 0x00, out_buff, bytes_to_read, 1000);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to read AD9361 (%d: %s)") % ret % libusb_error_name(ret)).str());
+
+ if (ret == bytes_to_read)
+ return;
}
- throw uhd::io_error(str(boost::format("ad9361_transact failed with usb error: %d") % ret));
- }
+ throw uhd::io_error(str(boost::format("Failed to read complete AD9361 (expecting: %d, last read: %d)") % bytes_to_read % ret));
+ }
- void load_firmware(const std::string filestring, bool force = false)
+ void load_firmware(const std::string filestring, UHD_UNUSED(bool force) = false)
{
const char *filename = filestring.c_str();
@@ -323,8 +352,11 @@ public:
std::string record;
file >> record;
+ if (!(record.length() > 0))
+ continue;
+
/* Check for valid Intel HEX record. */
- if (!checksum(&record) || !parse_record(&record, len, \
+ if (!checksum(record) || !parse_record(record, len, \
lower_address_bits, type, data)) {
throw uhd::io_error("fx3_load_firmware: bad intel hex record checksum");
}
@@ -397,46 +429,75 @@ public:
throw uhd::io_error("fx3_load_firmware: No EOF record found.");
}
-
void reset_fx3(void) {
unsigned char data[4];
memset(data, 0x00, sizeof(data));
+ const int bytes_to_send = sizeof(data);
- fx3_control_write(B200_VREQ_FX3_RESET, 0x00, 0x00, data, 4);
+ int ret = fx3_control_write(B200_VREQ_FX3_RESET, 0x00, 0x00, data, bytes_to_send);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to reset FX3 (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_send)
+ throw uhd::io_error((boost::format("Short write on reset FX3 (expecting: %d, returned: %d)") % bytes_to_send % ret).str());
}
void reset_gpif(void) {
unsigned char data[4];
memset(data, 0x00, sizeof(data));
+ const int bytes_to_send = sizeof(data);
- fx3_control_write(B200_VREQ_GPIF_RESET, 0x00, 0x00, data, 4);
+ int ret = fx3_control_write(B200_VREQ_GPIF_RESET, 0x00, 0x00, data, bytes_to_send);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to reset GPIF (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_send)
+ throw uhd::io_error((boost::format("Short write on reset GPIF (expecting: %d, returned: %d)") % bytes_to_send % ret).str());
}
- void set_fpga_reset_pin(const bool reset)
- {
+ void set_fpga_reset_pin(const bool reset) {
unsigned char data[4];
memset(data, (reset)? 0xFF : 0x00, sizeof(data));
UHD_THROW_INVALID_CODE_PATH();
- fx3_control_write(B200_VREQ_FPGA_RESET, 0x00, 0x00, data, 4);
+ // Below is dead code as long as UHD_THROW_INVALID_CODE_PATH(); is declared above.
+ // It is preserved here in a comment in case it is needed later:
+ /*
+ const int bytes_to_send = sizeof(data);
+
+ int ret = fx3_control_write(B200_VREQ_FPGA_RESET, 0x00, 0x00, data, bytes_to_send);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to reset FPGA (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_send)
+ throw uhd::io_error((boost::format("Short write on reset FPGA (expecting: %d, returned: %d)") % bytes_to_send % ret).str());
+ */
}
boost::uint8_t get_usb_speed(void) {
unsigned char rx_data[1];
+ memset(rx_data, 0x00, sizeof(rx_data));
+ const int bytes_to_recv = sizeof(rx_data);
- fx3_control_read(B200_VREQ_GET_USB, 0x00, 0x00, rx_data, 1);
+ int ret = fx3_control_read(B200_VREQ_GET_USB, 0x00, 0x00, rx_data, bytes_to_recv);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to get USB speed (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_recv)
+ throw uhd::io_error((boost::format("Short read on get USB speed (expecting: %d, returned: %d)") % bytes_to_recv % ret).str());
return boost::lexical_cast<boost::uint8_t>(rx_data[0]);
}
-
boost::uint8_t get_fx3_status(void) {
unsigned char rx_data[1];
+ memset(rx_data, 0x00, sizeof(rx_data));
+ const int bytes_to_recv = sizeof(rx_data);
- fx3_control_read(B200_VREQ_GET_STATUS, 0x00, 0x00, &rx_data[0], 1);
+ int ret = fx3_control_read(B200_VREQ_GET_STATUS, 0x00, 0x00, rx_data, bytes_to_recv);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to get FX3 status (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_recv)
+ throw uhd::io_error((boost::format("Short read on get FX3 status (expecting: %d, returned: %d)") % bytes_to_recv % ret).str());
return boost::lexical_cast<boost::uint8_t>(rx_data[0]);
}
@@ -444,40 +505,72 @@ public:
boost::uint16_t get_compat_num(void) {
unsigned char rx_data[2];
+ memset(rx_data, 0x00, sizeof(rx_data));
+ const int bytes_to_recv = sizeof(rx_data);
- fx3_control_read(B200_VREQ_GET_COMPAT , 0x00, 0x00, rx_data, 2);
-
- boost::uint16_t compat = 0x0000;
- compat |= (((uint16_t) rx_data[0]) << 8);
- compat |= (rx_data[1] & 0x00FF);
+ int ret = fx3_control_read(B200_VREQ_GET_COMPAT , 0x00, 0x00, rx_data, bytes_to_recv);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to get compat num (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_recv)
+ throw uhd::io_error((boost::format("Short read on get compat num (expecting: %d, returned: %d)") % bytes_to_recv % ret).str());
- return compat;
+ return (((uint16_t)rx_data[0]) << 8) | rx_data[1];
}
void usrp_get_firmware_hash(hash_type &hash) {
- fx3_control_read(B200_VREQ_GET_FW_HASH, 0x00, 0x00,
- (unsigned char*) &hash, 4, 500);
+ const int bytes_to_recv = 4;
+ if (sizeof(hash_type) != bytes_to_recv)
+ throw uhd::type_error((boost::format("hash_type is %d bytes but transfer length is %d bytes") % sizeof(hash_type) % bytes_to_recv).str());
+
+ int ret = fx3_control_read(B200_VREQ_GET_FW_HASH, 0x00, 0x00, (unsigned char*) &hash, bytes_to_recv, 500);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to get firmware hash (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_recv)
+ throw uhd::io_error((boost::format("Short read on get firmware hash (expecting: %d, returned: %d)") % bytes_to_recv % ret).str());
}
void usrp_set_firmware_hash(hash_type hash) {
- fx3_control_write(B200_VREQ_SET_FW_HASH, 0x00, 0x00,
- (unsigned char*) &hash, 4);
+ const int bytes_to_send = 4;
+ if (sizeof(hash_type) != bytes_to_send)
+ throw uhd::type_error((boost::format("hash_type is %d bytes but transfer length is %d bytes") % sizeof(hash_type) % bytes_to_send).str());
+
+ int ret = fx3_control_write(B200_VREQ_SET_FW_HASH, 0x00, 0x00, (unsigned char*) &hash, bytes_to_send);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to set firmware hash (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_send)
+ throw uhd::io_error((boost::format("Short write on set firmware hash (expecting: %d, returned: %d)") % bytes_to_send % ret).str());
}
void usrp_get_fpga_hash(hash_type &hash) {
- fx3_control_read(B200_VREQ_GET_FPGA_HASH, 0x00, 0x00,
- (unsigned char*) &hash, 4, 500);
+ const int bytes_to_recv = 4;
+ if (sizeof(hash_type) != bytes_to_recv)
+ throw uhd::type_error((boost::format("hash_type is %d bytes but transfer length is %d bytes") % sizeof(hash_type) % bytes_to_recv).str());
+
+ int ret = fx3_control_read(B200_VREQ_GET_FPGA_HASH, 0x00, 0x00, (unsigned char*) &hash, bytes_to_recv, 500);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to get FPGA hash (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_recv)
+ throw uhd::io_error((boost::format("Short read on get FPGA hash (expecting: %d, returned: %d)") % bytes_to_recv % ret).str());
}
void usrp_set_fpga_hash(hash_type hash) {
- fx3_control_write(B200_VREQ_SET_FPGA_HASH, 0x00, 0x00,
- (unsigned char*) &hash, 4);
+ const int bytes_to_send = 4;
+ if (sizeof(hash_type) != bytes_to_send)
+ throw uhd::type_error((boost::format("hash_type is %d bytes but transfer length is %d bytes") % sizeof(hash_type) % bytes_to_send).str());
+
+ int ret = fx3_control_write(B200_VREQ_SET_FPGA_HASH, 0x00, 0x00, (unsigned char*) &hash, bytes_to_send);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to set FPGA hash (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_send)
+ throw uhd::io_error((boost::format("Short write on set FPGA hash (expecting: %d, returned: %d)") % bytes_to_send % ret).str());
}
boost::uint32_t load_fpga(const std::string filestring) {
boost::uint8_t fx3_state = 0;
boost::uint32_t wait_count;
+ int ret = 0;
+ int bytes_to_xfer = 0;
const char *filename = filestring.c_str();
@@ -485,9 +578,27 @@ public:
hash_type loaded_hash; usrp_get_fpga_hash(loaded_hash);
if (hash == loaded_hash) return 0;
- unsigned char out_buff[64];
- memset(out_buff, 0x00, sizeof(out_buff));
- fx3_control_write(B200_VREQ_FPGA_CONFIG, 0, 0, out_buff, 1, 1000);
+ // Establish default largest possible control request transfer size based on operating USB speed
+ int transfer_size = VREQ_DEFAULT_SIZE;
+ int current_usb_speed = get_usb_speed();
+ if (current_usb_speed == 3)
+ transfer_size = VREQ_MAX_SIZE_USB3;
+ else if (current_usb_speed != 2)
+ throw uhd::io_error("load_fpga: get_usb_speed returned invalid USB speed (not 2 or 3).");
+
+ UHD_ASSERT_THROW(transfer_size <= VREQ_MAX_SIZE);
+
+ unsigned char out_buff[VREQ_MAX_SIZE];
+
+ // Request loopback read, which will indicate the firmware's current control request buffer size
+ // Make sure that if operating as USB2, requested length is within spec
+ int ntoread = std::min(transfer_size, (int)sizeof(out_buff));
+ int nread = fx3_control_read(B200_VREQ_LOOP, 0, 0, out_buff, ntoread, 1000);
+ if (nread < 0)
+ throw uhd::io_error((boost::format("load_fpga: unable to complete firmware loopback request (%d: %s)") % nread % libusb_error_name(nread)).str());
+ else if (nread != ntoread)
+ throw uhd::io_error((boost::format("load_fpga: short read on firmware loopback request (expecting: %d, returned: %d)") % ntoread % nread).str());
+ transfer_size = std::min(transfer_size, nread); // Select the smaller value
size_t file_size = 0;
{
@@ -498,15 +609,26 @@ public:
std::ifstream file;
file.open(filename, std::ios::in | std::ios::binary);
- if(!file.good()) {
+ if (!file.good()) {
throw uhd::io_error("load_fpga: cannot open FPGA input file.");
}
+ // Zero the hash, in case we abort programming another image and revert to the previously programmed image
+ usrp_set_fpga_hash(0);
+
+ memset(out_buff, 0x00, sizeof(out_buff));
+ bytes_to_xfer = 1;
+ ret = fx3_control_write(B200_VREQ_FPGA_CONFIG, 0, 0, out_buff, bytes_to_xfer, 1000);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to start FPGA config (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_xfer)
+ throw uhd::io_error((boost::format("Short write on start FPGA config (expecting: %d, returned: %d)") % bytes_to_xfer % ret).str());
+
wait_count = 0;
do {
fx3_state = get_fx3_status();
- if((wait_count >= 500) || (fx3_state == FX3_STATE_ERROR)) {
+ if((wait_count >= 500) || (fx3_state == FX3_STATE_ERROR) || (fx3_state == FX3_STATE_UNDEFINED)) {
return fx3_state;
}
@@ -518,13 +640,18 @@ public:
if (load_img_msg) UHD_MSG(status) << "Loading FPGA image: " \
<< filestring << "..." << std::flush;
- fx3_control_write(B200_VREQ_FPGA_START, 0, 0, out_buff, 1, 1000);
+ bytes_to_xfer = 1;
+ ret = fx3_control_write(B200_VREQ_FPGA_START, 0, 0, out_buff, bytes_to_xfer, 1000);
+ if (ret < 0)
+ throw uhd::io_error((boost::format("Failed to start FPGA bitstream (%d: %s)") % ret % libusb_error_name(ret)).str());
+ else if (ret != bytes_to_xfer)
+ throw uhd::io_error((boost::format("Short write on start FPGA bitstream (expecting: %d, returned: %d)") % bytes_to_xfer % ret).str());
wait_count = 0;
do {
fx3_state = get_fx3_status();
- if((wait_count >= 1000) || (fx3_state == FX3_STATE_ERROR)) {
+ if((wait_count >= 1000) || (fx3_state == FX3_STATE_ERROR) || (fx3_state == FX3_STATE_UNDEFINED)) {
return fx3_state;
}
@@ -534,15 +661,20 @@ public:
} while(fx3_state != FX3_STATE_CONFIGURING_FPGA);
size_t bytes_sent = 0;
- while(!file.eof()) {
- file.read((char *) out_buff, sizeof(out_buff));
+ while (!file.eof()) {
+ file.read((char *) out_buff, transfer_size);
const std::streamsize n = file.gcount();
- if(n == 0) continue;
+ if(n == 0)
+ continue;
boost::uint16_t transfer_count = boost::uint16_t(n);
/* Send the data to the device. */
- fx3_control_write(B200_VREQ_FPGA_DATA, 0, 0, out_buff, transfer_count, 5000);
+ int nwritten = fx3_control_write(B200_VREQ_FPGA_DATA, 0, 0, out_buff, transfer_count, 5000);
+ if (nwritten < 0)
+ throw uhd::io_error((boost::format("load_fpga: cannot write bitstream to FX3 (%d: %s)") % nwritten % libusb_error_name(nwritten)).str());
+ else if (nwritten != transfer_count)
+ throw uhd::io_error((boost::format("load_fpga: short write while transferring bitstream to FX3 (expecting: %d, returned: %d)") % transfer_count % nwritten).str());
if (load_img_msg)
{
@@ -563,7 +695,7 @@ public:
do {
fx3_state = get_fx3_status();
- if((wait_count >= 500) || (fx3_state == FX3_STATE_ERROR)) {
+ if((wait_count >= 500) || (fx3_state == FX3_STATE_ERROR) || (fx3_state == FX3_STATE_UNDEFINED)) {
return fx3_state;
}
@@ -574,7 +706,8 @@ public:
usrp_set_fpga_hash(hash);
- if (load_img_msg) UHD_MSG(status) << "\b\b\b\b done" << std::endl;
+ if (load_img_msg)
+ UHD_MSG(status) << "\b\b\b\b done" << std::endl;
return 0;
}
@@ -583,6 +716,29 @@ private:
usb_control::sptr _usb_ctrl;
};
+
+std::string b200_iface::fx3_state_string(boost::uint8_t state)
+{
+ switch (state)
+ {
+ case FX3_STATE_FPGA_READY:
+ return std::string("Ready");
+ case FX3_STATE_CONFIGURING_FPGA:
+ return std::string("Configuring FPGA");
+ case FX3_STATE_BUSY:
+ return std::string("Busy");
+ case FX3_STATE_RUNNING:
+ return std::string("Running");
+ case FX3_STATE_UNCONFIGURED:
+ return std::string("Unconfigured");
+ case FX3_STATE_ERROR:
+ return std::string("Error");
+ default:
+ break;
+ }
+ return std::string("Unknown");
+}
+
/***********************************************************************
* Make an instance of the implementation
**********************************************************************/
diff --git a/host/lib/usrp/b200/b200_iface.hpp b/host/lib/usrp/b200/b200_iface.hpp
index 1247d1f86..20b4a7a89 100644
--- a/host/lib/usrp/b200/b200_iface.hpp
+++ b/host/lib/usrp/b200/b200_iface.hpp
@@ -25,7 +25,17 @@
#include <boost/utility.hpp>
#include "ad9361_ctrl.hpp"
-class b200_iface: boost::noncopyable, public virtual uhd::i2c_iface,
+const static boost::uint16_t B200_VENDOR_ID = 0x2500;
+const static boost::uint16_t B200_PRODUCT_ID = 0x0020;
+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";
+
+class UHD_API b200_iface: boost::noncopyable, public virtual uhd::i2c_iface,
public ad9361_ctrl_iface_type {
public:
typedef boost::shared_ptr<b200_iface> sptr;
@@ -64,6 +74,12 @@ public:
//! send SPI through the FX3
virtual void transact_spi( unsigned char *tx_data, size_t num_tx_bits, \
unsigned char *rx_data, size_t num_rx_bits) = 0;
+
+ virtual void write_eeprom(boost::uint16_t addr, boost::uint16_t offset, const uhd::byte_vector_t &bytes) = 0;
+
+ virtual uhd::byte_vector_t read_eeprom(boost::uint16_t addr, boost::uint16_t offset, size_t num_bytes) = 0;
+
+ static std::string fx3_state_string(boost::uint8_t state);
};
diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp
index 0da388b93..132b1198d 100644
--- a/host/lib/usrp/b200/b200_impl.cpp
+++ b/host/lib/usrp/b200/b200_impl.cpp
@@ -37,10 +37,6 @@ using namespace uhd;
using namespace uhd::usrp;
using namespace uhd::transport;
-const boost::uint16_t B200_VENDOR_ID = 0x2500;
-const boost::uint16_t B200_PRODUCT_ID = 0x0020;
-const boost::uint16_t INIT_PRODUCT_ID = 0x00f0;
-
static const boost::posix_time::milliseconds REENUMERATION_TIMEOUT_MS(3000);
//! mapping of frontend to radio perif index
@@ -99,7 +95,7 @@ static device_addrs_t b200_find(const device_addr_t &hint)
catch(const uhd::exception &){continue;} //ignore claimed
//check if fw was already loaded
- if (handle->get_manufacturer() != "Ettus Research LLC")
+ if (!(handle->firmware_loaded()))
{
b200_iface::make(control)->load_firmware(b200_fw_image);
}
@@ -160,8 +156,15 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
const fs_path mb_path = "/mboards/0";
//try to match the given device address with something on the USB bus
+ uint16_t vid = B200_VENDOR_ID;
+ uint16_t pid = B200_PRODUCT_ID;
+ if (device_addr.has_key("vid"))
+ sscanf(device_addr.get("vid").c_str(), "%x", &vid);
+ if (device_addr.has_key("pid"))
+ sscanf(device_addr.get("pid").c_str(), "%x", &pid);
+
std::vector<usb_device_handle::sptr> device_list =
- usb_device_handle::get_device_list(B200_VENDOR_ID, B200_PRODUCT_ID);
+ usb_device_handle::get_device_list(vid, pid);
//locate the matching handle in the device list
usb_device_handle::sptr handle;
@@ -252,7 +255,7 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
////////////////////////////////////////////////////////////////////
_async_task_data.reset(new AsyncTaskData());
_async_task_data->async_md.reset(new async_md_type(1000/*messages deep*/));
- _async_task = uhd::task::make(boost::bind(&b200_impl::handle_async_task, this, _ctrl_transport, _async_task_data));
+ _async_task = uhd::msg_task::make(boost::bind(&b200_impl::handle_async_task, this, _ctrl_transport, _async_task_data));
////////////////////////////////////////////////////////////////////
// Local control endpoint
@@ -474,7 +477,7 @@ b200_impl::b200_impl(const device_addr_t &device_addr)
b200_impl::~b200_impl(void)
{
- UHD_SAFE_CALL
+ UHD_SAFE_CALL
(
_async_task.reset();
)
@@ -612,7 +615,7 @@ void b200_impl::setup_radio(const size_t dspno)
/***********************************************************************
* loopback tests
**********************************************************************/
-
+
void b200_impl::register_loopback_self_test(wb_iface::sptr iface)
{
bool test_fail = false;
diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp
index 818906e60..bee42679b 100644
--- a/host/lib/usrp/b200/b200_impl.hpp
+++ b/host/lib/usrp/b200/b200_impl.hpp
@@ -44,13 +44,9 @@
#include <uhd/transport/bounded_buffer.hpp>
#include <boost/weak_ptr.hpp>
#include "recv_packet_demuxer_3000.hpp"
-
-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";
-static const boost::uint8_t B200_FW_COMPAT_NUM_MAJOR = 0x03;
+static const boost::uint8_t B200_FW_COMPAT_NUM_MAJOR = 0x04;
static const boost::uint8_t B200_FW_COMPAT_NUM_MINOR = 0x00;
-static const boost::uint16_t B200_FPGA_COMPAT_NUM = 0x02;
+static const boost::uint16_t B200_FPGA_COMPAT_NUM = 0x03;
static const double B200_LINK_RATE_BPS = (5e9)/8; //practical link rate (5 Gbps)
static const double B200_BUS_CLOCK_RATE = 100e6;
static const double B200_DEFAULT_TICK_RATE = 32e6;
@@ -120,7 +116,7 @@ struct b200_impl : public uhd::device
boost::weak_ptr<uhd::tx_streamer> _tx_streamer;
//async ctrl + msgs
- uhd::task::sptr _async_task;
+ uhd::msg_task::sptr _async_task;
typedef uhd::transport::bounded_buffer<uhd::async_metadata_t> async_md_type;
struct AsyncTaskData
{
@@ -130,10 +126,10 @@ struct b200_impl : public uhd::device
b200_uart::sptr gpsdo_uart;
};
boost::shared_ptr<AsyncTaskData> _async_task_data;
- void handle_async_task(uhd::transport::zero_copy_if::sptr, boost::shared_ptr<AsyncTaskData>);
+ boost::optional<uhd::msg_task::msg_type_t> handle_async_task(uhd::transport::zero_copy_if::sptr, boost::shared_ptr<AsyncTaskData>);
- void register_loopback_self_test(wb_iface::sptr iface);
- void codec_loopback_self_test(wb_iface::sptr iface);
+ void register_loopback_self_test(uhd::wb_iface::sptr iface);
+ void codec_loopback_self_test(uhd::wb_iface::sptr iface);
void set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &);
void check_fw_compat(void);
void check_fpga_compat(void);
diff --git a/host/lib/usrp/b200/b200_io_impl.cpp b/host/lib/usrp/b200/b200_io_impl.cpp
index d643ef855..4768aa37b 100644
--- a/host/lib/usrp/b200/b200_io_impl.cpp
+++ b/host/lib/usrp/b200/b200_io_impl.cpp
@@ -139,27 +139,44 @@ bool b200_impl::recv_async_msg(
return _async_task_data->async_md->pop_with_timed_wait(async_metadata, timeout);
}
-void b200_impl::handle_async_task(
+/*
+ * This method is constantly called in a msg_task loop.
+ * Incoming messages are dispatched in to the hosts radio_ctrl_cores.
+ * The radio_ctrl_core queues are accessed via a weak_ptr to them, stored in AsyncTaskData.
+ * During shutdown the radio_ctrl_core dtor's are called.
+ * An empty peek32(0) is sent out to flush pending async messages.
+ * The response to those messages can't be delivered to the ctrl_core queues anymore
+ * because the shared pointer corresponding to the weak_ptrs is no longer valid.
+ * Those stranded messages are put into a dump_queue implemented in msg_task.
+ * A radio_ctrl_core can search for missing messages there.
+ */
+boost::optional<uhd::msg_task::msg_type_t> b200_impl::handle_async_task(
uhd::transport::zero_copy_if::sptr xport,
boost::shared_ptr<AsyncTaskData> data
)
{
managed_recv_buffer::sptr buff = xport->get_recv_buff();
- if (not buff or buff->size() < 8) return;
+ if (not buff or buff->size() < 8)
+ return NULL;
+
const boost::uint32_t sid = uhd::wtohx(buff->cast<const boost::uint32_t *>()[1]);
- switch (sid)
- {
+ switch (sid) {
//if the packet is a control response
case B200_RESP0_MSG_SID:
case B200_RESP1_MSG_SID:
case B200_LOCAL_RESP_SID:
{
- radio_ctrl_core_3000::sptr ctrl;
+ radio_ctrl_core_3000::sptr ctrl;
if (sid == B200_RESP0_MSG_SID) ctrl = data->radio_ctrl[0].lock();
if (sid == B200_RESP1_MSG_SID) ctrl = data->radio_ctrl[1].lock();
if (sid == B200_LOCAL_RESP_SID) ctrl = data->local_ctrl.lock();
- if (ctrl) ctrl->push_response(buff->cast<const boost::uint32_t *>());
+ if (ctrl){
+ ctrl->push_response(buff->cast<const boost::uint32_t *>());
+ }
+ else{
+ return std::make_pair(sid, uhd::msg_task::buff_to_vector(buff->cast<boost::uint8_t *>(), buff->size() ) );
+ }
break;
}
@@ -204,6 +221,7 @@ void b200_impl::handle_async_task(
default:
UHD_MSG(error) << "Got a ctrl packet with unknown SID " << sid << std::endl;
}
+ return NULL;
}
/***********************************************************************
@@ -231,14 +249,14 @@ rx_streamer::sptr b200_impl::get_rx_stream(const uhd::stream_args_t &args_)
//calculate packet size
static const size_t hdr_size = 0
+ vrt::max_if_hdr_words32*sizeof(boost::uint32_t)
- + sizeof(vrt::if_packet_info_t().tlr) //forced to have trailer
+ //+ sizeof(vrt::if_packet_info_t().tlr) //no longer using trailer
- sizeof(vrt::if_packet_info_t().cid) //no class id ever used
- sizeof(vrt::if_packet_info_t().tsi) //no int time ever used
;
const size_t bpp = _data_transport->get_recv_frame_size() - hdr_size;
const size_t bpi = convert::get_bytes_per_item(args.otw_format);
size_t spp = unsigned(args.args.cast<double>("spp", bpp/bpi));
- spp = std::min<size_t>(2000, spp); //magic maximum for framing at full rate
+ spp = std::min<size_t>(4092, spp); //FPGA FIFO maximum for framing at full rate
//make the new streamer given the samples per packet
if (not my_streamer) my_streamer = boost::make_shared<sph::recv_packet_streamer>(spp);
diff --git a/host/lib/usrp/common/fifo_ctrl_excelsior.hpp b/host/lib/usrp/common/fifo_ctrl_excelsior.hpp
index c3ef65a2c..bd7777ffa 100644
--- a/host/lib/usrp/common/fifo_ctrl_excelsior.hpp
+++ b/host/lib/usrp/common/fifo_ctrl_excelsior.hpp
@@ -24,7 +24,7 @@
#include <uhd/transport/zero_copy.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <string>
@@ -40,7 +40,8 @@ struct fifo_ctrl_excelsior_config
/*!
* Provide access to peek, poke, spi, and async messages.
*/
-class fifo_ctrl_excelsior : public wb_iface, public uhd::spi_iface{
+class fifo_ctrl_excelsior : public uhd::wb_iface, public uhd::spi_iface
+{
public:
typedef boost::shared_ptr<fifo_ctrl_excelsior> sptr;
diff --git a/host/lib/usrp/common/fx2_ctrl.cpp b/host/lib/usrp/common/fx2_ctrl.cpp
index 6111efea9..6552f1b2d 100644
--- a/host/lib/usrp/common/fx2_ctrl.cpp
+++ b/host/lib/usrp/common/fx2_ctrl.cpp
@@ -119,6 +119,9 @@ bool parse_record(std::string *record, unsigned int &len,
std::istringstream(record->substr(3, 4)) >> std::hex >> addr;
std::istringstream(record->substr(7, 2)) >> std::hex >> type;
+ if (len > (2 * (record->length() - 9))) // sanity check to prevent buffer overrun
+ return false;
+
for (i = 0; i < len; i++) {
std::istringstream(record->substr(9 + 2 * i, 2)) >> std::hex >> val;
data[i] = (unsigned char) val;
@@ -181,6 +184,9 @@ public:
std::string record;
file >> record;
+ if (!(record.length() > 0))
+ continue;
+
//check for valid record
if (not checksum(&record) or not parse_record(&record, len, addr, type, data)) {
throw uhd::io_error("usrp_load_firmware: bad record checksum");
diff --git a/host/lib/usrp/cores/CMakeLists.txt b/host/lib/usrp/cores/CMakeLists.txt
index f526319bc..f28ae040f 100644
--- a/host/lib/usrp/cores/CMakeLists.txt
+++ b/host/lib/usrp/cores/CMakeLists.txt
@@ -22,7 +22,6 @@
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
LIBUHD_APPEND_SOURCES(
- ${CMAKE_CURRENT_SOURCE_DIR}/wb_iface.cpp
${CMAKE_CURRENT_SOURCE_DIR}/gpio_core_200.cpp
${CMAKE_CURRENT_SOURCE_DIR}/i2c_core_100.cpp
${CMAKE_CURRENT_SOURCE_DIR}/i2c_core_200.cpp
diff --git a/host/lib/usrp/cores/gpio_core_200.hpp b/host/lib/usrp/cores/gpio_core_200.hpp
index a3edf5454..15fe5f2dd 100644
--- a/host/lib/usrp/cores/gpio_core_200.hpp
+++ b/host/lib/usrp/cores/gpio_core_200.hpp
@@ -23,7 +23,7 @@
#include <boost/cstdint.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class gpio_core_200 : boost::noncopyable{
public:
@@ -33,7 +33,7 @@ public:
typedef uhd::usrp::dboard_iface::atr_reg_t atr_reg_t;
//! makes a new GPIO core from iface and slave base
- static sptr make(wb_iface::sptr iface, const size_t base, const size_t rb_addr);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t base, const size_t rb_addr);
//! 1 = ATR
virtual void set_pin_ctrl(const unit_t unit, const boost::uint16_t value) = 0;
@@ -56,7 +56,7 @@ public:
typedef uhd::usrp::dboard_iface::atr_reg_t atr_reg_t;
- static sptr make(wb_iface::sptr iface, const size_t);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t);
virtual void set_atr_reg(const atr_reg_t atr, const boost::uint32_t value) = 0;
diff --git a/host/lib/usrp/cores/i2c_core_100.hpp b/host/lib/usrp/cores/i2c_core_100.hpp
index f7a5ae4f7..4e7a2874b 100644
--- a/host/lib/usrp/cores/i2c_core_100.hpp
+++ b/host/lib/usrp/cores/i2c_core_100.hpp
@@ -22,14 +22,14 @@
#include <uhd/types/serial.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class i2c_core_100 : boost::noncopyable, public uhd::i2c_iface{
public:
typedef boost::shared_ptr<i2c_core_100> sptr;
//! makes a new i2c core from iface and slave base
- static sptr make(wb_iface::sptr iface, const size_t base);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t base);
};
#endif /* INCLUDED_LIBUHD_USRP_I2C_CORE_100_HPP */
diff --git a/host/lib/usrp/cores/i2c_core_100_wb32.hpp b/host/lib/usrp/cores/i2c_core_100_wb32.hpp
index f2ac98292..b5912ba9a 100644
--- a/host/lib/usrp/cores/i2c_core_100_wb32.hpp
+++ b/host/lib/usrp/cores/i2c_core_100_wb32.hpp
@@ -22,14 +22,14 @@
#include <uhd/types/serial.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class i2c_core_100_wb32 : boost::noncopyable, public uhd::i2c_iface{
public:
typedef boost::shared_ptr<i2c_core_100_wb32> sptr;
//! makes a new i2c core from iface and slave base
- static sptr make(wb_iface::sptr iface, const size_t base);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t base);
virtual void set_clock_rate(const double rate) = 0;
};
diff --git a/host/lib/usrp/cores/i2c_core_200.hpp b/host/lib/usrp/cores/i2c_core_200.hpp
index 508855985..1b20455d3 100644
--- a/host/lib/usrp/cores/i2c_core_200.hpp
+++ b/host/lib/usrp/cores/i2c_core_200.hpp
@@ -22,14 +22,14 @@
#include <uhd/types/serial.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class i2c_core_200 : boost::noncopyable, public uhd::i2c_iface{
public:
typedef boost::shared_ptr<i2c_core_200> sptr;
//! makes a new i2c core from iface and slave base
- static sptr make(wb_iface::sptr iface, const size_t base, const size_t readback);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t base, const size_t readback);
};
#endif /* INCLUDED_LIBUHD_USRP_I2C_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/radio_ctrl_core_3000.cpp b/host/lib/usrp/cores/radio_ctrl_core_3000.cpp
index 5298fd213..27fac3471 100644
--- a/host/lib/usrp/cores/radio_ctrl_core_3000.cpp
+++ b/host/lib/usrp/cores/radio_ctrl_core_3000.cpp
@@ -35,35 +35,27 @@ using namespace uhd::transport;
static const double ACK_TIMEOUT = 2.0; //supposed to be worst case practical timeout
static const double MASSIVE_TIMEOUT = 10.0; //for when we wait on a timed command
-static const size_t SR_READBACK = 32;
+static const size_t SR_READBACK = 32;
-class radio_ctrl_core_3000_impl : public radio_ctrl_core_3000
+class radio_ctrl_core_3000_impl: public radio_ctrl_core_3000
{
public:
- radio_ctrl_core_3000_impl(
- const bool big_endian,
- uhd::transport::zero_copy_if::sptr ctrl_xport,
- uhd::transport::zero_copy_if::sptr resp_xport,
- const boost::uint32_t sid,
- const std::string &name
- ):
- _link_type(vrt::if_packet_info_t::LINK_TYPE_CHDR),
- _packet_type(vrt::if_packet_info_t::PACKET_TYPE_CONTEXT),
- _bige(big_endian),
- _ctrl_xport(ctrl_xport),
- _resp_xport(resp_xport),
- _sid(sid),
- _name(name),
- _seq_out(0),
- _timeout(ACK_TIMEOUT),
- _resp_queue(128/*max response msgs*/),
- _resp_queue_size(_resp_xport? _resp_xport->get_num_recv_frames() : 3)
+ radio_ctrl_core_3000_impl(const bool big_endian,
+ uhd::transport::zero_copy_if::sptr ctrl_xport,
+ uhd::transport::zero_copy_if::sptr resp_xport,
+ const boost::uint32_t sid, const std::string &name) :
+ _link_type(vrt::if_packet_info_t::LINK_TYPE_CHDR), _packet_type(
+ vrt::if_packet_info_t::PACKET_TYPE_CONTEXT), _bige(
+ big_endian), _ctrl_xport(ctrl_xport), _resp_xport(
+ resp_xport), _sid(sid), _name(name), _seq_out(0), _timeout(
+ ACK_TIMEOUT), _resp_queue(128/*max response msgs*/), _resp_queue_size(
+ _resp_xport ? _resp_xport->get_num_recv_frames() : 3)
{
- UHD_LOG << "radio_ctrl_core_3000_impl() " << _name << std::endl;
+ UHD_LOG<< "radio_ctrl_core_3000_impl() " << _name << std::endl;
if (resp_xport)
{
- while (resp_xport->get_recv_buff(0.0)){} //flush
+ while (resp_xport->get_recv_buff(0.0)) {} //flush
}
this->set_time(uhd::time_spec_t(0.0));
this->set_tick_rate(1.0); //something possible but bogus
@@ -74,8 +66,8 @@ public:
UHD_LOG << "~radio_ctrl_core_3000_impl() " << _name << std::endl;
_timeout = ACK_TIMEOUT; //reset timeout to something small
UHD_SAFE_CALL(
- this->peek32(0); //dummy peek with the purpose of ack'ing all packets
- _async_task.reset(); //now its ok to release the task
+ this->peek32(0);//dummy peek with the purpose of ack'ing all packets
+ _async_task.reset();//now its ok to release the task
)
}
@@ -95,7 +87,6 @@ public:
{
boost::mutex::scoped_lock lock(_mutex);
UHD_LOGV(always) << _name << std::hex << " addr 0x" << addr << std::dec << std::endl;
-
this->send_pkt(SR_READBACK, addr/8);
this->wait_for_ack(false);
@@ -136,6 +127,11 @@ public:
}
private:
+ // This is the buffer type for messages in radio control core.
+ struct resp_buff_type
+ {
+ boost::uint32_t data[8];
+ };
/*******************************************************************
* Primary control and interaction private methods
@@ -143,7 +139,7 @@ private:
UHD_INLINE void send_pkt(const boost::uint32_t addr, const boost::uint32_t data = 0)
{
managed_send_buffer::sptr buff = _ctrl_xport->get_send_buff(0.0);
- if (not buff){
+ if (not buff) {
throw uhd::runtime_error("fifo ctrl timed out getting a send buffer");
}
boost::uint32_t *pkt = buff->cast<boost::uint32_t *>();
@@ -173,12 +169,11 @@ private:
pkt[packet_info.num_header_words32+0] = (_bige)? uhd::htonx(addr) : uhd::htowx(addr);
pkt[packet_info.num_header_words32+1] = (_bige)? uhd::htonx(data) : uhd::htowx(data);
//UHD_MSG(status) << boost::format("0x%08x, 0x%08x\n") % addr % data;
-
//send the buffer over the interface
_outstanding_seqs.push(_seq_out);
buff->commit(sizeof(boost::uint32_t)*(packet_info.num_packet_words32));
- _seq_out++; //inc seq for next call
+ _seq_out++;//inc seq for next call
}
UHD_INLINE boost::uint64_t wait_for_ack(const bool readback)
@@ -186,7 +181,6 @@ private:
while (readback or (_outstanding_seqs.size() >= _resp_queue_size))
{
UHD_LOGV(always) << _name << " wait_for_ack: " << "readback = " << readback << " outstanding_seqs.size() " << _outstanding_seqs.size() << std::endl;
-
//get seq to ack from outstanding packets list
UHD_ASSERT_THROW(not _outstanding_seqs.empty());
const size_t seq_to_ack = _outstanding_seqs.front();
@@ -195,6 +189,7 @@ private:
//parse the packet
vrt::if_packet_info_t packet_info;
resp_buff_type resp_buff;
+ memset(&resp_buff, 0x00, sizeof(resp_buff));
boost::uint32_t const *pkt = NULL;
managed_recv_buffer::sptr buff;
@@ -218,7 +213,27 @@ private:
//get buffer from response endpoint - or die in timeout
else
{
- UHD_ASSERT_THROW(_resp_queue.pop_with_timed_wait(resp_buff, _timeout));
+ /*
+ * Couldn't get message with haste.
+ * Now check both possible queues for messages.
+ * Messages should come in on _resp_queue,
+ * but could end up in dump_queue.
+ * If we don't get a message --> Die in timeout.
+ */
+ double accum_timeout = 0.0;
+ const double short_timeout = 0.005; // == 5ms
+ while(not ((_resp_queue.pop_with_haste(resp_buff))
+ || (check_dump_queue(resp_buff))
+ || (_resp_queue.pop_with_timed_wait(resp_buff, short_timeout))
+ )){
+ /*
+ * If a message couldn't be received within a given timeout
+ * --> throw AssertionError!
+ */
+ accum_timeout += short_timeout;
+ UHD_ASSERT_THROW(accum_timeout < _timeout);
+ }
+
pkt = resp_buff.data;
packet_info.num_packet_words32 = sizeof(resp_buff)/sizeof(boost::uint32_t);
}
@@ -233,7 +248,12 @@ private:
catch(const std::exception &ex)
{
UHD_MSG(error) << "Radio ctrl bad VITA packet: " << ex.what() << std::endl;
- UHD_VAR(buff->size());
+ if (buff){
+ UHD_VAR(buff->size());
+ }
+ else{
+ UHD_MSG(status) << "buff is NULL" << std::endl;
+ }
UHD_MSG(status) << std::hex << pkt[0] << std::dec << std::endl;
UHD_MSG(status) << std::hex << pkt[1] << std::dec << std::endl;
UHD_MSG(status) << std::hex << pkt[2] << std::dec << std::endl;
@@ -262,9 +282,34 @@ private:
return ((hi << 32) | lo);
}
}
+
return 0;
}
+ /*
+ * If ctrl_core waits for a message that didn't arrive it can search for it in the dump queue.
+ * This actually happens during shutdown.
+ * handle_async_task can't access radio_ctrl_cores queue anymore thus it returns the corresponding message.
+ * msg_task class implements a dump_queue to store such messages.
+ * With check_dump_queue we can check if a message we are waiting for got stranded there.
+ * If a message got stuck we get it here and push it onto our own message_queue.
+ */
+ bool check_dump_queue(resp_buff_type& b) {
+ const size_t min_buff_size = 8; // Same value as in b200_io_impl->handle_async_task
+ boost::uint32_t recv_sid = (((_sid)<<16)|((_sid)>>16));
+ uhd::msg_task::msg_payload_t msg;
+ do{
+ msg = _async_task->get_msg_from_dump_queue(recv_sid);
+ }
+ while(msg.size() < min_buff_size && msg.size() != 0);
+
+ if(msg.size() >= min_buff_size) {
+ memcpy(b.data, &msg.front(), std::min(msg.size(), sizeof(b.data)));
+ return true;
+ }
+ return false;
+ }
+
void push_response(const boost::uint32_t *buff)
{
resp_buff_type resp_buff;
@@ -272,7 +317,7 @@ private:
_resp_queue.push_with_haste(resp_buff);
}
- void hold_task(boost::shared_ptr<void> task)
+ void hold_task(uhd::msg_task::sptr task)
{
_async_task = task;
}
@@ -282,7 +327,7 @@ private:
const bool _bige;
const uhd::transport::zero_copy_if::sptr _ctrl_xport;
const uhd::transport::zero_copy_if::sptr _resp_xport;
- boost::shared_ptr<void> _async_task;
+ uhd::msg_task::sptr _async_task;
const boost::uint32_t _sid;
const std::string _name;
boost::mutex _mutex;
@@ -292,22 +337,15 @@ private:
double _tick_rate;
double _timeout;
std::queue<size_t> _outstanding_seqs;
- struct resp_buff_type
- {
- boost::uint32_t data[8];
- };
bounded_buffer<resp_buff_type> _resp_queue;
const size_t _resp_queue_size;
};
-
-radio_ctrl_core_3000::sptr radio_ctrl_core_3000::make(
- const bool big_endian,
- zero_copy_if::sptr ctrl_xport,
- zero_copy_if::sptr resp_xport,
- const boost::uint32_t sid,
- const std::string &name
-)
+radio_ctrl_core_3000::sptr radio_ctrl_core_3000::make(const bool big_endian,
+ zero_copy_if::sptr ctrl_xport, zero_copy_if::sptr resp_xport,
+ const boost::uint32_t sid, const std::string &name)
{
- return sptr(new radio_ctrl_core_3000_impl(big_endian, ctrl_xport, resp_xport, sid, name));
+ return sptr(
+ new radio_ctrl_core_3000_impl(big_endian, ctrl_xport, resp_xport,
+ sid, name));
}
diff --git a/host/lib/usrp/cores/radio_ctrl_core_3000.hpp b/host/lib/usrp/cores/radio_ctrl_core_3000.hpp
index 8c0548d89..51a307c10 100644
--- a/host/lib/usrp/cores/radio_ctrl_core_3000.hpp
+++ b/host/lib/usrp/cores/radio_ctrl_core_3000.hpp
@@ -18,17 +18,18 @@
#ifndef INCLUDED_LIBUHD_USRP_RADIO_CTRL_3000_HPP
#define INCLUDED_LIBUHD_USRP_RADIO_CTRL_3000_HPP
+#include <uhd/utils/msg_task.hpp>
#include <uhd/types/time_spec.hpp>
#include <uhd/transport/zero_copy.hpp>
+#include <uhd/types/wb_iface.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
-#include "wb_iface.hpp"
#include <string>
/*!
* Provide access to peek, poke for the radio ctrl module
*/
-class radio_ctrl_core_3000 : public wb_iface
+class radio_ctrl_core_3000 : public uhd::wb_iface
{
public:
typedef boost::shared_ptr<radio_ctrl_core_3000> sptr;
@@ -43,7 +44,7 @@ public:
);
//! Hold a ref to a task thats feeding push response
- virtual void hold_task(boost::shared_ptr<void> task) = 0;
+ virtual void hold_task(uhd::msg_task::sptr task) = 0;
//! Push a response externall (resp_xport is NULL)
virtual void push_response(const boost::uint32_t *buff) = 0;
diff --git a/host/lib/usrp/cores/rx_dsp_core_200.cpp b/host/lib/usrp/cores/rx_dsp_core_200.cpp
index ef6b85de9..2fdc220b5 100644
--- a/host/lib/usrp/cores/rx_dsp_core_200.cpp
+++ b/host/lib/usrp/cores/rx_dsp_core_200.cpp
@@ -59,8 +59,11 @@ public:
const size_t dsp_base, const size_t ctrl_base,
const boost::uint32_t sid, const bool lingering_packet
):
- _iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base), _sid(sid)
+ _iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base), _sid(sid)
{
+ // previously uninitialized - assuming zero for all
+ _tick_rate = _link_rate = _host_extra_scaling = _fxpt_scalar_correction = 0.0;
+
//init to something so update method has reasonable defaults
_scaling_adjustment = 1.0;
_dsp_extra_scaling = 1.0;
diff --git a/host/lib/usrp/cores/rx_dsp_core_200.hpp b/host/lib/usrp/cores/rx_dsp_core_200.hpp
index b01f751e9..3937df9e8 100644
--- a/host/lib/usrp/cores/rx_dsp_core_200.hpp
+++ b/host/lib/usrp/cores/rx_dsp_core_200.hpp
@@ -24,7 +24,7 @@
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <uhd/types/stream_cmd.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <string>
class rx_dsp_core_200 : boost::noncopyable{
@@ -32,7 +32,7 @@ public:
typedef boost::shared_ptr<rx_dsp_core_200> sptr;
static sptr make(
- wb_iface::sptr iface,
+ uhd::wb_iface::sptr iface,
const size_t dsp_base, const size_t ctrl_base,
const boost::uint32_t sid, const bool lingering_packet = false
);
diff --git a/host/lib/usrp/cores/rx_dsp_core_3000.cpp b/host/lib/usrp/cores/rx_dsp_core_3000.cpp
index 7b3324f74..525916032 100644
--- a/host/lib/usrp/cores/rx_dsp_core_3000.cpp
+++ b/host/lib/usrp/cores/rx_dsp_core_3000.cpp
@@ -50,10 +50,13 @@ public:
):
_iface(iface), _dsp_base(dsp_base)
{
+ // previously uninitialized - assuming zero for all
+ _link_rate = _host_extra_scaling = _fxpt_scalar_correction = 0.0;
+
//init to something so update method has reasonable defaults
_scaling_adjustment = 1.0;
_dsp_extra_scaling = 1.0;
- this->set_tick_rate(1.0);
+ _tick_rate = 1.0;
}
~rx_dsp_core_3000_impl(void)
diff --git a/host/lib/usrp/cores/rx_dsp_core_3000.hpp b/host/lib/usrp/cores/rx_dsp_core_3000.hpp
index 23b12b9b7..02e5587a2 100644
--- a/host/lib/usrp/cores/rx_dsp_core_3000.hpp
+++ b/host/lib/usrp/cores/rx_dsp_core_3000.hpp
@@ -24,7 +24,7 @@
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <uhd/types/stream_cmd.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <string>
class rx_dsp_core_3000 : boost::noncopyable{
@@ -32,7 +32,7 @@ public:
typedef boost::shared_ptr<rx_dsp_core_3000> sptr;
static sptr make(
- wb_iface::sptr iface,
+ uhd::wb_iface::sptr iface,
const size_t dsp_base
);
diff --git a/host/lib/usrp/cores/rx_frontend_core_200.cpp b/host/lib/usrp/cores/rx_frontend_core_200.cpp
index 1813758da..864b5cc53 100644
--- a/host/lib/usrp/cores/rx_frontend_core_200.cpp
+++ b/host/lib/usrp/cores/rx_frontend_core_200.cpp
@@ -18,6 +18,8 @@
#include "rx_frontend_core_200.hpp"
#include <boost/math/special_functions/round.hpp>
+using namespace uhd;
+
#define REG_RX_FE_SWAP_IQ _base + 0 //lower bit
#define REG_RX_FE_MAG_CORRECTION _base + 4 //18 bits
#define REG_RX_FE_PHASE_CORRECTION _base + 8 //18 bits
@@ -36,7 +38,7 @@ static boost::uint32_t fs_to_bits(const double num, const size_t bits){
class rx_frontend_core_200_impl : public rx_frontend_core_200{
public:
rx_frontend_core_200_impl(wb_iface::sptr iface, const size_t base):
- _iface(iface), _base(base)
+ _i_dc_off(0), _q_dc_off(0), _iface(iface), _base(base)
{
//NOP
}
diff --git a/host/lib/usrp/cores/rx_frontend_core_200.hpp b/host/lib/usrp/cores/rx_frontend_core_200.hpp
index 5755424c8..8327aef8b 100644
--- a/host/lib/usrp/cores/rx_frontend_core_200.hpp
+++ b/host/lib/usrp/cores/rx_frontend_core_200.hpp
@@ -21,7 +21,7 @@
#include <uhd/config.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <complex>
#include <string>
@@ -29,7 +29,7 @@ class rx_frontend_core_200 : boost::noncopyable{
public:
typedef boost::shared_ptr<rx_frontend_core_200> sptr;
- static sptr make(wb_iface::sptr iface, const size_t base);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t base);
virtual void set_mux(const bool swap) = 0;
diff --git a/host/lib/usrp/cores/rx_vita_core_3000.hpp b/host/lib/usrp/cores/rx_vita_core_3000.hpp
index b011a7388..577510728 100644
--- a/host/lib/usrp/cores/rx_vita_core_3000.hpp
+++ b/host/lib/usrp/cores/rx_vita_core_3000.hpp
@@ -24,7 +24,7 @@
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <uhd/types/stream_cmd.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <string>
class rx_vita_core_3000 : boost::noncopyable
@@ -33,7 +33,7 @@ public:
typedef boost::shared_ptr<rx_vita_core_3000> sptr;
static sptr make(
- wb_iface::sptr iface,
+ uhd::wb_iface::sptr iface,
const size_t base
);
diff --git a/host/lib/usrp/cores/spi_core_100.hpp b/host/lib/usrp/cores/spi_core_100.hpp
index 87d328aaa..ce53c0b86 100644
--- a/host/lib/usrp/cores/spi_core_100.hpp
+++ b/host/lib/usrp/cores/spi_core_100.hpp
@@ -22,14 +22,14 @@
#include <uhd/types/serial.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class spi_core_100 : boost::noncopyable, public uhd::spi_iface{
public:
typedef boost::shared_ptr<spi_core_100> sptr;
//! makes a new spi core from iface and slave base
- static sptr make(wb_iface::sptr iface, const size_t base);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t base);
};
#endif /* INCLUDED_LIBUHD_USRP_SPI_CORE_100_HPP */
diff --git a/host/lib/usrp/cores/spi_core_3000.hpp b/host/lib/usrp/cores/spi_core_3000.hpp
index 995ad59db..923efed3d 100644
--- a/host/lib/usrp/cores/spi_core_3000.hpp
+++ b/host/lib/usrp/cores/spi_core_3000.hpp
@@ -22,7 +22,7 @@
#include <uhd/types/serial.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class spi_core_3000 : boost::noncopyable, public uhd::spi_iface
{
@@ -30,7 +30,7 @@ public:
typedef boost::shared_ptr<spi_core_3000> sptr;
//! makes a new spi core from iface and slave base
- static sptr make(wb_iface::sptr iface, const size_t base, const size_t readback);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t base, const size_t readback);
//! Set the spi clock divider to something usable
virtual void set_divider(const double div) = 0;
diff --git a/host/lib/usrp/cores/time64_core_200.cpp b/host/lib/usrp/cores/time64_core_200.cpp
index 11b310362..ad5e6477c 100644
--- a/host/lib/usrp/cores/time64_core_200.cpp
+++ b/host/lib/usrp/cores/time64_core_200.cpp
@@ -48,6 +48,7 @@ public:
):
_iface(iface), _base(base),
_readback_bases(readback_bases),
+ _tick_rate(0.0),
_mimo_delay_cycles(mimo_delay_cycles)
{
_sources.push_back("none");
diff --git a/host/lib/usrp/cores/time64_core_200.hpp b/host/lib/usrp/cores/time64_core_200.hpp
index 315f2ba67..e211ce040 100644
--- a/host/lib/usrp/cores/time64_core_200.hpp
+++ b/host/lib/usrp/cores/time64_core_200.hpp
@@ -22,7 +22,7 @@
#include <uhd/types/time_spec.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <string>
#include <vector>
@@ -37,7 +37,7 @@ public:
//! makes a new time64 core from iface and slave base
static sptr make(
- wb_iface::sptr iface, const size_t base,
+ uhd::wb_iface::sptr iface, const size_t base,
const readback_bases_type &readback_bases,
const size_t mimo_delay_cycles = 0 // 0 means no-mimo
);
diff --git a/host/lib/usrp/cores/time_core_3000.hpp b/host/lib/usrp/cores/time_core_3000.hpp
index ffe2f4133..fad408810 100644
--- a/host/lib/usrp/cores/time_core_3000.hpp
+++ b/host/lib/usrp/cores/time_core_3000.hpp
@@ -22,7 +22,7 @@
#include <uhd/types/time_spec.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class time_core_3000 : boost::noncopyable
{
@@ -37,7 +37,7 @@ public:
//! makes a new time core from iface and slave base
static sptr make(
- wb_iface::sptr iface, const size_t base,
+ uhd::wb_iface::sptr iface, const size_t base,
const readback_bases_type &readback_bases
);
diff --git a/host/lib/usrp/cores/tx_dsp_core_200.cpp b/host/lib/usrp/cores/tx_dsp_core_200.cpp
index 808f13028..f8aa87aa3 100644
--- a/host/lib/usrp/cores/tx_dsp_core_200.cpp
+++ b/host/lib/usrp/cores/tx_dsp_core_200.cpp
@@ -60,6 +60,9 @@ public:
):
_iface(iface), _dsp_base(dsp_base), _ctrl_base(ctrl_base), _sid(sid)
{
+ // previously uninitialized - assuming zero for all
+ _tick_rate = _link_rate = _host_extra_scaling = _fxpt_scalar_correction = 0.0;
+
//init to something so update method has reasonable defaults
_scaling_adjustment = 1.0;
_dsp_extra_scaling = 1.0;
diff --git a/host/lib/usrp/cores/tx_dsp_core_200.hpp b/host/lib/usrp/cores/tx_dsp_core_200.hpp
index 0e1cfb6bc..ce3d1dbdd 100644
--- a/host/lib/usrp/cores/tx_dsp_core_200.hpp
+++ b/host/lib/usrp/cores/tx_dsp_core_200.hpp
@@ -23,14 +23,14 @@
#include <uhd/types/ranges.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class tx_dsp_core_200 : boost::noncopyable{
public:
typedef boost::shared_ptr<tx_dsp_core_200> sptr;
static sptr make(
- wb_iface::sptr iface,
+ uhd::wb_iface::sptr iface,
const size_t dsp_base, const size_t ctrl_base,
const boost::uint32_t sid
);
diff --git a/host/lib/usrp/cores/tx_dsp_core_3000.cpp b/host/lib/usrp/cores/tx_dsp_core_3000.cpp
index feb749cd9..93c8702bc 100644
--- a/host/lib/usrp/cores/tx_dsp_core_3000.cpp
+++ b/host/lib/usrp/cores/tx_dsp_core_3000.cpp
@@ -45,6 +45,9 @@ public:
):
_iface(iface), _dsp_base(dsp_base)
{
+ // previously uninitialized - assuming zero for all
+ _link_rate = _host_extra_scaling = _fxpt_scalar_correction = 0.0;
+
//init to something so update method has reasonable defaults
_scaling_adjustment = 1.0;
_dsp_extra_scaling = 1.0;
diff --git a/host/lib/usrp/cores/tx_dsp_core_3000.hpp b/host/lib/usrp/cores/tx_dsp_core_3000.hpp
index eb5ffaf0f..6f725b836 100644
--- a/host/lib/usrp/cores/tx_dsp_core_3000.hpp
+++ b/host/lib/usrp/cores/tx_dsp_core_3000.hpp
@@ -23,14 +23,14 @@
#include <uhd/types/ranges.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class tx_dsp_core_3000 : boost::noncopyable{
public:
typedef boost::shared_ptr<tx_dsp_core_3000> sptr;
static sptr make(
- wb_iface::sptr iface,
+ uhd::wb_iface::sptr iface,
const size_t dsp_base
);
diff --git a/host/lib/usrp/cores/tx_frontend_core_200.cpp b/host/lib/usrp/cores/tx_frontend_core_200.cpp
index e35874173..d701027e5 100644
--- a/host/lib/usrp/cores/tx_frontend_core_200.cpp
+++ b/host/lib/usrp/cores/tx_frontend_core_200.cpp
@@ -21,6 +21,8 @@
#include <boost/assign/list_of.hpp>
#include <boost/math/special_functions/round.hpp>
+using namespace uhd;
+
#define REG_TX_FE_DC_OFFSET_I _base + 0 //24 bits
#define REG_TX_FE_DC_OFFSET_Q _base + 4 //24 bits
#define REG_TX_FE_MAG_CORRECTION _base + 8 //18 bits
diff --git a/host/lib/usrp/cores/tx_frontend_core_200.hpp b/host/lib/usrp/cores/tx_frontend_core_200.hpp
index 8ee0f3e6d..7d09b39d2 100644
--- a/host/lib/usrp/cores/tx_frontend_core_200.hpp
+++ b/host/lib/usrp/cores/tx_frontend_core_200.hpp
@@ -21,7 +21,7 @@
#include <uhd/config.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <complex>
#include <string>
@@ -29,7 +29,7 @@ class tx_frontend_core_200 : boost::noncopyable{
public:
typedef boost::shared_ptr<tx_frontend_core_200> sptr;
- static sptr make(wb_iface::sptr iface, const size_t base);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t base);
virtual void set_mux(const std::string &mode) = 0;
diff --git a/host/lib/usrp/cores/tx_vita_core_3000.hpp b/host/lib/usrp/cores/tx_vita_core_3000.hpp
index 2070936ce..d4677a3e3 100644
--- a/host/lib/usrp/cores/tx_vita_core_3000.hpp
+++ b/host/lib/usrp/cores/tx_vita_core_3000.hpp
@@ -24,7 +24,7 @@
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <uhd/types/stream_cmd.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <string>
class tx_vita_core_3000 : boost::noncopyable
@@ -33,7 +33,7 @@ public:
typedef boost::shared_ptr<tx_vita_core_3000> sptr;
static sptr make(
- wb_iface::sptr iface,
+ uhd::wb_iface::sptr iface,
const size_t base
);
diff --git a/host/lib/usrp/cores/user_settings_core_200.cpp b/host/lib/usrp/cores/user_settings_core_200.cpp
index d262631b1..391725edc 100644
--- a/host/lib/usrp/cores/user_settings_core_200.cpp
+++ b/host/lib/usrp/cores/user_settings_core_200.cpp
@@ -17,6 +17,8 @@
#include "user_settings_core_200.hpp"
+using namespace uhd;
+
#define REG_USER_ADDR _base + 0
#define REG_USER_DATA _base + 4
diff --git a/host/lib/usrp/cores/user_settings_core_200.hpp b/host/lib/usrp/cores/user_settings_core_200.hpp
index 1f5d13de7..f5fca2ce6 100644
--- a/host/lib/usrp/cores/user_settings_core_200.hpp
+++ b/host/lib/usrp/cores/user_settings_core_200.hpp
@@ -21,14 +21,14 @@
#include <uhd/config.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
class user_settings_core_200 : boost::noncopyable{
public:
typedef boost::shared_ptr<user_settings_core_200> sptr;
typedef std::pair<boost::uint8_t, boost::uint32_t> user_reg_t;
- static sptr make(wb_iface::sptr iface, const size_t base);
+ static sptr make(uhd::wb_iface::sptr iface, const size_t base);
virtual void set_reg(const user_reg_t &reg) = 0;
};
diff --git a/host/lib/usrp/dboard/db_dbsrx.cpp b/host/lib/usrp/dboard/db_dbsrx.cpp
index b1cee4aa7..9d04d8e16 100644
--- a/host/lib/usrp/dboard/db_dbsrx.cpp
+++ b/host/lib/usrp/dboard/db_dbsrx.cpp
@@ -179,7 +179,7 @@ dbsrx::dbsrx(ctor_args_t args) : rx_dboard_base(args){
"DBSRX: incorrect dbid\n"
"Expected dbid 0x0002 and R193\n"
"found dbid == %d\n"
- "Please see the daughterboard app notes"
+ "Please see the daughterboard app notes"
) % this->get_rx_id().to_pp_string();
//warn user about incorrect DBID on non-USRP1, requires R194 populated
@@ -188,7 +188,7 @@ dbsrx::dbsrx(ctor_args_t args) : rx_dboard_base(args){
"DBSRX: incorrect dbid\n"
"Expected dbid 0x000D and R194\n"
"found dbid == %d\n"
- "Please see the daughterboard app notes"
+ "Please see the daughterboard app notes"
) % this->get_rx_id().to_pp_string();
//send initial register settings
@@ -305,13 +305,13 @@ double dbsrx::set_lo_freq(double target_freq){
goto done_loop;
}
- }
+ }
done_loop:
- //Assert because we failed to find a suitable combination of ref_clock, R and N
+ //Assert because we failed to find a suitable combination of ref_clock, R and N
UHD_ASSERT_THROW(ref_clock <= 27.0e6 and ref_clock >= 0.0);
- UHD_ASSERT_THROW(ref_clock/m >= 1e6 and ref_clock/m <= 2.5e6);
+ UHD_ASSERT_THROW(m and ref_clock/m >= 1e6 and ref_clock/m <= 2.5e6);
UHD_ASSERT_THROW((pfd_freq >= dbsrx_pfd_freq_range.start()) and (pfd_freq <= dbsrx_pfd_freq_range.stop()));
UHD_ASSERT_THROW((N >= 256) and (N <= 32768));
@@ -332,7 +332,7 @@ double dbsrx::set_lo_freq(double target_freq){
_max2118_write_regs.r_divider = (max2118_write_regs_t::r_divider_t) r;
_max2118_write_regs.set_n_divider(N);
_max2118_write_regs.ade_vco_ade_read = max2118_write_regs_t::ADE_VCO_ADE_READ_ENABLED;
-
+
//compute prescaler variables
int scaler = actual_freq > 1125e6 ? 2 : 4;
_max2118_write_regs.div2 = scaler == 4 ? max2118_write_regs_t::DIV2_DIV4 : max2118_write_regs_t::DIV2_DIV2;
@@ -377,7 +377,7 @@ double dbsrx::set_lo_freq(double target_freq){
if (_max2118_read_regs.adc == 0){
if (_max2118_write_regs.osc_band == 0){
UHD_MSG(warning) << boost::format(
- "DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n"
+ "DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n"
) % int(_max2118_write_regs.osc_band);
UHD_ASSERT_THROW(_max2118_read_regs.adc != 0); //just to cause a throw
}
@@ -389,7 +389,7 @@ double dbsrx::set_lo_freq(double target_freq){
if (_max2118_read_regs.adc == 7){
if (_max2118_write_regs.osc_band == 7){
UHD_MSG(warning) << boost::format(
- "DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n"
+ "DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n"
) % int(_max2118_write_regs.osc_band);
UHD_ASSERT_THROW(_max2118_read_regs.adc != 7); //just to cause a throw
}
@@ -408,7 +408,7 @@ double dbsrx::set_lo_freq(double target_freq){
//allow for setup time before checking condition again
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
}
-
+
UHD_LOGV(often) << boost::format(
"DBSRX: final vco %d, vtune adc %d"
) % int(_max2118_write_regs.osc_band) % int(_max2118_read_regs.adc) << std::endl;
@@ -417,7 +417,7 @@ double dbsrx::set_lo_freq(double target_freq){
if (_max2118_read_regs.adc <= 2) _max2118_write_regs.cp_current = max2118_write_regs_t::CP_CURRENT_I_CP_100UA;
else if (_max2118_read_regs.adc >= 5) _max2118_write_regs.cp_current = max2118_write_regs_t::CP_CURRENT_I_CP_400UA;
else _max2118_write_regs.cp_current = max2118_write_regs_t::CP_CURRENT_I_CP_200UA;
-
+
//update charge pump bias current setting
send_reg(0x2, 0x2);
@@ -524,7 +524,7 @@ double dbsrx::set_bandwidth(double bandwidth){
bandwidth = dbsrx_bandwidth_range.clip(bandwidth);
double ref_clock = this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX);
-
+
//NOTE: _max2118_write_regs.m_divider set in set_lo_freq
//compute f_dac setting
diff --git a/host/lib/usrp/dboard/db_dbsrx2.cpp b/host/lib/usrp/dboard/db_dbsrx2.cpp
index 013f3178a..8a8f61a69 100644
--- a/host/lib/usrp/dboard/db_dbsrx2.cpp
+++ b/host/lib/usrp/dboard/db_dbsrx2.cpp
@@ -358,12 +358,12 @@ double dbsrx2::set_gain(double gain, const std::string &name){
* Bandwidth Handling
**********************************************************************/
double dbsrx2::set_bandwidth(double bandwidth){
- //convert complex bandpass to lowpass bandwidth
- bandwidth = bandwidth/2.0;
-
//clip the input
bandwidth = dbsrx2_bandwidth_range.clip(bandwidth);
+ //convert complex bandpass to lowpass bandwidth
+ bandwidth = bandwidth/2.0;
+
_max2112_write_regs.lp = int((bandwidth/1e6 - 4)/0.29 + 12);
_bandwidth = double(4 + (_max2112_write_regs.lp - 12) * 0.29)*1e6;
diff --git a/host/lib/usrp/dboard/db_sbx_common.cpp b/host/lib/usrp/dboard/db_sbx_common.cpp
index 9db29e65a..5b713c6d7 100644
--- a/host/lib/usrp/dboard/db_sbx_common.cpp
+++ b/host/lib/usrp/dboard/db_sbx_common.cpp
@@ -21,6 +21,137 @@ using namespace uhd;
using namespace uhd::usrp;
using namespace boost::assign;
+/***********************************************************************
+ * ADF 4350/4351 Tuning Utility
+ **********************************************************************/
+sbx_xcvr::sbx_versionx::adf435x_tuning_settings sbx_xcvr::sbx_versionx::_tune_adf435x_synth(
+ double target_freq,
+ double ref_freq,
+ const adf435x_tuning_constraints& constraints,
+ double& actual_freq)
+{
+ //Default invalid value for actual_freq
+ actual_freq = 0;
+
+ double pfd_freq = 0;
+ boost::uint16_t R = 0, BS = 0, N = 0, FRAC = 0, MOD = 0;
+ boost::uint16_t RFdiv = static_cast<boost::uint16_t>(constraints.rf_divider_range.start());
+ bool D = false, T = false;
+
+ //Reference doubler for 50% duty cycle
+ //If ref_freq < 12.5MHz enable the reference doubler
+ D = (ref_freq <= constraints.ref_doubler_threshold);
+
+ static const double MIN_VCO_FREQ = 2.2e9;
+ static const double MAX_VCO_FREQ = 4.4e9;
+
+ //increase RF divider until acceptable VCO frequency
+ double vco_freq = target_freq;
+ while (vco_freq < MIN_VCO_FREQ && RFdiv < static_cast<boost::uint16_t>(constraints.rf_divider_range.stop())) {
+ vco_freq *= 2;
+ RFdiv *= 2;
+ }
+
+ /*
+ * The goal here is to loop though possible R dividers,
+ * band select clock dividers, N (int) dividers, and FRAC
+ * (frac) dividers.
+ *
+ * Calculate the N and F dividers for each set of values.
+ * The loop exits when it meets all of the constraints.
+ * The resulting loop values are loaded into the registers.
+ *
+ * from pg.21
+ *
+ * f_pfd = f_ref*(1+D)/(R*(1+T))
+ * f_vco = (N + (FRAC/MOD))*f_pfd
+ * N = f_vco/f_pfd - FRAC/MOD = f_vco*((R*(T+1))/(f_ref*(1+D))) - FRAC/MOD
+ * f_rf = f_vco/RFdiv)
+ * f_actual = f_rf/2
+ */
+ for(R = 1; R <= 1023; R+=1){
+ //PFD input frequency = f_ref/R ... ignoring Reference doubler/divide-by-2 (D & T)
+ pfd_freq = ref_freq*(D?2:1)/(R*(T?2:1));
+
+ //keep the PFD frequency at or below 25MHz (Loop Filter Bandwidth)
+ if (pfd_freq > constraints.pfd_freq_max) continue;
+
+ //ignore fractional part of tuning
+ //N is computed from target_freq and not vco_freq because the feedback
+ //mode is set to FEEDBACK_SELECT_DIVIDED
+ N = boost::uint16_t(std::floor(target_freq/pfd_freq));
+
+ //keep N > minimum int divider requirement
+ if (N < static_cast<boost::uint16_t>(constraints.int_range.start())) continue;
+
+ for(BS=1; BS <= 255; BS+=1){
+ //keep the band select frequency at or below band_sel_freq_max
+ //constraint on band select clock
+ if (pfd_freq/BS > constraints.band_sel_freq_max) continue;
+ goto done_loop;
+ }
+ } done_loop:
+
+ //Fractional-N calculation
+ MOD = 4095; //max fractional accuracy
+ //N is computed from target_freq and not vco_freq because the feedback
+ //mode is set to FEEDBACK_SELECT_DIVIDED
+ FRAC = static_cast<boost::uint16_t>((target_freq/pfd_freq - N)*MOD);
+ if (constraints.force_frac0) {
+ if (FRAC > (MOD / 2)) { //Round integer such that actual freq is closest to target
+ N++;
+ }
+ FRAC = 0;
+ }
+
+ //Reference divide-by-2 for 50% duty cycle
+ // if R even, move one divide by 2 to to regs.reference_divide_by_2
+ if(R % 2 == 0) {
+ T = true;
+ R /= 2;
+ }
+
+ //Typical phase resync time documented in data sheet pg.24
+ static const double PHASE_RESYNC_TIME = 400e-6;
+
+ //actual frequency calculation
+ actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(D?2:1)/(R*(T?2:1)));
+
+ //load the settings
+ adf435x_tuning_settings settings;
+ settings.frac_12_bit = FRAC;
+ settings.int_16_bit = N;
+ settings.mod_12_bit = MOD;
+ settings.clock_divider_12_bit = std::max<boost::uint16_t>(1, std::ceil(PHASE_RESYNC_TIME*pfd_freq/MOD));
+ settings.r_counter_10_bit = R;
+ settings.r_divide_by_2_en = T;
+ settings.r_doubler_en = D;
+ settings.band_select_clock_div = BS;
+ settings.rf_divider = RFdiv;
+ settings.feedback_after_divider = true;
+
+ UHD_LOGV(often)
+ << boost::format("ADF 435X Frequencies (MHz): REQUESTED=%0.9f, ACTUAL=%0.9f"
+ ) % (target_freq/1e6) % (actual_freq/1e6) << std::endl
+ << boost::format("ADF 435X Intermediates (MHz): VCO=%0.2f, PFD=%0.2f, BAND=%0.2f, REF=%0.2f"
+ ) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) % (ref_freq/1e6) << std::endl
+ << boost::format("ADF 435X Settings: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d"
+ ) % R % BS % N % FRAC % MOD % T % D % RFdiv << std::endl;
+
+ UHD_ASSERT_THROW((settings.frac_12_bit & ((boost::uint16_t)~0xFFF)) == 0);
+ UHD_ASSERT_THROW((settings.mod_12_bit & ((boost::uint16_t)~0xFFF)) == 0);
+ UHD_ASSERT_THROW((settings.clock_divider_12_bit & ((boost::uint16_t)~0xFFF)) == 0);
+ UHD_ASSERT_THROW((settings.r_counter_10_bit & ((boost::uint16_t)~0x3FF)) == 0);
+
+ UHD_ASSERT_THROW(vco_freq >= MIN_VCO_FREQ and vco_freq <= MAX_VCO_FREQ);
+ UHD_ASSERT_THROW(settings.rf_divider >= static_cast<boost::uint16_t>(constraints.rf_divider_range.start()));
+ UHD_ASSERT_THROW(settings.rf_divider <= static_cast<boost::uint16_t>(constraints.rf_divider_range.stop()));
+ UHD_ASSERT_THROW(settings.int_16_bit >= static_cast<boost::uint16_t>(constraints.int_range.start()));
+ UHD_ASSERT_THROW(settings.int_16_bit <= static_cast<boost::uint16_t>(constraints.int_range.stop()));
+
+ return settings;
+}
+
/***********************************************************************
* Register the SBX dboard (min freq, max freq, rx div2, tx div2)
@@ -362,4 +493,3 @@ void sbx_xcvr::flash_leds(void) {
this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, (TXIO_MASK|TX_LED_IO));
this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, (RXIO_MASK|RX_LED_IO));
}
-
diff --git a/host/lib/usrp/dboard/db_sbx_common.hpp b/host/lib/usrp/dboard/db_sbx_common.hpp
index 4f3a2eeaa..e9bb2434c 100644
--- a/host/lib/usrp/dboard/db_sbx_common.hpp
+++ b/host/lib/usrp/dboard/db_sbx_common.hpp
@@ -181,6 +181,34 @@ protected:
~sbx_versionx(void) {}
virtual double set_lo_freq(dboard_iface::unit_t unit, double target_freq) = 0;
+ protected:
+ struct adf435x_tuning_constraints {
+ bool force_frac0;
+ double ref_doubler_threshold;
+ double pfd_freq_max;
+ double band_sel_freq_max;
+ uhd::range_t rf_divider_range;
+ uhd::range_t int_range;
+ };
+
+ struct adf435x_tuning_settings {
+ boost::uint16_t frac_12_bit;
+ boost::uint16_t int_16_bit;
+ boost::uint16_t mod_12_bit;
+ boost::uint16_t r_counter_10_bit;
+ bool r_doubler_en;
+ bool r_divide_by_2_en;
+ boost::uint16_t clock_divider_12_bit;
+ boost::uint8_t band_select_clock_div;
+ boost::uint16_t rf_divider;
+ bool feedback_after_divider;
+ };
+
+ adf435x_tuning_settings _tune_adf435x_synth(
+ double target_freq,
+ double ref_freq,
+ const adf435x_tuning_constraints& constraints,
+ double& actual_freq);
};
/*!
diff --git a/host/lib/usrp/dboard/db_sbx_version3.cpp b/host/lib/usrp/dboard/db_sbx_version3.cpp
index 2765d530c..b0c9cd18f 100644
--- a/host/lib/usrp/dboard/db_sbx_version3.cpp
+++ b/host/lib/usrp/dboard/db_sbx_version3.cpp
@@ -63,85 +63,21 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
(16, adf4350_regs_t::RF_DIVIDER_SELECT_DIV16)
;
- double actual_freq, pfd_freq;
- double ref_freq = self_base->get_iface()->get_clock_rate(unit);
- int R=0, BS=0, N=0, FRAC=0, MOD=0;
- int RFdiv = 1;
- adf4350_regs_t::reference_divide_by_2_t T = adf4350_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED;
- adf4350_regs_t::reference_doubler_t D = adf4350_regs_t::REFERENCE_DOUBLER_DISABLED;
-
- //Reference doubler for 50% duty cycle
- // if ref_freq < 12.5MHz enable regs.reference_divide_by_2
- if(ref_freq <= 12.5e6) D = adf4350_regs_t::REFERENCE_DOUBLER_ENABLED;
-
- //increase RF divider until acceptable VCO frequency
- double vco_freq = target_freq;
- while (vco_freq < 2.2e9) {
- vco_freq *= 2;
- RFdiv *= 2;
- }
-
//use 8/9 prescaler for vco_freq > 3 GHz (pg.18 prescaler)
adf4350_regs_t::prescaler_t prescaler = target_freq > 3e9 ? adf4350_regs_t::PRESCALER_8_9 : adf4350_regs_t::PRESCALER_4_5;
- /*
- * The goal here is to loop though possible R dividers,
- * band select clock dividers, N (int) dividers, and FRAC
- * (frac) dividers.
- *
- * Calculate the N and F dividers for each set of values.
- * The loop exits when it meets all of the constraints.
- * The resulting loop values are loaded into the registers.
- *
- * from pg.21
- *
- * f_pfd = f_ref*(1+D)/(R*(1+T))
- * f_vco = (N + (FRAC/MOD))*f_pfd
- * N = f_vco/f_pfd - FRAC/MOD = f_vco*((R*(T+1))/(f_ref*(1+D))) - FRAC/MOD
- * f_rf = f_vco/RFdiv)
- * f_actual = f_rf/2
- */
- for(R = 1; R <= 1023; R+=1){
- //PFD input frequency = f_ref/R ... ignoring Reference doubler/divide-by-2 (D & T)
- pfd_freq = ref_freq*(1+D)/(R*(1+T));
-
- //keep the PFD frequency at or below 25MHz (Loop Filter Bandwidth)
- if (pfd_freq > 25e6) continue;
-
- //ignore fractional part of tuning
- N = int(std::floor(target_freq/pfd_freq));
-
- //keep N > minimum int divider requirement
- if (N < prescaler_to_min_int_div[prescaler]) continue;
-
- for(BS=1; BS <= 255; BS+=1){
- //keep the band select frequency at or below 100KHz
- //constraint on band select clock
- if (pfd_freq/BS > 100e3) continue;
- goto done_loop;
- }
- } done_loop:
-
- //Fractional-N calculation
- MOD = 4095; //max fractional accuracy
- FRAC = int((target_freq/pfd_freq - N)*MOD);
-
- //Reference divide-by-2 for 50% duty cycle
- // if R even, move one divide by 2 to to regs.reference_divide_by_2
- if(R % 2 == 0){
- T = adf4350_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED;
- R /= 2;
- }
-
- //actual frequency calculation
- actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T))));
+ adf435x_tuning_constraints tuning_constraints;
+ tuning_constraints.force_frac0 = false;
+ tuning_constraints.band_sel_freq_max = 100e3;
+ tuning_constraints.ref_doubler_threshold = 12.5e6;
+ tuning_constraints.int_range = uhd::range_t(prescaler_to_min_int_div[prescaler], 4095); //INT is a 12-bit field
+ tuning_constraints.pfd_freq_max = 25e6;
+ tuning_constraints.rf_divider_range = uhd::range_t(1, 16);
- UHD_LOGV(often)
- << boost::format("SBX Intermediates: ref=%0.2f, outdiv=%f, fbdiv=%f") % (ref_freq*(1+int(D))/(R*(1+int(T)))) % double(RFdiv*2) % double(N + double(FRAC)/double(MOD)) << std::endl
- << boost::format("SBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d"
- ) % R % BS % N % FRAC % MOD % T % D % RFdiv << std::endl
- << boost::format("SBX Frequencies (MHz): REQ=%0.2f, ACT=%0.2f, VCO=%0.2f, PFD=%0.2f, BAND=%0.2f"
- ) % (target_freq/1e6) % (actual_freq/1e6) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) << std::endl;
+ double actual_freq;
+ adf435x_tuning_settings tuning_settings = _tune_adf435x_synth(
+ target_freq, self_base->get_iface()->get_clock_rate(unit),
+ tuning_constraints, actual_freq);
//load the register values
adf4350_regs_t regs;
@@ -151,19 +87,25 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
else
regs.output_power = adf4350_regs_t::OUTPUT_POWER_5DBM;
- regs.frac_12_bit = FRAC;
- regs.int_16_bit = N;
- regs.mod_12_bit = MOD;
- regs.clock_divider_12_bit = std::max(1, int(std::ceil(400e-6*pfd_freq/MOD)));
- regs.feedback_select = adf4350_regs_t::FEEDBACK_SELECT_DIVIDED;
- regs.clock_div_mode = adf4350_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE;
- regs.prescaler = prescaler;
- regs.r_counter_10_bit = R;
- regs.reference_divide_by_2 = T;
- regs.reference_doubler = D;
- regs.band_select_clock_div = BS;
- UHD_ASSERT_THROW(rfdivsel_to_enum.has_key(RFdiv));
- regs.rf_divider_select = rfdivsel_to_enum[RFdiv];
+ regs.frac_12_bit = tuning_settings.frac_12_bit;
+ regs.int_16_bit = tuning_settings.int_16_bit;
+ regs.mod_12_bit = tuning_settings.mod_12_bit;
+ regs.clock_divider_12_bit = tuning_settings.clock_divider_12_bit;
+ regs.feedback_select = tuning_settings.feedback_after_divider ?
+ adf4350_regs_t::FEEDBACK_SELECT_DIVIDED :
+ adf4350_regs_t::FEEDBACK_SELECT_FUNDAMENTAL;
+ regs.clock_div_mode = adf4350_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE;
+ regs.prescaler = prescaler;
+ regs.r_counter_10_bit = tuning_settings.r_counter_10_bit;
+ regs.reference_divide_by_2 = tuning_settings.r_divide_by_2_en ?
+ adf4350_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED :
+ adf4350_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED;
+ regs.reference_doubler = tuning_settings.r_doubler_en ?
+ adf4350_regs_t::REFERENCE_DOUBLER_ENABLED :
+ adf4350_regs_t::REFERENCE_DOUBLER_DISABLED;
+ regs.band_select_clock_div = tuning_settings.band_select_clock_div;
+ UHD_ASSERT_THROW(rfdivsel_to_enum.has_key(tuning_settings.rf_divider));
+ regs.rf_divider_select = rfdivsel_to_enum[tuning_settings.rf_divider];
//reset the N and R counter
regs.counter_reset = adf4350_regs_t::COUNTER_RESET_ENABLED;
diff --git a/host/lib/usrp/dboard/db_sbx_version4.cpp b/host/lib/usrp/dboard/db_sbx_version4.cpp
index 27fd68b05..8d95b0655 100644
--- a/host/lib/usrp/dboard/db_sbx_version4.cpp
+++ b/host/lib/usrp/dboard/db_sbx_version4.cpp
@@ -66,85 +66,21 @@ double sbx_xcvr::sbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
(64, adf4351_regs_t::RF_DIVIDER_SELECT_DIV64)
;
- double actual_freq, pfd_freq;
- double ref_freq = self_base->get_iface()->get_clock_rate(unit);
- int R=0, BS=0, N=0, FRAC=0, MOD=0;
- int RFdiv = 1;
- adf4351_regs_t::reference_divide_by_2_t T = adf4351_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED;
- adf4351_regs_t::reference_doubler_t D = adf4351_regs_t::REFERENCE_DOUBLER_DISABLED;
-
- //Reference doubler for 50% duty cycle
- // if ref_freq < 12.5MHz enable regs.reference_divide_by_2
- if(ref_freq <= 12.5e6) D = adf4351_regs_t::REFERENCE_DOUBLER_ENABLED;
-
- //increase RF divider until acceptable VCO frequency
- double vco_freq = target_freq;
- while (vco_freq < 2.2e9) {
- vco_freq *= 2;
- RFdiv *= 2;
- }
-
//use 8/9 prescaler for vco_freq > 3 GHz (pg.18 prescaler)
- adf4351_regs_t::prescaler_t prescaler = target_freq > 3e9 ? adf4351_regs_t::PRESCALER_8_9 : adf4351_regs_t::PRESCALER_4_5;
-
- /*
- * The goal here is to loop though possible R dividers,
- * band select clock dividers, N (int) dividers, and FRAC
- * (frac) dividers.
- *
- * Calculate the N and F dividers for each set of values.
- * The loop exits when it meets all of the constraints.
- * The resulting loop values are loaded into the registers.
- *
- * from pg.21
- *
- * f_pfd = f_ref*(1+D)/(R*(1+T))
- * f_vco = (N + (FRAC/MOD))*f_pfd
- * N = f_vco/f_pfd - FRAC/MOD = f_vco*((R*(T+1))/(f_ref*(1+D))) - FRAC/MOD
- * f_rf = f_vco/RFdiv)
- * f_actual = f_rf/2
- */
- for(R = 1; R <= 1023; R+=1){
- //PFD input frequency = f_ref/R ... ignoring Reference doubler/divide-by-2 (D & T)
- pfd_freq = ref_freq*(1+D)/(R*(1+T));
-
- //keep the PFD frequency at or below 25MHz (Loop Filter Bandwidth)
- if (pfd_freq > 25e6) continue;
-
- //ignore fractional part of tuning
- N = int(std::floor(vco_freq/pfd_freq));
-
- //keep N > minimum int divider requirement
- if (N < prescaler_to_min_int_div[prescaler]) continue;
-
- for(BS=1; BS <= 255; BS+=1){
- //keep the band select frequency at or below 100KHz
- //constraint on band select clock
- if (pfd_freq/BS > 100e3) continue;
- goto done_loop;
- }
- } done_loop:
-
- //Fractional-N calculation
- MOD = 4095; //max fractional accuracy
- FRAC = int((target_freq/pfd_freq - N)*MOD);
-
- //Reference divide-by-2 for 50% duty cycle
- // if R even, move one divide by 2 to to regs.reference_divide_by_2
- if(R % 2 == 0){
- T = adf4351_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED;
- R /= 2;
- }
+ adf4351_regs_t::prescaler_t prescaler = target_freq > 3.6e9 ? adf4351_regs_t::PRESCALER_8_9 : adf4351_regs_t::PRESCALER_4_5;
- //actual frequency calculation
- actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T))));
+ adf435x_tuning_constraints tuning_constraints;
+ tuning_constraints.force_frac0 = false;
+ tuning_constraints.band_sel_freq_max = 100e3;
+ tuning_constraints.ref_doubler_threshold = 12.5e6;
+ tuning_constraints.int_range = uhd::range_t(prescaler_to_min_int_div[prescaler], 4095); //INT is a 12-bit field
+ tuning_constraints.pfd_freq_max = 25e6;
+ tuning_constraints.rf_divider_range = uhd::range_t(1, 64);
- UHD_LOGV(often)
- << boost::format("SBX Intermediates: ref=%0.2f, outdiv=%f, fbdiv=%f") % (ref_freq*(1+int(D))/(R*(1+int(T)))) % double(RFdiv*2) % double(N + double(FRAC)/double(MOD)) << std::endl
- << boost::format("SBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d"
- ) % R % BS % N % FRAC % MOD % T % D % RFdiv << std::endl
- << boost::format("SBX Frequencies (MHz): REQ=%0.2f, ACT=%0.2f, VCO=%0.2f, PFD=%0.2f, BAND=%0.2f"
- ) % (target_freq/1e6) % (actual_freq/1e6) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) << std::endl;
+ double actual_freq;
+ adf435x_tuning_settings tuning_settings = _tune_adf435x_synth(
+ target_freq, self_base->get_iface()->get_clock_rate(unit),
+ tuning_constraints, actual_freq);
//load the register values
adf4351_regs_t regs;
@@ -154,19 +90,25 @@ double sbx_xcvr::sbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
else
regs.output_power = adf4351_regs_t::OUTPUT_POWER_5DBM;
- regs.frac_12_bit = FRAC;
- regs.int_16_bit = N;
- regs.mod_12_bit = MOD;
- regs.clock_divider_12_bit = std::max(1, int(std::ceil(400e-6*pfd_freq/MOD)));
- regs.feedback_select = adf4351_regs_t::FEEDBACK_SELECT_DIVIDED;
- regs.clock_div_mode = adf4351_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE;
- regs.prescaler = prescaler;
- regs.r_counter_10_bit = R;
- regs.reference_divide_by_2 = T;
- regs.reference_doubler = D;
- regs.band_select_clock_div = BS;
- UHD_ASSERT_THROW(rfdivsel_to_enum.has_key(RFdiv));
- regs.rf_divider_select = rfdivsel_to_enum[RFdiv];
+ regs.frac_12_bit = tuning_settings.frac_12_bit;
+ regs.int_16_bit = tuning_settings.int_16_bit;
+ regs.mod_12_bit = tuning_settings.mod_12_bit;
+ regs.clock_divider_12_bit = tuning_settings.clock_divider_12_bit;
+ regs.feedback_select = tuning_settings.feedback_after_divider ?
+ adf4351_regs_t::FEEDBACK_SELECT_DIVIDED :
+ adf4351_regs_t::FEEDBACK_SELECT_FUNDAMENTAL;
+ regs.clock_div_mode = adf4351_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE;
+ regs.prescaler = prescaler;
+ regs.r_counter_10_bit = tuning_settings.r_counter_10_bit;
+ regs.reference_divide_by_2 = tuning_settings.r_divide_by_2_en ?
+ adf4351_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED :
+ adf4351_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED;
+ regs.reference_doubler = tuning_settings.r_doubler_en ?
+ adf4351_regs_t::REFERENCE_DOUBLER_ENABLED :
+ adf4351_regs_t::REFERENCE_DOUBLER_DISABLED;
+ regs.band_select_clock_div = tuning_settings.band_select_clock_div;
+ UHD_ASSERT_THROW(rfdivsel_to_enum.has_key(tuning_settings.rf_divider));
+ regs.rf_divider_select = rfdivsel_to_enum[tuning_settings.rf_divider];
//reset the N and R counter
regs.counter_reset = adf4351_regs_t::COUNTER_RESET_ENABLED;
diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp
index edee46cd5..e9f60f765 100644
--- a/host/lib/usrp/dboard/db_tvrx.cpp
+++ b/host/lib/usrp/dboard/db_tvrx.cpp
@@ -267,7 +267,7 @@ static std::string get_band(double freq) {
* \return a voltage to feed the TVRX analog gain
*/
-static double gain_interp(double gain, boost::array<double, 17> db_vector, boost::array<double, 17> volts_vector) {
+static double gain_interp(double gain, const boost::array<double, 17>& db_vector, const boost::array<double, 17>& volts_vector) {
double volts;
gain = uhd::clip<double>(gain, db_vector.front(), db_vector.back()); //let's not get carried away here
diff --git a/host/lib/usrp/dboard/db_wbx_common.hpp b/host/lib/usrp/dboard/db_wbx_common.hpp
index 9e984dce7..d1beb160e 100644
--- a/host/lib/usrp/dboard/db_wbx_common.hpp
+++ b/host/lib/usrp/dboard/db_wbx_common.hpp
@@ -118,7 +118,7 @@ protected:
*/
class wbx_versionx {
public:
- wbx_versionx() {}
+ wbx_versionx():self_base(NULL) {}
~wbx_versionx(void) {}
virtual double set_tx_gain(double gain, const std::string &name) = 0;
diff --git a/host/lib/usrp/e100/e100_impl.hpp b/host/lib/usrp/e100/e100_impl.hpp
index 6f64d4b80..813f9cc8f 100644
--- a/host/lib/usrp/e100/e100_impl.hpp
+++ b/host/lib/usrp/e100/e100_impl.hpp
@@ -61,7 +61,7 @@ extern void e100_load_fpga(const std::string &bin_file);
//! Make an e100 dboard interface
uhd::usrp::dboard_iface::sptr make_e100_dboard_iface(
- wb_iface::sptr wb_iface,
+ uhd::wb_iface::sptr wb_iface,
uhd::i2c_iface::sptr i2c_iface,
uhd::spi_iface::sptr spi_iface,
e100_clock_ctrl::sptr clock,
diff --git a/host/lib/usrp/gps_ctrl.cpp b/host/lib/usrp/gps_ctrl.cpp
index c3af75faa..105a52b30 100644
--- a/host/lib/usrp/gps_ctrl.cpp
+++ b/host/lib/usrp/gps_ctrl.cpp
@@ -223,7 +223,6 @@ private:
boost::this_thread::sleep(milliseconds(GPS_TIMEOUT_DELAY_MS));
}
throw uhd::value_error(str(boost::format("get_nmea(): no %s message found") % msgtype));
- return std::string();
}
//helper function to retrieve a field from an NMEA sentence
@@ -322,7 +321,6 @@ private:
boost::this_thread::sleep(milliseconds(GPS_TIMEOUT_DELAY_MS));
}
throw uhd::value_error("get_stat(): no servo message found");
- return std::string();
}
uart_iface::sptr _uart;
diff --git a/host/lib/usrp/usrp1/io_impl.cpp b/host/lib/usrp/usrp1/io_impl.cpp
index d384eb13f..e1f17e5a6 100644
--- a/host/lib/usrp/usrp1/io_impl.cpp
+++ b/host/lib/usrp/usrp1/io_impl.cpp
@@ -63,7 +63,7 @@ static const size_t alignment_padding = 512;
* Helper struct to associate an offset with a buffer
**********************************************************************/
struct offset_send_buffer{
- offset_send_buffer(void){
+ offset_send_buffer(void):offset(0){
/* NOP */
}
diff --git a/host/lib/usrp/usrp1/usrp1_iface.cpp b/host/lib/usrp/usrp1/usrp1_iface.cpp
index 9301721aa..6eff9d3ad 100644
--- a/host/lib/usrp/usrp1/usrp1_iface.cpp
+++ b/host/lib/usrp/usrp1/usrp1_iface.cpp
@@ -91,11 +91,11 @@ public:
return uhd::ntohx(value_out);
}
-
+
void poke16(boost::uint32_t, boost::uint16_t) {
throw uhd::not_implemented_error("Unhandled command poke16()");
}
-
+
boost::uint16_t peek16(boost::uint32_t) {
throw uhd::not_implemented_error("Unhandled command peek16()");
return 0;
@@ -141,8 +141,10 @@ public:
if (readback) {
unsigned char buff[4] = {
- (bits >> 0) & 0xff, (bits >> 8) & 0xff,
- (bits >> 16) & 0xff, (bits >> 24) & 0xff
+ (unsigned char)(bits & 0xff),
+ (unsigned char)((bits >> 8) & 0xff),
+ (unsigned char)((bits >> 16) & 0xff),
+ (unsigned char)((bits >> 24) & 0xff)
};
//conditions where there are two header bytes
if (num_bytes >= 3 and buff[num_bytes-1] != 0 and buff[num_bytes-2] != 0 and buff[num_bytes-3] == 0){
@@ -168,7 +170,7 @@ public:
(((boost::uint32_t)buff[1]) << 8) |
(((boost::uint32_t)buff[2]) << 16) |
(((boost::uint32_t)buff[3]) << 24);
- return val;
+ return val;
}
else {
// Byteswap on num_bytes
diff --git a/host/lib/usrp/usrp1/usrp1_iface.hpp b/host/lib/usrp/usrp1/usrp1_iface.hpp
index 4612d7912..7fc943190 100644
--- a/host/lib/usrp/usrp1/usrp1_iface.hpp
+++ b/host/lib/usrp/usrp1/usrp1_iface.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2011 Ettus Research LLC
+// Copyright 2010-2013 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
@@ -19,7 +19,7 @@
#define INCLUDED_USRP1_IFACE_HPP
#include "fx2_ctrl.hpp"
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <uhd/types/serial.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
@@ -42,7 +42,8 @@
* Provides a set of functions to implementation layer.
* Including spi, peek, poke, control...
*/
-class usrp1_iface : public wb_iface, public uhd::i2c_iface, public uhd::spi_iface, boost::noncopyable{
+class usrp1_iface : public uhd::wb_iface, public uhd::i2c_iface, public uhd::spi_iface, boost::noncopyable
+{
public:
typedef boost::shared_ptr<usrp1_iface> sptr;
diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp
index 253ac1d6f..625926f36 100644
--- a/host/lib/usrp/usrp1/usrp1_impl.cpp
+++ b/host/lib/usrp/usrp1/usrp1_impl.cpp
@@ -258,12 +258,14 @@ usrp1_impl::usrp1_impl(const device_addr_t &device_addr){
_tree->create<std::string>(rx_codec_path / "name").set("ad9522");
_tree->create<meta_range_t>(rx_codec_path / "gains/pga/range").set(usrp1_codec_ctrl::rx_pga_gain_range);
_tree->create<double>(rx_codec_path / "gains/pga/value")
- .coerce(boost::bind(&usrp1_impl::update_rx_codec_gain, this, db, _1));
+ .coerce(boost::bind(&usrp1_impl::update_rx_codec_gain, this, db, _1))
+ .set(0.0);
_tree->create<std::string>(tx_codec_path / "name").set("ad9522");
_tree->create<meta_range_t>(tx_codec_path / "gains/pga/range").set(usrp1_codec_ctrl::tx_pga_gain_range);
_tree->create<double>(tx_codec_path / "gains/pga/value")
.subscribe(boost::bind(&usrp1_codec_ctrl::set_tx_pga_gain, _dbc[db].codec, _1))
- .publish(boost::bind(&usrp1_codec_ctrl::get_tx_pga_gain, _dbc[db].codec));
+ .publish(boost::bind(&usrp1_codec_ctrl::get_tx_pga_gain, _dbc[db].codec))
+ .set(0.0);
}
////////////////////////////////////////////////////////////////////
@@ -407,7 +409,7 @@ usrp1_impl::usrp1_impl(const device_addr_t &device_addr){
_tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(_rx_subdev_spec);
if (_tree->list(mb_path / "tx_dsps").size() > 0)
_tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(_tx_subdev_spec);
-
+
}
usrp1_impl::~usrp1_impl(void){
diff --git a/host/lib/usrp/usrp2/usrp2_clk_regs.hpp b/host/lib/usrp/usrp2/usrp2_clk_regs.hpp
index 8b185eac0..d5e506d8d 100644
--- a/host/lib/usrp/usrp2/usrp2_clk_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_clk_regs.hpp
@@ -22,8 +22,18 @@
class usrp2_clk_regs_t {
public:
- usrp2_clk_regs_t(void) { ; }
+ usrp2_clk_regs_t(void):
+ test(0),
+ fpga(0),
+ adc(0),
+ dac(0),
+ serdes(0),
+ exp(0),
+ tx_db(0),
+ rx_db(0) {}
+
usrp2_clk_regs_t(usrp2_iface::rev_type rev) {
+ fpga = adc = serdes = exp = tx_db = 0;
test = 0;
fpga = 1;
dac = 3;
@@ -54,7 +64,7 @@ public:
//dont throw, it may be unitialized
break;
}
-
+
rx_db = 7;
}
diff --git a/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp
index b48d05aa2..13dfb5b46 100644
--- a/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp
@@ -23,14 +23,15 @@
#include <uhd/transport/zero_copy.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <string>
/*!
* The usrp2 FIFO control class:
* Provide high-speed peek/poke interface.
*/
-class usrp2_fifo_ctrl : public wb_iface, public uhd::spi_iface{
+class usrp2_fifo_ctrl : public uhd::wb_iface, public uhd::spi_iface
+{
public:
typedef boost::shared_ptr<usrp2_fifo_ctrl> sptr;
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
index 3b230ca69..5f97045e1 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.cpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -271,7 +271,7 @@ public:
//send and recv
usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data, MIN_PROTO_COMPAT_I2C);
UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE);
- UHD_ASSERT_THROW(in_data.data.i2c_args.addr = num_bytes);
+ UHD_ASSERT_THROW(in_data.data.i2c_args.bytes == num_bytes);
//copy out the data
byte_vector_t result(num_bytes);
diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp
index ed4de02d5..a01f2ccfa 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.hpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010-2012 Ettus Research LLC
+// Copyright 2010-2013 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
@@ -25,7 +25,7 @@
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include "usrp2_regs.hpp"
-#include "wb_iface.hpp"
+#include <uhd/types/wb_iface.hpp>
#include <string>
/*!
@@ -33,7 +33,8 @@
* Provides a set of functions to implementation layer.
* Including spi, peek, poke, control...
*/
-class usrp2_iface : public wb_iface, public uhd::spi_iface, public uhd::i2c_iface{
+class usrp2_iface : public uhd::wb_iface, public uhd::spi_iface, public uhd::i2c_iface
+{
public:
typedef boost::shared_ptr<usrp2_iface> sptr;
/*!
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index a6c0d87cf..f9988287f 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -57,7 +57,7 @@ static const std::string USRP2_EEPROM_MAP_KEY = "N100";
//! Make a usrp2 dboard interface.
uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface(
- wb_iface::sptr wb_iface,
+ uhd::wb_iface::sptr wb_iface,
uhd::i2c_iface::sptr i2c_iface,
uhd::spi_iface::sptr spi_iface,
usrp2_clock_ctrl::sptr clk_ctrl
@@ -84,7 +84,7 @@ private:
usrp2_iface::sptr iface;
usrp2_fifo_ctrl::sptr fifo_ctrl;
uhd::spi_iface::sptr spiface;
- wb_iface::sptr wbiface;
+ uhd::wb_iface::sptr wbiface;
usrp2_clock_ctrl::sptr clock;
usrp2_codec_ctrl::sptr codec;
uhd::gps_ctrl::sptr gps;
diff --git a/host/lib/utils/paths.cpp b/host/lib/utils/paths.cpp
index 53055314b..3e2bea1c6 100644
--- a/host/lib/utils/paths.cpp
+++ b/host/lib/utils/paths.cpp
@@ -34,8 +34,19 @@
namespace fs = boost::filesystem;
/***********************************************************************
+ * Get a list of paths for an environment variable
+ **********************************************************************/
+static std::string get_env_var(const std::string &var_name, const std::string &def_val = ""){
+ const char *var_value_ptr = std::getenv(var_name.c_str());
+ return (var_value_ptr == NULL)? def_val : var_value_ptr;
+}
+
+static std::vector<fs::path> get_env_paths(const std::string &var_name){
+
+/***********************************************************************
* Determine the paths separator
**********************************************************************/
+
#ifdef UHD_PLATFORM_WIN32
static const std::string env_path_sep = ";";
#else
@@ -46,16 +57,6 @@ namespace fs = boost::filesystem;
boost::tokenizer<boost::char_separator<char> > \
(inp, boost::char_separator<char>(env_path_sep.c_str()))
-/***********************************************************************
- * Get a list of paths for an environment variable
- **********************************************************************/
-static std::string get_env_var(const std::string &var_name, const std::string &def_val = ""){
- const char *var_value_ptr = std::getenv(var_name.c_str());
- return (var_value_ptr == NULL)? def_val : var_value_ptr;
-}
-
-static std::vector<fs::path> get_env_paths(const std::string &var_name){
-
std::string var_value = get_env_var(var_name);
//convert to filesystem path, filter blank paths
@@ -85,6 +86,7 @@ std::vector<fs::path> get_image_paths(void){
std::vector<fs::path> get_module_paths(void){
std::vector<fs::path> paths = get_env_paths("UHD_MODULE_PATH");
paths.push_back(fs::path(uhd::get_pkg_path()) / UHD_LIB_DIR / "uhd" / "modules");
+ paths.push_back(fs::path(uhd::get_pkg_path()) / "share" / "uhd" / "modules");
return paths;
}
@@ -113,8 +115,8 @@ std::string uhd::get_tmp_path(void){
//try the stdio define if available
#ifdef P_tmpdir
- if (P_tmpdir != NULL) return P_tmpdir;
- #endif
+ return P_tmpdir;
+ #else
//try unix environment variables
tmp_path = std::getenv("TMPDIR");
@@ -122,6 +124,7 @@ std::string uhd::get_tmp_path(void){
//give up and use the unix default
return "/tmp";
+ #endif
}
std::string uhd::get_app_path(void){
diff --git a/host/lib/utils/tasks.cpp b/host/lib/utils/tasks.cpp
index 1f735de06..08c32a5fb 100644
--- a/host/lib/utils/tasks.cpp
+++ b/host/lib/utils/tasks.cpp
@@ -16,11 +16,13 @@
//
#include <uhd/utils/tasks.hpp>
+#include <uhd/utils/msg_task.hpp>
#include <uhd/utils/msg.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/barrier.hpp>
#include <exception>
#include <iostream>
+#include <vector>
using namespace uhd;
@@ -80,3 +82,100 @@ private:
task::sptr task::make(const task_fcn_type &task_fcn){
return task::sptr(new task_impl(task_fcn));
}
+
+/*
+ * During shutdown pointers to queues for radio_ctrl_core might not be available anymore.
+ * msg_task_impl provides a dump_queue for such messages.
+ * ctrl_cores can check this queue for stranded messages.
+ */
+
+class msg_task_impl : public msg_task{
+public:
+
+ msg_task_impl(const task_fcn_type &task_fcn):
+ _spawn_barrier(2)
+ {
+ _thread_group.create_thread(boost::bind(&msg_task_impl::task_loop, this, task_fcn));
+ _spawn_barrier.wait();
+ }
+
+ ~msg_task_impl(void){
+ _running = false;
+ _thread_group.interrupt_all();
+ _thread_group.join_all();
+ }
+
+ /*
+ * Returns the first message for the given SID.
+ * This way a radio_ctrl_core doesn't have to die in timeout but can check for stranded messages here.
+ * This might happen during shutdown when dtors are called.
+ * See also: comments in b200_io_impl->handle_async_task
+ */
+ msg_payload_t get_msg_from_dump_queue(boost::uint32_t sid)
+ {
+ boost::mutex::scoped_lock lock(_mutex);
+ msg_payload_t b;
+ for (size_t i = 0; i < _dump_queue.size(); i++) {
+ if (sid == _dump_queue[i].first) {
+ b = _dump_queue[i].second;
+ _dump_queue.erase(_dump_queue.begin() + i);
+ break;
+ }
+ }
+ return b;
+ }
+
+private:
+
+ void task_loop(const task_fcn_type &task_fcn){
+ _running = true;
+ _spawn_barrier.wait();
+
+ try{
+ while (_running){
+ boost::optional<msg_type_t> buff = task_fcn();
+ if(buff != boost::none){
+ /*
+ * If a message gets stranded it is returned by task_fcn and then pushed to the dump_queue.
+ * This way ctrl_cores can check dump_queue for missing messages.
+ */
+ boost::mutex::scoped_lock lock(_mutex);
+ _dump_queue.push_back(buff.get() );
+ }
+ }
+ }
+ catch(const boost::thread_interrupted &){
+ //this is an ok way to exit the task loop
+ }
+ catch(const std::exception &e){
+ do_error_msg(e.what());
+ }
+ catch(...){
+ //FIXME
+ //Unfortunately, this is also an ok way to end a task,
+ //because on some systems boost throws uncatchables.
+ }
+ }
+
+ void do_error_msg(const std::string &msg){
+ UHD_MSG(error)
+ << "An unexpected exception was caught in a task loop." << std::endl
+ << "The task loop will now exit, things may not work." << std::endl
+ << msg << std::endl
+ ;
+ }
+
+ boost::mutex _mutex;
+ boost::thread_group _thread_group;
+ boost::barrier _spawn_barrier;
+ bool _running;
+
+ /*
+ * This queue holds stranded messages until a radio_ctrl_core grabs them via 'get_msg_from_dump_queue'.
+ */
+ std::vector <msg_type_t> _dump_queue;
+};
+
+msg_task::sptr msg_task::make(const task_fcn_type &task_fcn){
+ return msg_task::sptr(new msg_task_impl(task_fcn));
+}
diff --git a/host/tests/sph_recv_test.cpp b/host/tests/sph_recv_test.cpp
index 9339a9739..316e24779 100644
--- a/host/tests/sph_recv_test.cpp
+++ b/host/tests/sph_recv_test.cpp
@@ -395,7 +395,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_normal){
//check the received packets
size_t num_accum_samps = 0;
- std::vector<std::complex<float> > mem(NUM_SAMPS_PER_BUFF*NCHANNELS);
+ std::complex<float> mem[NUM_SAMPS_PER_BUFF*NCHANNELS];
std::vector<std::complex<float> *> buffs(NCHANNELS);
for (size_t ch = 0; ch < NCHANNELS; ch++){
buffs[ch] = &mem[ch*NUM_SAMPS_PER_BUFF];
@@ -481,7 +481,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_sequence_error){
//check the received packets
size_t num_accum_samps = 0;
- std::vector<std::complex<float> > mem(NUM_SAMPS_PER_BUFF*NCHANNELS);
+ std::complex<float> mem[NUM_SAMPS_PER_BUFF*NCHANNELS];
std::vector<std::complex<float> *> buffs(NCHANNELS);
for (size_t ch = 0; ch < NCHANNELS; ch++){
buffs[ch] = &mem[ch*NUM_SAMPS_PER_BUFF];
@@ -574,7 +574,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_time_error){
//check the received packets
size_t num_accum_samps = 0;
- std::vector<std::complex<float> > mem(NUM_SAMPS_PER_BUFF*NCHANNELS);
+ std::complex<float> mem[NUM_SAMPS_PER_BUFF*NCHANNELS];
std::vector<std::complex<float> *> buffs(NCHANNELS);
for (size_t ch = 0; ch < NCHANNELS; ch++){
buffs[ch] = &mem[ch*NUM_SAMPS_PER_BUFF];
@@ -659,7 +659,7 @@ BOOST_AUTO_TEST_CASE(test_sph_recv_multi_channel_fragment){
//check the received packets
size_t num_accum_samps = 0;
- std::vector<std::complex<float> > mem(NUM_SAMPS_PER_BUFF*NCHANNELS);
+ std::complex<float> mem[NUM_SAMPS_PER_BUFF*NCHANNELS];
std::vector<std::complex<float> *> buffs(NCHANNELS);
for (size_t ch = 0; ch < NCHANNELS; ch++){
buffs[ch] = &mem[ch*NUM_SAMPS_PER_BUFF];
diff --git a/host/tests/time_spec_test.cpp b/host/tests/time_spec_test.cpp
index 37a039cc5..c9b9652f9 100644
--- a/host/tests/time_spec_test.cpp
+++ b/host/tests/time_spec_test.cpp
@@ -117,6 +117,7 @@ BOOST_AUTO_TEST_CASE(test_time_error_irrational_rate)
const uhd::time_spec_t ts = uhd::time_spec_t::from_ticks(tick_in, rate);
const long long tick_out = ts.to_ticks(rate);
const long long err = tick_in - tick_out;
+ std::streamsize precision = std::cout.precision();
std::cout << std::setprecision(18);
std::cout << "time ............ " << ts.get_real_secs() << std::endl;
@@ -124,6 +125,7 @@ BOOST_AUTO_TEST_CASE(test_time_error_irrational_rate)
std::cout << "tick out ........ " << tick_out << std::endl;
std::cout << "tick error ...... " << err << std::endl;
std::cout << std::endl;
+ std::cout.precision(precision);
BOOST_CHECK_EQUAL(err, (long long)(0));
}
diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt
index 92df0b7cf..abf2a546b 100644
--- a/host/utils/CMakeLists.txt
+++ b/host/utils/CMakeLists.txt
@@ -50,6 +50,8 @@ IF(ENABLE_USB)
b2xx_fx3_utils.cpp
)
INCLUDE_DIRECTORIES(${LIBUSB_INCLUDE_DIRS})
+ # Additional include directories for b2xx_fx3_utils
+ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../lib/usrp/b200 ${CMAKE_CURRENT_SOURCE_DIR}/../lib/usrp/common)
ENDIF(ENABLE_USB)
IF(LINUX AND ENABLE_USB)
diff --git a/host/utils/b2xx_fx3_utils.cpp b/host/utils/b2xx_fx3_utils.cpp
index 36688c6c7..96cd1f3e7 100644
--- a/host/utils/b2xx_fx3_utils.cpp
+++ b/host/utils/b2xx_fx3_utils.cpp
@@ -34,43 +34,37 @@
#include <boost/thread/thread.hpp>
#include <boost/functional/hash.hpp>
+#include <b200_iface.hpp>
#include <uhd/config.hpp>
-#include <uhd/utils/msg.hpp>
-
-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 B2XX_VID = 0x2500;
-const static boost::uint16_t B2XX_PID = 0x0020;
-
-const static boost::uint8_t VRT_VENDOR_OUT = (LIBUSB_REQUEST_TYPE_VENDOR
- | LIBUSB_ENDPOINT_OUT);
-const static boost::uint8_t VRT_VENDOR_IN = (LIBUSB_REQUEST_TYPE_VENDOR
- | LIBUSB_ENDPOINT_IN);
-const static boost::uint8_t FX3_FIRMWARE_LOAD = 0xA0;
-
-const static boost::uint8_t B2XX_VREQ_FPGA_START = 0x02;
-const static boost::uint8_t B2XX_VREQ_FPGA_DATA = 0x12;
-const static boost::uint8_t B2XX_VREQ_SET_FPGA_HASH = 0x1C;
-const static boost::uint8_t B2XX_VREQ_GET_FPGA_HASH = 0x1D;
-const static boost::uint8_t B2XX_VREQ_FPGA_RESET = 0x62;
-const static boost::uint8_t B2XX_VREQ_GET_USB = 0x80;
-const static boost::uint8_t B2XX_VREQ_GET_STATUS = 0x83;
-const static boost::uint8_t B2XX_VREQ_FX3_RESET = 0x99;
-const static boost::uint8_t B2XX_VREQ_EEPROM_WRITE = 0xBA;
-
-const static boost::uint8_t FX3_STATE_FPGA_READY = 0x00;
-const static boost::uint8_t FX3_STATE_CONFIGURING_FPGA = 0x01;
-const static boost::uint8_t FX3_STATE_BUSY = 0x02;
-const static boost::uint8_t FX3_STATE_RUNNING = 0x03;
-
-typedef boost::uint32_t hash_type;
-typedef std::vector<boost::uint8_t> byte_vector_t;
-
+#include <uhd/transport/usb_control.hpp>
+#include <uhd/transport/usb_device_handle.hpp>
+#include <uhd/exception.hpp>
+#include <uhd/utils/images.hpp>
namespace po = boost::program_options;
namespace fs = boost::filesystem;
+struct vid_pid_t {
+ boost::uint16_t vid;
+ boost::uint16_t pid;
+};
+const static vid_pid_t known_vid_pids[] = {
+ {FX3_VID, FX3_DEFAULT_PID},
+ {FX3_VID, FX3_REENUM_PID},
+ {B200_VENDOR_ID, B200_PRODUCT_ID}
+ };
+const static std::vector<vid_pid_t> known_vid_pid_vector(known_vid_pids, known_vid_pids + (sizeof(known_vid_pids) / sizeof(known_vid_pids[0])));
+const static boost::uint8_t eeprom_init_values[] = {
+ 0x43,
+ 0x59,
+ 0x14,
+ 0xB2,
+ (B200_PRODUCT_ID & 0xff),
+ (B200_PRODUCT_ID >> 8),
+ (B200_VENDOR_ID & 0xff),
+ (B200_VENDOR_ID >> 8)
+ };
+const static uhd::byte_vector_t eeprom_init_value_vector(eeprom_init_values, eeprom_init_values + (sizeof(eeprom_init_values) / sizeof(eeprom_init_values[0])));
//!used with lexical cast to parse a hex string
template <class T> struct to_hex{
@@ -90,657 +84,472 @@ boost::uint16_t atoh(const std::string &string){
return boost::lexical_cast<boost::uint16_t>(string);
}
-
-/*!
- * Create a file hash
- * The hash will be used to identify the loaded firmware and fpga image
- * \param filename file used to generate hash value
- * \return hash value in a size_t type
- */
-static hash_type generate_hash(const char *filename)
+int reset_usb()
{
- std::ifstream file(filename);
- if (not file){
- std::cerr << std::string("cannot open input file ") + filename
- << std::endl;
- }
-
- size_t hash = 0;
+ /* Okay, first, we need to discover what the path is to the ehci and
+ * xhci device files. */
+ std::set<fs::path> path_list;
+ path_list.insert("/sys/bus/pci/drivers/xhci-pci/");
+ path_list.insert("/sys/bus/pci/drivers/ehci-pci/");
+ path_list.insert("/sys/bus/pci/drivers/xhci_hcd/");
+ path_list.insert("/sys/bus/pci/drivers/ehci_hcd/");
- char ch;
- while (file.get(ch)) {
- boost::hash_combine(hash, ch);
- }
-
- if (not file.eof()){
- std::cerr << std::string("file error ") + filename << std::endl;
- }
+ /* Check each of the possible paths above to find which ones this system
+ * uses. */
+ for(std::set<fs::path>::iterator found = path_list.begin();
+ found != path_list.end(); ++found) {
- file.close();
- return hash_type(hash);
-}
+ if(fs::exists(*found)) {
-/*!
- * Verify checksum of a Intel HEX record
- * \param record a line from an Intel HEX file
- * \return true if record is valid, false otherwise
- */
-bool checksum(std::string *record) {
-
- size_t len = record->length();
- unsigned int i;
- unsigned char sum = 0;
- unsigned int val;
-
- for (i = 1; i < len; i += 2) {
- std::istringstream(record->substr(i, 2)) >> std::hex >> val;
- sum += val;
- }
+ fs::path devpath = *found;
- if (sum == 0)
- return true;
- else
- return false;
-}
+ std::set<fs::path> globbed;
+ /* Now, glob all of the files in the directory. */
+ fs::directory_iterator end_itr;
+ for(fs::directory_iterator itr(devpath); itr != end_itr; ++itr) {
+ globbed.insert((*itr).path());
+ }
-/*!
- * Parse Intel HEX record
- *
- * \param record a line from an Intel HEX file
- * \param len output length of record
- * \param addr output address
- * \param type output type
- * \param data output data
- * \return true if record is sucessfully read, false on error
- */
-bool parse_record(std::string *record, boost::uint16_t &len, boost::uint16_t &addr,
- uint16_t &type, unsigned char* data) {
-
- unsigned int i;
- std::string _data;
- unsigned int val;
-
- if (record->substr(0, 1) != ":")
- return false;
-
- std::istringstream(record->substr(1, 2)) >> std::hex >> len;
- std::istringstream(record->substr(3, 4)) >> std::hex >> addr;
- std::istringstream(record->substr(7, 2)) >> std::hex >> type;
-
- for (i = 0; i < len; i++) {
- std::istringstream(record->substr(9 + 2 * i, 2)) >> std::hex >> val;
- data[i] = (unsigned char) val;
+ /* Check each file path string to see if it is a device file. */
+ for(std::set<fs::path>::iterator it = globbed.begin();
+ it != globbed.end(); ++it) {
+
+ std::string file = fs::path((*it).filename()).string();
+
+ if (file.length() < 5)
+ continue;
+
+ if(file.compare(0, 5, "0000:") == 0) {
+ /* Un-bind the device. */
+ std::fstream unbind((devpath.string() + "unbind").c_str(),
+ std::fstream::out);
+ unbind << file;
+ unbind.close();
+
+ /* Re-bind the device. */
+ std::cout << "Re-binding: " << file << " in "
+ << devpath.string() << std::endl;
+ std::fstream bind((devpath.string() + "bind").c_str(),
+ std::fstream::out);
+ bind << file;
+ bind.close();
+ }
+ }
+ }
}
- return true;
+ return 0;
}
+uhd::transport::usb_device_handle::sptr open_device(const boost::uint16_t vid, const boost::uint16_t pid, const bool user_supplied = false)
+{
+ std::vector<uhd::transport::usb_device_handle::sptr> handles;
+ uhd::transport::usb_device_handle::sptr handle;
+ vid_pid_t vp = {vid, pid};
+
+ try {
+ // try caller's VID/PID first
+ handles = uhd::transport::usb_device_handle::get_device_list(vp.vid,vp.pid);
+ if (user_supplied && handles.size() == 0)
+ std::cerr << (boost::format("Failed to open device with VID 0x%04x and PID 0x%04x - trying other known VID/PIDs") % vid % pid).str() << std::endl;
+
+ // try known VID/PIDs next
+ for (size_t i = 0; handles.size() == 0 && i < known_vid_pid_vector.size(); i++)
+ {
+ vp = known_vid_pid_vector[i];
+ handles = uhd::transport::usb_device_handle::get_device_list(vp.vid,vp.pid);
+ }
-/*!
- * Write data to the FX3.
- *
- * \param dev_handle the libusb-1.0 device handle
- * \param request the usb transfer request type
- * \param value the USB bValue
- * \param index the USB bIndex
- * \param buff the data to write
- * \param length the number of bytes to write
- * \return the number of bytes written
- */
-libusb_error fx3_control_write(libusb_device_handle *dev_handle, boost::uint8_t request,
- boost::uint16_t value, boost::uint16_t index, unsigned char *buff,
- boost::uint16_t length, boost::uint32_t timeout = 0) {
-
-#if 0
- if(DEBUG) {
- std::cout << "Writing: <" << std::hex << std::setw(6) << std::showbase \
- << std::internal << std::setfill('0') << (int) request \
- << ", " << std::setw(6) << (int) VRT_VENDOR_OUT \
- << ", " << std::setw(6) << value \
- << ", " << std::setw(6) << index \
- << ", " << std::dec << std::setw(2) << length \
- << ">" << std::endl;
-
- std::cout << "\t\tData: 0x " << std::noshowbase;
-
- for(int count = 0; count < length; count++) {
- std::cout << std::hex << std::setw(2) << (int) buff[count] << " ";
+ if (handles.size() > 0)
+ {
+ handle = handles[0];
+ std::cout << (boost::format("Device opened (VID=0x%04x,PID=0x%04x)") % vp.vid % vp.pid).str() << std::endl;
}
- std::cout << std::showbase << std::endl;
+ if (!handle)
+ std::cerr << "Cannot open device" << std::endl;
}
-#endif
-
- return (libusb_error) libusb_control_transfer(dev_handle, VRT_VENDOR_OUT, request, \
- value, index, buff, length, timeout);
-}
-
-
-/*!
- * Read data from the FX3.
- *
- * \param dev_handle the libusb-1.0 device handle
- * \param request the usb transfer request type
- * \param value the USB bValue
- * \param index the USB bIndex
- * \param buff a buffer to store the read bytes to
- * \param length the number of bytes to read
- * \return the number of bytes read
- */
-libusb_error fx3_control_read(libusb_device_handle *dev_handle, boost::uint8_t request,
- boost::uint16_t value, boost::uint16_t index, unsigned char *buff,
- boost::uint16_t length, boost::uint32_t timeout = 0) {
-
-#if 0
- if(DEBUG) {
- std::cout << "Reading: <" << std::hex << std::setw(6) << std::showbase \
- << std::internal << std::setfill('0') << (int) request \
- << ", " << std::setw(6) << (int) VRT_VENDOR_IN \
- << ", " << std::setw(6) << value \
- << ", " << std::setw(6) << index \
- << ", " << std::dec << std::setw(2) << length \
- << ">" << std::endl << std::endl;
+ catch(const std::exception &e) {
+ std::cerr << "Failed to communicate with the device!" << std::endl;
+ #ifdef UHD_PLATFORM_WIN32
+ std::cerr << "The necessary drivers are not installed. Read the UHD Transport Application Notes for details:\nhttp://files.ettus.com/uhd_docs/manual/html/transport.html" << std::endl;
+ #endif /* UHD_PLATFORM_WIN32 */
+ handle.reset();
}
-#endif
- return (libusb_error) libusb_control_transfer(dev_handle, VRT_VENDOR_IN, request, \
- value, index, buff, length, timeout);
+ return handle;
}
+b200_iface::sptr make_b200_iface(const uhd::transport::usb_device_handle::sptr &handle)
+{
+ b200_iface::sptr b200;
-void write_eeprom(libusb_device_handle *dev_handle, boost::uint8_t addr,
- boost::uint8_t offset, const byte_vector_t &bytes) {
- fx3_control_write(dev_handle, B2XX_VREQ_EEPROM_WRITE,
- 0, offset | (boost::uint16_t(addr) << 8),
- (unsigned char *) &bytes[0],
- bytes.size());
-}
-
-
-boost::uint8_t get_fx3_status(libusb_device_handle *dev_handle) {
-
- unsigned char rx_data[1];
+ try {
+ uhd::transport::usb_control::sptr usb_ctrl = uhd::transport::usb_control::make(handle, 0);
+ b200 = b200_iface::make(usb_ctrl);
- fx3_control_read(dev_handle, B2XX_VREQ_GET_STATUS, 0x00, 0x00, rx_data, 1);
+ if (!b200)
+ std::cerr << "Cannot create device interface" << std::endl;
+ }
+ catch(const std::exception &e) {
+ std::cerr << "Failed to communicate with the device!" << std::endl;
+ #ifdef UHD_PLATFORM_WIN32
+ std::cerr << "The necessary drivers are not installed. Read the UHD Transport Application Notes for details:\nhttp://files.ettus.com/uhd_docs/manual/html/transport.html" << std::endl;
+ #endif /* UHD_PLATFORM_WIN32 */
+ b200.reset();
+ }
- return boost::lexical_cast<boost::uint8_t>(rx_data[0]);
+ return b200;
}
-void usrp_get_fpga_hash(libusb_device_handle *dev_handle, hash_type &hash) {
- fx3_control_read(dev_handle, B2XX_VREQ_GET_FPGA_HASH, 0x00, 0x00,
- (unsigned char*) &hash, 4, 500);
-}
+int read_eeprom(b200_iface::sptr& b200, uhd::byte_vector_t& data)
+{
+ try {
+ data = b200->read_eeprom(0x0, 0x0, 8);
+ } catch (std::exception &e) {
+ std::cerr << "Exception while reading EEPROM: " << e.what() << std::endl;
+ return -1;
+ }
-void usrp_set_fpga_hash(libusb_device_handle *dev_handle, hash_type hash) {
- fx3_control_write(dev_handle, B2XX_VREQ_SET_FPGA_HASH, 0x00, 0x00,
- (unsigned char*) &hash, 4);
+ return 0;
}
-boost::int32_t load_fpga(libusb_device_handle *dev_handle,
- const std::string filestring) {
-
- if (filestring.empty())
- {
- std::cerr << "load_fpga: input file is empty." << std::endl;
- exit(-1);
+int write_eeprom(b200_iface::sptr& b200, const uhd::byte_vector_t& data)
+{
+ try {
+ b200->write_eeprom(0x0, 0x0, data);
+ } catch (std::exception &e) {
+ std::cerr << "Exception while writing EEPROM: " << e.what() << std::endl;
+ return -1;
}
- boost::uint8_t fx3_state = 0;
-
- const char *filename = filestring.c_str();
+ return 0;
+}
- hash_type hash = generate_hash(filename);
- hash_type loaded_hash; usrp_get_fpga_hash(dev_handle, loaded_hash);
- if (hash == loaded_hash) return 0;
+int verify_eeprom(b200_iface::sptr& b200, const uhd::byte_vector_t& data)
+{
+ bool verified = true;
+ uhd::byte_vector_t read_bytes;
+ if (read_eeprom(b200, read_bytes))
+ return -1;
- size_t file_size = 0;
+ if (data.size() != read_bytes.size())
{
- std::ifstream file(filename, std::ios::in | std::ios::binary | std::ios::ate);
- file_size = file.tellg();
+ std::cerr << "ERROR: Only able to verify first " << std::min(data.size(), read_bytes.size()) << " bytes." << std::endl;
+ verified = false;
}
- std::ifstream file;
- file.open(filename, std::ios::in | std::ios::binary);
-
- if(!file.good()) {
- std::cerr << "load_fpga: cannot open FPGA input file." << std::endl;
- exit(-1);
+ for (size_t i = 0; i < std::min(data.size(), read_bytes.size()); i++) {
+ if (data[i] != read_bytes[i]) {
+ verified = false;
+ std::cerr << "Byte " << i << " Expected: " << data[i] << ", Got: " << read_bytes[i] << std::endl;
+ }
}
- do {
- fx3_state = get_fx3_status(dev_handle);
- boost::this_thread::sleep(boost::posix_time::milliseconds(10));
- } while(fx3_state != FX3_STATE_FPGA_READY);
-
- std::cout << "Loading FPGA image: " \
- << filestring << "..." << std::flush;
-
- unsigned char out_buff[64];
- memset(out_buff, 0x00, sizeof(out_buff));
- fx3_control_write(dev_handle, B2XX_VREQ_FPGA_START, 0, 0, out_buff, 1, 1000);
-
- do {
- fx3_state = get_fx3_status(dev_handle);
- boost::this_thread::sleep(boost::posix_time::milliseconds(10));
- } while(fx3_state != FX3_STATE_CONFIGURING_FPGA);
-
-
- size_t bytes_sent = 0;
- while(!file.eof()) {
- file.read((char *) out_buff, sizeof(out_buff));
- const std::streamsize n = file.gcount();
- if(n == 0) continue;
-
- boost::uint16_t transfer_count = boost::uint16_t(n);
-
- /* Send the data to the device. */
- fx3_control_write(dev_handle, B2XX_VREQ_FPGA_DATA, 0, 0, out_buff,
- transfer_count, 5000);
-
- if (bytes_sent == 0) std::cout << " 0%" << std::flush;
- const size_t percent_before = size_t((bytes_sent*100)/file_size);
- bytes_sent += transfer_count;
- const size_t percent_after = size_t((bytes_sent*100)/file_size);
- if (percent_before/10 != percent_after/10) {
- std::cout << "\b\b\b\b" << std::setw(3) << percent_after
- << "%" << std::flush;
- }
+ if (!verified) {
+ std::cerr << "Verification failed" << std::endl;
+ return -1;
}
- file.close();
+ return 0;
+}
+
+int write_and_verify_eeprom(b200_iface::sptr& b200, const uhd::byte_vector_t& data)
+{
+ if (write_eeprom(b200, data))
+ return -1;
+ if (verify_eeprom(b200, data))
+ return -1;
- do {
- fx3_state = get_fx3_status(dev_handle);
- boost::this_thread::sleep(boost::posix_time::milliseconds(10));
- } while(fx3_state != FX3_STATE_RUNNING);
+ return 0;
+}
- usrp_set_fpga_hash(dev_handle, hash);
+int erase_eeprom(b200_iface::sptr& b200)
+{
+ uhd::byte_vector_t bytes(8);
- std::cout << "\b\b\b\b done" << std::endl;
+ memset(&bytes[0], 0xFF, 8);
+ if (write_and_verify_eeprom(b200, bytes))
+ return -1;
return 0;
}
+boost::int32_t main(boost::int32_t argc, char *argv[]) {
+ boost::uint16_t vid, pid;
+ std::string pid_str, vid_str, fw_file, fpga_file;
+ bool user_supplied_vid_pid = false;
-/*!
- * Program the FX3 with a firmware file (Intel HEX format)
- *
- * \param dev_handle the libusb-1.0 device handle
- * \param filestring the filename of the firmware file
- * \return 0 for success, otherwise error code
- */
-boost::int32_t fx3_load_firmware(libusb_device_handle *dev_handle, \
- std::string filestring) {
-
- if (filestring.empty())
- {
- std::cerr << "fx3_load_firmware: input file is empty." << std::endl;
- exit(-1);
- }
+ po::options_description visible("Allowed options");
+ visible.add_options()
+ ("help,h", "help message")
+ ("vid,v", po::value<std::string>(&vid_str),
+ "Specify VID of device to use.")
+ ("pid,p", po::value<std::string>(&pid_str),
+ "Specify PID of device to use.")
+ ("speed,S", "Read back the USB mode currently in use.")
+ ("reset-device,D", "Reset the B2xx Device.")
+ ("reset-fpga,F", "Reset the FPGA (does not require re-programming.")
+ ("reset-usb,U", "Reset the USB subsystem on your host computer.")
+ ("init-device,I", "Initialize a B2xx device.")
+ ("load-fw,W", po::value<std::string>(&fw_file),
+ "Load a firmware (hex) file into the FX3.")
+ ("load-fpga,L", po::value<std::string>(&fpga_file),
+ "Load a FPGA (bin) file into the FPGA.")
+ ;
- const char *filename = filestring.c_str();
+ // Hidden options provided for testing - use at your own risk!
+ po::options_description hidden("Hidden options");
+ hidden.add_options()
+ ("uninit-device,U", "Uninitialize a B2xx device.")
+ ("read-eeprom,R", "Read first 8 bytes of EEPROM")
+ ("erase-eeprom,E", "Erase first 8 bytes of EEPROM");
- /* Fields used in each USB control transfer. */
- boost::uint16_t len = 0;
- boost::uint16_t type = 0;
- boost::uint16_t lower_address_bits = 0x0000;
- unsigned char data[512];
+ po::options_description desc;
+ desc.add(visible);
+ desc.add(hidden);
- /* Can be set by the Intel HEX record 0x04, used for all 0x00 records
- * thereafter. Note this field takes the place of the 'index' parameter in
- * libusb calls, and is necessary for FX3's 32-bit addressing. */
- boost::uint16_t upper_address_bits = 0x0000;
+ po::variables_map vm;
- std::ifstream file;
- file.open(filename, std::ifstream::in);
+ try {
+ po::store(po::parse_command_line(argc, argv, desc), vm);
+ po::notify(vm);
+ } catch (std::exception &e) {
+ std::cerr << "Exception while parsing arguments: " << e.what() << std::endl;
+ std::cout << boost::format("B2xx Utility Program %s") % visible << std::endl;
+ return ~0;
+ }
- if(!file.good()) {
- std::cerr << "fx3_load_firmware: cannot open firmware input file"
- << std::endl;
- exit(-1);
+ if (vm.count("help")){
+ try {
+ std::cout << boost::format("B2xx Utility Program %s") % visible << std::endl;
+ } catch(...) {}
+ return ~0;
}
- std::cout << "Loading firmware image: " \
- << filestring << "..." << std::flush;
+ if (vm.count("reset-usb")) {
+ return reset_usb();
+ }
- while (!file.eof()) {
- boost::int32_t ret = 0;
- std::string record;
- file >> record;
+ uhd::transport::usb_device_handle::sptr handle;
+ b200_iface::sptr b200;
- /* Check for valid Intel HEX record. */
- if (!checksum(&record) || !parse_record(&record, len, \
- lower_address_bits, type, data)) {
- std::cerr << "fx3_load_firmware: bad intel hex record checksum"
- << std::endl;
+ vid = B200_VENDOR_ID; // Default
+ pid = B200_PRODUCT_ID; // Default
+ if (vm.count("vid") && vm.count("pid"))
+ {
+ try {
+ vid = atoh(vid_str);
+ pid = atoh(pid_str);
+ } catch (std::exception &e) {
+ std::cerr << "Exception while parsing VID and PID: " << e.what() << std:: endl;
+ return ~0;
}
+ user_supplied_vid_pid = true;
+ }
- /* Type 0x00: Data. */
- if (type == 0x00) {
- ret = fx3_control_write(dev_handle, FX3_FIRMWARE_LOAD, \
- lower_address_bits, upper_address_bits, data, len);
-
- if (ret < 0) {
- std::cerr << "usrp_load_firmware: usrp_control_write failed"
- << std::endl;
- }
- }
+ // open the device
+ handle = open_device(vid, pid, user_supplied_vid_pid);
+ if (!handle)
+ return -1;
+ std::cout << "B2xx detected..." << std::flush;
- /* Type 0x01: EOF. */
- else if (type == 0x01) {
- if (lower_address_bits != 0x0000 || len != 0 ) {
- std::cerr << "fx3_load_firmware: For EOF record, address must be 0, length must be 0." << std::endl;
- }
+ // make the interface
+ b200 = make_b200_iface(handle);
+ if (!b200)
+ return -1;
+ std::cout << " Control of B2xx granted..." << std::endl << std::endl;
- /* Successful termination! */
- file.close();
+ // if we are supposed to load a new firmware image and one already exists, reset the FX3 so we can load the new one
+ if (vm.count("load-fw") && handle->firmware_loaded())
+ {
+ std::cout << "Overwriting existing firmware" << std::endl;
- /* Let the system settle. */
- boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
- return 0;
+ // before we reset, make sure we have a good firmware file
+ if(!(fs::exists(fw_file)))
+ {
+ std::cerr << "Invalid firmware filepath: " << fw_file << std::endl;
+ return -1;
}
- /* Type 0x04: Extended Linear Address Record. */
- else if (type == 0x04) {
- if (lower_address_bits != 0x0000 || len != 2 ) {
- std::cerr << "fx3_load_firmware: For ELA record, address must be 0, length must be 2." << std::endl;
- }
-
- upper_address_bits = ((boost::uint16_t)((data[0] & 0x00FF) << 8))\
- + ((boost::uint16_t)(data[1] & 0x00FF));
+ // reset the device
+ try {
+ b200->reset_fx3();
+ } catch (std::exception &e) {
+ std::cerr << "Exception while reseting FX3: " << e.what() << std::endl;
}
- /* Type 0x05: Start Linear Address Record. */
- else if (type == 0x05) {
- if (lower_address_bits != 0x0000 || len != 4 ) {
- std::cerr << "fx3_load_firmware: For SLA record, address must be 0, length must be 4." << std::endl;
- }
+ // re-open device
+ b200.reset();
+ handle.reset();
+ boost::this_thread::sleep(boost::posix_time::seconds(2)); // wait 2 seconds for FX3 to reset
+ handle = open_device(vid, pid);
+ if (!handle)
+ return -1;
+ b200 = make_b200_iface(handle);
+ if (!b200)
+ return -1;
+ }
- /* The firmware load is complete. We now need to tell the CPU
- * to jump to an execution address start point, now contained within
- * the data field. Parse these address bits out, and then push the
- * instruction. */
- upper_address_bits = ((boost::uint16_t)((data[0] & 0x00FF) << 8))\
- + ((boost::uint16_t)(data[1] & 0x00FF));
- lower_address_bits = ((boost::uint16_t)((data[2] & 0x00FF) << 8))\
- + ((boost::uint16_t)(data[3] & 0x00FF));
+ // Check to make sure firmware is loaded
+ if (!(handle->firmware_loaded()))
+ {
+ std::cout << "Loading firmware" << std::endl;
- fx3_control_write(dev_handle, FX3_FIRMWARE_LOAD, lower_address_bits, \
- upper_address_bits, 0, 0);
+ if (fw_file.empty())
+ fw_file = uhd::find_image_path(B200_FW_FILE_NAME);
- std::cout << " done" << std::endl;
+ if(fw_file.empty()) {
+ std::cerr << "Firmware image not found!" << std::endl;
+ return -1;
}
- /* If we receive an unknown record type, error out. */
- else {
- std::cerr << "fx3_load_firmware: unsupported record type." << std::endl;
+ if(!(fs::exists(fw_file))) {
+ std::cerr << "Invalid filepath: " << fw_file << std::endl;
+ return -1;
}
- }
-
- /* There was no valid EOF. */
- std::cerr << "fx3_load_firmware: No EOF record found." << std::cout;
- return ~0;
-}
+ // load firmware
+ try {
+ b200->load_firmware(fw_file);
+ } catch (std::exception &e) {
+ std::cerr << "Exception while loading firmware: " << e.what() << std::endl;
+ return ~0;
+ }
-boost::int32_t main(boost::int32_t argc, char *argv[]) {
- boost::uint16_t vid, pid;
- std::string pid_str, vid_str, fw_file, fpga_file;
+ // re-open device
+ b200.reset();
+ handle.reset();
+ handle = open_device(vid, pid);
+ if (!handle)
+ return -1;
+ b200 = make_b200_iface(handle);
+ if (!b200)
+ return -1;
- po::options_description desc("Allowed options");
- desc.add_options()
- ("help,h", "help message")
- ("vid,v", po::value<std::string>(&vid_str)->default_value("0x2500"),
- "Specify VID of device to use.")
- ("pid,p", po::value<std::string>(&pid_str)->default_value("0x0020"),
- "Specify PID of device to use.")
- ("speed,S", "Read back the USB mode currently in use.")
- ("reset-device,D", "Reset the B2xx Device.")
- ("reset-fpga,F", "Reset the FPGA (does not require re-programming.")
- ("reset-usb,U", "Reset the USB subsystem on your host computer.")
- ("init-device,I", "Initialize a B2xx device.")
- ("load-fw,W", po::value<std::string>(&fw_file)->default_value(""),
- "Load a firmware (hex) file into the FX3.")
- ("load-fpga,L", po::value<std::string>(&fpga_file)->default_value(""),
- "Load a FPGA (bin) file into the FPGA.")
- ;
+ std::cout << "Firmware loaded" << std::endl;
+ }
- po::variables_map vm;
- po::store(po::parse_command_line(argc, argv, desc), vm);
- po::notify(vm);
+ // Added for testing purposes - not exposed
+ if (vm.count("read-eeprom"))
+ {
+ uhd::byte_vector_t data;
- if (vm.count("help")){
- std::cout << boost::format("B2xx Utilitiy Program %s") % desc << std::endl;
- return ~0;
- } else if (vm.count("reset-usb")) {
- /* Okay, first, we need to discover what the path is to the ehci and
- * xhci device files. */
- std::set<fs::path> path_list;
- path_list.insert("/sys/bus/pci/drivers/xhci-pci/");
- path_list.insert("/sys/bus/pci/drivers/ehci-pci/");
- path_list.insert("/sys/bus/pci/drivers/xhci_hcd/");
- path_list.insert("/sys/bus/pci/drivers/ehci_hcd/");
-
- /* Check each of the possible paths above to find which ones this system
- * uses. */
- for(std::set<fs::path>::iterator found = path_list.begin();
- found != path_list.end(); ++found) {
-
- if(fs::exists(*found)) {
-
- fs::path devpath = *found;
-
- std::set<fs::path> globbed;
-
- /* Now, glob all of the files in the directory. */
- fs::directory_iterator end_itr;
- for(fs::directory_iterator itr(devpath); itr != end_itr; ++itr) {
- globbed.insert((*itr).path());
- }
+ if (read_eeprom(b200, data))
+ return -1;
- /* Check each file path string to see if it is a device file. */
- for(std::set<fs::path>::iterator it = globbed.begin();
- it != globbed.end(); ++it) {
-
- std::string file = fs::path((*it).filename()).string();
-
- if(file.compare(0, 5, "0000:") == 0) {
- /* Un-bind the device. */
- std::fstream unbind((devpath.string() + "unbind").c_str(),
- std::fstream::out);
- unbind << file;
- unbind.close();
-
- /* Re-bind the device. */
- std::cout << "Re-binding: " << file << " in "
- << devpath.string() << std::endl;
- std::fstream bind((devpath.string() + "bind").c_str(),
- std::fstream::out);
- bind << file;
- bind.close();
- }
- }
- }
- }
+ for (int i = 0; i < 8; i++)
+ std::cout << i << ": " << boost::format("0x%X") % (int)data[i] << std::endl;
return 0;
}
- vid = atoh(vid_str);
- pid = atoh(pid_str);
-
- /* Pointer to pointer of device, used to retrieve a list of devices. */
- libusb_device **devs;
- libusb_device_handle *dev_handle;
- libusb_context *ctx = NULL;
- libusb_error error_code;
-
- libusb_init(&ctx);
- libusb_set_debug(ctx, 3);
- libusb_get_device_list(ctx, &devs);
-
- /* If we are initializing the device, the VID/PID will default to the
- * Cypress VID/PID for the initial FW load. */
- if (vm.count("init-device")) {
- dev_handle = libusb_open_device_with_vid_pid(ctx, FX3_VID,
- FX3_DEFAULT_PID);
- if(dev_handle == NULL) {
- std::cerr << "Cannot open device with vid: " << vid << " and pid: "
- << pid << std::endl;
+ // Added for testing purposes - not exposed
+ if (vm.count("erase-eeprom"))
+ {
+ if (erase_eeprom(b200))
return -1;
- } else { std::cout << "Uninitialized B2xx detected..." << std::flush; }
- libusb_free_device_list(devs, 1);
- /* Find out if kernel driver is attached, and if so, detach it. */
- if(libusb_kernel_driver_active(dev_handle, 0) == 1) {
- std::cout << " Competing Driver Identified... " << std::flush;
+ std::cout << "Erase Successful!" << std::endl;
- if(libusb_detach_kernel_driver(dev_handle, 0) == 0) {
- std::cout << " Competing Driver Destroyed!" << std::flush;
- }
- }
- libusb_claim_interface(dev_handle, 0);
- std::cout << " Control of B2xx granted..." << std::endl << std::endl;
-
- /* Load the FW. */
- error_code = (libusb_error) fx3_load_firmware(dev_handle, fw_file);
- if(error_code != 0) {
- std::cerr << std::flush << "Error loading firmware. Error code: "
- << error_code << std::endl;
- libusb_release_interface(dev_handle, 0);
- libusb_close(dev_handle);
- libusb_exit(ctx);
- return ~0;
- }
+ return 0;
+ }
- /* Let the device re-enumerate. */
- libusb_release_interface(dev_handle, 0);
- libusb_close(dev_handle);
- dev_handle = libusb_open_device_with_vid_pid(ctx, FX3_VID,
- FX3_REENUM_PID);
- if(dev_handle == NULL) {
- std::cerr << "Cannot open device with vid: " << vid << " and pid: "
- << pid << std::endl;
- return -1;
- } else {
- std::cout << "Detected in-progress init of B2xx..." << std::flush;
- }
- //libusb_free_device_list(devs, 1);
- libusb_claim_interface(dev_handle, 0);
- std::cout << " Reenumeration complete, Device claimed..."
- << std::endl;
+ // Added for testing purposes - not exposed
+ if (vm.count("uninit-device"))
+ {
+ // erase EEPROM
+ erase_eeprom(b200);
- /* Now, initialize the device. */
- byte_vector_t bytes(8);
- bytes[0] = 0x43;
- bytes[1] = 0x59;
- bytes[2] = 0x14;
- bytes[3] = 0xB2;
- bytes[4] = (B2XX_PID & 0xff);
- bytes[5] = (B2XX_PID >> 8);
- bytes[6] = (B2XX_VID & 0xff);
- bytes[7] = (B2XX_VID >> 8);
- write_eeprom(dev_handle, 0x0, 0x0, bytes);
- std::cout << "EEPROM initialized, resetting device..."
+ std::cout << "EEPROM uninitialized, resetting device..."
<< std::endl << std::endl;
- /* Reset the device! */
- boost::uint8_t data_buffer[1];
- fx3_control_write(dev_handle, B2XX_VREQ_FX3_RESET,
- 0x00, 0x00, data_buffer, 1, 5000);
+ // reset the device
+ try {
+ b200->reset_fx3();
+ } catch (uhd::exception &e) {
+ std::cerr << "Exception while resetting FX3: " << e.what() << std::endl;
+ return -1;
+ }
- std::cout << "Initialization Process Complete."
+ std::cout << "Uninitialization Process Complete."
<< std::endl << std::endl;
- libusb_release_interface(dev_handle, 0);
- libusb_close(dev_handle);
- libusb_exit(ctx);
+
return 0;
}
- dev_handle = libusb_open_device_with_vid_pid(ctx, vid, pid);
- if(dev_handle == NULL) {
- std::cerr << "Cannot open device with vid: " << vid << " and pid: "
- << pid << std::endl;
+ /* If we are initializing the device, the VID/PID should default to the
+ * Cypress VID/PID for the initial FW load, but we can initialize from any state. */
+ if (vm.count("init-device"))
+ {
+ /* Now, initialize the device. */
+ if (write_and_verify_eeprom(b200, eeprom_init_value_vector))
return -1;
- } else { std::cout << "Reactor Core Online..." << std::flush; }
- libusb_free_device_list(devs, 1);
- /* Find out if kernel driver is attached, and if so, detach it. */
- if(libusb_kernel_driver_active(dev_handle, 0) == 1) {
- std::cout << " Competing Driver Identified... " << std::flush;
+ std::cout << "EEPROM initialized, resetting device..."
+ << std::endl << std::endl;
- if(libusb_detach_kernel_driver(dev_handle, 0) == 0) {
- std::cout << " Competing Driver Destroyed!" << std::flush;
+ /* Reset the device! */
+ try {
+ b200->reset_fx3();
+ } catch (const std::exception &e) {
+ std::cerr << "Exception while resetting device: " << e.what() << std::endl;
+ return -1;
}
- }
- /* Claim interface 0 of device. */
- error_code = (libusb_error) libusb_claim_interface(dev_handle, 0);
- std::cout << " All Systems Nominal..." << std::endl << std::endl;
+ std::cout << "Initialization Process Complete."
+ << std::endl << std::endl;
+ return 0;
+ }
boost::uint8_t data_buffer[16];
memset(data_buffer, 0x0, sizeof(data_buffer));
if (vm.count("speed")){
- error_code = fx3_control_read(dev_handle, B2XX_VREQ_GET_USB,
- 0x00, 0x00, data_buffer, 1, 5000);
-
- boost::uint8_t speed = boost::lexical_cast<boost::uint8_t>(data_buffer[0]);
-
+ boost::uint8_t speed;
+ try {speed = b200->get_usb_speed();}
+ catch (uhd::exception &e) {
+ std::cerr << "Exception while getting USB speed: " << e.what() << std::endl;
+ return -1;
+ }
std::cout << "Currently operating at USB " << (int) speed << std::endl;
+ }
- } else if (vm.count("reset-device")) {
- error_code = fx3_control_write(dev_handle, B2XX_VREQ_FX3_RESET,
- 0x00, 0x00, data_buffer, 1, 5000);
+ if (vm.count("reset-device")) {
+ try {b200->reset_fx3();}
+ catch (uhd::exception &e) {
+ std::cerr << "Exception while resetting FX3: " << e.what() << std::endl;
+ return -1;
+ }
} else if (vm.count("reset-fpga")) {
- error_code = fx3_control_write(dev_handle, B2XX_VREQ_FPGA_RESET,
- 0x00, 0x00, data_buffer, 1, 5000);
-
- } else if (vm.count("load-fw")) {
- error_code = (libusb_error) fx3_load_firmware(dev_handle, fw_file);
-
- if(error_code != 0) {
- std::cerr << std::flush << "Error loading firmware. Error code: "
- << error_code << std::endl;
- libusb_release_interface(dev_handle, 0);
- libusb_close(dev_handle);
- libusb_exit(ctx);
- return ~0;
+ try {b200->set_fpga_reset_pin(true);}
+ catch (uhd::exception &e) {
+ std::cerr << "Exception while resetting FPGA: " << e.what() << std::endl;
+ return -1;
}
- std::cout << "Firmware load complete, releasing USB interface..."
- << std::endl;
-
} else if (vm.count("load-fpga")) {
- error_code = (libusb_error) load_fpga(dev_handle, fpga_file);
-
- if(error_code != 0) {
- std::cerr << std::flush << "Error loading FPGA. Error code: "
- << error_code << std::endl;
- libusb_release_interface(dev_handle, 0);
- libusb_close(dev_handle);
- libusb_exit(ctx);
+ std::cout << "Loading FPGA image (" << fpga_file << ")" << std::endl;
+ uint32_t fx3_state;
+ try {fx3_state = b200->load_fpga(fpga_file);} // returns 0 on success, or FX3 state on error
+ catch (uhd::exception &e) {
+ std::cerr << "Exception while loading FPGA: " << e.what() << std::endl;
+ return ~0;
+ }
+
+ if (fx3_state != 0) {
+ std::cerr << std::flush << "Error loading FPGA. FX3 state ("
+ << fx3_state << "): " << b200_iface::fx3_state_string(fx3_state) << std::endl;
return ~0;
}
std::cout << "FPGA load complete, releasing USB interface..."
<< std::endl;
-
- } else {
- std::cout << boost::format("B2xx Utilitiy Program %s") % desc << std::endl;
- libusb_release_interface(dev_handle, 0);
- libusb_close(dev_handle);
- libusb_exit(ctx);
- return ~0;
}
- std::cout << std::endl << "Reactor Shutting Down..." << std::endl;
-
- error_code = (libusb_error) libusb_release_interface(dev_handle, 0);
- libusb_close(dev_handle);
- libusb_exit(ctx);
+ std::cout << "Operation complete! I did it! I did it!" << std::endl;
return 0;
}
diff --git a/host/utils/uhd_images_downloader.py.in b/host/utils/uhd_images_downloader.py.in
index e7fc9e8a5..697bd4e16 100644
--- a/host/utils/uhd_images_downloader.py.in
+++ b/host/utils/uhd_images_downloader.py.in
@@ -16,117 +16,341 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-import atexit
-import hashlib
+import sys, os, string, tempfile, math
+import traceback
+import shutil, hashlib, urllib2, zipfile
+
from optparse import OptionParser
-import os
-import os.path
-import shutil
-import string
-import sys
-import tempfile
-import urllib2
-import zipfile
+
+_DEFAULT_BUFFER_SIZE = 8192
+_BASE_DIR_STRUCTURE_PARTS = ["share", "uhd", "images"]
+_BASE_DIR_STRUCTURE = os.path.join(_BASE_DIR_STRUCTURE_PARTS)
+_DEFAULT_INSTALL_PATH = os.path.join("@CMAKE_INSTALL_PREFIX@", *_BASE_DIR_STRUCTURE)
+_AUTOGEN_IMAGES_SOURCE = "@UHD_IMAGES_DOWNLOAD_SRC@"
+_AUTOGEN_IMAGES_CHECKSUM = "@UHD_IMAGES_MD5SUM@"
+_IMAGES_CHECKSUM_TYPE = "md5"
+_CONTACT = "support@ettus.com"
def md5Checksum(filePath):
- with open(filePath, 'rb') as fh:
- m = hashlib.md5()
- while True:
- data = fh.read(8192)
- if not data:
- break
- m.update(data)
- return m.hexdigest()
+ try:
+ with open(filePath, 'rb') as fh:
+ m = hashlib.md5()
+ while True:
+ data = fh.read(_DEFAULT_BUFFER_SIZE)
+ if not data:
+ break
+ m.update(data)
+ return m.hexdigest()
+ except Exception, e:
+ print "Failed to calculated MD5 sum of: %s (%s)" % (filePath, e)
+ raise e
-class temp_dir():
+_checksum_fns = {
+ 'md5': md5Checksum
+}
+class temporary_directory():
def __enter__(self):
- self.name = tempfile.mkdtemp()
- return self.name
+ try:
+ self.name = tempfile.mkdtemp()
+ return self.name
+ except Exception, e:
+ print "Failed to create a temporary directory (%s)" % (e)
+ raise e
+
+ # Can return 'True' to suppress incoming exception
def __exit__(self, type, value, traceback):
- os.removedirs(self.name)
-
-if __name__ == "__main__":
+ try:
+ shutil.rmtree(self.name)
+ except Exception, e:
+ print "Could not delete temporary directory: %s (%s)" % (self.name, e)
- #Command line options
- parser = OptionParser()
- parser.add_option("--install-location", type="string", default="", help="Set custom install location for images")
- parser.add_option("--buffer-size", type="int", default=8192, help="Set download buffer size, [default=%default]",)
- (options, args) = parser.parse_args()
+class uhd_images_downloader():
+ def __init__(self):
+ pass
- #Configuring image download info
- images_src = "@UHD_IMAGES_DOWNLOAD_SRC@"
- images_zip_md5sum = "@UHD_IMAGES_MD5SUM@"
- filename = images_src.split("/")[-1]
-
- with temp_dir() as dirname:
- os.chdir(dirname)
-
- #Configuring image destination
- if options.install_location != "":
- images_dir = options.install_location
- elif os.environ.get("UHD_IMAGES_DIR") != "" and os.environ.get("UHD_IMAGES_DIR") != None:
- images_dir = os.environ.get("UHD_IMAGES_DIR")
- else:
- images_dir = "@CMAKE_INSTALL_PREFIX@/share/uhd/images"
-
+ def download(self, images_url, filename, buffer_size=_DEFAULT_BUFFER_SIZE, print_progress=False):
opener = urllib2.build_opener()
opener.add_headers = [('User-Agent', 'UHD Images Downloader')]
- u = opener.open(images_src)
- f = open(filename, "wb")
+ u = opener.open(images_url)
meta = u.info()
filesize = float(meta.getheaders("Content-Length")[0])
- print "Downloading images from: %s" % images_src
+ filesize_dl = 0
- filesize_dl = 0.0
-
- #Downloading file
- while True:
- buffer = u.read(options.buffer_size)
- if not buffer:
- break
-
- filesize_dl -= len(buffer)
- f.write(buffer)
+ with open(filename, "wb") as f:
+ while True:
+ buffer = u.read(buffer_size)
+ if not buffer:
+ break
+
+ f.write(buffer)
- status = r"%2.2f MB/%2.2f MB (%3.2f" % (-filesize_dl/1e6, filesize/1e6, (-filesize_dl*100.)/filesize) + r"%)"
- status += chr(8)*(len(status)+1)
- print status,
+ filesize_dl += len(buffer)
+
+ if print_progress:
+ status = r"%05d kB / %05d kB (%03d%%)" % (int(math.ceil(filesize_dl/1000.)), int(math.ceil(filesize/1000.)), int(math.ceil(filesize_dl*100.)/filesize))
+ status += chr(8)*(len(status)+1)
+ print status,
- f.close()
-
- #Checking md5sum of zip file
- downloaded_zip_md5sum = md5Checksum(filename)
- if images_zip_md5sum != downloaded_zip_md5sum:
- print "\nMD5 checksum does not match!"
- print "Expected %s, got %s" % (images_zip_md5sum, downloaded_zip_md5sum)
- os.remove(filename)
- os.chdir("/".join(images_dir.split("/")[:-1]))
+ if print_progress:
+ print
+
+ return (filesize, filesize_dl)
+
+ def check_directories(self, dirs, print_progress=False):
+ if dirs is None or dirs == "":
+ dirs = "."
+ dirs = os.path.abspath(dirs)
+
+ def _check_part(head, tail=None):
+ if print_progress:
+ print "Checking: %s" % (head)
+ if tail is not None and tail == "":
+ return True
+ if not os.path.exists(head):
+ if print_progress:
+ print "Does not exist: %s" % (head)
+ return _check_part(*os.path.split(head))
+ if not os.path.isdir(head):
+ if print_progress:
+ print "Is not a directory: %s" % (head)
+ return (False, head)
+ if not os.access(head, os.W_OK):
+ if print_progress:
+ print "Write permission denied on: %s" % (head)
+ return (False, head)
+ if print_progress:
+ print "Write permission granted on: %s" % (head)
+ return (True, head)
+
+ return _check_part(dirs)
+
+ def validate_checksum(self, checksum_fn, file_path, expecting, print_progress=False):
+ if checksum_fn is None:
+ return (True, "")
+
+ calculated_checksum = checksum_fn(file_path)
+
+ if (expecting is not None) and (expecting != "") and calculated_checksum != expecting:
+ return (False, calculated_checksum)
+
+ return (True, calculated_checksum)
+
+ def extract_images_archive(self, archive_path, destination=None, print_progress=False):
+ if not os.path.exists(archive_path):
+ if print_progress:
+ print "Path does not exist: %s" % (archive_path)
+ raise Exception("path does not exist: %s" % (archive_path))
+
+ if print_progress:
+ print "Archive path: %s" % (archive_path)
+
+ (head, tail) = os.path.split(archive_path)
+
+ if not os.access(head, os.W_OK):
+ if print_progress:
+ print "Write access denied on: %s" % (head)
+ raise Exception("write access denied on: %s" % (head))
+
+ (root, ext) = os.path.splitext(tail)
+ temp_dir = os.path.join(head, root)
+
+ if print_progress:
+ print "Temporary extraction location: %s" % (temp_dir)
+
+ if os.path.exists(temp_dir):
+ if print_progress:
+ print "Deleting existing location: %s" % (temp_dir)
+ shutil.rmtree(temp_dir)
+
+ if print_progress:
+ print "Creating directory: %s" % (temp_dir)
+ os.mkdir(temp_dir)
+
+ if print_progress:
+ print "Extracting archive %s to %s" % (archive_path, temp_dir)
+
+ images_zip = zipfile.ZipFile(archive_path)
+ images_zip.extractall(temp_dir)
+ images_zip.close()
+
+ return temp_dir
+
+ def install_images(self, source, dest, keep=False, print_progress=False):
+ if not os.path.exists(source):
+ if print_progress:
+ print "Source path does not exist: %s" % (source)
+ return
+
+ if keep:
+ if print_progress:
+ print "Not wiping directory tree (existing files will be overwritten): %s" % (dest)
+ elif os.path.exists(dest):
+ if print_progress:
+ print "Deleting directory tree: %s" % (dest)
+ shutil.rmtree(dest)
+
+ (head, tail) = os.path.split(source)
+
+ if print_progress:
+ print "Source install path: %s" % (source)
+
+ uhd_source = os.path.join(source, tail, *_BASE_DIR_STRUCTURE_PARTS)
+
+ if print_progress:
+ print "Copying files from: %s" % (uhd_source)
+ print "Copying files to: %s" % (dest)
+
+ if keep:
+ # mgrant @ http://stackoverflow.com/questions/12683834/how-to-copy-directory-recursively-in-python-and-overwrite-all
+ def _recursive_overwrite(src, dest, ignore=None):
+ if os.path.isdir(src):
+ if not os.path.isdir(dest):
+ os.makedirs(dest)
+ files = os.listdir(src)
+ if ignore is not None:
+ ignored = ignore(src, files)
+ else:
+ ignored = set()
+ for f in files:
+ if f not in ignored:
+ _recursive_overwrite(os.path.join(src, f), os.path.join(dest, f), ignore)
+ else:
+ shutil.copyfile(src, dest)
+
+ _recursive_overwrite(uhd_source, dest)
else:
- #Extracting contents of zip file
- if os.path.exists("tempdir"):
- shutil.rmtree("tempdir")
- os.mkdir("tempdir")
-
- images_zip = zipfile.ZipFile(filename)
- images_zip.extractall("tempdir")
+ shutil.copytree(uhd_source, dest)
- #Removing images currently in images_dir
- if os.path.exists(images_dir):
- try:
- shutil.rmtree(images_dir)
- except:
- sys.stderr.write("\nMake sure you have write permissions in the images directory.\n")
- sys.exit(0)
-
- #Copying downloaded images into images_dir
- shutil.copytree("tempdir/%s/share/uhd/images" % filename[:-4],images_dir)
-
- #Removing tempdir and zip file
- shutil.rmtree("tempdir")
- images_zip.close()
- os.remove(filename)
+def main():
+ if os.environ.get("UHD_IMAGES_DIR") != None and os.environ.get("UHD_IMAGES_DIR") != "":
+ default_images_dir = os.environ.get("UHD_IMAGES_DIR")
+ print "UHD_IMAGES_DIR environment variable is set. Default install location: %s" % default_images_dir
+ else:
+ default_images_dir = _DEFAULT_INSTALL_PATH
+
+ parser = OptionParser()
+ parser.add_option("-i", "--install-location", type="string", default=default_images_dir,
+ help="Set custom install location for images [default=%default]")
+ parser.add_option("--buffer-size", type="int", default=_DEFAULT_BUFFER_SIZE,
+ help="Set download buffer size [default=%default]")
+ parser.add_option("-u", "--url", type="string", default=_AUTOGEN_IMAGES_SOURCE,
+ help="Set images download location [default=%default]")
+ parser.add_option("-c", "--checksum", type="string", default=_AUTOGEN_IMAGES_CHECKSUM,
+ help="Validate images archive against this checksum (blank to skip) [default=%default]")
+ parser.add_option("-t", "--checksum-type", type="string", default=_IMAGES_CHECKSUM_TYPE,
+ help=("Select checksum hash function (options: %s) [default=%%default]" % (",".join(_checksum_fns.keys()))))
+ parser.add_option("-k", "--keep", action="store_true", default=False,
+ help="Do not clear images directory before extracting new files [default=%default]")
+ parser.add_option("-v", "--verbose", action="store_true", default=False,
+ help="Enable verbose output [default=%default]")
+
+ (options, args) = parser.parse_args()
+
+ if options.buffer_size <= 0:
+ print "Invalid buffer size: %s" % (options.buffer_size)
+ return 1
+
+ checksum_fn = None
+ if options.checksum != "":
+ options.checksum_type = options.checksum_type.lower()
+ if not _checksum_fns.has_key(options.checksum_type):
+ print "Not a supported checksum function: %s" % (options.checksum_type)
+ return 1
+ checksum_fn = _checksum_fns[options.checksum_type]
+
+ url_parts = options.url.split("/")
+ if len(url_parts) <= 1 or url_parts[-1] == "":
+ print "Not a valid URL: %s" % (options.url)
+ return 1
+ images_filename = url_parts[-1]
+
+ images_dir = os.path.abspath(options.install_location) # This will use the current working directory if it's not absolute
+
+ if options.verbose:
+ print "Requested install location: %s" % (options.install_location)
+ print "Images source: %s" % (options.url)
+ print "Images filename: %s" % (images_filename)
+ print "Images checksum: %s (%s)" % (options.checksum, _IMAGES_CHECKSUM_TYPE)
+ print "Final install location: %s" % (images_dir)
+ else:
+ print "Images destination: %s" % (images_dir)
+
+ downloader = uhd_images_downloader()
+
+ try:
+ (access, last_path) = downloader.check_directories(images_dir, print_progress=options.verbose)
+ if access:
+ with temporary_directory() as temp_dir:
+ if options.verbose:
+ print "Using temporary directory: %s" % (temp_dir)
+
+ print "Downloading images from: %s" % options.url
+
+ temp_images_dest = os.path.join(temp_dir, images_filename)
+
+ print "Downloading images to: %s" % (temp_images_dest)
+
+ (reported_size, downloaded_size) = downloader.download(images_url=options.url, filename=temp_images_dest, buffer_size=options.buffer_size, print_progress=True)
+
+ if options.verbose:
+ print "Downloaded %d of %d bytes" % (downloaded_size, reported_size)
+
+ (checksum_match, calculated_checksum) = downloader.validate_checksum(checksum_fn, temp_images_dest, options.checksum, print_progress=options.verbose)
+
+ if options.verbose:
+ print "Calculated checksum: %s" % (calculated_checksum)
+
+ if checksum_match:
+ if options.verbose:
+ if options.checksum == "":
+ print "Ignoring checksum"
+ else:
+ print "Checksum OK"
+
+ try:
+ extract_path = downloader.extract_images_archive(temp_images_dest, print_progress=options.verbose)
+
+ if options.verbose:
+ print "Image archive extracted to: %s" % (extract_path)
+
+ downloader.install_images(extract_path, images_dir, options.keep, print_progress=options.verbose)
+
+ print
+ print "Images successfully installed to: %s" % (images_dir)
+ except Exception, e:
+ print "Failed to install image archive: %s" % (e)
+ print "This is usually a permissions problem."
+ print "Please check your file system access rights and try again."
+
+ if options.verbose:
+ traceback.print_exc()
+ else:
+ print "You can run this again with the '--verbose' flag to see more information"
+ print "If the problem persists, please email the output to: %s" % (_CONTACT)
+ else:
+ print "Checksum of downloaded file is not correct (not installing - see options to override)"
+ print "Expected: %s" % (options.checksum)
+ print "Calculated: %s" % (calculated_checksum)
+ print "Please try downloading again."
+ print "If the problem persists, please email the output to: %s" % (_CONTACT)
+ else:
+ print "You do not have sufficient permissions to write to: %s" % (last_path)
+ print "Are you root?"
+ except KeyboardInterrupt:
+ print
+ print "Cancelled at user request"
+ except Exception, e:
+ print "Downloader raised an unhandled exception: %s" % (e)
+ if options.verbose:
+ traceback.print_exc()
+ else:
+ print "You can run this again with the '--verbose' flag to see more information"
+ print "If the problem persists, please email the output to: %s" % (_CONTACT)
+ return 1
+
+ return 0
- os.chdir(images_dir)
- print "\nImages successfully installed to: %s" % images_dir
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/host/utils/usrp_burn_mb_eeprom.cpp b/host/utils/usrp_burn_mb_eeprom.cpp
index 1b13fb615..ce0879c8e 100644
--- a/host/utils/usrp_burn_mb_eeprom.cpp
+++ b/host/utils/usrp_burn_mb_eeprom.cpp
@@ -1,5 +1,5 @@
//
-// Copyright 2010 Ettus Research LLC
+// Copyright 2010,2013 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
@@ -19,9 +19,11 @@
#include <uhd/device.hpp>
#include <uhd/property_tree.hpp>
#include <uhd/usrp/mboard_eeprom.hpp>
+#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <iostream>
+#include <vector>
namespace po = boost::program_options;
@@ -32,8 +34,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
desc.add_options()
("help", "help message")
("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]")
- ("key", po::value<std::string>(&key), "the indentifier for a value in EEPROM")
- ("val", po::value<std::string>(&val), "the new value to set, omit for readback")
+ ("key", po::value<std::string>(&key), "identifiers for new values in EEPROM, separate multiple by \",\"")
+ ("val", po::value<std::string>(&val), "the new values to set, omit for readback, separate multiple by \",\"")
;
po::variables_map vm;
@@ -55,20 +57,35 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
uhd::property_tree::sptr tree = dev->get_tree();
std::cout << std::endl;
- if (true /*always readback*/){
- std::cout << "Fetching current settings from EEPROM..." << std::endl;
- uhd::usrp::mboard_eeprom_t mb_eeprom = tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").get();
- if (not mb_eeprom.has_key(key)){
- std::cerr << boost::format("Cannot find value for EEPROM[%s]") % key << std::endl;
+ //remove whitespace, split arguments and values
+ boost::algorithm::erase_all(key, " ");
+ boost::algorithm::erase_all(val, " ");
+
+ std::vector<std::string> keys_vec, vals_vec;
+ boost::split(keys_vec, key, boost::is_any_of("\"',"));
+ boost::split(vals_vec, val, boost::is_any_of("\"',"));
+
+ if((keys_vec.size() != vals_vec.size()) and val != "") {
+ //If zero values are given, then user just wants values read to them
+ throw std::runtime_error("Number of keys must match number of values!");
+ }
+
+ std::cout << "Fetching current settings from EEPROM..." << std::endl;
+ uhd::usrp::mboard_eeprom_t mb_eeprom = tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").get();
+ for(size_t i = 0; i < keys_vec.size(); i++){
+ if (not mb_eeprom.has_key(keys_vec[i])){
+ std::cerr << boost::format("Cannot find value for EEPROM[%s]") % keys_vec[i] << std::endl;
return EXIT_FAILURE;
}
- std::cout << boost::format(" EEPROM [\"%s\"] is \"%s\"") % key % mb_eeprom[key] << std::endl;
- std::cout << std::endl;
+ std::cout << boost::format(" EEPROM [\"%s\"] is \"%s\"") % keys_vec[i] % mb_eeprom[keys_vec[i]] << std::endl;
}
+ std::cout << std::endl;
if (vm.count("val")){
- uhd::usrp::mboard_eeprom_t mb_eeprom; mb_eeprom[key] = val;
- std::cout << boost::format("Setting EEPROM [\"%s\"] to \"%s\"...") % key % val << std::endl;
- tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").set(mb_eeprom);
+ for(size_t i = 0; i < vals_vec.size(); i++){
+ uhd::usrp::mboard_eeprom_t mb_eeprom; mb_eeprom[keys_vec[i]] = vals_vec[i];
+ std::cout << boost::format("Setting EEPROM [\"%s\"] to \"%s\"...") % keys_vec[i] % vals_vec[i] << std::endl;
+ tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").set(mb_eeprom);
+ }
std::cout << "Power-cycle the USRP device for the changes to take effect." << std::endl;
std::cout << std::endl;
}
diff --git a/host/utils/usrp_n2xx_simple_net_burner.cpp b/host/utils/usrp_n2xx_simple_net_burner.cpp
index c3ccba173..1898ee9ae 100644
--- a/host/utils/usrp_n2xx_simple_net_burner.cpp
+++ b/host/utils/usrp_n2xx_simple_net_burner.cpp
@@ -468,13 +468,21 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
std::cout << "Searching for specified images." << std::endl << std::endl;
if(burn_fpga){
if(!use_custom_fpga) fpga_path = find_image_path(default_fpga_filename);
- else validate_custom_fpga_file(filename_map[hw_rev], fpga_path);
+ else{
+ //Replace ~ with home directory
+ if(fpga_path.find("~/") == 0) fpga_path.replace(0,1,getenv("HOME"));
+ validate_custom_fpga_file(filename_map[hw_rev], fpga_path);
+ }
grab_fpga_image(fpga_path);
}
if(burn_fw){
if(!use_custom_fw) fw_path = find_image_path(default_fw_filename);
- else validate_custom_fw_file(filename_map[hw_rev], fw_path);
+ else{
+ //Replace ~ with home directory
+ if(fw_path.find("~/") == 0) fw_path.replace(0,1,getenv("HOME"));
+ validate_custom_fw_file(filename_map[hw_rev], fw_path);
+ }
grab_fw_image(fw_path);
}